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); } } } } } }
// 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); } }