private Operand FactorScalar(string vectorName, Sum sum, Context context)
        {
            List <string> basisVectorList = context.ReturnBasisVectors();

            Sum remainderSum = sum.Copy() as Sum;
            Sum modifiedSum  = new Sum();

            foreach (string basisVectorName in basisVectorList)
            {
                if (context.BilinearForm(vectorName, basisVectorName).IsAdditiveIdentity)
                {
                    continue;
                }

                bool found = false;

                foreach (Blade blade in remainderSum.operandList.Select(term => term as Blade))
                {
                    if (blade.Grade == 0 && blade.scalar is SymbolicScalarTerm scalarTerm)
                    {
                        foreach (SymbolicScalarTerm.Factor factor in scalarTerm.factorList)
                        {
                            if (factor is SymbolicScalarTerm.SymbolicDot symbolicDot && symbolicDot.InvolvesVectors(vectorName, basisVectorName))
                            {
                                remainderSum.operandList.Remove(blade);
                                scalarTerm.factorList.Remove(symbolicDot);
                                blade.vectorList.Add(basisVectorName);
                                modifiedSum.operandList.Add(blade);
                                found = true;
                                break;
                            }
                        }
                    }

                    if (found)
                    {
                        break;
                    }
                }

                if (!found)
                {
                    return(null);
                }
            }

            Sum resultSum = new Sum();

            resultSum.operandList.Add(new InnerProduct(new List <Operand>()
            {
                new Blade(vectorName), new FactorDot(new List <Operand>()
                {
                    modifiedSum
                })
            }));
            resultSum.operandList.Add(new FactorDot(new List <Operand>()
            {
                remainderSum
            }));
            return(resultSum);
        }
        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);
        }
        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);
                            }
                        }
                    }
                }
            }
        }
