public void ExtendedVectorNorm() { // Check that vector norm is correctly computed even when vector is enormous (square would overflow) or tiny (square woudl underflow) double x = Double.MaxValue / 32.0; // Use the pythagorian quadrouple (2, 3, 6, 7) ColumnVector v = new ColumnVector(2.0, 3.0, 6.0); Assert.IsTrue(TestUtilities.IsNearlyEqual(v.Norm(), 7.0)); ColumnVector bv = x * v; Assert.IsTrue(TestUtilities.IsNearlyEqual(bv.Norm(), 7.0 * x)); ColumnVector sv = v / x; Assert.IsTrue(TestUtilities.IsNearlyEqual(sv.Norm(), 7.0 / x)); // Use the pythagorian 7-tuple (1, 2, 3, 4, 5, 27, 28) RowVector u = new RowVector(1.0, 2.0, 3.0, 4.0, 5.0, 27.0); Assert.IsTrue(TestUtilities.IsNearlyEqual(u.Norm(), 28.0)); RowVector bu = x * u; Assert.IsTrue(TestUtilities.IsNearlyEqual(bu.Norm(), 28.0 * x)); RowVector su = u / x; Assert.IsTrue(TestUtilities.IsNearlyEqual(su.Norm(), 28.0 / x)); }
public void VectorNorm() { RowVector nR = R / R.Norm(); Assert.IsTrue(TestUtilities.IsNearlyEqual(nR.Norm(), 1.0)); ColumnVector nC = C / C.Norm(); Assert.IsTrue(TestUtilities.IsNearlyEqual(nC.Norm(), 1.0)); }
public static void VectorsAndMatrices() { ColumnVector v = new ColumnVector(0.0, 1.0, 2.0); ColumnVector w = new ColumnVector(new double[] { 1.0, -0.5, 1.5 }); SquareMatrix A = new SquareMatrix(new double[, ] { { 1, -2, 3 }, { 2, -5, 12 }, { 0, 2, -10 } }); RowVector u = new RowVector(4); for (int i = 0; i < u.Dimension; i++) { u[i] = i; } Random rng = new Random(1); RectangularMatrix B = new RectangularMatrix(4, 3); for (int r = 0; r < B.RowCount; r++) { for (int c = 0; c < B.ColumnCount; c++) { B[r, c] = rng.NextDouble(); } } SquareMatrix AI = A.Inverse(); PrintMatrix("A * AI", A * AI); PrintMatrix("v + 2.0 * w", v + 2.0 * w); PrintMatrix("Av", A * v); PrintMatrix("B A", B * A); PrintMatrix("v^T", v.Transpose); PrintMatrix("B^T", B.Transpose); Console.WriteLine($"|v| = {v.Norm()}"); Console.WriteLine($"sqrt(v^T v) = {Math.Sqrt(v.Transpose * v)}"); UnitMatrix I = UnitMatrix.OfDimension(3); PrintMatrix("IA", I * A); Console.WriteLine(v == w); Console.WriteLine(I * A == A); }
/// <summary> /// Finds a vector argument which makes a vector function zero. /// </summary> /// <param name="f">The vector function.</param> /// <param name="x0">The vector argument.</param> /// <returns>The vector argument which makes all components of the vector function zero.</returns> /// <exception cref="ArgumentNullException"><paramref name="f"/> or <paramref name="x0"/> is null.</exception> /// <exception cref="DimensionMismatchException">The dimension of <paramref name="f"/> is not equal to the /// dimension of <paramref name="x0"/>.</exception> public static ColumnVector FindZero(Func <IList <double>, IList <double> > f, IList <double> x0) { if (f == null) { throw new ArgumentNullException("f"); } if (x0 == null) { throw new ArgumentNullException("x0"); } // we will use Broyden's method, which is a generalization of the secant method to the multi-dimensional problem // just as the secant method is essentially Newton's method with a crude, numerical value for the slope, // Broyden's method is a multi-dimensional Newton's method with a crude, numerical value for the Jacobian matrix int d = x0.Count; // we should re-engineer this code to work directly on vector/matrix storage rather than go back and forth // between vectors and arrays, but for the moment this works; implementing Blas2 rank-1 update would help // starting values ColumnVector x = new ColumnVector(x0); //double[] x = new double[d]; Blas1.dCopy(x0, 0, 1, x, 0, 1, d); ColumnVector F = new ColumnVector(f(x.ToArray())); //double[] F = f(x); if (F.Dimension != d) { throw new DimensionMismatchException(); } SquareMatrix B = ApproximateJacobian(f, x0); double g = MoreMath.Pow2(F.Norm()); //double g = Blas1.dDot(F, 0, 1, F, 0, 1, d); for (int n = 0; n < Global.SeriesMax; n++) { // determine the Newton step LUDecomposition LU = B.LUDecomposition(); ColumnVector dx = -LU.Solve(F); //for (int i = 0; i < d; i++) { // Console.WriteLine("F[{0}]={1} x[{0}]={2} dx[{0}]={3}", i, F[i], x[i], dx[i]); //} // determine how far we will move along the Newton step ColumnVector x1 = x + dx; ColumnVector F1 = new ColumnVector(f(x1)); double g1 = MoreMath.Pow2(F1.Norm()); // check whether the Newton step decreases the function vector magnitude // NR suggest that it's necessary to ensure that it decrease by a certain amount, but I have yet to see that make a diference double gm = g - 0.0; if (g1 > gm) { // the Newton step did not reduce the function vector magnitude, so we won't step that far // determine how far along the descent direction we will step by parabolic interpolation double z = g / (g + g1); //Console.WriteLine("z={0}", z); // take at least a small step in the descent direction if (z < (1.0 / 16.0)) { z = 1.0 / 16.0; } dx = z * dx; x1 = x + dx; F1 = new ColumnVector(f(x1.ToArray())); g1 = MoreMath.Pow2(F1.Norm()); // NR suggest that this be repeated, but I have yet to see that make a difference } // take the step x = x + dx; // check for convergence if ((F1.InfinityNorm() < Global.Accuracy) || (dx.InfinityNorm() < Global.Accuracy)) { //if ((g1 < Global.Accuracy) || (dx.Norm() < Global.Accuracy)) { return(x); } // update B ColumnVector dF = F1 - F; RectangularMatrix dB = (dF - B * dx) * (dx / (dx.Transpose() * dx)).Transpose(); //RectangularMatrix dB = F1 * ( dx / MoreMath.Pow(dx.Norm(), 2) ).Transpose(); for (int i = 0; i < d; i++) { for (int j = 0; j < d; j++) { B[i, j] += dB[i, j]; } } // prepare for the next iteration F = F1; g = g1; } throw new NonconvergenceException(); }
public static void Integration() { // This is the area of the upper half-circle, so the value should be pi/2. IntegrationResult i = FunctionMath.Integrate(x => Math.Sqrt(1.0 - x * x), -1.0, +1.0); Console.WriteLine($"i = {i.Estimate} after {i.EvaluationCount} evaluations."); Interval zeroToPi = Interval.FromEndpoints(0.0, Math.PI); IntegrationResult watson = MultiFunctionMath.Integrate( x => 1.0 / (1.0 - Math.Cos(x[0]) * Math.Cos(x[1]) * Math.Cos(x[2])), new Interval[] { zeroToPi, zeroToPi, zeroToPi } ); IntegrationResult i2 = FunctionMath.Integrate( x => Math.Sqrt(1.0 - x * x), -1.0, +1.0, new IntegrationSettings() { RelativePrecision = 1.0E-4 } ); // This integrand has a log singularity at x = 0. // The value of this integral is the Catalan constant. IntegrationResult soft = FunctionMath.Integrate( x => - Math.Log(x) / (1.0 + x * x), 0.0, 1.0 ); // This integral has a power law singularity at x = 0. // The value of this integral is 4. IntegrationResult hard = FunctionMath.Integrate( x => Math.Pow(x, -3.0 / 4.0), 0.0, 1.0, new IntegrationSettings() { RelativePrecision = 1.0E-6 } ); // The value of this infinite integral is sqrt(pi) IntegrationResult infinite = FunctionMath.Integrate( x => Math.Exp(-x * x), Double.NegativeInfinity, Double.PositiveInfinity ); Func <IReadOnlyList <double>, double> distance = z => { ColumnVector x = new ColumnVector(z[0], z[1], z[2]); ColumnVector y = new ColumnVector(z[3], z[4], z[5]); ColumnVector d = x - y; return(d.Norm()); }; Interval oneBox = Interval.FromEndpoints(0.0, 1.0); Interval[] sixBox = new Interval[] { oneBox, oneBox, oneBox, oneBox, oneBox, oneBox }; IntegrationSettings settings = new IntegrationSettings() { RelativePrecision = 1.0E-4, AbsolutePrecision = 0.0, Listener = r => { Console.WriteLine($"Estimate {r.Estimate} after {r.EvaluationCount} evaluations."); } }; IntegrationResult numeric = MultiFunctionMath.Integrate(distance, sixBox, settings); Console.WriteLine($"The numeric result is {numeric.Estimate}."); double analytic = 4.0 / 105.0 + 17.0 / 105.0 * Math.Sqrt(2.0) - 2.0 / 35.0 * Math.Sqrt(3.0) + Math.Log(1.0 + Math.Sqrt(2.0)) / 5.0 + 2.0 / 5.0 * Math.Log(2.0 + Math.Sqrt(3.0)) - Math.PI / 15.0; Console.WriteLine($"The analytic result is {analytic}."); }