//copy constructor public NMMatrix(NMMatrix A) { _matrix = new double[A.N, A.M]; _n = A.N; _m = A.M; for (int i = 0; i < A.N; i++) for (int j = 0; j < A.M; j++) _matrix[i, j] = A[i, j]; }
public NMMatrix ExtractMatrix(int col, int coln) { NMMatrix A = new NMMatrix(N, coln); for (int i = 0; i < N; i++) for (int j = 0; j < coln; j++) A[i, j] = this[i, col + j]; return A; }
public NMMatrix Transpose() { //make shallow copy, so both transposed and untransposed matrix may be used in same calculation NMMatrix A = new NMMatrix(); A._matrix = _matrix; A._m = _m; A._n = _n; A._transpose = !_transpose; return A; }
public NMMatrix Augment(NVector V) { if (N != V.N) throw new Exception("NMMatrix.Concatenate: incompatable sizes"); NMMatrix B = new NMMatrix(N, M + 1); for (int i = 0; i < N; i++) { for (int j = 0; j < M; j++) B[i, j] = this[i, j]; B[i, M] = V[i]; } return B; }
public NMMatrix Augment(NMMatrix A) { if (N != A.N) throw new Exception("NMMatrix.Concatenate: incompatable sizes"); NMMatrix B = new NMMatrix(N, M + A.M); for (int i = 0; i < N; i++) { for (int j = 0; j < M; j++) B[i, j] = this[i, j]; for (int j = 0; j < A.M; j++) B[i, M + j] = A[i, j]; } return B; }
static void Main2(string[] args) { NVector A = new NVector(new double[] { 1, 3, 5, -2, 0 }); NVector B = new NVector(new double[] { -1, -2, 3, 1, 2 }); NVector C = A + B; Console.WriteLine("A =" + A.ToString("0.000")); Console.WriteLine("B =" + B.ToString("0.000")); Console.WriteLine("A+B =" + C.ToString("0.000")); double p = A.Dot(B); NMMatrix E = A.Cross(B); Console.WriteLine("A x B =" + E.ToString("0.000")); E[4, 0] = -2; E[4, 1] = 3; E[4, 2] = 5; E[4, 3] = -5; E[4, 4] = 7; E[0, 0] = -7; E[1, 3] = -3; E[3, 4] = -3.5; E[2, 4] = -2; NMMatrix H = new NMMatrix(new double[,] { { 5, 3, -2 ,1}, { 0, 3, 2,-3 }, { 4, 2, 3,2 }, { -6, 2, 8,-5 } }); Console.WriteLine("H =" + H.ToString("0.000")); NVector V = new NVector(new double[] { 1, -1, 3, -2 }); Console.WriteLine("V =" + V.ToString("0.000")); Console.WriteLine(" V / H =" + (V / H).ToString("0.0000")); NMMatrix HI = H.Inverse(); Console.WriteLine("Inverse H =" + HI.ToString("0.000")); Console.WriteLine("H * HI " + (H * HI).ToString("0.00000")); Console.ReadKey(); NVector F = C / E; NMMatrix G = E.Inverse(); NMMatrix N = (G * E - NMMatrix.I(5)).Apply((LinearAlgebra.F)Math.Abs); double e = N.Max(); Console.WriteLine((e*1E15).ToString("0.00")); Console.ReadKey(); }
public NMMatrix Apply(F func) { NMMatrix A = new NMMatrix(this); for (int i = 0; i < A.N; i++) for (int j = 0; j < A.M; j++) A[i, j] = func(A[i, j]); return A; }
public static NMMatrix operator -(NMMatrix A, NMMatrix B) { if (A.N != B.N || A.M != B.M) throw new Exception("NMMatrix.Add: incompatable sizes"); NMMatrix C = new NMMatrix(A); for (int i = 0; i < A.N; i++) for (int j = 0; j < A.M; j++) C._matrix[i, j] -= B[i, j]; return C; }
public static NMMatrix operator /(NMMatrix A, double b) { NMMatrix C = new NMMatrix(A.N, A.M); for (int i = 0; i < A.N; i++) for (int j = 0; j < A.M; j++) C._matrix[i, j] = A[i, j] / b; return C; }
public static NMMatrix operator *(NMMatrix A, NMMatrix B) { if (A.M != B.N ) throw new Exception("NMMatrix.Mul: incompatable sizes"); NMMatrix C = new NMMatrix(A.N, B.M); for (int i = 0; i < A.N; i++) for (int j = 0; j < B.M; j++) { double c = 0D; for (int k = 0; k < A.M; k++) c += A[i, k] * B[k, j]; C._matrix[i, j] = c; } return C; }
public static NMMatrix operator *(double a, NMMatrix B) { NMMatrix C = new NMMatrix(B); for (int i = 0; i < B.N; i++) for (int j = 0; j < B.M; j++) C._matrix[i, j] *= a; return C; }
private NMMatrix Jacobian(NVector p, NVector y) { NVector ps = new NVector(p); //save a copy NMMatrix J = new NMMatrix(m, n); //creating a new J from scratch double del_p; for (int j = 0; j < n; j++) { del_p = Math.Max(dp[j] * Math.Abs(p[j]), dp[j]); p[j] = ps[j] + del_p; NVector y1 = func(t, p); if (dp[j] != 0D) //forward or backward difference J.ReplaceColumn(j, (y1 - y) / del_p); else //central difference { p[j] = ps[j] - del_p; J.ReplaceColumn(j, (y1 - func(t, p)) / (2D * del_p)); } p[j] = ps[j]; //restore this value } return J; }
private NMMatrix Broyden(NVector p_old, NVector y_old, NMMatrix J, NVector p, NVector y) { NVector h = p - p_old; J = J + (y - y_old - J * h).Cross(h) / h.Dot(h); return J; }
public NVector Calculate(NVector par_initial, NVector t, NVector y_dat) { _result = 0; m = t.N; if (par_initial.N != n) throw new Exception("LevenbergMarquardt.Calculate: size mismatch parms"); this.p = par_initial; this.t = t; if (y_dat.N != m) throw new Exception("LevenbergMarquardt.Calculate: size mismatch t-y"); this.y_dat = y_dat; // weight_sq = (m - n + 1) / y_dat.Dot(y_dat); DOF = (double)(m - n + 1); //initalize Jacobian and related matrices y_hat = func(t, p); y_old = y_hat; if (Jfunc == null) J = Jacobian(p, y_hat); else J = Jfunc(t, p); NVector delta_y = y_dat - y_hat; X2 = delta_y.Dot(delta_y); JtJ = J.Transpose() * J; Jtdy = J.Transpose() * delta_y; iteration = 0; if (Jtdy.Abs().Max() < eps[0]) { _result = 1; return p; //Good guess!!! } if (updateType == UpdateType.Marquardt) lambda = 0.01D; else lambda = 0.01D * JtJ.Diag().Max(); bool stop = false; /************************** Begin Main loop ***********************/ // y_hat = vector of y estimates for current value of parameters // y_try = vector of y estimates for current trial value of parameters // y_dat = given dependent values (fixed) // y_old = vector of y estimates for previous value of parameters (used in Broyden estimate of J) // t = given independent values (fixed) // p = current accepted estimate of parameters // h = last calculated (trial) increment for the parameters // p_try = current trial value for the parameters // p_old = previous accepted value of parameters (used in Broyden estimate of J) // X2 = chi^2 of last accepted estimate // X2_try = chi^2 of current trial estimate // J = current estimate of Jacobian at p while (!stop) { iteration++; NVector h; if (updateType == UpdateType.Marquardt) h = Jtdy / (JtJ + lambda * JtJ.Diag().Diag()); else h = Jtdy / (JtJ + lambda * NMMatrix.I(n)); NVector p_try = (p + h).Max(p_min).Min(p_max); NVector y_try = func(t, p_try); delta_y = y_dat - y_try; double X2_try = delta_y.Dot(delta_y); if (updateType == UpdateType.Quadratic) { alpha = Jtdy.Dot(h) / ((X2_try - X2) / 2D + 2D * Jtdy.Dot(h)); h = h * alpha; p_try = (p_try + h).Max(p_min).Min(p_max); delta_y = y_dat - func(t, p_try); X2_try = delta_y .Dot(delta_y); } dX2 = X2_try - X2; double rho = -dX2 / (2D * (lambda * h + Jtdy).Dot(h)); if (dX2 < 0D) //found a better estimate { X2 = X2_try; p_old = p; p = p_try; y_old = y_hat; y_hat = y_try; if (iteration % (2 * n) == 0) //|| dX2 > 0 or is it rho > ep[3] ? if (Jfunc == null) J = Jacobian(p, y_hat); else J = Jfunc(t, p); else J = J + (y_hat - y_old - J * h).Cross(h) / h.Dot(h); //Broyden rank-1 update of J JtJ = J.Transpose() * J; Jtdy = J.Transpose() * delta_y; switch (updateType) { case UpdateType.Marquardt: lambda = Math.Max(lambda / lambda_DN_fac, 1E-7); break; case UpdateType.Quadratic: lambda = Math.Max(lambda / (1 + alpha), 1E-7); break; case UpdateType.Nielsen: lambda = lambda * Math.Max(1D / 3D, 1D - Math.Pow(2D * rho - 1D, 3)); nu = 2D; break; } if (Jtdy.Abs().Max() < eps[0] && iteration > 2) { _result = 1; stop = true; } else if ((h / p).Abs().Max() < eps[1] && iteration > 2) { _result = 2; stop = true; } else if (X2 / (m - n + 1) < eps[2] && iteration > 2) { _result = 3; stop = true; } } else //Not a better estimate { if (iteration % (2 * n) == 0) //update J every 2n th no matter what { if (Jfunc == null) J = Jacobian(p, y_hat); else J = Jfunc(t, p); JtJ = J.Transpose() * J; Jtdy = J.Transpose() * (y_dat - y_hat); } switch (updateType) { case UpdateType.Marquardt: lambda = Math.Min(lambda * lambda_UP_fac, 1E7); break; case UpdateType.Quadratic: lambda = lambda + Math.Abs(dX2 / (2D * alpha)); break; case UpdateType.Nielsen: lambda = lambda * nu; nu *= 2D; break; } } if (iteration > MaxIter && !stop) { _result = -1; return p; } } /************************** End Main loop ************************/ return p; }
public NMMatrix Cross(NVector A) { NMMatrix C = new NMMatrix(_n, A._n); for (int i = 0; i < _n; i++) for (int j = 0; j < A._n; j++) C[i,j] += _vector[i] * A._vector[j]; return C; }
public static NMMatrix I(int n) { NMMatrix A = new NMMatrix(n, n); for (int i = 0; i < n; i++) A._matrix[i, i] = 1D; return A; }
public NMMatrix Diag() { NMMatrix A = new NMMatrix(_n, _n); for (int i = 0; i < _n; i++) A[i, i] = _vector[i]; return A; }
static NMMatrix Jfunc(NVector t, NVector p) { double eat; double ebt; NMMatrix J = new NMMatrix(t.N, p.N); for (int i = 0; i < t.N; i++) { double t0 = t[i] - p[5]; if (t0 < 0D) J[i, 2] = 1D; else { eat = Math.Exp(-p[3] * t0); ebt = Math.Exp(-p[4] * t0); J[i, 0] = ebt * (1D - eat); J[i, 1] = 1D - ebt; J[i, 2] = ebt; J[i, 3] = p[0] * t0 * eat * ebt; J[i, 4] = -ebt * t0 * (p[0] * (1D - eat) + p[2] - p[1]); J[i, 5] = ebt * (p[0] * (p[4] * (1D - eat) - p[3] * eat) + (p[2] - p[1]) * p[4]); } } return J; }