int main(int argc, char* argv[])
{
	//--This first declaration is included for software engineering reasons: allow main method to control flow of data
	//create function pointer for calculateDependentVariable
	//We want to do this so that calculateJacobian can call calculateDependentVariables as it needs to,
	//but we explicitly give it this authority from the main method
	void (*yourCalculateDependentVariables)(const Teuchos::SerialDenseMatrix<int, std::complex<double> >&, const Teuchos::SerialDenseVector<int, std::complex<double> >&, Teuchos::SerialDenseVector<int, std::complex<double> >&);
	yourCalculateDependentVariables = &calculateDependentVariables;

	//Create an object to allow access to LAPACK using a library found in Trilinos
	//
	Teuchos::LAPACK<int, std::complex<double> > Teuchos_LAPACK_Object;	

	//The problem being solved is to find the intersection of three infinite paraboloids:
	//(x-1)^2 + y^2 + z = 0
	//x^2 + y^2 -(z+1) = 0
	//x^2 + y^2 +(z-1) = 0
	//
	//They should intersect at the point (1, 0, 0)
	Teuchos::SerialDenseMatrix<int, std::complex<double> > offsets(NUMDIMENSIONS, NUMDIMENSIONS); 
	offsets(0,0) = 1.0;
	offsets(1,2) = 1.0;
	offsets(2,2) = 1.0;

	//We need to initialize the target vectors and provide an initial guess
	Teuchos::SerialDenseVector<int, std::complex<double> > targetsDesired(NUMDIMENSIONS);
	Teuchos::SerialDenseVector<int, std::complex<double> > targetsCalculated(NUMDIMENSIONS);
	Teuchos::SerialDenseVector<int, std::complex<double> > unperturbedTargetsCalculated(NUMDIMENSIONS);
	Teuchos::SerialDenseVector<int, std::complex<double> > currentGuess(NUMDIMENSIONS);
	Teuchos::SerialDenseVector<int, std::complex<double> > guessAdjustment(NUMDIMENSIONS);

	currentGuess[0] = 2.0;
	currentGuess[1] = 1.0;
	currentGuess[2] = 1.0;
	//Place to store our tangent-stiffness matrix or Jacobian
	//One element for every combination of dependent variable with independent variable
	Teuchos::SerialDenseMatrix<int, std::complex<double> > jacobian(NUMDIMENSIONS, NUMDIMENSIONS);

	int count = 0;
	double error = 1.0E5;

	std::cout << "Running Forward Difference Example" << std::endl;
	while(count < MAXITERATIONS and error > ERRORTOLLERANCE)
	{


		//Calculate Jacobian tangent to currentGuess point
		//at the same time, an unperturbed targetsCalculated is, well, calculated
		calculateJacobian(offsets,
				  jacobian,
				  targetsCalculated,
				  unperturbedTargetsCalculated,
				  currentGuess,
                                  yourCalculateDependentVariables);


		//Compute a guessChange and immediately set the currentGuess equal to the guessChange
 		updateGuess(currentGuess,
			    targetsCalculated,
			    jacobian,
			    Teuchos_LAPACK_Object);


		//Compute F(x) with the updated, currentGuess
		calculateDependentVariables(offsets,
				            currentGuess,
			       		    targetsCalculated);	


		//Calculate the L2 norm of Ftarget - F(xCurrentGuess)
		calculateResidual(targetsDesired,
			          targetsCalculated,
			  	  error);	  


		count ++;
		//If we have converged, or if we have exceeded our alloted number of iterations, discontinue the loop
		std::cout << "Residual Error: " << error << std::endl;
	}
	
	std::cout << "******************************************" << std::endl;
	std::cout << "Number of iterations: " << count << std::endl;
	std::cout << "Final guess:\n x, y, z\n " << currentGuess[0] << ", " << currentGuess[1] << ", " << currentGuess[2] << std::endl;
	std::cout << "Error tollerance: " << ERRORTOLLERANCE << std::endl;
	std::cout << "Final error: " << error << std::endl;
	std::cout << "--program complete--" << std::endl;

	return 0;
}
int main(int argc, char* argv[])
{
	//--This first declaration is included for software engineering reasons: allow main method to control flow of data
	//create function pointer for calculateDependentVariable
	//We want to do this so that calculateJacobian can call calculateDependentVariables as it needs to,
	//but we explicitly give it this authority from the main method
	void (*yourCalculateDependentVariables)(const arma::Mat<std::complex<double> >&, const arma::Col<std::complex<double> >&, arma::Col<std::complex<double> >&);
	yourCalculateDependentVariables = &calculateDependentVariables;

	//The problem being solved is to find the intersection of three infinite paraboloids:
	//(x-1)^2 + y^2 + z = 0
	//x^2 + y^2 -(z+1) = 0
	//x^2 + y^2 +(z-1) = 0
	//
	//They should intersect at the point (1, 0, 0)
	arma::Mat<std::complex<double> > offsets(NUMDIMENSIONS, NUMDIMENSIONS); 
	offsets.fill(0.0);
	offsets.col(0)[0] = 1.0;
	offsets.col(2)[1] = 1.0;
	offsets.col(2)[2] = 1.0;

	//We need to initialize the target vectors and provide an initial guess
	arma::Col<std::complex<double> > targetsDesired(NUMDIMENSIONS);
	targetsDesired.fill(0.0);

	arma::Col<std::complex<double> > targetsCalculated(NUMDIMENSIONS);
	targetsCalculated.fill(0.0);

	arma::Col<double> realTargetsCalculated(NUMDIMENSIONS);
	realTargetsCalculated.fill(0.0);

	arma::Col<std::complex<double> > currentGuess(NUMDIMENSIONS);
	currentGuess.fill(2.0);

	//Place to store our tangent-stiffness matrix or Jacobian
	//One element for every combination of dependent variable with independent variable
	arma::Mat<double> jacobian(NUMDIMENSIONS, NUMDIMENSIONS);
	jacobian.fill(0.0);

	int count = 0;
	double error = 1.0E5;

	std::cout << "Running complex step example ................" << std::endl;
	while(count < MAXITERATIONS and error > ERRORTOLLERANCE)
	{

		//Calculate Jacobian tangent to currentGuess point
		//at the same time, an unperturbed targetsCalculated is, well, calculated
		calculateJacobian(offsets,
				  jacobian,
				  targetsCalculated,
				  currentGuess,
                                  yourCalculateDependentVariables);

		//Compute a new currentGuess 
		updateGuess(currentGuess,
			    realTargetsCalculated,
			    targetsCalculated,
			    jacobian);

		//Compute F(x) with the updated, currentGuess
		calculateDependentVariables(offsets,
				            currentGuess,
			       		    targetsCalculated);	

		//Calculate the L2 norm of Ftarget - F(xCurrentGuess)
		calculateResidual(targetsDesired,
			          targetsCalculated,
			  	  error);	  

		count ++;
		//If we have converged, or if we have exceeded our alloted number of iterations, discontinue the loop
		std::cout << "Residual Error: " << error << std::endl;
	}
	
	std::cout << "******************************************" << std::endl;
	std::cout << "Number of iterations: " << count << std::endl;
	std::cout << "Final guess:\n x, y, z\n" << arma::real(currentGuess.t());
	std::cout << "Error tollerance: " << ERRORTOLLERANCE << std::endl;
	std::cout << "Final error: " << error << std::endl;
	std::cout << "--program complete--" << std::endl;

	return 0;
}