Ignore:
Timestamp:
09/24/20 11:14:43 (22 months ago)
Author:
gkronber
Message:

#3073 change sorting order for BoxBound

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/3073_IA_constraint_splitting/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalInterpreter.cs

    r17756 r17757  
    242242      // https://docs.microsoft.com/en-us/dotnet/api/system.collections.idictionary.keys?view=netcore-3.1#remarks
    243243      var box = variableIntervals.Values;
    244       if(minimization) {
     244      if (minimization) {
    245245        prioQ.Add(new BoxBound(box, interval.LowerBound));
    246246      } else {
     
    273273      }
    274274
    275       return minimization ? 
    276         prioQ.First().bound : 
     275      return minimization ?
     276        prioQ.First().bound :
    277277        -prioQ.First().bound;
    278278    }
     
    286286
    287287    // a multi-dimensional box with an associated bound
    288     // boxbounds are ordered first by bound (smaller first), then by size of box (smaller first) then by extent in each dimension
     288    // boxbounds are ordered first by bound (smaller first), then by size of box (larger first) then by distance of bottom left corner to origin
    289289    private class BoxBound : IComparable<BoxBound> {
    290290      public List<Interval> box;
     
    296296      public int CompareTo(BoxBound other) {
    297297        if (bound != other.bound) return bound.CompareTo(other.bound);
    298        
     298
    299299        var thisSize = box.Aggregate(1.0, (current, dimExtent) => current * dimExtent.Width);
    300300        var otherSize = other.box.Aggregate(1.0, (current, dimExtent) => current * dimExtent.Width);
    301         if (thisSize != otherSize) return thisSize.CompareTo(otherSize);
    302 
    303         for(int i=0;i<box.Count;i++) {
    304           if (box[i].Width != other.box[i].Width) return box[i].Width.CompareTo(other.box[i].Width);
    305         }
     301        if (thisSize != otherSize) return -thisSize.CompareTo(otherSize);
     302
     303        var thisDist = box.Sum(dimExtent => dimExtent.LowerBound * dimExtent.LowerBound);
     304        var otherDist = other.box.Sum(dimExtent => dimExtent.LowerBound * dimExtent.LowerBound);
     305        if (thisDist != otherDist) return thisDist.CompareTo(otherDist);
     306
     307        // which is smaller first along the dimensions?
     308        for (int i = 0; i < box.Count; i++) {
     309          if (box[i].LowerBound != other.box[i].LowerBound) return box[i].LowerBound.CompareTo(other.box[i].LowerBound);
     310        }
     311
    306312        return 0;
    307313      }
    308     }
    309 
    310     public static Interval EvaluateRecursive(
    311       Instruction[] instructions,
    312       IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals,
    313       IDictionary<string, Interval> variableIntervals, IList<string> variables,
    314       double minWidth, int maxDepth, ref int currIndex, ref int currDepth,
    315       ISymbolicExpressionTree tree) {
    316       Interval evaluate() {
    317         var ic = 0;
    318         IReadOnlyDictionary<string, Interval> readonlyRanges =
    319           new ReadOnlyDictionary<string, Interval>(variableIntervals);
    320         return Evaluate(instructions, ref ic, nodeIntervals, readonlyRanges);
    321       }
    322 
    323       Interval recurse(ref int idx, ref int depth) {
    324         return EvaluateRecursive(instructions, nodeIntervals, variableIntervals, variables, minWidth, maxDepth, ref idx,
    325           ref depth, tree);
    326       }
    327 
    328 
    329       var v = variables[currIndex];
    330       var x = variableIntervals[v];
    331       if (x.Width < minWidth || currDepth == maxDepth || !MultipleTimes(tree, v)) {
    332         if (currIndex + 1 < variables.Count) {
    333           currDepth = 0;
    334           currIndex++;
    335           var z = recurse(ref currIndex, ref currDepth);
    336           currIndex--;
    337           return z;
    338         }
    339 
    340         return evaluate();
    341       }
    342 
    343       var t = x.Split();
    344       var xa = t.Item1;
    345       var xb = t.Item2;
    346       var d = currDepth;
    347       currDepth = d + 1;
    348       variableIntervals[v] = xa;
    349       var ya = recurse(ref currIndex, ref currDepth);
    350       currDepth = d + 1;
    351       variableIntervals[v] = xb;
    352       var yb = recurse(ref currIndex, ref currDepth);
    353       variableIntervals[v] = x; // restore interval
    354       return ya | yb;
    355     }
    356 
    357     public static Interval Evaluate(
    358       Instruction[] instructions, ref int instructionCounter,
    359       IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals = null,
    360       IReadOnlyDictionary<string, Interval> variableIntervals = null) {
    361       var currentInstr = instructions[instructionCounter];
    362       //Use ref parameter, because the tree will be iterated through recursively from the left-side branch to the right side
    363       //Update instructionCounter, whenever Evaluate is called
    364       instructionCounter++;
    365       Interval result = null;
    366 
    367       switch (currentInstr.opCode) {
    368         //Variables, Constants, ...
    369         case OpCodes.Variable: {
    370             var variableTreeNode = (VariableTreeNode)currentInstr.dynamicNode;
    371             var weightInterval = new Interval(variableTreeNode.Weight, variableTreeNode.Weight);
    372             //var variableInterval = (Interval)currentInstr.data;
    373 
    374             Interval variableInterval;
    375             if (variableIntervals != null && variableIntervals.ContainsKey(variableTreeNode.VariableName))
    376               variableInterval = variableIntervals[variableTreeNode.VariableName];
    377             else
    378               variableInterval = (Interval)currentInstr.data;
    379 
    380             result = Interval.Multiply(variableInterval, weightInterval);
    381             break;
     314
     315      public static Interval EvaluateRecursive(
     316        Instruction[] instructions,
     317        IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals,
     318        IDictionary<string, Interval> variableIntervals, IList<string> variables,
     319        double minWidth, int maxDepth, ref int currIndex, ref int currDepth,
     320        ISymbolicExpressionTree tree) {
     321        Interval evaluate() {
     322          var ic = 0;
     323          IReadOnlyDictionary<string, Interval> readonlyRanges =
     324            new ReadOnlyDictionary<string, Interval>(variableIntervals);
     325          return Evaluate(instructions, ref ic, nodeIntervals, readonlyRanges);
     326        }
     327
     328        Interval recurse(ref int idx, ref int depth) {
     329          return EvaluateRecursive(instructions, nodeIntervals, variableIntervals, variables, minWidth, maxDepth, ref idx,
     330            ref depth, tree);
     331        }
     332
     333
     334        var v = variables[currIndex];
     335        var x = variableIntervals[v];
     336        if (x.Width < minWidth || currDepth == maxDepth || !MultipleTimes(tree, v)) {
     337          if (currIndex + 1 < variables.Count) {
     338            currDepth = 0;
     339            currIndex++;
     340            var z = recurse(ref currIndex, ref currDepth);
     341            currIndex--;
     342            return z;
    382343          }
    383         case OpCodes.Constant: {
    384             var constTreeNode = (ConstantTreeNode)currentInstr.dynamicNode;
    385             result = new Interval(constTreeNode.Value, constTreeNode.Value);
    386             break;
    387           }
    388         //Elementary arithmetic rules
    389         case OpCodes.Add: {
    390             //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    391             result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    392             for (var i = 1; i < currentInstr.nArguments; i++) {
    393               //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    394               var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    395               result = Interval.Add(result, argumentInterval);
    396             }
    397 
    398             break;
    399           }
    400         case OpCodes.Sub: {
    401             //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    402             result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    403             if (currentInstr.nArguments == 1)
    404               result = Interval.Multiply(new Interval(-1, -1), result);
    405 
    406             for (var i = 1; i < currentInstr.nArguments; i++) {
    407               //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    408               var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    409               result = Interval.Subtract(result, argumentInterval);
    410             }
    411 
    412             break;
    413           }
    414         case OpCodes.Mul: {
    415             //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    416             result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    417             for (var i = 1; i < currentInstr.nArguments; i++) {
    418               var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    419               //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    420               result = Interval.Multiply(result, argumentInterval);
    421             }
    422 
    423             break;
    424           }
    425         case OpCodes.Div: {
    426             //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    427             result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    428             if (currentInstr.nArguments == 1)
    429               result = Interval.Divide(new Interval(1, 1), result);
    430 
    431             for (var i = 1; i < currentInstr.nArguments; i++) {
    432               //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    433               var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    434               result = Interval.Divide(result, argumentInterval);
    435             }
    436 
    437             break;
    438           }
    439         //Trigonometric functions
    440         case OpCodes.Sin: {
    441             //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    442             var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    443             result = Interval.Sine(argumentInterval);
    444             break;
    445           }
    446         case OpCodes.Cos: {
    447             //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    448             var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    449             result = Interval.Cosine(argumentInterval);
    450             break;
    451           }
    452         case OpCodes.Tan: {
    453             //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    454             var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    455             result = Interval.Tangens(argumentInterval);
    456             break;
    457           }
    458         case OpCodes.Tanh: {
    459             //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    460             var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    461             result = Interval.HyperbolicTangent(argumentInterval);
    462             break;
    463           }
    464         //Exponential functions
    465         case OpCodes.Log: {
    466             //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    467             var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    468             result = Interval.Logarithm(argumentInterval);
    469             break;
    470           }
    471         case OpCodes.Exp: {
    472             //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    473             var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    474             result = Interval.Exponential(argumentInterval);
    475             break;
    476           }
    477         case OpCodes.Square: {
    478             //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    479             var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    480             result = Interval.Square(argumentInterval);
    481             break;
    482           }
    483         case OpCodes.SquareRoot: {
    484             //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    485             var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    486             result = Interval.SquareRoot(argumentInterval);
    487             break;
    488           }
    489         case OpCodes.Cube: {
    490             //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    491             var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    492             result = Interval.Cube(argumentInterval);
    493             break;
    494           }
    495         case OpCodes.CubeRoot: {
    496             //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    497             var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    498             result = Interval.CubicRoot(argumentInterval);
    499             break;
    500           }
    501         case OpCodes.Absolute: {
    502             //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    503             var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    504             result = Interval.Absolute(argumentInterval);
    505             break;
    506           }
    507         case OpCodes.AnalyticQuotient: {
    508             //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    509             result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    510             for (var i = 1; i < currentInstr.nArguments; i++) {
    511               //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    512               var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
    513               result = Interval.AnalyticalQuotient(result, argumentInterval);
    514             }
    515 
    516             break;
    517           }
    518         default:
    519           throw new NotSupportedException($"The tree contains the unknown symbol {currentInstr.dynamicNode.Symbol}");
    520       }
    521 
    522       if (!(nodeIntervals == null || nodeIntervals.ContainsKey(currentInstr.dynamicNode)))
    523         nodeIntervals.Add(currentInstr.dynamicNode, result);
    524 
    525       return result;
    526     }
    527 
    528     private static bool MultipleTimes(ISymbolicExpressionTree tree, string variable) {
    529       var varlist = tree.IterateNodesPrefix().OfType<VariableTreeNode>().GroupBy(x => x.VariableName);
    530       var group = varlist.Select(x => x.Key == variable).Count();
    531 
    532       return group > 1;
    533     }
    534 
    535     private static bool ContainsVariableMultipleTimes(ISymbolicExpressionTree tree) {
    536       var varlist = tree.IterateNodesPrefix().OfType<VariableTreeNode>().GroupBy(x => x.VariableName);
    537       return varlist.Any(group => group.Count() > 1);
    538     }
    539 
    540 
    541     public static bool IsCompatible(ISymbolicExpressionTree tree) {
    542       var containsUnknownSymbols = (
    543         from n in tree.Root.GetSubtree(0).IterateNodesPrefix()
    544         where
    545           !(n.Symbol is Variable) &&
    546           !(n.Symbol is Constant) &&
    547           !(n.Symbol is StartSymbol) &&
    548           !(n.Symbol is Addition) &&
    549           !(n.Symbol is Subtraction) &&
    550           !(n.Symbol is Multiplication) &&
    551           !(n.Symbol is Division) &&
    552           !(n.Symbol is Sine) &&
    553           !(n.Symbol is Cosine) &&
    554           !(n.Symbol is Tangent) &&
    555           !(n.Symbol is HyperbolicTangent) &&
    556           !(n.Symbol is Logarithm) &&
    557           !(n.Symbol is Exponential) &&
    558           !(n.Symbol is Square) &&
    559           !(n.Symbol is SquareRoot) &&
    560           !(n.Symbol is Cube) &&
    561           !(n.Symbol is CubeRoot) &&
    562           !(n.Symbol is Absolute) &&
    563           !(n.Symbol is AnalyticQuotient)
    564         select n).Any();
    565       return !containsUnknownSymbols;
     344
     345          return evaluate();
     346        }
     347
     348        var t = x.Split();
     349        var xa = t.Item1;
     350        var xb = t.Item2;
     351        var d = currDepth;
     352        currDepth = d + 1;
     353        variableIntervals[v] = xa;
     354        var ya = recurse(ref currIndex, ref currDepth);
     355        currDepth = d + 1;
     356        variableIntervals[v] = xb;
     357        var yb = recurse(ref currIndex, ref currDepth);
     358        variableIntervals[v] = x; // restore interval
     359        return ya | yb;
     360      }
     361
     362      public static Interval Evaluate(
     363        Instruction[] instructions, ref int instructionCounter,
     364        IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals = null,
     365        IReadOnlyDictionary<string, Interval> variableIntervals = null) {
     366        var currentInstr = instructions[instructionCounter];
     367        //Use ref parameter, because the tree will be iterated through recursively from the left-side branch to the right side
     368        //Update instructionCounter, whenever Evaluate is called
     369        instructionCounter++;
     370        Interval result = null;
     371
     372        switch (currentInstr.opCode) {
     373          //Variables, Constants, ...
     374          case OpCodes.Variable: {
     375              var variableTreeNode = (VariableTreeNode)currentInstr.dynamicNode;
     376              var weightInterval = new Interval(variableTreeNode.Weight, variableTreeNode.Weight);
     377              //var variableInterval = (Interval)currentInstr.data;
     378
     379              Interval variableInterval;
     380              if (variableIntervals != null && variableIntervals.ContainsKey(variableTreeNode.VariableName))
     381                variableInterval = variableIntervals[variableTreeNode.VariableName];
     382              else
     383                variableInterval = (Interval)currentInstr.data;
     384
     385              result = Interval.Multiply(variableInterval, weightInterval);
     386              break;
     387            }
     388          case OpCodes.Constant: {
     389              var constTreeNode = (ConstantTreeNode)currentInstr.dynamicNode;
     390              result = new Interval(constTreeNode.Value, constTreeNode.Value);
     391              break;
     392            }
     393          //Elementary arithmetic rules
     394          case OpCodes.Add: {
     395              //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     396              result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     397              for (var i = 1; i < currentInstr.nArguments; i++) {
     398                //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     399                var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     400                result = Interval.Add(result, argumentInterval);
     401              }
     402
     403              break;
     404            }
     405          case OpCodes.Sub: {
     406              //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     407              result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     408              if (currentInstr.nArguments == 1)
     409                result = Interval.Multiply(new Interval(-1, -1), result);
     410
     411              for (var i = 1; i < currentInstr.nArguments; i++) {
     412                //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     413                var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     414                result = Interval.Subtract(result, argumentInterval);
     415              }
     416
     417              break;
     418            }
     419          case OpCodes.Mul: {
     420              //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     421              result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     422              for (var i = 1; i < currentInstr.nArguments; i++) {
     423                var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     424                //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     425                result = Interval.Multiply(result, argumentInterval);
     426              }
     427
     428              break;
     429            }
     430          case OpCodes.Div: {
     431              //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     432              result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     433              if (currentInstr.nArguments == 1)
     434                result = Interval.Divide(new Interval(1, 1), result);
     435
     436              for (var i = 1; i < currentInstr.nArguments; i++) {
     437                //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     438                var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     439                result = Interval.Divide(result, argumentInterval);
     440              }
     441
     442              break;
     443            }
     444          //Trigonometric functions
     445          case OpCodes.Sin: {
     446              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     447              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     448              result = Interval.Sine(argumentInterval);
     449              break;
     450            }
     451          case OpCodes.Cos: {
     452              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     453              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     454              result = Interval.Cosine(argumentInterval);
     455              break;
     456            }
     457          case OpCodes.Tan: {
     458              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     459              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     460              result = Interval.Tangens(argumentInterval);
     461              break;
     462            }
     463          case OpCodes.Tanh: {
     464              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     465              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     466              result = Interval.HyperbolicTangent(argumentInterval);
     467              break;
     468            }
     469          //Exponential functions
     470          case OpCodes.Log: {
     471              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     472              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     473              result = Interval.Logarithm(argumentInterval);
     474              break;
     475            }
     476          case OpCodes.Exp: {
     477              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     478              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     479              result = Interval.Exponential(argumentInterval);
     480              break;
     481            }
     482          case OpCodes.Square: {
     483              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     484              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     485              result = Interval.Square(argumentInterval);
     486              break;
     487            }
     488          case OpCodes.SquareRoot: {
     489              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     490              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     491              result = Interval.SquareRoot(argumentInterval);
     492              break;
     493            }
     494          case OpCodes.Cube: {
     495              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     496              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     497              result = Interval.Cube(argumentInterval);
     498              break;
     499            }
     500          case OpCodes.CubeRoot: {
     501              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     502              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     503              result = Interval.CubicRoot(argumentInterval);
     504              break;
     505            }
     506          case OpCodes.Absolute: {
     507              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     508              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     509              result = Interval.Absolute(argumentInterval);
     510              break;
     511            }
     512          case OpCodes.AnalyticQuotient: {
     513              //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     514              result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     515              for (var i = 1; i < currentInstr.nArguments; i++) {
     516                //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     517                var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
     518                result = Interval.AnalyticalQuotient(result, argumentInterval);
     519              }
     520
     521              break;
     522            }
     523          default:
     524            throw new NotSupportedException($"The tree contains the unknown symbol {currentInstr.dynamicNode.Symbol}");
     525        }
     526
     527        if (!(nodeIntervals == null || nodeIntervals.ContainsKey(currentInstr.dynamicNode)))
     528          nodeIntervals.Add(currentInstr.dynamicNode, result);
     529
     530        return result;
     531      }
     532
     533      private static bool MultipleTimes(ISymbolicExpressionTree tree, string variable) {
     534        var varlist = tree.IterateNodesPrefix().OfType<VariableTreeNode>().GroupBy(x => x.VariableName);
     535        var group = varlist.Select(x => x.Key == variable).Count();
     536
     537        return group > 1;
     538      }
     539
     540      private static bool ContainsVariableMultipleTimes(ISymbolicExpressionTree tree) {
     541        var varlist = tree.IterateNodesPrefix().OfType<VariableTreeNode>().GroupBy(x => x.VariableName);
     542        return varlist.Any(group => group.Count() > 1);
     543      }
     544
     545
     546      public static bool IsCompatible(ISymbolicExpressionTree tree) {
     547        var containsUnknownSymbols = (
     548          from n in tree.Root.GetSubtree(0).IterateNodesPrefix()
     549          where
     550            !(n.Symbol is Variable) &&
     551            !(n.Symbol is Constant) &&
     552            !(n.Symbol is StartSymbol) &&
     553            !(n.Symbol is Addition) &&
     554            !(n.Symbol is Subtraction) &&
     555            !(n.Symbol is Multiplication) &&
     556            !(n.Symbol is Division) &&
     557            !(n.Symbol is Sine) &&
     558            !(n.Symbol is Cosine) &&
     559            !(n.Symbol is Tangent) &&
     560            !(n.Symbol is HyperbolicTangent) &&
     561            !(n.Symbol is Logarithm) &&
     562            !(n.Symbol is Exponential) &&
     563            !(n.Symbol is Square) &&
     564            !(n.Symbol is SquareRoot) &&
     565            !(n.Symbol is Cube) &&
     566            !(n.Symbol is CubeRoot) &&
     567            !(n.Symbol is Absolute) &&
     568            !(n.Symbol is AnalyticQuotient)
     569          select n).Any();
     570        return !containsUnknownSymbols;
     571      }
    566572    }
    567573  }
    568 }
Note: See TracChangeset for help on using the changeset viewer.