/// <summary> /// Evaluates a Multivector to a summary of its expected value (-1, 0, 1). /// The function uses a Symbolic.RandomSymbolicEvaluator to randomly evaluate /// <paramref name="A"/>. If the results are consistently negative, zero or /// positive then -1, 0 or 1 is returned. Otherwise an exception is thrown. /// </summary> /// <param name="A">The multivector to evaluate</param> /// <returns>-1, 0 or 1</returns> /// <remarks> /// Used by Multivector.Exp(), Multivector.Cos() and Multivector.Sin() to see /// if the input bivector has a scalar square. /// </remarks> public static double EvaluateRandomSymbolicToScalar(Multivector A) { double EPS = 1e-4; int NB_ITER = 100; int REQ = 98; Symbolic.RandomSymbolicEvaluator RSE = new Symbolic.RandomSymbolicEvaluator(-100.0, 100.0); int pos = 0, neg = 0, zero = 0; for (int i = 0; i < NB_ITER; i++) { Multivector E = A.SymbolicEval(RSE); double scalarPart = E.RealScalarPart(); Multivector theRest = Multivector.Subtract(E, scalarPart); if (Math.Abs(theRest.Norm_e().RealScalarPart()) > Math.Abs(scalarPart) * EPS) { throw new Exception("Multivector did not evaluate to scalar"); } if (scalarPart > EPS) { pos++; } else if (scalarPart < -EPS) { neg++; } else { zero++; } } if (pos >= REQ) { return(1.0); } else if (zero >= REQ) { return(0.0); } else if (neg >= REQ) { return(-1.0); } else { throw new Exception("Multivector did not evaluate to a consistent value"); } }
/// <summary> /// Substitutes all symbolic scalars for doubles (as evaluated by <paramref name="E"/>) /// and evaluates the symbolic ScalarOps. E.g. sqrt(2.0) would evaluate to 1.4142... /// </summary> /// <param name="E">SymbolicEvaluator used to evaluate the symbolic scalars</param> /// <returns></returns> public double SymbolicEval(RefGA.Symbolic.SymbolicEvaluator E) { Multivector A = m_value1.SymbolicEval(E); Multivector B = m_value2.SymbolicEval(E); if (!(A.IsScalar() && B.IsScalar())) { throw new ArgumentException("BinaryScalarOp.SymbolicEval: argument is not scalar"); } double a = A.RealScalarPart(); double b = B.RealScalarPart(); if (m_opName == ATAN2) { return(Math.Atan2(a, b)); } else { throw new ArgumentException("BinaryScalarOp.SymbolicEval: unknown opname " + m_opName); } }
/// <summary> /// Substitutes all symbolic scalars for doubles (as evaluated by <paramref name="E"/>) /// and evaluates the symbolic ScalarOps. E.g. sqrt(2.0) would evaluate to 1.4142... /// </summary> /// <param name="E">SymbolicEvaluator used to evaluate the symbolic scalars</param> /// <returns></returns> public double SymbolicEval(RefGA.Symbolic.SymbolicEvaluator E) { Multivector V = m_value.SymbolicEval(E); if (!V.IsScalar()) { throw new ArgumentException("UnaryScalarOp.SymbolicEval: argument is not scalar"); } double v = V.RealScalarPart(); if (m_opName == INVERSE) { if (v == 0.0) { throw new ArgumentException("UnaryScalarOp.SymbolicEval: divide by zero"); } return(1.0 / v); } else if (m_opName == SQRT) { if (v < 0.0) { throw new ArgumentException("UnaryScalarOp.SymbolicEval: square root of negative value"); } else { return(Math.Sqrt(v)); } } else if (m_opName == EXP) { return(Math.Exp(v)); } else if (m_opName == LOG) { if (v <= 0.0) { throw new ArgumentException("UnaryScalarOp.SymbolicEval: logarithm of value <= 0"); } else { return(Math.Log(v)); } } else if (m_opName == SIN) { return(Math.Sin(v)); } else if (m_opName == COS) { return(Math.Cos(v)); } else if (m_opName == TAN) { // how to detect bad input (1/2 pi, etc)? return(Math.Tan(v)); } else if (m_opName == SINH) { return(Math.Sinh(v)); } else if (m_opName == COSH) { return(Math.Cosh(v)); } else if (m_opName == TANH) { return(Math.Tanh(v)); } else if (m_opName == ABS) { return(Math.Abs(v)); } else { throw new ArgumentException("UnaryScalarOp.SymbolicEval: unknown opname " + m_opName); } }