public static ExtendedDualNumber Sqr(ExtendedDualNumber f) { return new ExtendedDualNumber(f, f.value * f.value, 2.0 * f.value, 2.0, 0.0); }
public static ExtendedDualNumber Sqrt(ExtendedDualNumber f) { double g = Math.Sqrt(f.value); double g1 = 0.5 / g; double g11 = -0.5 * g1 / f.value; double g111 = -3.0 * g11 / (2.0 * f.value); return new ExtendedDualNumber(f, g, g1, g11, g111); }
public static ExtendedDualNumber Pow(ExtendedDualNumber f1, ExtendedDualNumber f2) { // FIXME Optimize this! double g = Math.Pow(f1.value, f2.value); double g1 = f2.value * Math.Pow(f1.value, f2.value - 1.0); double g2 = Math.Log(f1.value) * Math.Pow(f1.value, f2.value); double g11 = f2.value * (f2.value - 1.0) * Math.Pow(f1.value, f2.value - 2.0); double g22 = Math.Log(f1.value) * Math.Log(f1.value) * Math.Pow(f1.value, f2.value); double g12 = Math.Pow(f1.value, f2.value - 1.0) * (1.0 + Math.Log(f1.value) * f2.value); double g111 = f2.value * (f2.value - 1.0) * (f2.value - 2.0) * Math.Pow(f1.value, f2.value - 3.0); double g222 = Math.Log(f1.value) * Math.Log(f1.value) * Math.Log(f1.value) * Math.Pow(f1.value, f2.value); double g112 = (2.0 * f2.value - 1.0 + f2.value * (f2.value - 1.0) * Math.Log(f1.value)) * Math.Pow(f1.value, f2.value - 2.0); double g122 = 2.0 * Math.Log(f1.value) / f1.value * Math.Pow(f1.value, f2.value) + Math.Log(f1.value) * Math.Log(f1.value) * f2.value * Math.Pow(f1.value, f2.value - 1.0); return new ExtendedDualNumber(f1, f2, g, g1, g2, g11, g12, g22, g111, g112, g122, g222); }
public static ExtendedDualNumber Sin(ExtendedDualNumber f) { double g = Math.Sin(f.value); double g1 = Math.Cos(f.value); double g11 = -g; double g111 = -g1; return new ExtendedDualNumber(f, g, g1, g11, g111); }
public static ExtendedDualNumber Log(ExtendedDualNumber f) { double g = Math.Log(f.value); double g1 = 1.0 / f.value; double g11 = -g1 / f.value; double g111 = -2.0 * g11 / f.value; return new ExtendedDualNumber(f, g, g1, g11, g111); }
public static ExtendedDualNumber Exp(ExtendedDualNumber f) { double g = Math.Exp(f.value); double g1 = g; double g11 = g; double g111 = g; return new ExtendedDualNumber(f, g, g1, g11, g111); }
static ExtendedDualNumber() { zero = new ExtendedDualNumber(0.0); }
public ExtendedDualNumber(ExtendedDualNumber f1, ExtendedDualNumber f2, double g, double g1, double g2, double g11, double g12, double g22, double g111, double g112, double g122, double g222) { value = g; if (f1.gradientArray != null || f2.gradientArray != null) { if (f1.gradientArray != null && f2.gradientArray != null && (f1.n != f2.n || f1.n0 != f2.n0)) { throw new ArgumentException("Inconsistent number of derivatives."); } // One of the counters may be zero if the corresponding ExtendedDualNumber is a constant. n = Math.Max(f1.n, f2.n); n0 = Math.Max(f1.n0, f2.n0); gradientArray = new double[n]; if (g1 != 0.0 && f1.gradientArray != null) { for (int i = 0; i < n; i++) { gradientArray[i] += g1 * f1.gradientArray[i]; } } if (g2 != 0.0 && f2.gradientArray != null) { for (int i = 0; i < n; i++) { gradientArray[i] += g2 * f2.gradientArray[i]; } } if (f1.hessianArray != null || f2.hessianArray != null || g11 != 0.0 || g12 != 0.0 || g22 != 0.0 || g111 != 0.0 || g112 != 0.0 || g122 != 0.0 || g222 != 0.0) { hessianArray = new double[HessianSize(n)]; if (g1 != 0.0 && f1.hessianArray != null) { for (int i = 0, l = 0; i < n; i++) { for (int j = i; j < n; j++, l++) { hessianArray[l] += g1 * f1.hessianArray[l]; } } } if (g2 != 0.0 && f2.hessianArray != null) { for (int i = 0, l = 0; i < n; i++) { for (int j = i; j < n; j++, l++) { hessianArray[l] += g2 * f2.hessianArray[l]; } } } if (g11 != 0.0 && f1.gradientArray != null) { for (int i = 0, l = 0; i < n; i++) { for (int j = i; j < n; j++, l++) { hessianArray[l] += g11 * f1.gradientArray[i] * f1.gradientArray[j]; } } } if (g22 != 0.0 && f2.gradientArray != null) { for (int i = 0, l = 0; i < n; i++) { for (int j = i; j < n; j++, l++) { hessianArray[l] += g22 * f2.gradientArray[i] * f2.gradientArray[j]; } } } if (g12 != 0.0 && f1.gradientArray != null && f2.gradientArray != null) { for (int i = 0, l = 0; i < n; i++) { for (int j = i; j < n; j++, l++) { hessianArray[l] += g12 * (f1.gradientArray[i] * f2.gradientArray[j] + f2.gradientArray[i] * f1.gradientArray[j]); } } } if (f1.hessianArray != null || f2.hessianArray != null || g111 != 0.0 || g112 != 0.0 || g122 != 0.0 || g222 != 0.0) { thirdArray = new double[ThirdReducedSize(n, n0)]; // The counters below are constructed so that: // // hessianArray[l1] is the (i,j)th entry of the Hessian, // hessianArray[l2] is the (i,k)th entry of the Hessian, // hessianArray[l3] is the (j,k)th entry of the Hessian, // thirdArray[m] is the (i,j,k)th entry of the third derivatives tensor. // // It's made this way to eliminate redundant entries. In case of the Hessian, only // the upper triangular part is stored. if (g1 != 0.0 && f1.thirdArray != null) { for (int i = 0, m = 0; i < n0; i++) { for (int j = i; j < n; j++) { for (int k = j; k < n; k++, m++) { thirdArray[m] += g1 * f1.thirdArray[m]; } } } } if (g2 != 0.0 && f2.thirdArray != null) { for (int i = 0, m = 0; i < n0; i++) { for (int j = i; j < n; j++) { for (int k = j; k < n; k++, m++) { thirdArray[m] += g2 * f2.thirdArray[m]; } } } } if (g11 != 0.0 && f1.hessianArray != null) { for (int i = 0, l1 = 0, l2 = 0, m = 0; i < n0; i++) { for (int j = i, l3 = l2; j < n; j++, l1++, l2 -= n - j) { for (int k = j; k < n; k++, l2++, l3++, m++) { thirdArray[m] += g11 * (f1.gradientArray[i] * f1.hessianArray[l3] + f1.gradientArray[j] * f1.hessianArray[l2] + f1.gradientArray[k] * f1.hessianArray[l1]); } } } } if (g22 != 0.0 && f2.hessianArray != null) { for (int i = 0, l1 = 0, l2 = 0, m = 0; i < n0; i++) { for (int j = i, l3 = l2; j < n; j++, l1++, l2 -= n - j) { for (int k = j; k < n; k++, l2++, l3++, m++) { thirdArray[m] += g22 * (f2.gradientArray[i] * f2.hessianArray[l3] + f2.gradientArray[j] * f2.hessianArray[l2] + f2.gradientArray[k] * f2.hessianArray[l1]); } } } } if (g12 != 0.0 && f1.gradientArray != null && f2.hessianArray != null) { for (int i = 0, l1 = 0, l2 = 0, m = 0; i < n0; i++) { for (int j = i, l3 = l2; j < n; j++, l1++, l2 -= n - j) { for (int k = j; k < n; k++, l2++, l3++, m++) { thirdArray[m] += g12 * (f1.gradientArray[i] * f2.hessianArray[l3] + f1.gradientArray[j] * f2.hessianArray[l2] + f1.gradientArray[k] * f2.hessianArray[l1]); } } } } if (g12 != 0.0 && f2.gradientArray != null && f1.hessianArray != null) { for (int i = 0, l1 = 0, l2 = 0, m = 0; i < n0; i++) { for (int j = i, l3 = l2; j < n; j++, l1++, l2 -= n - j) { for (int k = j; k < n; k++, l2++, l3++, m++) { thirdArray[m] += g12 * (f2.gradientArray[i] * f1.hessianArray[l3] + f2.gradientArray[j] * f1.hessianArray[l2] + f2.gradientArray[k] * f1.hessianArray[l1]); } } } } if (g111 != 0.0 && f1.gradientArray != null) { for (int i = 0, m = 0; i < n0; i++) { for (int j = i; j < n; j++) { for (int k = j; k < n; k++, m++) { thirdArray[m] += g111 * f1.gradientArray[i] * f1.gradientArray[j] * f1.gradientArray[k]; } } } } if (g222 != 0.0 && f2.gradientArray != null) { for (int i = 0, m = 0; i < n0; i++) { for (int j = i; j < n; j++) { for (int k = j; k < n; k++, m++) { thirdArray[m] += g222 * f2.gradientArray[i] * f2.gradientArray[j] * f2.gradientArray[k]; } } } } if (g112 != 0.0 && f1.gradientArray != null && f2.gradientArray != null) { for (int i = 0, m = 0; i < n0; i++) { for (int j = i; j < n; j++) { for (int k = j; k < n; k++, m++) { thirdArray[m] += g112 * (f1.gradientArray[i] * f1.gradientArray[j] * f2.gradientArray[k] + f1.gradientArray[i] * f2.gradientArray[j] * f1.gradientArray[k] + f2.gradientArray[i] * f1.gradientArray[j] * f1.gradientArray[k]); } } } } if (g122 != 0.0 && f1.gradientArray != null && f2.gradientArray != null) { for (int i = 0, m = 0; i < n0; i++) { for (int j = i; j < n; j++) { for (int k = j; k < n; k++, m++) { thirdArray[m] += g122 * (f2.gradientArray[i] * f2.gradientArray[j] * f1.gradientArray[k] + f2.gradientArray[i] * f1.gradientArray[j] * f2.gradientArray[k] + f1.gradientArray[i] * f2.gradientArray[j] * f2.gradientArray[k]); } } } } } } } }
public ExtendedDualNumber(ExtendedDualNumber f, double g, double g1, double g11, double g111) { value = g; if (f.gradientArray != null) { n = f.n; n0 = f.n0; gradientArray = new double[n]; if (g1 != 0.0) { for (int i = 0; i < n; i++) { gradientArray[i] += g1 * f.gradientArray[i]; } } if (f.hessianArray != null || g11 != 0.0 || g111 != 0.0) { hessianArray = new double[HessianSize(n)]; if (g1 != 0.0 && f.hessianArray != null) { for (int i = 0, l = 0; i < n; i++) { for (int j = i; j < n; j++, l++) { hessianArray[l] += g1 * f.hessianArray[l]; } } } if (g11 != 0.0) { for (int i = 0, l = 0; i < n; i++) { for (int j = i; j < n; j++, l++) { hessianArray[l] += g11 * f.gradientArray[i] * f.gradientArray[j]; } } } if (f.hessianArray != null || g111 != 0.0) { thirdArray = new double[ThirdReducedSize(n, n0)]; // See how the counters work in the constructor below. if (g1 != 0.0 && f.thirdArray != null) { for (int i = 0, m = 0; i < n0; i++) { for (int j = i; j < n; j++) { for (int k = j; k < n; k++, m++) { thirdArray[m] += g1 * f.thirdArray[m]; } } } } if (g11 != 0.0 && f.hessianArray != null) { for (int i = 0, l1 = 0, l2 = 0, m = 0; i < n0; i++) { for (int j = i, l3 = l2; j < n; j++, l1++, l2 -= n - j) { for (int k = j; k < n; k++, l2++, l3++, m++) { thirdArray[m] += g11 * (f.gradientArray[i] * f.hessianArray[l3] + f.gradientArray[j] * f.hessianArray[l2] + f.gradientArray[k] * f.hessianArray[l1]); } } } } if (g111 != 0.0) { for (int i = 0, m = 0; i < n0; i++) { for (int j = i; j < n; j++) { for (int k = j; k < n; k++, m++) { thirdArray[m] += g111 * f.gradientArray[i] * f.gradientArray[j] * f.gradientArray[k]; } } } } } } } }