Beispiel #4
0
        // Note that here that we do not consider unary operator precedence.
        // So for example, if we have -1~, we don't try to choose between (-1)~ and -(1~),
        // though both are the same in this particular case.  Also, we don't recognize unary
        // operator stacking.  E.g., -~1 will not parse as -(~1) would.  In short, working with
        // unary operators will sometimes requires parenthesis.
        public Operand BuildOperandTree(List <Token> tokenList)
        {
            while (tokenList.Count > 0)
            {
                int count = tokenList.Count;

                if (tokenList[0].kind == Token.Kind.LEFT_PARAN && tokenList[0].paranType == Token.ParanType.ROUND)
                {
                    int i = FindMatchingParan(tokenList, 0);
                    if (i == tokenList.Count - 1)
                    {
                        tokenList.RemoveAt(0);
                        tokenList.RemoveAt(tokenList.Count - 1);
                    }
                }

                if (tokenList.Count == count)
                {
                    break;
                }
            }

            if (tokenList.Count == 0)
            {
                throw new ParseException("Encountered empty token list.");
            }

            if (tokenList.Count == 1)
            {
                Token token = tokenList[0];
                switch (token.kind)
                {
                case Token.Kind.SYMBOL:
                {
                    if (token.data[0] == '@')
                    {
                        return(new Variable(token.data.Substring(1)));
                    }

                    if (token.data[0] == '$')
                    {
                        return(new SymbolicScalarTerm(token.data.Substring(1)));
                    }

                    string vectorName    = token.data;
                    bool   isBasisVector = false;

                    List <string> basisVectorList = context.ReturnBasisVectors();
                    if (basisVectorList != null)
                    {
                        isBasisVector = basisVectorList.Contains(vectorName);
                        if (basisVectorsOnly && !isBasisVector)
                        {
                            Sum sum = new Sum();

                            foreach (string basisVectorName in basisVectorList)
                            {
                                InnerProduct dot = new InnerProduct(new List <Operand>()
                                    {
                                        new Blade(vectorName), new Blade(basisVectorName)
                                    });
                                sum.operandList.Add(new GeometricProduct(new List <Operand>()
                                    {
                                        dot, new Blade(basisVectorName)
                                    }));
                            }

                            return(sum);
                        }
                    }

                    generatedSymbolicVector = !isBasisVector;
                    return(new Blade(vectorName));
                }

                case Token.Kind.NUMBER:
                {
                    double value;
                    if (!double.TryParse(token.data, out value))
                    {
                        throw new ParseException(string.Format("Encountered non-parsable number ({0}).", token.data));
                    }

                    return(new NumericScalar(value));
                }

                default:
                {
                    throw new ParseException(string.Format("Encountered lone token ({0}) that isn't handled.", token.data));
                }
                }
            }
            else if (tokenList[0].kind == Token.Kind.OPERATOR && (ParansMatch(tokenList, 1, tokenList.Count - 1) || tokenList.Count == 2 || IsFunctionPattern(tokenList.Skip(1).ToList())))
            {
                Token token = tokenList[0];

                if (token.data == "-")
                {
                    return(new GeometricProduct(new List <Operand>()
                    {
                        new Blade(-1.0), BuildOperandTree(tokenList.Skip(1).ToList())
                    }));
                }

                throw new ParseException(string.Format("Encounterd unary operator ({0}) that isn't recognized on the left.", token.data));
            }
            else if (tokenList[tokenList.Count - 1].kind == Token.Kind.OPERATOR && (ParansMatch(tokenList, 0, tokenList.Count - 2) || tokenList.Count == 2 || IsFunctionPattern(tokenList.Take(tokenList.Count - 1).ToList())))
            {
                Token token = tokenList[tokenList.Count - 1];

                if (token.data == "~")
                {
                    return(new Reverse(new List <Operand>()
                    {
                        BuildOperandTree(tokenList.Take(tokenList.Count - 1).ToList())
                    }));
                }

                throw new ParseException(string.Format("Encountered unary operator ({0}) that isn't recognized on the right.", token.data));
            }
            else if (IsFunctionPattern(tokenList))
            {
                Token token = tokenList[0];

                Operation operation = context.CreateFunction(token.data);
                if (operation == null)
                {
                    throw new ParseException(string.Format("Encountered unknown function \"{0}\".", token.data));
                }

                List <List <Token> > argumentList = ParseListOfTokenLists(tokenList.Skip(2).Take(tokenList.Count - 3).ToList());
                foreach (List <Token> subTokenList in argumentList)
                {
                    operation.operandList.Add(BuildOperandTree(subTokenList));
                }

                return(operation);
            }
            else if (tokenList[0].paranType == Token.ParanType.SQUARE && ParansMatch(tokenList, 0, tokenList.Count - 1))
            {
                List <List <Operand> > listOfOperandLists = new List <List <Operand> >();

                List <List <Token> > rowList = ParseListOfTokenLists(tokenList.Skip(1).Take(tokenList.Count - 2).ToList());
                foreach (List <Token> rowTokenList in rowList)
                {
                    listOfOperandLists.Add(new List <Operand>());

                    List <List <Token> > colList;
                    if (rowTokenList[0].paranType == Token.ParanType.SQUARE && ParansMatch(rowTokenList, 0, rowTokenList.Count - 1))
                    {
                        colList = ParseListOfTokenLists(rowTokenList.Skip(1).Take(rowTokenList.Count - 2).ToList());
                    }
                    else
                    {
                        colList = new List <List <Token> >()
                        {
                            rowTokenList
                        }
                    };

                    foreach (List <Token> subTokenList in colList)
                    {
                        listOfOperandLists[listOfOperandLists.Count - 1].Add(BuildOperandTree(subTokenList));
                    }
                }

                return(new Matrix(listOfOperandLists));
            }
            else
            {
                // Our goal here is to find an operator of lowest precedence.  It will never be
                // at the very beginning or end of the entire token sequence.
                List <Token> opTokenList = null;
                foreach (Token token in WalkTokensSkipSubexpressions(tokenList))
                {
                    if (token.kind != Token.Kind.OPERATOR)
                    {
                        continue;
                    }

                    // Only unary operators can be at the start or end of the token list.
                    if (tokenList.IndexOf(token) == 0 || tokenList.IndexOf(token) == tokenList.Count - 1)
                    {
                        continue;
                    }

                    // Ignore unary operators on left.
                    if (token.data == "-" && tokenList[tokenList.IndexOf(token) - 1].kind == Token.Kind.OPERATOR)
                    {
                        continue;
                    }

                    // Ignore unary operators on right.
                    if (token.data == "~" && tokenList[tokenList.IndexOf(token) + 1].kind == Token.Kind.OPERATOR)
                    {
                        continue;
                    }

                    // At this point we should be reasonably sure it's a binary operator we're looking at.
                    if (opTokenList == null || PrecedenceLevel(opTokenList[0].data) > PrecedenceLevel(token.data))
                    {
                        opTokenList = new List <Token>()
                        {
                            token
                        }
                    }
                    ;
                    else if (opTokenList != null && PrecedenceLevel(opTokenList[0].data) == PrecedenceLevel(token.data))
                    {
                        opTokenList.Add(token);
                    }
                }

                if (opTokenList == null)
                {
                    throw new ParseException("Did not encounter binary operator token.");
                }

                Token operatorToken = null;
                switch (OperatorAssociativity(opTokenList[0].data))
                {
                case Associativity.LEFT_TO_RIGHT:
                    operatorToken = opTokenList[opTokenList.Count - 1];
                    break;

                case Associativity.RIGHT_TO_LEFT:
                    operatorToken = opTokenList[0];
                    break;
                }

                Operation operation = null;

                if (operatorToken.data == ";")
                {
                    operation = new Sequence();
                }
                else if (operatorToken.data == "+" || operatorToken.data == "-")
                {
                    operation = new Sum();
                }
                else if (operatorToken.data == "*" || operatorToken.data == "/")
                {
                    operation = new GeometricProduct();
                }
                else if (operatorToken.data == ".")
                {
                    operation = new InnerProduct();
                }
                else if (operatorToken.data == "^")
                {
                    operation = new OuterProduct();
                }
                else if (operatorToken.data == "=")
                {
                    operation = new Assignment();
                }
                else if (operatorToken.data == ":=")
                {
                    operation = new Assignment(false);
                }

                if (operation == null)
                {
                    throw new ParseException(string.Format("Did not recognized operator token ({0}).", operatorToken.data));
                }

                int i = tokenList.IndexOf(operatorToken);

                Operand leftOperand  = BuildOperandTree(tokenList.Take(i).ToList());
                Operand rightOperand = BuildOperandTree(tokenList.Skip(i + 1).Take(tokenList.Count - 1 - i).ToList());

                operation.operandList.Add(leftOperand);

                if (operatorToken.data == "-")
                {
                    operation.operandList.Add(new GeometricProduct(new List <Operand>()
                    {
                        new NumericScalar(-1.0), rightOperand
                    }));
                }
                else if (operatorToken.data == "/")
                {
                    operation.operandList.Add(new Inverse(new List <Operand>()
                    {
                        rightOperand
                    }));
                }
                else
                {
                    operation.operandList.Add(rightOperand);
                }

                return(operation);
            }
        }