Example #1
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);
        }
Example #2
0
        public static Operand CalculateJoin(List <Operand> operandList, Context context)
        {
            OuterProduct[] bladeArray = new OuterProduct[operandList.Count];

            int j = -1;

            for (int i = 0; i < bladeArray.Length; i++)
            {
                try
                {
                    bladeArray[i] = FactorBlade.Factor(operandList[i], context);

                    if (j < 0 || bladeArray[i].Grade > bladeArray[j].Grade)
                    {
                        j = i;
                    }
                }
                catch (MathException exc)
                {
                    throw new MathException($"Failed to factor argument {i} as blade.", exc);
                }
            }

            OuterProduct join = bladeArray[j];

            for (int i = 0; i < bladeArray.Length; i++)
            {
                if (i != j)
                {
                    foreach (Operand vector in bladeArray[i].operandList)
                    {
                        Operand operand = Operand.ExhaustEvaluation(new Trim(new List <Operand>()
                        {
                            new OuterProduct(new List <Operand>()
                            {
                                vector.Copy(), join.Copy()
                            })
                        }), context);
                        if (!operand.IsAdditiveIdentity)
                        {
                            join.operandList.Add(vector);
                        }
                    }
                }
            }

            return(join);
        }
Example #3
0
        // Note that factorizations of blades are not generally unique.
        // Here I'm just going to see if I can find any factorization.
        // My method here is the obvious one, and probably quite naive.
        // Lastly, the returned factorization, if any, will be correct up to scale.
        // It is up to the caller to determine the correct scale.
        public static OuterProduct FactorMultivectorAsBlade(Sum multivector, Context context)
        {
            if (!multivector.operandList.All(operand => operand is Blade))
            {
                throw new MathException("Can only factor elements in multivector form.");
            }

            if (!multivector.operandList.All(blade => (blade as Blade).scalar is NumericScalar))
            {
                throw new MathException("Cannot yet perform symbolic factorization of blades.");
            }

            OuterProduct factorization = new OuterProduct();

            int grade = multivector.Grade;

            if (grade == -1)
            {
                throw new MathException("Could not determine grade of given element.  It might not be homogeneous of a single grade.");
            }
            else if (grade == 0 || grade == 1)
            {
                factorization.operandList.Add(multivector.Copy());
            }
            else
            {
                // Given a blade A of grade n>1 and any vector v such that v.A != 0,
                // our method here is based on the identity L*A = (v.A) ^ ((v.A).A),
                // where L is a non-zero scalar.  Here, v.A is of grade n-1, and
                // (v.A).A is of grade 1.  This suggests a recursive algorithm.
                // This all, however, assumes a purely euclidean geometric algebra.
                // For those involving null-vectors, the search for a useful probing
                // vector requires that we take the algorithm to its conclusion before
                // we know if a given probing vector worked.

                bool foundFactorization = false;

                List <string> basisVectorList = context.ReturnBasisVectors();
                foreach (Sum probingVector in GenerateProbingVectors(basisVectorList))
                {
                    Operand reduction = Operand.ExhaustEvaluation(new InnerProduct(new List <Operand>()
                    {
                        probingVector, multivector.Copy()
                    }), context);
                    if (!reduction.IsAdditiveIdentity)
                    {
                        Sum     reducedMultivector = CanonicalizeMultivector(reduction);
                        Operand vectorFactor       = Operand.ExhaustEvaluation(new InnerProduct(new List <Operand>()
                        {
                            reducedMultivector, multivector
                        }), context);
                        if (vectorFactor.Grade == 1)        // I'm pretty sure that this check is not necessary in a purely euclidean GA.
                        {
                            OuterProduct subFactorization = FactorMultivectorAsBlade(reducedMultivector, context);
                            if (subFactorization.Grade != grade - 1)
                            {
                                throw new MathException($"Expected sub-factorization to be of grade {grade - 1}.");
                            }

                            factorization.operandList = subFactorization.operandList;
                            factorization.operandList.Add(vectorFactor);

                            // In a purely euclidean geometric algebra, this check is also not necessary.
                            Operand expansion = Operand.ExhaustEvaluation(factorization.Copy(), context);
                            if (!expansion.IsAdditiveIdentity)
                            {
                                foundFactorization = true;
                                break;
                            }
                        }
                    }
                }

                if (!foundFactorization)
                {
                    throw new MathException("Failed to find a vector factor of the given multivector.  This does not necessarily mean that the multivector doesn't factor as a blade.");
                }
            }

            return(factorization);
        }