- Timestamp:
- 01/03/22 12:23:11 (3 years ago)
- Location:
- branches/3136_Structural_GP
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/3136_Structural_GP
- Property svn:mergeinfo changed
/trunk merged: 18165-18174
- Property svn:mergeinfo changed
-
branches/3136_Structural_GP/HeuristicLab.Problems.DataAnalysis.Symbolic
- Property svn:mergeinfo changed
/trunk/HeuristicLab.Problems.DataAnalysis.Symbolic merged: 18169,18171-18172,18174
- Property svn:mergeinfo changed
-
branches/3136_Structural_GP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/DerivativeCalculator.cs
r18146 r18176 158 158 var newExponent = (NumberTreeNode)numberSy.CreateTreeNode(); 159 159 newExponent.Value = ((NumberTreeNode)newPower.GetSubtree(1)).Value - 1; 160 newPower.RemoveSubtree(1); 161 newPower.AddSubtree(newExponent); 160 162 return Product(Product(CreateNumber(exponent.Value), newPower), Derive(f, variableName)); 161 163 } else throw new NotSupportedException("Cannot derive non-integer powers"); -
branches/3136_Structural_GP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/InfixExpressionFormatter.cs
r18157 r18176 37 37 var token = GetToken(node.Symbol); 38 38 // operators 39 if (token == "+" || token == "-" || token == "OR" || token == "XOR" || 40 token == "*" || token == "/" || token == "AND") { 41 strBuilder.Append("("); 39 if (token == "+" || token == "-" || token == "OR" || token == "XOR") { 40 var parenthesisRequired = false; 41 if (node.Parent != null && node.Parent.SubtreeCount > 1) { 42 var parentOp = GetToken(node.Parent.Symbol); 43 if (parentOp != "+" && parentOp != "-" && parentOp != "OR" && parentOp != "XOR") 44 parenthesisRequired = true; 45 } 46 if (parenthesisRequired) strBuilder.Append("("); 42 47 FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString, parameters); 43 48 … … 47 52 } 48 53 49 strBuilder.Append(")"); 54 if (parenthesisRequired) strBuilder.Append(")"); 55 } else if (token == "*" || token == "/" || token == "AND") { 56 FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString, parameters); 57 58 foreach (var subtree in node.Subtrees.Skip(1)) { 59 strBuilder.Append(" ").Append(token).Append(" "); 60 // a / b * c => a / (b * C) 61 if (subtree.SubtreeCount > 1 && token == "/" && GetToken(subtree.Symbol) == "*") { 62 strBuilder.Append("("); 63 FormatRecursively(subtree, strBuilder, numberFormat, formatString, parameters); 64 strBuilder.Append(")"); 65 } else { 66 FormatRecursively(subtree, strBuilder, numberFormat, formatString, parameters); 67 } 68 } 50 69 } else if (token == "^") { 51 70 // handle integer powers directly 52 strBuilder.Append("(");53 71 FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString, parameters); 54 72 … … 60 78 FormatRecursively(power, strBuilder, numberFormat, formatString, parameters); 61 79 } 62 63 strBuilder.Append(")");64 80 } else { 65 81 // function with multiple arguments … … 78 94 var token = GetToken(node.Symbol); 79 95 if (token == "-" || token == "NOT") { 80 strBuilder.Append("(").Append(token).Append("("); 81 FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, parameters); 82 strBuilder.Append("))"); 96 strBuilder.Append(token); 97 FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, parameters); 83 98 } else if (token == "/") { 84 99 strBuilder.Append("1/"); … … 97 112 var varNode = node as LaggedVariableTreeNode; 98 113 if (!varNode.Weight.IsAlmost(1.0)) { 99 strBuilder.Append("(");100 114 AppendNumber(strBuilder, parameters, varNode.Weight, formatString, numberFormat); 101 115 strBuilder.Append("*"); … … 107 121 .AppendFormat(numberFormat, "{0}", varNode.Lag) 108 122 .Append(")"); 109 if (!varNode.Weight.IsAlmost(1.0)) strBuilder.Append(")");110 123 } else if (node.Symbol is Variable) { 111 124 var varNode = node as VariableTreeNode; 112 125 if (!varNode.Weight.IsAlmost(1.0)) { 113 strBuilder.Append("(");114 126 AppendNumber(strBuilder, parameters, varNode.Weight, formatString, numberFormat); 115 127 strBuilder.Append("*"); 116 128 } 117 118 129 AppendVariableName(strBuilder, varNode.VariableName); 119 120 if (!varNode.Weight.IsAlmost(1.0)) strBuilder.Append(")");121 130 } else if (node.Symbol is FactorVariable) { 122 131 var factorNode = node as FactorVariableTreeNode; … … 132 141 var factorNode = node as BinaryFactorVariableTreeNode; 133 142 if (!factorNode.Weight.IsAlmost(1.0)) { 134 strBuilder.Append("(");135 143 AppendNumber(strBuilder, parameters, factorNode.Weight, formatString, numberFormat); 136 137 144 strBuilder.Append("*"); 138 145 } 139 140 146 AppendVariableName(strBuilder, factorNode.VariableName); 141 147 strBuilder.Append(" = "); 142 148 AppendVariableName(strBuilder, factorNode.VariableValue); 143 144 if (!factorNode.Weight.IsAlmost(1.0)) strBuilder.Append(")");145 149 } else if (node is INumericTreeNode numNode) { 146 150 if (parameters == null && numNode.Value < 0) { 147 151 // negative value 148 strBuilder.Append("(").Append(numNode.Value.ToString(formatString, numberFormat)) 149 .Append(")"); 152 strBuilder.Append(numNode.Value.ToString(formatString, numberFormat)); 150 153 } else { 151 154 AppendNumber(strBuilder, parameters, numNode.Value, formatString, numberFormat); -
branches/3136_Structural_GP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/InfixExpressionParser.cs
r18157 r18176 40 40 /// 41 41 /// S = Expr EOF 42 /// Expr = ['-' | '+']Term { '+' Term | '-' Term }42 /// Expr = Term { '+' Term | '-' Term } 43 43 /// Term = Fact { '*' Fact | '/' Fact } 44 44 /// Fact = SimpleFact [ '^' SimpleFact ] … … 49 49 /// | VarExpr 50 50 /// | number 51 /// | ['+' | '-'] SimpleFact 51 52 /// ArgList = Expr { ',' Expr } 52 53 /// VarExpr = varId OptFactorPart 53 /// OptFactorPart = [ ('=' varVal | '[' ['+' | '-' ] number {',' ['+' | '-' ]number } ']' ) ]54 /// OptFactorPart = [ ('=' varVal | '[' ['+' | '-' ] number {',' ['+' | '-' ] number } ']' ) ] 54 55 /// varId = ident | ' ident ' | " ident " 55 56 /// varVal = ident | ' ident ' | " ident " … … 84 85 85 86 private Number number = new Number(); 86 private Constant constant = new Constant();87 private Constant minusOne = new Constant() { Value = -1 }; 87 88 private Variable variable = new Variable(); 88 89 private BinaryFactorVariable binaryFactorVar = new BinaryFactorVariable(); … … 139 140 { "XOR", new Xor()}, 140 141 { "DIFF", new Derivative()}, 141 { "LAG", new LaggedVariable() } 142 { "LAG", new LaggedVariable() }, 142 143 }; 143 144 … … 163 164 int pos = 0; 164 165 while (true) { 165 while (pos < str.Length && Char.IsWhiteSpace(str[pos])) pos++;166 while (pos < str.Length && char.IsWhiteSpace(str[pos])) pos++; 166 167 if (pos >= str.Length) { 167 168 yield return new Token { TokenType = TokenType.End, strVal = "" }; … … 169 170 } 170 171 if (char.IsDigit(str[pos])) { 171 // read number (=> read until white space or o perator or comma)172 // read number (=> read until white space or other symbol) 172 173 var sb = new StringBuilder(); 173 174 sb.Append(str[pos]); … … 270 271 } else if (str[pos] == '<') { 271 272 pos++; 272 yield return new Token { TokenType = TokenType.LeftAngleBracket, strVal = "<"};273 yield return new Token { TokenType = TokenType.LeftAngleBracket, strVal = "<" }; 273 274 } else if (str[pos] == '>') { 274 275 pos++; 275 yield return new Token { TokenType = TokenType.RightAngleBracket, strVal = ">"};276 yield return new Token { TokenType = TokenType.RightAngleBracket, strVal = ">" }; 276 277 } else { 277 278 throw new ArgumentException("Invalid character: " + str[pos]); … … 290 291 } 291 292 292 /// Expr = ['-' | '+']Term { '+' Term | '-' Term }293 /// Expr = Term { '+' Term | '-' Term } 293 294 private ISymbolicExpressionTreeNode ParseExpr(Queue<Token> tokens) { 295 // build tree from bottom to top and left to right 296 // a + b - c => ((a + b) - c) 297 // a - b - c => ((a - b) - c) 298 // and then flatten as far as possible 299 var left = ParseTerm(tokens); 300 294 301 var next = tokens.Peek(); 295 var posTerms = new List<ISymbolicExpressionTreeNode>();296 var negTerms = new List<ISymbolicExpressionTreeNode>();297 bool negateFirstTerm = false;298 if (next.TokenType == TokenType.Operator && (next.strVal == "+" || next.strVal == "-")) {299 tokens.Dequeue();300 if (next.strVal == "-")301 negateFirstTerm = true;302 }303 var t = ParseTerm(tokens);304 if (negateFirstTerm) negTerms.Add(t);305 else posTerms.Add(t);306 307 next = tokens.Peek();308 302 while (next.strVal == "+" || next.strVal == "-") { 309 303 switch (next.strVal) { 310 304 case "+": { 311 305 tokens.Dequeue(); 312 var term = ParseTerm(tokens); 313 posTerms.Add(term); 306 var right = ParseTerm(tokens); 307 var op = GetSymbol("+").CreateTreeNode(); 308 op.AddSubtree(left); 309 op.AddSubtree(right); 310 left = op; 314 311 break; 315 312 } 316 313 case "-": { 317 314 tokens.Dequeue(); 318 var term = ParseTerm(tokens); 319 negTerms.Add(term); 315 var right = ParseTerm(tokens); 316 var op = GetSymbol("-").CreateTreeNode(); 317 op.AddSubtree(left); 318 op.AddSubtree(right); 319 left = op; 320 320 break; 321 321 } … … 324 324 } 325 325 326 var sum = GetSymbol("+").CreateTreeNode(); 327 foreach (var posTerm in posTerms) sum.AddSubtree(posTerm); 328 if (negTerms.Any()) { 329 if (negTerms.Count == 1) { 330 var sub = GetSymbol("-").CreateTreeNode(); 331 sub.AddSubtree(negTerms.Single()); 332 sum.AddSubtree(sub); 333 } else { 334 var sumNeg = GetSymbol("+").CreateTreeNode(); 335 foreach (var negTerm in negTerms) sumNeg.AddSubtree(negTerm); 336 337 var constNode = (NumberTreeNode)number.CreateTreeNode(); 338 constNode.Value = -1.0; 339 var prod = GetSymbol("*").CreateTreeNode(); 340 prod.AddSubtree(constNode); 341 prod.AddSubtree(sumNeg); 342 343 sum.AddSubtree(prod); 344 } 345 } 346 if (sum.SubtreeCount == 1) return sum.Subtrees.First(); 347 else return sum; 326 FoldLeftRecursive(left); 327 return left; 348 328 } 349 329 350 330 private ISymbol GetSymbol(string tok) { 351 if (knownSymbols.ContainsFirst(tok))331 if (knownSymbols.ContainsFirst(tok)) 352 332 return knownSymbols.GetByFirst(tok).FirstOrDefault(); 353 333 else … … 357 337 /// Term = Fact { '*' Fact | '/' Fact } 358 338 private ISymbolicExpressionTreeNode ParseTerm(Queue<Token> tokens) { 359 var factors = new List<ISymbolicExpressionTreeNode>(); 360 var firstFactor = ParseFact(tokens); 361 factors.Add(firstFactor); 339 // build tree from bottom to top and left to right 340 // a / b * c => ((a / b) * c) 341 // a / b / c => ((a / b) / c) 342 // and then flatten as far as possible 343 344 var left = ParseFact(tokens); 362 345 363 346 var next = tokens.Peek(); … … 366 349 case "*": { 367 350 tokens.Dequeue(); 368 var fact = ParseFact(tokens); 369 factors.Add(fact); 351 var right = ParseFact(tokens); 352 353 var op = GetSymbol("*").CreateTreeNode(); 354 op.AddSubtree(left); 355 op.AddSubtree(right); 356 left = op; 370 357 break; 371 358 } 372 359 case "/": { 373 360 tokens.Dequeue(); 374 var invFact = ParseFact(tokens); 375 var divNode = GetSymbol("/").CreateTreeNode(); // 1/x 376 divNode.AddSubtree(invFact); 377 factors.Add(divNode); 361 var right = ParseFact(tokens); 362 var op = GetSymbol("/").CreateTreeNode(); 363 op.AddSubtree(left); 364 op.AddSubtree(right); 365 left = op; 378 366 break; 379 367 } … … 382 370 next = tokens.Peek(); 383 371 } 384 if (factors.Count == 1) return factors.First(); 385 else { 386 var prod = GetSymbol("*").CreateTreeNode(); 387 foreach (var f in factors) prod.AddSubtree(f); 388 return prod; 372 // remove all nodes where the child op is the same as the parent op 373 // (a * b) * c) => (a * b * c) 374 // (a / b) / c) => (a / b / c) 375 376 FoldLeftRecursive(left); 377 return left; 378 } 379 380 private void FoldLeftRecursive(ISymbolicExpressionTreeNode parent) { 381 if (parent.SubtreeCount > 1) { 382 var child = parent.GetSubtree(0); 383 FoldLeftRecursive(child); 384 if (parent.Symbol == child.Symbol && IsAssociative(parent.Symbol)) { 385 parent.RemoveSubtree(0); 386 for (int i = 0; i < child.SubtreeCount; i++) { 387 parent.InsertSubtree(i, child.GetSubtree(i)); 388 } 389 } 389 390 } 390 391 } … … 411 412 /// | funcId '(' ArgList ') 412 413 /// | VarExpr 414 /// | '<' 'num' [ '=' [ '+' | '-' ] number ] '>' 413 415 /// | number 416 /// | ['+' | '-' ] SimpleFact 414 417 /// ArgList = Expr { ',' Expr } 415 418 /// VarExpr = varId OptFactorPart … … 435 438 if (tokens.Peek().TokenType == TokenType.LeftPar) { 436 439 // function identifier or LAG 437 var funcId = idTok.strVal.ToUpperInvariant(); 438 439 var funcNode = GetSymbol(funcId).CreateTreeNode(); 440 var lPar = tokens.Dequeue(); 441 if (lPar.TokenType != TokenType.LeftPar) 442 throw new ArgumentException("expected ("); 443 444 // handle 'lag' specifically 445 if (funcNode.Symbol is LaggedVariable) { 446 var varId = tokens.Dequeue(); 447 if (varId.TokenType != TokenType.Identifier) throw new ArgumentException("Identifier expected. Format for lagged variables: \"lag(x, -1)\""); 448 var comma = tokens.Dequeue(); 449 if (comma.TokenType != TokenType.Comma) throw new ArgumentException("',' expected, Format for lagged variables: \"lag(x, -1)\""); 450 double sign = 1.0; 451 if (tokens.Peek().strVal == "+" || tokens.Peek().strVal == "-") { 452 // read sign 453 var signTok = tokens.Dequeue(); 454 if (signTok.strVal == "-") sign = -1.0; 455 } 456 var lagToken = tokens.Dequeue(); 457 if (lagToken.TokenType != TokenType.Number) throw new ArgumentException("Number expected, Format for lagged variables: \"lag(x, -1)\""); 458 if (!lagToken.doubleVal.IsAlmost(Math.Round(lagToken.doubleVal))) 459 throw new ArgumentException("Time lags must be integer values"); 460 var laggedVarNode = funcNode as LaggedVariableTreeNode; 461 laggedVarNode.VariableName = varId.strVal; 462 laggedVarNode.Lag = (int)Math.Round(sign * lagToken.doubleVal); 463 laggedVarNode.Weight = 1.0; 464 } else if (funcNode.Symbol is SubFunctionSymbol) { // SubFunction 465 var subFunction = funcNode as SubFunctionTreeNode; 466 subFunction.Name = next.strVal; 467 // input arguments 468 var args = ParseArgList(tokens); 469 IList<string> arguments = new List<string>(); 470 foreach (var arg in args) 471 if(arg is VariableTreeNode varTreeNode) 472 arguments.Add(varTreeNode.VariableName); 473 subFunction.Arguments = arguments; 440 return ParseFunctionOrLaggedVariable(tokens, idTok); 441 } else { 442 return ParseVariable(tokens, idTok); 443 } 444 } else if (next.TokenType == TokenType.LeftAngleBracket) { 445 // '<' 'num' [ '=' ['+'|'-'] number ] '>' 446 return ParseNumber(tokens); 447 } else if (next.TokenType == TokenType.Operator && (next.strVal == "-" || next.strVal == "+")) { 448 // ['+' | '-' ] SimpleFact 449 if (tokens.Dequeue().strVal == "-") { 450 var arg = ParseSimpleFact(tokens); 451 if (arg is NumberTreeNode numNode) { 452 numNode.Value *= -1; 453 return numNode; 454 } else if (arg is ConstantTreeNode constNode) { 455 var constSy = new Constant { Value = -constNode.Value }; 456 return constSy.CreateTreeNode(); 457 } else if (arg is VariableTreeNode varNode) { 458 varNode.Weight *= -1; 459 return varNode; 474 460 } else { 475 // functions 476 var args = ParseArgList(tokens); 477 // check number of arguments 478 if (funcNode.Symbol.MinimumArity > args.Length || funcNode.Symbol.MaximumArity < args.Length) { 479 throw new ArgumentException(string.Format("Symbol {0} requires between {1} and {2} arguments.", funcId, 480 funcNode.Symbol.MinimumArity, funcNode.Symbol.MaximumArity)); 481 } 482 foreach (var arg in args) funcNode.AddSubtree(arg); 461 var mul = GetSymbol("*").CreateTreeNode(); 462 var neg = minusOne.CreateTreeNode(); 463 mul.AddSubtree(neg); 464 mul.AddSubtree(arg); 465 return mul; 483 466 } 484 485 var rPar = tokens.Dequeue();486 if (rPar.TokenType != TokenType.RightPar)487 throw new ArgumentException("expected )");488 489 490 return funcNode;491 467 } else { 492 // variable 493 if (tokens.Peek().TokenType == TokenType.Eq) { 494 // binary factor 495 tokens.Dequeue(); // skip Eq 496 var valTok = tokens.Dequeue(); 497 if (valTok.TokenType != TokenType.Identifier) throw new ArgumentException("expected identifier"); 498 var binFactorNode = (BinaryFactorVariableTreeNode)binaryFactorVar.CreateTreeNode(); 499 binFactorNode.Weight = 1.0; 500 binFactorNode.VariableName = idTok.strVal; 501 binFactorNode.VariableValue = valTok.strVal; 502 return binFactorNode; 503 } else if (tokens.Peek().TokenType == TokenType.LeftBracket) { 504 // factor variable 505 var factorVariableNode = (FactorVariableTreeNode)factorVar.CreateTreeNode(); 506 factorVariableNode.VariableName = idTok.strVal; 507 508 tokens.Dequeue(); // skip [ 509 var weights = new List<double>(); 510 // at least one weight is necessary 511 var sign = 1.0; 512 if (tokens.Peek().TokenType == TokenType.Operator) { 513 var opToken = tokens.Dequeue(); 514 if (opToken.strVal == "+") sign = 1.0; 515 else if (opToken.strVal == "-") sign = -1.0; 516 else throw new ArgumentException(); 517 } 518 if (tokens.Peek().TokenType != TokenType.Number) throw new ArgumentException("number expected"); 519 var weightTok = tokens.Dequeue(); 520 weights.Add(sign * weightTok.doubleVal); 521 while (tokens.Peek().TokenType == TokenType.Comma) { 522 // skip comma 523 tokens.Dequeue(); 524 if (tokens.Peek().TokenType == TokenType.Operator) { 525 var opToken = tokens.Dequeue(); 526 if (opToken.strVal == "+") sign = 1.0; 527 else if (opToken.strVal == "-") sign = -1.0; 528 else throw new ArgumentException(); 529 } 530 weightTok = tokens.Dequeue(); 531 if (weightTok.TokenType != TokenType.Number) throw new ArgumentException("number expected"); 532 weights.Add(sign * weightTok.doubleVal); 533 } 534 var rightBracketToken = tokens.Dequeue(); 535 if (rightBracketToken.TokenType != TokenType.RightBracket) throw new ArgumentException("closing bracket ] expected"); 536 factorVariableNode.Weights = weights.ToArray(); 537 return factorVariableNode; 538 } else { 539 // variable 540 var varNode = (VariableTreeNode)variable.CreateTreeNode(); 541 varNode.Weight = 1.0; 542 varNode.VariableName = idTok.strVal; 543 return varNode; 544 } 545 } 546 } else if (next.TokenType == TokenType.LeftAngleBracket) { 547 Token numberTok = null; 548 var leftAngleBracket = tokens.Dequeue(); 549 if (leftAngleBracket.TokenType != TokenType.LeftAngleBracket) 550 throw new ArgumentException("opening bracket < expected"); 551 552 var idTok = tokens.Dequeue(); 553 if (idTok.TokenType != TokenType.Identifier || idTok.strVal.ToLower() != "num") 554 throw new ArgumentException("string 'num' expected"); 555 556 if (tokens.Peek().TokenType == TokenType.Eq) { 557 var equalTok = tokens.Dequeue(); 558 if (tokens.Peek().TokenType != TokenType.Number) 559 throw new ArgumentException("No value for number specified."); 560 561 numberTok = tokens.Dequeue(); 562 } 563 564 var rightAngleBracket = tokens.Dequeue(); 565 if (rightAngleBracket.TokenType != TokenType.RightAngleBracket) 566 throw new ArgumentException("closing bracket > expected"); 567 var numNode = (NumberTreeNode)number.CreateTreeNode(); 568 if (numberTok != null) numNode.Value = numberTok.doubleVal; 569 return numNode; 468 return ParseSimpleFact(tokens); 469 } 570 470 } else if (next.TokenType == TokenType.Number) { 471 // number 571 472 var numTok = tokens.Dequeue(); 572 var constSy = new Constant { Value = numTok.doubleVal};473 var constSy = new Constant { Value = numTok.doubleVal }; 573 474 return constSy.CreateTreeNode(); 574 475 } else { 575 476 throw new ArgumentException(string.Format("unexpected token in expression {0}", next.strVal)); 576 477 } 478 } 479 480 private ISymbolicExpressionTreeNode ParseNumber(Queue<Token> tokens) { 481 // we distinguish parameters and constants. The values of parameters can be changed. 482 // a parameter is written as '<' 'num' [ '=' ['+'|'-'] number ] '>' with an optional initialization 483 Token numberTok = null; 484 var leftAngleBracket = tokens.Dequeue(); 485 if (leftAngleBracket.TokenType != TokenType.LeftAngleBracket) 486 throw new ArgumentException("opening bracket < expected"); 487 488 var idTok = tokens.Dequeue(); 489 if (idTok.TokenType != TokenType.Identifier || idTok.strVal.ToLower() != "num") 490 throw new ArgumentException("string 'num' expected"); 491 492 var numNode = (NumberTreeNode)number.CreateTreeNode(); 493 494 if (tokens.Peek().TokenType == TokenType.Eq) { 495 tokens.Dequeue(); // skip "=" 496 var next = tokens.Peek(); 497 if (next.strVal != "+" && next.strVal != "-" && next.TokenType != TokenType.Number) 498 throw new ArgumentException("Expected '+', '-' or number."); 499 500 var sign = 1.0; 501 if (next.strVal == "+" || next.strVal == "-") { 502 if (tokens.Dequeue().strVal == "-") sign = -1.0; 503 } 504 if (tokens.Peek().TokenType != TokenType.Number) { 505 throw new ArgumentException("Expected number."); 506 } 507 numberTok = tokens.Dequeue(); 508 numNode.Value = sign * numberTok.doubleVal; 509 } 510 511 var rightAngleBracket = tokens.Dequeue(); 512 if (rightAngleBracket.TokenType != TokenType.RightAngleBracket) 513 throw new ArgumentException("closing bracket > expected"); 514 515 return numNode; 516 } 517 518 private ISymbolicExpressionTreeNode ParseVariable(Queue<Token> tokens, Token idTok) { 519 // variable 520 if (tokens.Peek().TokenType == TokenType.Eq) { 521 // binary factor 522 tokens.Dequeue(); // skip Eq 523 var valTok = tokens.Dequeue(); 524 if (valTok.TokenType != TokenType.Identifier) throw new ArgumentException("expected identifier"); 525 var binFactorNode = (BinaryFactorVariableTreeNode)binaryFactorVar.CreateTreeNode(); 526 binFactorNode.Weight = 1.0; 527 binFactorNode.VariableName = idTok.strVal; 528 binFactorNode.VariableValue = valTok.strVal; 529 return binFactorNode; 530 } else if (tokens.Peek().TokenType == TokenType.LeftBracket) { 531 // factor variable 532 var factorVariableNode = (FactorVariableTreeNode)factorVar.CreateTreeNode(); 533 factorVariableNode.VariableName = idTok.strVal; 534 535 tokens.Dequeue(); // skip [ 536 var weights = new List<double>(); 537 // at least one weight is necessary 538 var sign = 1.0; 539 if (tokens.Peek().TokenType == TokenType.Operator) { 540 var opToken = tokens.Dequeue(); 541 if (opToken.strVal == "+") sign = 1.0; 542 else if (opToken.strVal == "-") sign = -1.0; 543 else throw new ArgumentException(); 544 } 545 if (tokens.Peek().TokenType != TokenType.Number) throw new ArgumentException("number expected"); 546 var weightTok = tokens.Dequeue(); 547 weights.Add(sign * weightTok.doubleVal); 548 while (tokens.Peek().TokenType == TokenType.Comma) { 549 // skip comma 550 tokens.Dequeue(); 551 if (tokens.Peek().TokenType == TokenType.Operator) { 552 var opToken = tokens.Dequeue(); 553 if (opToken.strVal == "+") sign = 1.0; 554 else if (opToken.strVal == "-") sign = -1.0; 555 else throw new ArgumentException(); 556 } 557 weightTok = tokens.Dequeue(); 558 if (weightTok.TokenType != TokenType.Number) throw new ArgumentException("number expected"); 559 weights.Add(sign * weightTok.doubleVal); 560 } 561 var rightBracketToken = tokens.Dequeue(); 562 if (rightBracketToken.TokenType != TokenType.RightBracket) throw new ArgumentException("closing bracket ] expected"); 563 factorVariableNode.Weights = weights.ToArray(); 564 return factorVariableNode; 565 } else { 566 // variable 567 var varNode = (VariableTreeNode)variable.CreateTreeNode(); 568 varNode.Weight = 1.0; 569 varNode.VariableName = idTok.strVal; 570 return varNode; 571 } 572 } 573 574 private ISymbolicExpressionTreeNode ParseFunctionOrLaggedVariable(Queue<Token> tokens, Token idTok) { 575 var funcId = idTok.strVal.ToUpperInvariant(); 576 577 var funcNode = GetSymbol(funcId).CreateTreeNode(); 578 var lPar = tokens.Dequeue(); 579 if (lPar.TokenType != TokenType.LeftPar) 580 throw new ArgumentException("expected ("); 581 582 // handle 'lag' specifically 583 if (funcNode.Symbol is LaggedVariable) { 584 ParseLaggedVariable(tokens, funcNode); 585 } else if (funcNode.Symbol is SubFunctionSymbol) { // SubFunction 586 var subFunction = funcNode as SubFunctionTreeNode; 587 subFunction.Name = idTok.strVal; 588 // input arguments 589 var args = ParseArgList(tokens); 590 IList<string> arguments = new List<string>(); 591 foreach (var arg in args) 592 if (arg is VariableTreeNode varTreeNode) 593 arguments.Add(varTreeNode.VariableName); 594 subFunction.Arguments = arguments; 595 } else { 596 // functions 597 var args = ParseArgList(tokens); 598 // check number of arguments 599 if (funcNode.Symbol.MinimumArity > args.Length || funcNode.Symbol.MaximumArity < args.Length) { 600 throw new ArgumentException(string.Format("Symbol {0} requires between {1} and {2} arguments.", funcId, 601 funcNode.Symbol.MinimumArity, funcNode.Symbol.MaximumArity)); 602 } 603 foreach (var arg in args) funcNode.AddSubtree(arg); 604 } 605 606 var rPar = tokens.Dequeue(); 607 if (rPar.TokenType != TokenType.RightPar) 608 throw new ArgumentException("expected )"); 609 610 611 return funcNode; 612 } 613 614 private static void ParseLaggedVariable(Queue<Token> tokens, ISymbolicExpressionTreeNode funcNode) { 615 var varId = tokens.Dequeue(); 616 if (varId.TokenType != TokenType.Identifier) throw new ArgumentException("Identifier expected. Format for lagged variables: \"lag(x, -1)\""); 617 var comma = tokens.Dequeue(); 618 if (comma.TokenType != TokenType.Comma) throw new ArgumentException("',' expected, Format for lagged variables: \"lag(x, -1)\""); 619 double sign = 1.0; 620 if (tokens.Peek().strVal == "+" || tokens.Peek().strVal == "-") { 621 // read sign 622 var signTok = tokens.Dequeue(); 623 if (signTok.strVal == "-") sign = -1.0; 624 } 625 var lagToken = tokens.Dequeue(); 626 if (lagToken.TokenType != TokenType.Number) throw new ArgumentException("Number expected, Format for lagged variables: \"lag(x, -1)\""); 627 if (!lagToken.doubleVal.IsAlmost(Math.Round(lagToken.doubleVal))) 628 throw new ArgumentException("Time lags must be integer values"); 629 var laggedVarNode = funcNode as LaggedVariableTreeNode; 630 laggedVarNode.VariableName = varId.strVal; 631 laggedVarNode.Lag = (int)Math.Round(sign * lagToken.doubleVal); 632 laggedVarNode.Weight = 1.0; 577 633 } 578 634 … … 588 644 return exprList.ToArray(); 589 645 } 646 647 private bool IsAssociative(ISymbol sy) { 648 return sy == GetSymbol("+") || sy == GetSymbol("-") || 649 sy == GetSymbol("*") || sy == GetSymbol("/") || 650 sy == GetSymbol("AND") || sy == GetSymbol("OR") || sy == GetSymbol("XOR"); 651 } 590 652 } 591 653 }
Note: See TracChangeset
for help on using the changeset viewer.