public override Operand Copy() { Blade clone = base.Copy() as Blade; clone.vectorList = (from vectorName in this.vectorList select vectorName).ToList(); return(clone); }
public override Operand EvaluationStep(Context context) { Operand operand = base.EvaluationStep(context); if (operand != null) { return(operand); } for (int i = 0; i < operandList.Count - 1; i++) { Blade bladeA = operandList[i] as Blade; Blade bladeB = operandList[i + 1] as Blade; if (bladeA != null && bladeB != null) { Blade blade = new Blade(new GeometricProduct(new List <Operand>() { bladeA.scalar, bladeB.scalar })); blade.vectorList = bladeA.vectorList.Concat(bladeB.vectorList).ToList(); operandList.RemoveAt(i); operandList[i] = blade; return(this); } } return(null); }
public static OuterProduct Factor(Operand operand, Context context) { // TODO: Support symbolic factorization? For example, it would be quite useful // to be able to evaluate factor(n*(a^b)*n). I wouldn't expect any kind // of miracle, though, like finding (n*a*n)^(n*b*n). Sum multivector = CanonicalizeMultivector(operand); OuterProduct factorization = FactorMultivectorAsBlade(multivector, context); operand = Operand.ExhaustEvaluation(factorization.Copy(), context); Sum expansion = CanonicalizeMultivector(operand); if (expansion.operandList.Count != multivector.operandList.Count) { throw new MathException("The multivector is not a blade."); } // Note that this should work by the sorting performed by the sum operation. double commonRatio = 0.0; for (int i = 0; i < expansion.operandList.Count; i++) { Blade bladeA = multivector.operandList[i] as Blade; Blade bladeB = expansion.operandList[i] as Blade; if (!bladeA.IsLike(bladeB)) { throw new MathException("The multivector is not a blade."); } double ratio = 0.0; try { ratio = (bladeA.scalar as NumericScalar).value / (bladeB.scalar as NumericScalar).value; } catch (DivideByZeroException) { ratio = 1.0; } if (Double.IsNaN(ratio)) { ratio = 1.0; } if (commonRatio == 0.0) { commonRatio = ratio; } else if (Math.Abs(ratio - commonRatio) >= context.epsilon) { throw new MathException("The multivector is not a blade."); } } factorization.operandList.Insert(0, new NumericScalar(commonRatio)); return(factorization); }
public override bool IsLike(Collectable collectable) { Blade blade = collectable as Blade; if (blade == null) { return(false); } // This works because blades are sorted as part of their evaluation. return(Enumerable.SequenceEqual <string>(vectorList, blade.vectorList)); }
public Blade MakeSubBlade(int i) { Blade subBlade = new Blade(); subBlade.scalar = this.scalar; string removedVectorName = this.vectorList[i]; subBlade.vectorList = (from vectorName in this.vectorList where vectorName != removedVectorName select vectorName).ToList(); return(subBlade); }
public static IEnumerable <Blade> GenerateBasisBlades(List <string> basisVectorList) { for (int i = 0; i <= basisVectorList.Count; i++) { List <string> vectorList = new List <string>(); foreach (List <string> vectorComboList in GenerateVectorCombinations(basisVectorList, vectorList, 0, i, 0)) { vectorComboList.Sort(); Blade basisBlade = new Blade(new NumericScalar(1.0), vectorComboList); yield return(basisBlade); } } }
private IEnumerable <List <int> > IteratePotentiallyFactorableBladesLists(List <int> bladeOffsetList, Sum sum, List <string> basisVectorList, string vectorName) { if (bladeOffsetList.Count == basisVectorList.Count) { yield return(bladeOffsetList); } else { string basisVectorName = basisVectorList[bladeOffsetList.Count]; for (int i = 0; i < sum.operandList.Count; i++) { if (bladeOffsetList.Contains(i)) { continue; } Blade blade = sum.operandList[i] as Blade; if (blade.vectorList.Contains(basisVectorName)) { if (blade.scalar is SymbolicScalarTerm term) { if (term.factorList.Any(factor => factor is SymbolicScalarTerm.SymbolicDot symbolicDot && symbolicDot.InvolvesVectors(vectorName, basisVectorName))) { bladeOffsetList.Add(i); foreach (List <int> otherBladeOffsetList in IteratePotentiallyFactorableBladesLists(bladeOffsetList, sum, basisVectorList, vectorName)) { yield return(otherBladeOffsetList); } bladeOffsetList.Remove(i); } } } } } }
public override Operand EvaluationStep(Context context) { Operand operand = base.EvaluationStep(context); if (operand != null) { return(operand); } // To avoid infinite evaluation looping, we must apply... // 1) vB = v.B + v^B, and // 2) v^B = vB - v.B, // ...according to rules that dictate when and where they're appropriate. // Also to avoid infinite looping, the distributive property must take // precedence over anything we do here. // All reduction cases must be eliminated before it is safe to handle the expansion cases. for (int i = 0; i < operandList.Count - 1; i++) { Blade bladeA = operandList[i] as Blade; Blade bladeB = operandList[i + 1] as Blade; if (bladeA != null && bladeB != null && bladeA.Grade > 1 && bladeB.Grade > 1) { GeometricProduct geometricProduct; if (context.useOperandCache) { geometricProduct = new GeometricProduct(new List <Operand>() { new Blade(new NumericScalar(1.0), bladeA.vectorList.ToList()), new Blade(new NumericScalar(1.0), bladeB.vectorList.ToList()) }); string key = geometricProduct.Print(Format.PARSEABLE, context); Operand cachedResult = null; if (!context.operandCache.GetStorage(key, ref cachedResult)) { context.useOperandCache = false; cachedResult = Operand.ExhaustEvaluation(geometricProduct, context); context.useOperandCache = true; context.operandCache.SetStorage(key, cachedResult); } return(new GeometricProduct(new List <Operand>() { bladeA.scalar, bladeB.scalar, cachedResult })); } // Here our choice of which blade to reduce is arbitrary from a stand-point of correctness. // However, we might converge faster by choosing the blade with smaller grade. // Note there is also something arbitrary about how we're reducing the blades. int j = bladeA.Grade <= bladeB.Grade ? i : i + 1; Blade blade = operandList[j] as Blade; Blade subBlade = blade.MakeSubBlade(0); Blade vector = new Blade(blade.vectorList[0]); geometricProduct = new GeometricProduct(new List <Operand>() { vector, subBlade }); InnerProduct innerProduct = new InnerProduct(new List <Operand>() { vector.Copy(), subBlade.Copy() }); operandList[j] = new Sum(new List <Operand>() { geometricProduct, new GeometricProduct(new List <Operand>() { new NumericScalar(-1.0), innerProduct }) }); return(this); } } // All reduction cases eliminated, it is now safe to handle some expansion cases. for (int i = 0; i < operandList.Count - 1; i++) { Blade bladeA = operandList[i] as Blade; Blade bladeB = operandList[i + 1] as Blade; if (bladeA == null || bladeB == null) { continue; } if ((bladeA.Grade == 1 && bladeB.Grade > 1) || (bladeA.Grade > 1 && bladeB.Grade == 1)) { InnerProduct innerProduct = new InnerProduct(new List <Operand>() { bladeA, bladeB }); OuterProduct outerProduct = new OuterProduct(new List <Operand>() { bladeA.Copy(), bladeB.Copy() }); operandList[i] = new Sum(new List <Operand>() { innerProduct, outerProduct }); operandList.RemoveAt(i + 1); return(this); } } // It is now safe to handle the remaining expansion cases. for (int i = 0; i < operandList.Count - 1; i++) { Blade bladeA = operandList[i] as Blade; Blade bladeB = operandList[i + 1] as Blade; if (bladeA == null || bladeB == null) { continue; } if (bladeA.Grade == 1 && bladeB.Grade == 1) { operandList.RemoveAt(i + 1); GeometricProduct innerProduct = new GeometricProduct(new List <Operand>() { bladeA.scalar, bladeB.scalar, context.BilinearForm(bladeA.vectorList[0], bladeB.vectorList[0]) }); Blade outerProduct = new Blade(new GeometricProduct(new List <Operand>() { bladeA.scalar.Copy(), bladeB.scalar.Copy() })); outerProduct.vectorList.Add(bladeA.vectorList[0]); outerProduct.vectorList.Add(bladeB.vectorList[0]); operandList[i] = new Sum(new List <Operand>() { innerProduct, outerProduct }); return(this); } } return(null); }
public override Operand EvaluationStep(Context context) { if (operandList.Count != 1) { throw new MathException(string.Format("Exponential function expected exactly 1 argument, got {0}.", operandList.Count)); } Operand operand = base.EvaluationStep(context); if (operand != null) { return(operand); } Operand exponentOperand = operandList[0]; if (exponentOperand is Sum sumExponent) { GeometricProduct geometricProduct = new GeometricProduct(); for (int i = 0; i < sumExponent.operandList.Count; i++) { geometricProduct.operandList.Add(new Exponent(new List <Operand>() { sumExponent.operandList[i] })); } return(geometricProduct); } if (exponentOperand is NumericScalar numericScalar) { return(new NumericScalar(Math.Exp(numericScalar.value))); } else if (exponentOperand is Blade blade) { Blade basisBlade = new Blade(new NumericScalar(1.0), blade.vectorList.ToList()); InnerProduct innerProduct = new InnerProduct(); innerProduct.operandList.Add(new NumericScalar(-1.0)); innerProduct.operandList.Add(basisBlade.Copy()); innerProduct.operandList.Add(basisBlade.Copy()); Operand result = Operand.ExhaustEvaluation(innerProduct, context); if (result.IsMultiplicativeIdentity) { Sum sum = new Sum(); sum.operandList.Add(new Cosine(new List <Operand>() { blade.scalar.Copy() })); sum.operandList.Add(new GeometricProduct(new List <Operand>() { basisBlade.Copy(), new Sine(new List <Operand>() { blade.scalar.Copy() }) })); return(sum); } else if (result.IsAdditiveIdentity) { // What if it's a null blade? } else { // Hyperbolic cosine/sine? } } return(null); }
public override Operand EvaluationStep(Context context) { Operand operand = base.EvaluationStep(context); if (operand != null) { return(operand); } if (operandList.Count == 2) { Blade bladeA = operandList[0] as Blade; Blade bladeB = operandList[1] as Blade; if (bladeA != null && bladeB != null) { if (bladeA.Grade == 1 && bladeB.Grade == 1) { return(new GeometricProduct(new List <Operand>() { bladeA.scalar, bladeB.scalar, context.BilinearForm(bladeA.vectorList[0], bladeB.vectorList[0]) })); } else if (bladeA.Grade == 1 && bladeB.Grade > 1) { Sum sum = new Sum(); for (int i = 0; i < bladeB.vectorList.Count; i++) { Blade subBlade = bladeB.MakeSubBlade(i); subBlade.scalar = new GeometricProduct(new List <Operand>() { new NumericScalar(i % 2 == 1 ? -1.0 : 1.0), bladeA.scalar, bladeB.scalar, context.BilinearForm(bladeA.vectorList[0], bladeB.vectorList[i]) }); sum.operandList.Add(subBlade); } return(sum); } else if (bladeA.Grade > 1 && bladeB.Grade == 1) { operandList[0] = bladeB; operandList[1] = bladeA; if (bladeA.Grade % 2 == 0) { operandList.Add(new NumericScalar(-1.0)); } return(this); } else if (bladeA.Grade > 1 && bladeB.Grade > 1) { if (context.useOperandCache) { InnerProduct innerProduct = new InnerProduct(new List <Operand>() { new Blade(new NumericScalar(1.0), bladeA.vectorList.ToList()), new Blade(new NumericScalar(1.0), bladeB.vectorList.ToList()) }); string key = innerProduct.Print(Format.PARSEABLE, context); Operand cachedResult = null; if (!context.operandCache.GetStorage(key, ref cachedResult)) { context.useOperandCache = false; cachedResult = Operand.ExhaustEvaluation(innerProduct, context); context.useOperandCache = true; context.operandCache.SetStorage(key, cachedResult); } return(new GeometricProduct(new List <Operand>() { bladeA.scalar, bladeB.scalar, cachedResult })); } if (bladeA.Grade <= bladeB.Grade) { return(new InnerProduct(new List <Operand>() { bladeA.MakeSubBlade(bladeA.Grade - 1), new InnerProduct(new List <Operand>() { new Blade(bladeA.vectorList[bladeA.Grade - 1]), bladeB }) })); } else { return(new InnerProduct(new List <Operand>() { new InnerProduct(new List <Operand>() { bladeA, new Blade(bladeB.vectorList[0]) }), bladeB.MakeSubBlade(0) })); } } } } return(null); }
private Operand FactorBlade(string vectorName, Sum sum, Context context) { List <string> basisVectorList = context.ReturnBasisVectors(); basisVectorList = basisVectorList.Where(basisVectorName => !context.BilinearForm(vectorName, basisVectorName).IsAdditiveIdentity).ToList(); List <int> emptyBladeOffsetList = new List <int>(); foreach (List <int> bladeOffsetList in this.IteratePotentiallyFactorableBladesLists(emptyBladeOffsetList, sum, basisVectorList, vectorName)) { List <Operand> modifiedOperandList = new List <Operand>(); for (int i = 0; i < bladeOffsetList.Count; i++) { string basisVectorName = basisVectorList[i]; Blade blade = sum.operandList[bladeOffsetList[i]].Copy() as Blade; SymbolicScalarTerm term = blade.scalar as SymbolicScalarTerm; int j = blade.vectorList.IndexOf(basisVectorName); if (j % 2 == 1) { term.scalar = new GeometricProduct(new List <Operand>() { new NumericScalar(-1.0), term.scalar }); } blade.vectorList.Remove(basisVectorName); term.factorList = term.factorList.Where(factor => !(factor is SymbolicScalarTerm.SymbolicDot symbolicDot && symbolicDot.InvolvesVectors(vectorName, basisVectorName))).ToList(); modifiedOperandList.Add(ExhaustEvaluation(blade, context)); } bool canFactor = Enumerable.Range(0, modifiedOperandList.Count - 1).All(j => { Operand bladeA = modifiedOperandList[j]; Operand bladeB = modifiedOperandList[j + 1]; Operand difference = new Sum(new List <Operand>() { bladeA.Copy(), new GeometricProduct(new List <Operand>() { new NumericScalar(-1.0), bladeB.Copy() }) }); difference = ExhaustEvaluation(difference, context); return(difference.IsAdditiveIdentity); }); if (canFactor) { Sum remainderSum = new Sum(sum.operandList.Where(operand => !bladeOffsetList.Contains(sum.operandList.IndexOf(operand))).ToList()); Sum resultSum = new Sum(); resultSum.operandList.Add(new OuterProduct(new List <Operand>() { new Blade(vectorName), modifiedOperandList[0] })); resultSum.operandList.Add(new FactorDot(new List <Operand>() { remainderSum })); return(resultSum); } } return(null); }