public void CheckHessianDeterminantsTests() { var func = new FunctionDefinition("f(x1,x2) = x1^2 +x2^2"); var point = new Point(5, 4); var StatCondition = Hessian.ChceckHessianDeterminants(func, point); Assert.AreEqual(Hessian.StationaryConditions.Minimum, StatCondition); }
public virtual IObjectiveFunction Fork() { // we need to deep-clone values since they may be updated inplace on evaluation ObjectiveFunctionBase objective = (ObjectiveFunctionBase)CreateNew(); objective.Point = Point == null ? null : Point.Clone(); objective.Value = Value; objective.Gradient = Gradient == null ? null : Gradient.Clone(); objective.Hessian = Hessian == null ? null : Hessian.Clone(); return(objective); }
public void CalculateHessianTests(double p1, double p2, double p3, double result) { var func = new FunctionDefinition("f(x1, x2, x3) = x1^3 + 2 * x2 * x3^2 + x3 * x2 + x3^3"); var point = new Point(p1, p2, p3); var der = Hessian.CalculateHessian(func, point); if (Math.Abs(der[0, 0] - result) < 0.0001 && Math.Abs(der[1, 2] - 5) < 0.0001) { Assert.Pass(); } else { Assert.AreEqual(result, der); } }
private void CalculateMinimum() { try { StartCalculating(); var value = Variables.Select(v => v.Value).ToArray(); var x0 = new Point(value); var NS = new FastestFallAlgorithm(_functionDefinition, x0, InputParameters.Beta, InputParameters.Tau, InputParameters.LIteration, InputParameters.Epsilon1, InputParameters.Epsilon2, InputParameters.Epsilon3); calcucatedPoints = NS.Run(); var result = calcucatedPoints.Last(); var hessianResult = Hessian.ChceckHessianDeterminants(_functionDefinition, result, InputParameters.Epsilon1); UpdateDataTable(calcucatedPoints); if (hessianResult == Hessian.StationaryConditions.Minimum) { _messageDialogService.ShowInfoDialog($"Znaleziono minimum lokalne w punkcie : {result} \nWartość : { _functionDefinition.GetValue(result)}"); } if (hessianResult != Hessian.StationaryConditions.Minimum) { _messageDialogService.ShowInfoDialog($"Obliczono resultat, który nie jest minimum lokalnym w punkcie : {result} \nWartość : { _functionDefinition.GetValue(result)}"); } } catch (InvalidTauException) { _messageDialogService.ShowInfoDialog("Nie można obliczyć minimum dla podaego tau. Podaj inny parametr"); } catch (UnfortunateFunctionCaseException fex) { calcucatedPoints = fex.Points; UpdateDataTable(fex.Points); var lastPoint = fex.Points.Last(); _messageDialogService.ShowInfoDialog($"Algorytm zakończył działanie z powodu zbyt dużej ilości obliczeń. \nOstatni obliczony punkt wynosi : {lastPoint} \nWartość : { _functionDefinition.GetValue(lastPoint)}"); } catch (Exception ex) { _messageDialogService.ShowInfoDialog(ex.ToString()); } }
public void Hessian___Gradient___Calculation___Test() { int accuracy = 15; /* * function obliczanie_hesjan_gradient() * clear(); * inp = [-1 -1;-1 1; 1 -1]; * dout = [1;0;0]; * topo = [3 1 2 4 1 2 3]; * ww = [1 1 1 1 1 1 1]; * act = [2 0]; * gain = [1 1]; * param = [3 2 1 7 2]; * iw = [1 4 8]; * format long; * * [gradient,hessian] = Hessian(inp,dout,topo,ww,act,gain,param,iw); * fprintf('Otrzymany gradient:\n'); * disp(gradient); * fprintf('\nOtrzymany hesjan:\n'); * disp(hessian); * * % To jest otrzymywane * % Otrzymany gradient: * % -0.839948683228052 * % 2.319597374905329 * % 2.319597374905329 * % -2.000000000000000 * % 5.523188311911530 * % 5.523188311911531 * % 6.889667569278484 * % * % * % Otrzymany hesjan: * % Columns 1 through 6 * % * % 1.058270685684809 -0.705513790456539 -0.705513790456539 2.519846049684157 -1.679897366456105 -1.679897366456105 * % -0.705513790456539 1.058270685684809 0.352756895228269 -1.679897366456105 2.519846049684157 0.839948683228052 * % -0.705513790456539 0.352756895228269 1.058270685684809 -1.679897366456105 0.839948683228052 2.519846049684157 * % 2.519846049684157 -1.679897366456105 -1.679897366456105 6.000000000000000 -4.000000000000000 -4.000000000000000 * % -1.679897366456105 2.519846049684157 0.839948683228052 -4.000000000000000 6.000000000000000 2.000000000000000 * % -1.679897366456105 0.839948683228052 2.519846049684157 -4.000000000000000 2.000000000000000 6.000000000000000 * % -0.639700008449225 1.279400016898449 1.279400016898449 -1.523188311911530 3.046376623823059 3.046376623823059 * % * % Column 7 * % * % -0.639700008449225 * % 1.279400016898449 * % 1.279400016898449 * % -1.523188311911530 * % 3.046376623823059 * % 3.046376623823059 * % 3.480153950315843 * end */ Input input = new Input(3, 2);//inp = [-1 -1;-1 1; 1 -1]; input[0, 0] = -1; input[0, 1] = -1; input[1, 0] = -1; input[1, 1] = 1; input[2, 0] = 1; input[2, 1] = -1; Output output = new Output(3, 1);//dout = [1;0;0]; output[0, 0] = 1; output[1, 0] = 0; output[2, 0] = 0; NetworkInfo info = new NetworkInfo();//param = [3 2 1 7 2]; info.ni = 2; info.nn = 2; info.no = 1; info.np = 3; info.nw = 7; VectorHorizontal vh = new VectorHorizontal(3); vh[0, 0] = 2; vh[0, 1] = 1; vh[0, 2] = 1; Topography topo = Topography.Generate(TopographyType.BMLP, vh);//topo = [3 1 2 4 1 2 3]; //w C# indeksy są od zera a nie od 1 więc wszystko o 1 w dół przestawione jest Assert.AreEqual(2, topo[0]); Assert.AreEqual(0, topo[1]); Assert.AreEqual(1, topo[2]); Assert.AreEqual(3, topo[3]); Assert.AreEqual(0, topo[4]); Assert.AreEqual(1, topo[5]); Assert.AreEqual(2, topo[6]); Weights weights = new Weights(info.nw); //w = [1 1 1 1 1 1 1]; weights.FillWithNumber(1); //załatwione Activation act = new Activation(2); //act = [2 0]; act[0] = 2; act[1] = 0; Gain gain = new Gain(2);//gain = [1 1]; gain[0] = 1; gain[1] = 1; Index iw = Index.Find(ref topo);//iw = [1 4 8]; //ta sama sytuacja, indeksy od 0 startują Assert.AreEqual(0, iw[0]); Assert.AreEqual(3, iw[1]); Assert.AreEqual(7, iw[2]); Console.WriteLine("Testowanie obliczania gradientu i macierzy hesjana"); Console.WriteLine("Użyte dane:"); Console.WriteLine("\nDane wejściowe:"); Console.WriteLine(input.MatrixToString()); Console.WriteLine("\nDane wyjściowe:"); Console.WriteLine(output.MatrixToString()); Console.WriteLine("\nWagi;"); Console.WriteLine(weights.MatrixToString()); Console.WriteLine("\nTopologia:"); Console.WriteLine(topo.MatrixToString()); Console.WriteLine("\nIndeksy topologii:"); Console.WriteLine(iw.MatrixToString()); Console.WriteLine("\nFunkcje aktywacji:"); Console.WriteLine(act.MatrixToString()); Console.WriteLine("\nWzmocnienia (gains):"); Console.WriteLine(gain.MatrixToString()); Console.WriteLine("\nParametry (param):"); Console.WriteLine(info.ToString()); Hessian hess = new Hessian(ref info); hess.Compute(ref info, ref input, ref output, ref topo, weights, ref act, ref gain, ref iw); var g = hess.GradientMat; var h = hess.HessianMat; Console.WriteLine("\nSprawdzanie gradientu z dokładnością do 15 miejsc po przecinku"); var matG = new double[] { -0.839948683228052, 2.319597374905329, 2.319597374905329, -2.000000000000000, 5.523188311911530, 5.523188311911531, 6.889667569278484 }; /* * % Otrzymany gradient: * % -0.839948683228052 * % 2.319597374905329 * % 2.319597374905329 * % -2.000000000000000 * % 5.523188311911530 * % 5.523188311911531 * % 6.889667569278484 */ for (int i = 0; i < matG.Length; i++) { Console.WriteLine(string.Format("NBN C#: {0}\tMatLab NBN: {1}\t{2}", Math.Round(g[i, 0], accuracy), matG[i], Math.Round(g[i, 0], accuracy) == matG[i] ? "OK" : "źle")); } Assert.AreEqual(-0.839948683228052, Math.Round(g[0, 0], accuracy)); Assert.AreEqual(2.319597374905329, Math.Round(g[1, 0], accuracy)); Assert.AreEqual(2.319597374905329, Math.Round(g[2, 0], accuracy)); Assert.AreEqual(-2.000000000000000, Math.Round(g[3, 0], accuracy)); Assert.AreEqual(5.523188311911530, Math.Round(g[4, 0], accuracy)); Assert.AreEqual(5.523188311911531, Math.Round(g[5, 0], accuracy)); Assert.AreEqual(6.889667569278484, Math.Round(g[6, 0], accuracy)); Console.WriteLine("\nSprawdzanie macierzy hesjana\nPorównania z dokładnością do 15 miejsc po przecinku"); MatrixMB matH = new MatrixMB(7, 7); //col 1 matH[0, 0] = 1.058270685684809; matH[1, 0] = -0.705513790456539; matH[2, 0] = -0.705513790456539; matH[3, 0] = 2.519846049684157; matH[4, 0] = -1.679897366456105; matH[5, 0] = -1.679897366456105; matH[6, 0] = -0.639700008449225; //col 2 matH[0, 1] = -0.705513790456539; matH[1, 1] = 1.058270685684809; matH[2, 1] = 0.352756895228269; matH[3, 1] = -1.679897366456105; matH[4, 1] = 2.519846049684157; matH[5, 1] = 0.839948683228052; matH[6, 1] = 1.279400016898449; //col 3 matH[0, 2] = -0.705513790456539; matH[1, 2] = 0.352756895228269; matH[2, 2] = 1.058270685684809; matH[3, 2] = -1.679897366456105; matH[4, 2] = 0.839948683228052; matH[5, 2] = 2.519846049684157; matH[6, 2] = 1.279400016898449; //col 4 matH[0, 3] = 2.519846049684157; matH[1, 3] = -1.679897366456105; matH[2, 3] = -1.679897366456105; matH[3, 3] = 6.000000000000000; matH[4, 3] = -4.000000000000000; matH[5, 3] = -4.000000000000000; matH[6, 3] = -1.523188311911530; //col 5 matH[0, 4] = -1.679897366456105; matH[1, 4] = 2.519846049684157; matH[2, 4] = 0.839948683228052; matH[3, 4] = -4.000000000000000; matH[4, 4] = 6.000000000000000; matH[5, 4] = 2.000000000000000; matH[6, 4] = 3.046376623823059; //col 6 matH[0, 5] = -1.679897366456105; matH[1, 5] = 0.839948683228052; matH[2, 5] = 2.519846049684157; matH[3, 5] = -4.000000000000000; matH[4, 5] = 2.000000000000000; matH[5, 5] = 6.000000000000000; matH[6, 5] = 3.046376623823059; //col 7 matH[0, 6] = -0.639700008449225; matH[1, 6] = 1.279400016898449; matH[2, 6] = 1.279400016898449; matH[3, 6] = -1.523188311911530; matH[4, 6] = 3.046376623823059; matH[5, 6] = 3.046376623823059; matH[6, 6] = 3.480153950315843; for (int k = 0; k < h.Cols; k++) { Console.WriteLine(string.Format("Kolumna {0}", k + 1)); for (int w = 0; w < h.Rows; w++) { decimal dh = Math.Round((decimal)h[w, k], accuracy); decimal dmh = Math.Round((decimal)matH[w, k], accuracy); Console.WriteLine(string.Format("NBN C#: {0}\tMatLab NBN: {1}\t{2}", dh, dmh, dh == dmh ? "OK" : "źle")); } Console.WriteLine(""); } for (int k = 0; k < h.Cols; k++) { for (int w = 0; w < h.Rows; w++) { decimal dh = Math.Round((decimal)h[w, k], accuracy); decimal dmh = Math.Round((decimal)matH[w, k], accuracy); Assert.AreEqual(dmh, dh); } } /* * % Otrzymany hesjan: * % Columns 1 through 6 * % * % 1.058270685684809 -0.705513790456539 -0.705513790456539 2.519846049684157 -1.679897366456105 -1.679897366456105 * % -0.705513790456539 1.058270685684809 0.352756895228269 -1.679897366456105 2.519846049684157 0.839948683228052 * % -0.705513790456539 0.352756895228269 1.058270685684809 -1.679897366456105 0.839948683228052 2.519846049684157 * % 2.519846049684157 -1.679897366456105 -1.679897366456105 6.000000000000000 -4.000000000000000 -4.000000000000000 * % -1.679897366456105 2.519846049684157 0.839948683228052 -4.000000000000000 6.000000000000000 2.000000000000000 * % -1.679897366456105 0.839948683228052 2.519846049684157 -4.000000000000000 2.000000000000000 6.000000000000000 * % -0.639700008449225 1.279400016898449 1.279400016898449 -1.523188311911530 3.046376623823059 3.046376623823059 * % * % Column 7 * % * % -0.639700008449225 * % 1.279400016898449 * % 1.279400016898449 * % -1.523188311911530 * % 3.046376623823059 * % 3.046376623823059 * % 3.480153950315843 */ }
public FunctionWrapper(Function function, Gradients gradient, Hessian hessian = null) { _function = function; _gradient = gradient; _hessian = hessian; }
public void FitLM(Multiplet exp, out string MSG, out string LATEX) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); //Matrix<double> Grad; Matrix <double> Hessiandiag; Matrix <double> parameters = Matrix <double> .Build.Dense(3, 1); Matrix <double> newparams;// = Matrix<double>.Build.Dense(3, 1); //Vector<double> error;// = Vector<double>.Build.Dense(3); LATEX = ""; parameters[0, 0] = exp.o2; parameters[1, 0] = exp.o4; parameters[2, 0] = exp.o6; double no2, no4, no6, sumfexp, sumdfexp; double lambda, chi2s, chi2n; lambda = 1 / 1024.0; sumdfexp = 0; sumfexp = 0; // chi2s = 0; chi2n = 0; Hessiandiag = Matrix <double> .Build.Dense(3, 3, 1); MSG = "Num.\tChi2\tO2\tO4\tO6\r\n"; Console.WriteLine("Beginnig fitting procedure."); for (int i = 1; i < 10; i++) { chi2s = Chi2(exp); CalculateHessian(exp, out Matrix <double> Hessian, out Matrix <double> Grad); /*Console.WriteLine("gradient"); * Console.WriteLine(Grad.ToString()); * Console.WriteLine("hessian"); * Console.WriteLine(Hessian.ToString()); */ Hessiandiag = Matrix <double> .Build.DiagonalOfDiagonalVector(Hessian.Diagonal()); //Console.WriteLine(Hessiandiag.ToString()); newparams = parameters - ((Hessian + lambda * Hessiandiag).Inverse() * Grad); //Console.WriteLine(newparams.ToString()); no2 = (newparams[0, 0]); no4 = (newparams[1, 0]); no6 = (newparams[2, 0]); chi2n = Chi2new(exp, no2, no4, no6); Console.WriteLine(i + " " + chi2s.ToString("G6") + " " + no2.ToString("G6") + " " + no4.ToString("G6") + " " + no6.ToString("G6")); MSG += i.ToString() + "\t" + chi2s.ToString("G6") + "\t" + no2.ToString("G6") + "\t" + no4.ToString("G6") + "\t" + no6.ToString("G6") + "\r\n"; if (chi2n < chi2s) { parameters = newparams; exp.o2 = no2; exp.o4 = no4; exp.o6 = no6; lambda *= 1.1; } else { lambda *= 1 / 1.1; } } Console.WriteLine("Fitting finished"); MSG += "Fitting finished \r\n"; DumpFitResult(exp, ref MSG, ref LATEX, sw, Hessiandiag, ref sumfexp, ref sumdfexp, chi2n); }
/// <summary> /// Non-linear least square fitting by the Levenberg-Marduardt algorithm. /// </summary> /// <param name="objective">The objective function, including model, observations, and parameter bounds.</param> /// <param name="initialGuess">The initial guess values.</param> /// <param name="initialMu">The initial damping parameter of mu.</param> /// <param name="gradientTolerance">The stopping threshold for infinity norm of the gradient vector.</param> /// <param name="stepTolerance">The stopping threshold for L2 norm of the change of parameters.</param> /// <param name="functionTolerance">The stopping threshold for L2 norm of the residuals.</param> /// <param name="maximumIterations">The max iterations.</param> /// <returns>The result of the Levenberg-Marquardt minimization</returns> public NonlinearMinimizationResult Minimum(IObjectiveModel objective, Vector <double> initialGuess, Vector <double> lowerBound = null, Vector <double> upperBound = null, Vector <double> scales = null, List <bool> isFixed = null, double initialMu = 1E-3, double gradientTolerance = 1E-15, double stepTolerance = 1E-15, double functionTolerance = 1E-15, int maximumIterations = -1) { // Non-linear least square fitting by the Levenberg-Marduardt algorithm. // // Levenberg-Marquardt is finding the minimum of a function F(p) that is a sum of squares of nonlinear functions. // // For given datum pair (x, y), uncertainties σ (or weighting W = 1 / σ^2) and model function f = f(x; p), // let's find the parameters of the model so that the sum of the quares of the deviations is minimized. // // F(p) = 1/2 * ∑{ Wi * (yi - f(xi; p))^2 } // pbest = argmin F(p) // // We will use the following terms: // Weighting W is the diagonal matrix and can be decomposed as LL', so L = 1/σ // Residuals, R = L(y - f(x; p)) // Residual sum of squares, RSS = ||R||^2 = R.DotProduct(R) // Jacobian J = df(x; p)/dp // Gradient g = -J'W(y − f(x; p)) = -J'LR // Approximated Hessian H = J'WJ // // The Levenberg-Marquardt algorithm is summarized as follows: // initially let μ = τ * max(diag(H)). // repeat // solve linear equations: (H + μI)ΔP = -g // let ρ = (||R||^2 - ||Rnew||^2) / (Δp'(μΔp - g)). // if ρ > ε, P = P + ΔP; μ = μ * max(1/3, 1 - (2ρ - 1)^3); ν = 2; // otherwise μ = μ*ν; ν = 2*ν; // // References: // [1]. Madsen, K., H. B. Nielsen, and O. Tingleff. // "Methods for Non-Linear Least Squares Problems. Technical University of Denmark, 2004. Lecture notes." (2004). // Available Online from: http://orbit.dtu.dk/files/2721358/imm3215.pdf // [2]. Gavin, Henri. // "The Levenberg-Marquardt method for nonlinear least squares curve-fitting problems." // Department of Civil and Environmental Engineering, Duke University (2017): 1-19. // Availble Online from: http://people.duke.edu/~hpgavin/ce281/lm.pdf if (objective == null) { throw new ArgumentNullException(nameof(objective)); } ValidateBounds(initialGuess, lowerBound, upperBound, scales); objective.SetParameters(initialGuess, isFixed); ExitCondition exitCondition = ExitCondition.None; // First, calculate function values and setup variables var P = ProjectToInternalParameters(initialGuess); // current internal parameters Vector <double> Pstep; // the change of parameters var RSS = EvaluateFunction(objective, P); // Residual Sum of Squares = R'R if (maximumIterations < 0) { maximumIterations = 200 * (initialGuess.Count + 1); } // if RSS == NaN, stop if (double.IsNaN(RSS)) { exitCondition = ExitCondition.InvalidValues; return(new NonlinearMinimizationResult(objective, -1, exitCondition)); } // When only function evaluation is needed, set maximumIterations to zero, if (maximumIterations == 0) { exitCondition = ExitCondition.ManuallyStopped; } // if RSS <= fTol, stop if (RSS <= functionTolerance) { exitCondition = ExitCondition.Converged; // SmallRSS } // Evaluate gradient and Hessian var(Gradient, Hessian) = EvaluateJacobian(objective, P); var diagonalOfHessian = Hessian.Diagonal(); // diag(H) // if ||g||oo <= gtol, found and stop if (Gradient.InfinityNorm() <= gradientTolerance) { exitCondition = ExitCondition.RelativeGradient; } if (exitCondition != ExitCondition.None) { return(new NonlinearMinimizationResult(objective, -1, exitCondition)); } double mu = initialMu * diagonalOfHessian.Max(); // μ double nu = 2; // ν int iterations = 0; while (iterations < maximumIterations && exitCondition == ExitCondition.None) { iterations++; while (true) { Hessian.SetDiagonal(Hessian.Diagonal() + mu); // hessian[i, i] = hessian[i, i] + mu; // solve normal equations Pstep = Hessian.Solve(-Gradient); // if ||ΔP|| <= xTol * (||P|| + xTol), found and stop if (Pstep.L2Norm() <= stepTolerance * (stepTolerance + P.DotProduct(P))) { exitCondition = ExitCondition.RelativePoints; break; } var Pnew = P + Pstep; // new parameters to test // evaluate function at Pnew var RSSnew = EvaluateFunction(objective, Pnew); if (double.IsNaN(RSSnew)) { exitCondition = ExitCondition.InvalidValues; break; } // calculate the ratio of the actual to the predicted reduction. // ρ = (RSS - RSSnew) / (Δp'(μΔp - g)) var predictedReduction = Pstep.DotProduct(mu * Pstep - Gradient); var rho = (predictedReduction != 0) ? (RSS - RSSnew) / predictedReduction : 0; if (rho > 0.0) { // accepted Pnew.CopyTo(P); RSS = RSSnew; // update gradient and Hessian (Gradient, Hessian) = EvaluateJacobian(objective, P); diagonalOfHessian = Hessian.Diagonal(); // if ||g||_oo <= gtol, found and stop if (Gradient.InfinityNorm() <= gradientTolerance) { exitCondition = ExitCondition.RelativeGradient; } // if ||R||^2 < fTol, found and stop if (RSS <= functionTolerance) { exitCondition = ExitCondition.Converged; // SmallRSS } mu = mu * Math.Max(1.0 / 3.0, 1.0 - Math.Pow(2.0 * rho - 1.0, 3)); nu = 2; break; } else { // rejected, increased μ mu = mu * nu; nu = 2 * nu; Hessian.SetDiagonal(diagonalOfHessian); } } } if (iterations >= maximumIterations) { exitCondition = ExitCondition.ExceedIterations; } return(new NonlinearMinimizationResult(objective, iterations, exitCondition)); }
public override void GenerateJacobian() { int i = 0; Jacobian.Clear(); var testEval = new Evaluator(); foreach (var equation in Equations) { var incidenceVector = equation.Incidence(testEval); foreach (var variable in incidenceVector) { if (!variable.IsConstant && variable.DefiningExpression == null) { int j = -1; if (_variableIndex.TryGetValue(variable, out j)) { Jacobian.Add(new JacobianElement() { EquationIndex = i, VariableIndex = j, Value = 1.0 }); if (UseHessian) { var differential = (equation.Right - equation.Left).SymbolicDiff(variable); foreach (var variable2 in incidenceVector) { if (!variable2.IsConstant && variable2.DefiningExpression == null) { int k = -1; if (_variableIndex.TryGetValue(variable2, out k) && k <= j) { Hessian.Add(new HessianElement() { EquationIndex = i, Variable1Index = j, Variable2Index = k, Expression = differential, Value = 1.0 }); } } } } } } } i++; } if (UseHessian) { var incidenceVector = ObjectiveFunction.Incidence(); foreach (var variable1 in incidenceVector) { if (!variable1.IsConstant && variable1.DefiningExpression == null) { int j = -1; if (_variableIndex.TryGetValue(variable1, out j)) { var differential = ObjectiveFunction.SymbolicDiff(variable1); foreach (var variable2 in incidenceVector) { if (!variable2.IsConstant && variable2.DefiningExpression == null) { int k = -1; if (_variableIndex.TryGetValue(variable2, out k) && k <= j) { ObjectiveHessian.Add(new HessianElement() { EquationIndex = 0, Variable1Index = j, Variable2Index = k, Expression = differential, Value = 1.0 }); } } } } } } } foreach (var equation in Constraints) { var incidenceVector = equation.Incidence(testEval); foreach (var variable in incidenceVector) { if (!variable.IsConstant && variable.DefiningExpression == null) { int j = -1; if (_variableIndex.TryGetValue(variable, out j)) { Jacobian.Add(new JacobianElement() { EquationIndex = i, VariableIndex = j, Value = 1.0 }); if (UseHessian) { var differential = (equation.Right - equation.Left).SymbolicDiff(variable); foreach (var variable2 in incidenceVector) { if (!variable2.IsConstant && variable2.DefiningExpression == null) { int k = -1; if (_variableIndex.TryGetValue(variable2, out k) && k <= j) { Hessian.Add(new HessianElement() { EquationIndex = i, Variable1Index = j, Variable2Index = k, Expression = differential, Value = 1.0 }); } } } } } } } i++; } if (UseHessian) { GenerateHessianStructureInfo(); } }