private static ISymbolicExpressionTreeNode CreateConstant(double v) { var constNode = (ConstantTreeNode)constantSy.CreateTreeNode(); constNode.Value = v; return(constNode); }
private ISymbolicExpressionTreeNode ParseSexp(Queue <Token> tokens) { if (tokens.Peek().Symbol == TokenSymbol.LPAR) { ISymbolicExpressionTreeNode tree; Expect(Token.LPAR, tokens); if (tokens.Peek().StringValue.StartsWith(VARSTART)) { tree = ParseVariable(tokens); } else if (tokens.Peek().StringValue.StartsWith(LAGGEDVARSTART)) { tree = ParseLaggedVariable(tokens); } else if (tokens.Peek().StringValue.StartsWith(TIMELAGSTART)) { tree = ParseTimeLag(tokens); tree.AddSubtree(ParseSexp(tokens)); } else if (tokens.Peek().StringValue.StartsWith(INTEGRALSTART)) { tree = ParseIntegral(tokens); tree.AddSubtree(ParseSexp(tokens)); } else if (tokens.Peek().StringValue.StartsWith(DEFUNSTART)) { tree = ParseDefun(tokens); while (!tokens.Peek().Equals(Token.RPAR)) { tree.AddSubtree(ParseSexp(tokens)); } } else if (tokens.Peek().StringValue.StartsWith(ARGSTART)) { tree = ParseArgument(tokens); } else if (tokens.Peek().StringValue.StartsWith(INVOKESTART)) { tree = ParseInvoke(tokens); while (!tokens.Peek().Equals(Token.RPAR)) { tree.AddSubtree(ParseSexp(tokens)); } } else if (tokens.Peek().StringValue.StartsWith("FACTOR")) { tree = ParseFactor(tokens); } else if (tokens.Peek().StringValue.StartsWith("BINFACTOR")) { tree = ParseBinaryFactor(tokens); } else { Token curToken = tokens.Dequeue(); tree = CreateTree(curToken); while (!tokens.Peek().Equals(Token.RPAR)) { tree.AddSubtree(ParseSexp(tokens)); } } Expect(Token.RPAR, tokens); return(tree); } else if (tokens.Peek().Symbol == TokenSymbol.NUMBER) { ConstantTreeNode t = (ConstantTreeNode)constant.CreateTreeNode(); t.Value = tokens.Dequeue().DoubleValue; return(t); } else { throw new FormatException("Expected function or constant symbol"); } }
/// Expr = ['-' | '+'] Term { '+' Term | '-' Term } private ISymbolicExpressionTreeNode ParseExpr(Queue <Token> tokens) { var next = tokens.Peek(); var posTerms = new List <ISymbolicExpressionTreeNode>(); var negTerms = new List <ISymbolicExpressionTreeNode>(); bool negateFirstTerm = false; if (next.TokenType == TokenType.Operator && (next.strVal == "+" || next.strVal == "-")) { tokens.Dequeue(); if (next.strVal == "-") { negateFirstTerm = true; } } var t = ParseTerm(tokens); if (negateFirstTerm) { negTerms.Add(t); } else { posTerms.Add(t); } next = tokens.Peek(); while (next.strVal == "+" || next.strVal == "-") { switch (next.strVal) { case "+": { tokens.Dequeue(); var term = ParseTerm(tokens); posTerms.Add(term); break; } case "-": { tokens.Dequeue(); var term = ParseTerm(tokens); negTerms.Add(term); break; } } next = tokens.Peek(); } var sum = GetSymbol("+").CreateTreeNode(); foreach (var posTerm in posTerms) { sum.AddSubtree(posTerm); } if (negTerms.Any()) { if (negTerms.Count == 1) { var sub = GetSymbol("-").CreateTreeNode(); sub.AddSubtree(negTerms.Single()); sum.AddSubtree(sub); } else { var sumNeg = GetSymbol("+").CreateTreeNode(); foreach (var negTerm in negTerms) { sumNeg.AddSubtree(negTerm); } var constNode = (ConstantTreeNode)constant.CreateTreeNode(); constNode.Value = -1.0; var prod = GetSymbol("*").CreateTreeNode(); prod.AddSubtree(constNode); prod.AddSubtree(sumNeg); sum.AddSubtree(prod); } } if (sum.SubtreeCount == 1) { return(sum.Subtrees.First()); } else { return(sum); } }
// simplify multiplications by reducing constants and div terms public static void SimplifyMultiplication(ref HashNode <ISymbolicExpressionTreeNode>[] nodes, int i) { var node = nodes[i]; var children = nodes.IterateChildren(i); for (int j = 0; j < children.Length; ++j) { var c = children[j]; var child = nodes[c]; if (!child.Enabled) { continue; } var symbol = child.Data.Symbol; if (child.Data is ConstantTreeNode firstConst) { // fold sibling constant nodes into the first constant for (int k = j + 1; k < children.Length; ++k) { var sibling = nodes[children[k]]; if (sibling.Data is ConstantTreeNode otherConst) { sibling.Enabled = false; node.Arity--; firstConst.Value *= otherConst.Value; } else { break; } } } else if (child.Data is VariableTreeNode variable) { // fold sibling constant nodes into the variable weight for (int k = j + 1; k < children.Length; ++k) { var sibling = nodes[children[k]]; if (sibling.Data is ConstantTreeNode constantNode) { sibling.Enabled = false; node.Arity--; variable.Weight *= constantNode.Value; } else { break; } } } else if (symbol is Division) { // 1/x is expressed as div(x) (with a single child) // we assume division always has arity 1 or 2 var d = child.Arity == 1 ? c - 1 : c - nodes[c - 1].Size - 2; var denominator = nodes[d]; // iterate children of node i to see if any of them matches the denominator of div node c for (int k = 0; k < children.Length; ++k) { var sibling = nodes[children[k]]; if (sibling.Enabled && sibling == denominator) { nodes.SetEnabled(children[j], false); // disable the div subtree nodes.SetEnabled(children[k], false); // disable the sibling matching the denominator node.Arity -= 2; // matching child + division node break; } } } if (node.Arity == 0) // if everything is simplified this node becomes constant { var constantTreeNode = constant.CreateTreeNode <ConstantTreeNode>(); constantTreeNode.Value = 1; nodes[i] = constantTreeNode.ToHashNode(); } else if (node.Arity == 1) // when i have only 1 arg left i can skip this node { node.Enabled = false; } } }