Changeset 17757
 Timestamp:
 09/24/20 11:14:43 (20 months ago)
 File:

 1 edited
Legend:
 Unmodified
 Added
 Removed

branches/3073_IA_constraint_splitting/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalInterpreter.cs
r17756 r17757 242 242 // https://docs.microsoft.com/enus/dotnet/api/system.collections.idictionary.keys?view=netcore3.1#remarks 243 243 var box = variableIntervals.Values; 244 if (minimization) {244 if (minimization) { 245 245 prioQ.Add(new BoxBound(box, interval.LowerBound)); 246 246 } else { … … 273 273 } 274 274 275 return minimization ? 276 prioQ.First().bound : 275 return minimization ? 276 prioQ.First().bound : 277 277 prioQ.First().bound; 278 278 } … … 286 286 287 287 // a multidimensional 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 dimension288 // boxbounds are ordered first by bound (smaller first), then by size of box (larger first) then by distance of bottom left corner to origin 289 289 private class BoxBound : IComparable<BoxBound> { 290 290 public List<Interval> box; … … 296 296 public int CompareTo(BoxBound other) { 297 297 if (bound != other.bound) return bound.CompareTo(other.bound); 298 298 299 299 var thisSize = box.Aggregate(1.0, (current, dimExtent) => current * dimExtent.Width); 300 300 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 306 312 return 0; 307 313 } 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 leftside 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; 382 343 } 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 leftside 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 } 566 572 } 567 573 } 568 }
Note: See TracChangeset
for help on using the changeset viewer.