using System; using System.Collections.Generic; namespace Science.Mathematics.OrdinaryDifferentialEquation { /// /// EquationWithBoundaryCondition /// public class EquationWithBoundaryCondition { public EquationWithBoundaryCondition() { } public EquationWithBoundaryCondition(Function.ToLastType firstDerivativeFunction, BoundaryCondition boundaryCondition, double[] initialGuess, int howMany) { fdf = firstDerivativeFunction; bc = boundaryCondition; initialpara = initialGuess; num = howMany; } private List xp = new List(); public List IndependentVariable { get{return xp;} } private List yp = new List(); public List Solution { get{return yp;} } private Function.ToLastType fdf; public Function.ToLastType FirstDerivativeFunction { set{ fdf = value; } } private BoundaryCondition bc; public BoundaryCondition Condition { set{ bc = value; } } private double[] initialpara; public double[] InitialGuess { set{ initialpara = value; } } int num = 100; public int HowMany { set { num = value; } } public void Solve() { double[] parameter = new double[initialpara.Length]; for (int i = 0; i < parameter.Length; i++) parameter[i] = initialpara[i]; int nv = bc.Load(bc.Start, parameter).Length; double[] variable = new double[nv]; variable = bc.Load(bc.Start,parameter); Function.ToLastType dele = new Function.ToLastType(Mshoot); Newt method = new Newt(); method.newt(parameter,dele); if (method.Check) { try { throw new Science.Error(); } catch (Science.Error e) { e.Write("shoot failed; bad initial guess"); } } } private double[] Mshoot(double[] p) { double[] xx = new double[p.Length]; double x1 = bc.Start; double x2 = bc.End; shoot(bc.Load(x1,p).Length,x1,x2,p,fdf,bc); for(int k = 0; k derivs, BoundaryCondition boundaryCondition) { double h1 = (x2 - x1) / (double)num; double hmin=0.0; double[] v = boundaryCondition.Load(x1,p); StepperBase s = new StepperDopr5(nvar); s.derivs = derivs; Output outt = new Output(num); Odeint dd = new Odeint(v, x1, x2, EPS, EPS, h1, hmin, outt, s); dd.integrate(); xp.Clear(); yp.Clear(); for (int i = 0; i <= num; i++) xp.Add(outt.xsave[i]); for (int i = 0; i < nvar; i++) { double[] a = new double[num + 1]; for (int j = 0; j <= num; j++) { a[j] = outt.ysave[i, j]; } yp.Add(a); } for (int i = 0; i < nvar; i++) v[i] = outt.ysave[i, num]; f = boundaryCondition.Score(x2,v,p); } } // private class class Newt { private bool check; public bool Check // output { get { return check; } } public Newt() { } public void newt(double[] x, Function.ToLastType vecfunc) // x is input and output { int MAXITS = 200; double TOLF = 1.0e-8; double TOLMIN = 1.0e-12; double TOLX = 1.0e-12; double STPMX = 100.0; int i, its, j, n = x.Length; double den, f, fold, stpmax, sum, temp, test; double[,] fjac = new Double[n, n]; double[] g = new Double[n]; double[] p = new Double[n]; double[] xold = new Double[n]; NRfdjac fd = new NRfdjac(vecfunc); NRfmin fm = new NRfmin(vecfunc); f = fm.Evaluate(x); double[] fvec = fm.Fvec; test = 0.0; for (i = 0; i < n; i++) if (Math.Abs(fvec[i]) > test) test = Math.Abs(fvec[i]); if (test < 0.01 * TOLF) { check = false; return; } sum = 0.0; for (i = 0; i < n; i++) sum += x[i] * x[i]; stpmax = STPMX * Math.Max(Math.Sqrt(sum), (double)n); for (its = 0; its < MAXITS; its++) { fvec = vecfunc(x); fjac = fd.Evaluate(x, fvec); for (i = 0; i < n; i++) { sum = 0.0; for (j = 0; j < n; j++) sum += fjac[j, i] * fvec[j]; g[i] = sum; } for (i = 0; i < n; i++) xold[i] = x[i]; fold = f; for (i = 0; i < n; i++) p[i] = -fvec[i]; LUdcmp obj = new LUdcmp(fjac); obj.solve(p, p); Function.ToLastType func = new Function.ToLastType(fm.Evaluate); Lnsrch ln = new Lnsrch(); ln.lnsrch(xold, fold, g, p, stpmax, func); check = ln.Check; for (i = 0; i < n; i++) x[i] = ln.X[i]; f = ln.F; test = 0.0; for (i = 0; i < n; i++) if (Math.Abs(fvec[i]) > test) test = Math.Abs(fvec[i]); if (test < TOLF) { check = false; return; } if (check) { test = 0.0; den = Math.Max(f, 0.5 * n); for (i = 0; i < n; i++) { temp = Math.Abs(g[i]) * Math.Max(Math.Abs(x[i]), 1.0) / den; if (temp > test) test = temp; } check = (test < TOLMIN ? true : false); return; } test = 0.0; for (i = 0; i < n; i++) { temp = (Math.Abs(x[i] - xold[i])) / Math.Max(Math.Abs(x[i]), 1.0); if (temp > test) test = temp; } if (test < TOLX) return; } try { throw new Science.Error(); } catch (Science.Error e) { e.Write("MAXITS exceeded in newt"); } } } class NRfdjac { private Function.ToLastType func; public NRfdjac(Function.ToLastType funcc) { func = funcc; } public double[,] Evaluate(double[] x, double[] fvec) { double EPS = 1.0e-8; int n = x.Length; double[,] df = new double[n, n]; double[] xh = x; for (int j = 0; j < n; j++) { double temp = xh[j]; double h = EPS * Math.Abs(temp); if (h == 0.0) h = EPS; xh[j] = temp + h; h = xh[j] - temp; double[] f = func(xh); xh[j] = temp; for (int i = 0; i < n; i++) df[i, j] = (f[i] - fvec[i]) / h; } return df; } } class NRfmin { private double[] fvec; public double[] Fvec { get { return fvec; } } private Function.ToLastType jv; public NRfmin(Function.ToLastType fv) { jv = fv; } public double Evaluate(double[] x) { int n = x.Length; double sum = 0.0; fvec = jv(x); for (int i = 0; i < n; i++) sum += fvec[i] * fvec[i]; return 0.5 * sum; } } class Lnsrch { private double[] x; public double[] X // output { get { return x; } } bool check; public bool Check // output { get { return check; } } double f; public double F // output { get { return f; } } public Lnsrch() { } public void lnsrch(double[] xold, double fold, double[] g, double[] p, double stpmax, Function.ToLastType func) { double ALF = 1.0e-4; double TOLX = 1.0e-12; double a, alam, alam2 = 0.0, alamin, b, disc, f2 = 0.0; double rhs1, rhs2, slope = 0.0, sum = 0.0, temp, test, tmplam; int i, n = xold.Length; x = new double[n]; check = false; for (i = 0; i < n; i++) sum += p[i] * p[i]; sum = Math.Sqrt(sum); if (sum > stpmax) for (i = 0; i < n; i++) p[i] *= stpmax / sum; for (i = 0; i < n; i++) slope += g[i] * p[i]; if (slope >= 0.0) try { throw new Science.Error(); } catch (Science.Error e) { e.Write("Roundoff problem in lnsrch."); } test = 0.0; for (i = 0; i < n; i++) { temp = Math.Abs(p[i]) / Math.Max(Math.Abs(xold[i]), 1.0); if (temp > test) test = temp; } alamin = TOLX / test; alam = 1.0; for (; ; ) { for (i = 0; i < n; i++) x[i] = xold[i] + alam * p[i]; f = func(x); if (alam < alamin) { for (i = 0; i < n; i++) x[i] = xold[i]; check = true; return; } else if (f <= fold + ALF * alam * slope) return; else { if (alam == 1.0) tmplam = -slope / (2.0 * (f - fold - slope)); else { rhs1 = f - fold - alam * slope; rhs2 = f2 - fold - alam2 * slope; a = (rhs1 / (alam * alam) - rhs2 / (alam2 * alam2)) / (alam - alam2); b = (-alam2 * rhs1 / (alam * alam) + alam * rhs2 / (alam2 * alam2)) / (alam - alam2); if (a == 0.0) tmplam = -slope / (2.0 * b); else { disc = b * b - 3.0 * a * slope; if (disc < 0.0) tmplam = 0.5 * alam; else if (b <= 0.0) tmplam = (-b + Math.Sqrt(disc)) / (3.0 * a); else tmplam = -slope / (b + Math.Sqrt(disc)); } if (tmplam > 0.5 * alam) tmplam = 0.5 * alam; } } alam2 = alam; f2 = f; alam = Math.Max(tmplam, 0.1 * alam); } } } class LUdcmp { int n; private double[,] lu; private int[] indx; private double d; private double[,] aref; public double[,] LU { get { return lu; } // output } public int[] RowPermutation // output { get { return indx; } } public double Sign // output { get { return d; } } public LUdcmp(double[,] a) // a input { n = a.GetLength(0); lu = new double[n, n]; for (int ir = 0; ir < n; ir++) for (int ic = 0; ic < n; ic++) lu[ir, ic] = a[ir, ic]; aref = a; indx = new int[n]; double TINY = 1.0e-40; int i, imax = 0, j, k; double big, temp; double[] vv = new Double[n]; d = 1.0; for (i = 0; i < n; i++) { big = 0.0; for (j = 0; j < n; j++) if ((temp = Math.Abs(lu[i, j])) > big) big = temp; if (big == 0.0) try { throw new Science.Error(); } catch (Science.Error e) { e.Write("Singular matrix in LUdcmp"); } vv[i] = 1.0 / big; } for (k = 0; k < n; k++) { big = 0.0; for (i = k; i < n; i++) { temp = vv[i] * Math.Abs(lu[i, k]); if (temp > big) { big = temp; imax = i; } } if (k != imax) { for (j = 0; j < n; j++) { temp = lu[imax, j]; lu[imax, j] = lu[k, j]; lu[k, j] = temp; } d = -d; vv[imax] = vv[k]; } indx[k] = imax; if (lu[k, k] == 0.0) lu[k, k] = TINY; for (i = k + 1; i < n; i++) { temp = lu[i, k] /= lu[k, k]; for (j = k + 1; j < n; j++) lu[i, j] -= temp * lu[k, j]; } } } public void solve(double[] b, double[] x) // b input and x output { int i, ii = 0, ip, j; double sum; if (b.Length != n || x.Length != n) try { throw new Science.Error(); } catch (Science.Error e) { e.Write("Bad sizes"); } for (i = 0; i < n; i++) x[i] = b[i]; for (i = 0; i < n; i++) { ip = indx[i]; sum = b[ip]; x[ip] = x[i]; if (ii != 0) for (j = ii - 1; j < i; j++) sum -= lu[i, j] * x[j]; else if (sum != 0.0) ii = i + 1; x[i] = sum; } for (i = n - 1; i >= 0; i--) { sum = x[i]; for (j = i + 1; j < n; j++) sum -= lu[i, j] * x[j]; x[i] = sum / lu[i, i]; } } public void solve(double[,] b, double[,] x) // b input and x output { int i, j, m = b.GetLength(1); if (b.GetLength(0) != n || x.GetLength(0) != n || b.GetLength(1) != x.GetLength(1)) try { throw new Science.Error(); } catch (Science.Error e) { e.Write("Bad sizes"); } double[] xx = new double[n]; for (j = 0; j < m; j++) { for (i = 0; i < n; i++) xx[i] = b[i, j]; solve(xx, xx); for (i = 0; i < n; i++) x[i, j] = xx[i]; } } public double[,] inverse() { double[,] ainv = new double[n, n]; for (int i = 0; i < n; i++) ainv[i, i] = 1.0; solve(ainv, ainv); return ainv; } public double det() { double dd = d; for (int i = 0; i < n; i++) dd *= lu[i, i]; return dd; } public void mprove(double[] b, double[] x) { int j, i; double sdp; double[] r = new Double[n]; for (i = 0; i < n; i++) { sdp = -b[i]; for (j = 0; j < n; j++) sdp += aref[i, j] * x[j]; r[i] = sdp; } solve(r, r); for (i = 0; i < n; i++) x[i] -= r[i]; } } }