예제 #1
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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));
        }
예제 #5
0
        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);
        }
예제 #6
0
 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);
         }
     }
 }
예제 #7
0
        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);
                            }
                        }
                    }
                }
            }
        }
예제 #8
0
        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);
        }
예제 #9
0
        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);
        }
예제 #10
0
        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);
        }
예제 #11
0
        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);
        }