Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
01/15/17 14:17:06 (7 years ago)
Author:
bburlacu
Message:

#1772: Merge trunk changes.

Location:
branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic
Files:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic

  • branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/InfixExpressionParser.cs

    r14307 r14576  
    2626using System.Text;
    2727using HeuristicLab.Collections;
     28using HeuristicLab.Common;
    2829using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
    2930
     
    3738  /// </summary>
    3839  public sealed class InfixExpressionParser {
    39     private enum TokenType { Operator, Identifier, Number, LeftPar, RightPar, End, NA };
     40    private enum TokenType { Operator, Identifier, Number, LeftPar, RightPar, Comma, End, NA };
    4041    private class Token {
    4142      internal double doubleVal;
     
    102103        { "MEAN", new Average()},
    103104        { "IF", new IfThenElse()},
    104         { ">", new GreaterThan()},
    105         { "<", new LessThan()},
     105        { "GT", new GreaterThan()},
     106        { "LT", new LessThan()},
    106107        { "AND", new And()},
    107108        { "OR", new Or()},
     
    109110        { "XOR", new Xor()},
    110111        { "DIFF", new Derivative()},
     112        { "LAG", new LaggedVariable() },
    111113      };
    112114
     
    138140        }
    139141        if (char.IsDigit(str[pos])) {
    140           // read number (=> read until white space or operator)
     142          // read number (=> read until white space or operator or comma)
    141143          var sb = new StringBuilder();
    142144          sb.Append(str[pos]);
    143145          pos++;
    144146          while (pos < str.Length && !char.IsWhiteSpace(str[pos])
    145             && (str[pos] != '+' || str[pos-1] == 'e' || str[pos-1] == 'E')     // continue reading exponents
     147            && (str[pos] != '+' || str[pos - 1] == 'e' || str[pos - 1] == 'E')     // continue reading exponents
    146148            && (str[pos] != '-' || str[pos - 1] == 'e' || str[pos - 1] == 'E')
    147             && str[pos] != '*'           
     149            && str[pos] != '*'
    148150            && str[pos] != '/'
    149             && str[pos] != ')') {
     151            && str[pos] != ')'
     152            && str[pos] != ',') {
    150153            sb.Append(str[pos]);
    151154            pos++;
     
    211214          pos++;
    212215          yield return new Token { TokenType = TokenType.RightPar, strVal = ")" };
    213         }
    214       }
    215     }
    216 
    217     // S = Expr EOF
    218     // Expr = ['-' | '+'] Term { '+' Term | '-' Term }
    219     // Term = Fact { '*' Fact | '/' Fact }
    220     // Fact = '(' Expr ')' | funcId '(' Expr ')' | varId | number
     216        } else if (str[pos] == ',') {
     217          pos++;
     218          yield return new Token { TokenType = TokenType.Comma, strVal = "," };
     219        } else {
     220          throw new ArgumentException("Invalid character: " + str[pos]);
     221        }
     222      }
     223    }
     224
     225    // S       = Expr EOF
     226    // Expr    = ['-' | '+'] Term { '+' Term | '-' Term }
     227    // Term    = Fact { '*' Fact | '/' Fact }
     228    // Fact    = '(' Expr ')' | funcId '(' ArgList ')' | varId | number
     229    // ArgList = Expr { ',' Expr }
    221230    private ISymbolicExpressionTreeNode ParseS(Queue<Token> tokens) {
    222231      var expr = ParseExpr(tokens);
     
    326335    }
    327336
    328     // Fact = '(' Expr ')' | funcId '(' Expr ')' | varId | number
     337    // Fact = '(' Expr ')' | 'LAG' '(' varId ',' ['+' | '-'] number ')' | funcId '(' ArgList ')' | varId | number
    329338    private ISymbolicExpressionTreeNode ParseFact(Queue<Token> tokens) {
    330339      var next = tokens.Peek();
     
    346355          if (lPar.TokenType != TokenType.LeftPar)
    347356            throw new ArgumentException("expected (");
    348           var expr = ParseExpr(tokens);
     357
     358          // handle 'lag' specifically
     359          if (funcNode.Symbol is LaggedVariable) {
     360            var varId = tokens.Dequeue();
     361            if (varId.TokenType != TokenType.Identifier) throw new ArgumentException("Identifier expected. Format for lagged variables: \"lag(x, -1)\"");
     362            var comma = tokens.Dequeue();
     363            if (comma.TokenType != TokenType.Comma) throw new ArgumentException("',' expected, Format for lagged variables: \"lag(x, -1)\"");
     364            double sign = 1.0;
     365            if (tokens.Peek().strVal == "+" || tokens.Peek().strVal == "-") {
     366              // read sign
     367              var signTok = tokens.Dequeue();
     368              if (signTok.strVal == "-") sign = -1.0;
     369            }
     370            var lagToken = tokens.Dequeue();
     371            if (lagToken.TokenType != TokenType.Number) throw new ArgumentException("Number expected, Format for lagged variables: \"lag(x, -1)\"");
     372            if (!lagToken.doubleVal.IsAlmost(Math.Round(lagToken.doubleVal)))
     373              throw new ArgumentException("Time lags must be integer values");
     374            var laggedVarNode = funcNode as LaggedVariableTreeNode;
     375            laggedVarNode.VariableName = varId.strVal;
     376            laggedVarNode.Lag = (int)Math.Round(sign * lagToken.doubleVal);
     377            laggedVarNode.Weight = 1.0;
     378          } else {
     379            // functions
     380            var args = ParseArgList(tokens);
     381            // check number of arguments
     382            if (funcNode.Symbol.MinimumArity > args.Length || funcNode.Symbol.MaximumArity < args.Length) {
     383              throw new ArgumentException(string.Format("Symbol {0} requires between {1} and  {2} arguments.", funcId,
     384                funcNode.Symbol.MinimumArity, funcNode.Symbol.MaximumArity));
     385            }
     386            foreach (var arg in args) funcNode.AddSubtree(arg);
     387          }
     388
    349389          var rPar = tokens.Dequeue();
    350390          if (rPar.TokenType != TokenType.RightPar)
    351391            throw new ArgumentException("expected )");
    352392
    353           funcNode.AddSubtree(expr);
    354393          return funcNode;
    355394        } else {
     
    369408      }
    370409    }
     410
     411    // ArgList = Expr { ',' Expr }
     412    private ISymbolicExpressionTreeNode[] ParseArgList(Queue<Token> tokens) {
     413      var exprList = new List<ISymbolicExpressionTreeNode>();
     414      exprList.Add(ParseExpr(tokens));
     415      while (tokens.Peek().TokenType != TokenType.RightPar) {
     416        var comma = tokens.Dequeue();
     417        if (comma.TokenType != TokenType.Comma) throw new ArgumentException("expected ',' ");
     418        exprList.Add(ParseExpr(tokens));
     419      }
     420      return exprList.ToArray();
     421    }
    371422  }
    372423}
Note: See TracChangeset for help on using the changeset viewer.