void calculateJacobian(const arma::Mat<std::complex<double> >& myOffsets, arma::Mat<double>& myJacobian, arma::Col<std::complex<double> >& myTargetsCalculated, arma::Col<std::complex<double> >& myCurrentGuess, void myCalculateDependentVariables(const arma::Mat<std::complex<double> >&, const arma::Col<std::complex<double> >&, arma::Col<std::complex<double> >&)) { //Calculate a temporary, unperturbed target evaluation, such as is needed for solving for the updated guess //formula arma::Col<std::complex<double> > unperturbedTargetsCalculated(NUMDIMENSIONS); unperturbedTargetsCalculated.fill(0.0); myCalculateDependentVariables(myOffsets, myCurrentGuess, unperturbedTargetsCalculated); std::complex<double> oldGuessValue(0.0, 0.0); //Each iteration fills a column in the Jacobian //The Jacobian takes this form: // // dF0/dx0 dF0/dx1 // dF1/dx0 dF1/dx1 // for(int j = 0; j< NUMDIMENSIONS; j++) { //Store old element value, perturb the current value oldGuessValue = myCurrentGuess[j]; myCurrentGuess[j] += std::complex<double>(0.0, PROBEDISTANCE); //Evaluate functions for perturbed guess myCalculateDependentVariables(myOffsets, myCurrentGuess, myTargetsCalculated); //The column of the Jacobian that goes with the independent variable we perturbed //can be determined using the finite-difference formula //The arma::Col allows this to be expressed as a single vector operation //note slice works as: std::slice(start_index, number_of_elements_to_access, index_interval_between_selections) //std::cout << "Jacobian column " << j << " with:" << std::endl; //std::cout << "myTargetsCalculated" << std::endl; //std::cout << myTargetsCalculated << std::endl; //std::cout << "unperturbedTargetsCalculated" << std::endl; //std::cout << unperturbedTargetsCalculated << std::endl; myJacobian.col(j) = arma::imag(myTargetsCalculated); myJacobian.col(j) *= pow(PROBEDISTANCE, -1.0); //std::cout << "The jacobian: " << std::endl; //std::cout << myJacobian << std::endl; myCurrentGuess[j] = oldGuessValue; } //Reset to unperturbed, so we dont waste a function evaluation myTargetsCalculated = unperturbedTargetsCalculated; }
void calculateJacobian(const Teuchos::SerialDenseMatrix<int, std::complex<double> >& myOffsets, Teuchos::SerialDenseMatrix<int, std::complex<double> >& myJacobian, Teuchos::SerialDenseVector<int, std::complex<double> >& myTargetsCalculated, Teuchos::SerialDenseVector<int, std::complex<double> >& myUnperturbedTargetsCalculated, Teuchos::SerialDenseVector<int, std::complex<double> >& myCurrentGuess, void myCalculateDependentVariables(const Teuchos::SerialDenseMatrix<int, std::complex<double> >&, const Teuchos::SerialDenseVector<int, std::complex<double> >&, Teuchos::SerialDenseVector<int, std::complex<double> >&) ) { //Calculate a temporary, unperturbed target evaluation, such as is needed for the finite-difference //formula myCalculateDependentVariables(myOffsets, myCurrentGuess, myUnperturbedTargetsCalculated); std::complex<double> oldGuessValue; //Each iteration fills a column in the Jacobian //The Jacobian takes this form: // // dF0/dx0 dF0/dx1 // dF1/dx0 dF1/dx1 // // for(int column = 0; column< NUMDIMENSIONS; column++) { //Store old element value, perturb the current value oldGuessValue = myCurrentGuess[column]; myCurrentGuess[column] += std::complex<double>(0.0, PROBEDISTANCE); //Evaluate functions for perturbed guess myCalculateDependentVariables(myOffsets, myCurrentGuess, myTargetsCalculated); myTargetsCalculated *= pow(PROBEDISTANCE, -1.0); for(int row = 0; row < NUMDIMENSIONS; row ++) { myJacobian(row, column) = std::imag(myTargetsCalculated[row]); } myCurrentGuess[column] = oldGuessValue; } //Reset to unperturbed, so we dont waste a function evaluation myTargetsCalculated = myUnperturbedTargetsCalculated; }