Changeset 14347


Ignore:
Timestamp:
10/22/16 10:21:15 (13 months ago)
Author:
gkronber
Message:

#2677: extended infix parser and infix formatter to support functions with multiple arguments

Location:
trunk/sources
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/InfixExpressionFormatter.cs

    r14026 r14347  
    8181          }
    8282          strBuilder.Append(")");
     83        } else {
     84          // function with multiple arguments
     85          strBuilder.Append(token).Append("(");
     86          FormatRecursively(node.Subtrees.First(), strBuilder);
     87          foreach (var subtree in node.Subtrees.Skip(1)) {
     88            strBuilder.Append(", ");
     89            FormatRecursively(subtree, strBuilder);
     90          }
     91          strBuilder.Append(")");
    8392        }
    8493      } else if (node.SubtreeCount == 1) {
     
    94103          FormatRecursively(node.GetSubtree(0), strBuilder);
    95104        } else {
    96           // function
     105          // function with only one argument
    97106          strBuilder.Append(token).Append("(");
    98107          FormatRecursively(node.GetSubtree(0), strBuilder);
  • trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/InfixExpressionParser.cs

    r14319 r14347  
    3737  /// </summary>
    3838  public sealed class InfixExpressionParser {
    39     private enum TokenType { Operator, Identifier, Number, LeftPar, RightPar, End, NA };
     39    private enum TokenType { Operator, Identifier, Number, LeftPar, RightPar, Comma, End, NA };
    4040    private class Token {
    4141      internal double doubleVal;
     
    102102        { "MEAN", new Average()},
    103103        { "IF", new IfThenElse()},
    104         { ">", new GreaterThan()},
    105         { "<", new LessThan()},
     104        { "GT", new GreaterThan()},
     105        { "LT", new LessThan()},
    106106        { "AND", new And()},
    107107        { "OR", new Or()},
     
    138138        }
    139139        if (char.IsDigit(str[pos])) {
    140           // read number (=> read until white space or operator)
     140          // read number (=> read until white space or operator or comma)
    141141          var sb = new StringBuilder();
    142142          sb.Append(str[pos]);
     
    147147            && str[pos] != '*'
    148148            && str[pos] != '/'
    149             && str[pos] != ')') {
     149            && str[pos] != ')'
     150            && str[pos] != ',') {
    150151            sb.Append(str[pos]);
    151152            pos++;
     
    211212          pos++;
    212213          yield return new Token { TokenType = TokenType.RightPar, strVal = ")" };
     214        } else if (str[pos] == ',') {
     215          pos++;
     216          yield return new Token { TokenType = TokenType.Comma, strVal = "," };
    213217        } else {
    214218          throw new ArgumentException("Invalid character: " + str[pos]);
     
    217221    }
    218222
    219     // S = Expr EOF
    220     // Expr = ['-' | '+'] Term { '+' Term | '-' Term }
    221     // Term = Fact { '*' Fact | '/' Fact }
    222     // Fact = '(' Expr ')' | funcId '(' Expr ')' | varId | number
     223    // S       = Expr EOF
     224    // Expr    = ['-' | '+'] Term { '+' Term | '-' Term }
     225    // Term    = Fact { '*' Fact | '/' Fact }
     226    // Fact    = '(' Expr ')' | funcId '(' ArgList ')' | varId | number
     227    // ArgList = Expr { ',' Expr }
    223228    private ISymbolicExpressionTreeNode ParseS(Queue<Token> tokens) {
    224229      var expr = ParseExpr(tokens);
     
    328333    }
    329334
    330     // Fact = '(' Expr ')' | funcId '(' Expr ')' | varId | number
     335    // Fact = '(' Expr ')' | funcId '(' ArgList ')' | varId | number
    331336    private ISymbolicExpressionTreeNode ParseFact(Queue<Token> tokens) {
    332337      var next = tokens.Peek();
     
    348353          if (lPar.TokenType != TokenType.LeftPar)
    349354            throw new ArgumentException("expected (");
    350           var expr = ParseExpr(tokens);
     355          var args = ParseArgList(tokens);
     356
     357          // check semantic constraints
     358          if (funcNode.Symbol.MinimumArity > args.Length || funcNode.Symbol.MaximumArity < args.Length)
     359            throw new ArgumentException(string.Format("Symbol {0} requires between {1} and  {2} arguments.", funcId,
     360              funcNode.Symbol.MinimumArity, funcNode.Symbol.MaximumArity));
     361          foreach (var arg in args) funcNode.AddSubtree(arg);
     362
    351363          var rPar = tokens.Dequeue();
    352364          if (rPar.TokenType != TokenType.RightPar)
    353365            throw new ArgumentException("expected )");
    354366
    355           funcNode.AddSubtree(expr);
    356367          return funcNode;
    357368        } else {
     
    371382      }
    372383    }
     384
     385    // ArgList = Expr { ',' Expr }
     386    private ISymbolicExpressionTreeNode[] ParseArgList(Queue<Token> tokens) {
     387      var exprList = new List<ISymbolicExpressionTreeNode>();
     388      exprList.Add(ParseExpr(tokens));
     389      while (tokens.Peek().TokenType != TokenType.RightPar) {
     390        var comma = tokens.Dequeue();
     391        if (comma.TokenType != TokenType.Comma) throw new ArgumentException("expected ',' ");
     392        exprList.Add(ParseExpr(tokens));
     393      }
     394      return exprList.ToArray();
     395    }
    373396  }
    374397}
  • trunk/sources/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/InfixExpressionParserTest.cs

    r14109 r14347  
    8686      Console.WriteLine(formatter.Format(parser.Parse("x1*x2+x3*x4")));
    8787
     88
     89      Console.WriteLine(formatter.Format(parser.Parse("POW(3, 2)")));
     90      Console.WriteLine(formatter.Format(parser.Parse("POW(3.1, 2.1)")));
     91      Console.WriteLine(formatter.Format(parser.Parse("POW(3.1 , 2.1)")));
     92      Console.WriteLine(formatter.Format(parser.Parse("POW(3.1 ,2.1)")));
     93      Console.WriteLine(formatter.Format(parser.Parse("POW(-3.1 , - 2.1)")));
     94      Console.WriteLine(formatter.Format(parser.Parse("ROOT(3, 2)")));
     95      Console.WriteLine(formatter.Format(parser.Parse("ROOT(3.1, 2.1)")));
     96      Console.WriteLine(formatter.Format(parser.Parse("ROOT(3.1 , 2.1)")));
     97      Console.WriteLine(formatter.Format(parser.Parse("ROOT(3.1 ,2.1)")));
     98      Console.WriteLine(formatter.Format(parser.Parse("ROOT(-3.1 , - 2.1)")));
     99
     100      Console.WriteLine(formatter.Format(parser.Parse("IF(GT( 0, 1), 1, 0)")));
     101      Console.WriteLine(formatter.Format(parser.Parse("IF(LT(0,1), 1 , 0)")));
     102
    88103    }
    89104  }
Note: See TracChangeset for help on using the changeset viewer.