Changeset 17891 for branches/3073_IA_constraint_splitting_reintegration/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalArithCompiledExpressionBoundsEstimator.cs
- Timestamp:
- 03/12/21 16:41:42 (3 years ago)
- Location:
- branches/3073_IA_constraint_splitting_reintegration
- Files:
-
- 1 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
branches/3073_IA_constraint_splitting_reintegration
- Property svn:ignore
-
old new 1 1 bin 2 TestResults
-
- Property svn:ignore
-
branches/3073_IA_constraint_splitting_reintegration/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalArithCompiledExpressionBoundsEstimator.cs
r17890 r17891 1 1 using HEAL.Attic; 2 3 2 using HeuristicLab.Common; 4 3 using HeuristicLab.Core; … … 6 5 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; 7 6 using HeuristicLab.Parameters; 8 9 7 using System; 10 8 using System.Collections.Generic; … … 12 10 using System.Linq.Expressions; 13 11 14 namespace HeuristicLab.Problems.DataAnalysis.Symbolic 15 { 12 namespace HeuristicLab.Problems.DataAnalysis.Symbolic { 16 13 [StorableType("60015D64-5D8B-408A-90A1-E4111BC114D4")] 17 [Item("IA Compiled Expression Bounds Estimator", "Compile a symbolic model into a lambda and use it to evaluate model bounds.")] 18 public class IACompiledExpressionBoundsEstimator : ParameterizedNamedItem, IBoundsEstimator 19 { 14 [Item("Interval Arithmetic Compiled Expression Bounds Estimator", "Compile a symbolic model into a lambda and use it to evaluate model bounds.")] 15 public class IntervalArithCompiledExpressionBoundsEstimator : ParameterizedNamedItem, IBoundsEstimator { 20 16 // interval method names 21 17 private static readonly Dictionary<byte, string> methodName = new Dictionary<byte, string>() { … … 39 35 40 36 private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions"; 41 private const string UseIntervalSplittingParameterName = "Use Interval splitting";42 private const string MaxSplitParameterName = "MaxSplit";43 private const string MinWidthParameterName = "MinWidth";44 45 37 public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter { 46 38 get => (IFixedValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName]; 47 39 } 48 49 public IFixedValueParameter<BoolValue> UseIntervalSplittingParameter {50 get => (IFixedValueParameter<BoolValue>)Parameters[UseIntervalSplittingParameterName];51 }52 53 public IFixedValueParameter<IntValue> MaxSplitParameter {54 get => (IFixedValueParameter<IntValue>)Parameters[MaxSplitParameterName];55 }56 57 public IFixedValueParameter<DoubleValue> MinWidthParameter {58 get => (IFixedValueParameter<DoubleValue>)Parameters[MinWidthParameterName];59 }60 61 public int MaxSplit {62 get => MaxSplitParameter.Value.Value;63 set => MaxSplitParameter.Value.Value = value;64 }65 66 public double MinWidth {67 get => MinWidthParameter.Value.Value;68 set => MinWidthParameter.Value.Value = value;69 }70 71 40 public int EvaluatedSolutions { 72 41 get => EvaluatedSolutionsParameter.Value.Value; … … 74 43 } 75 44 76 public bool UseIntervalSplitting {77 get => UseIntervalSplittingParameter.Value.Value;78 set => UseIntervalSplittingParameter.Value.Value = value;79 }80 81 45 private readonly object syncRoot = new object(); 82 46 83 public I ACompiledExpressionBoundsEstimator() : base("IABounds Estimator",47 public IntervalArithCompiledExpressionBoundsEstimator() : base("Interval Arith Bounds Estimator", 84 48 "Estimates the bounds of the model with interval arithmetic, by first compiling the model into a lambda.") { 85 49 Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName, 86 50 "A counter for the total number of solutions the estimator has evaluated.", new IntValue(0))); 87 Parameters.Add(new FixedValueParameter<BoolValue>(UseIntervalSplittingParameterName,88 "Defines whether interval splitting is activated or not.", new BoolValue(false)));89 Parameters.Add(new FixedValueParameter<IntValue>(MaxSplitParameterName,90 "Defines the number of iterations of splitting.", new IntValue(200)));91 Parameters.Add(new FixedValueParameter<DoubleValue>(MinWidthParameterName,92 "Width of interval, after the splitting should stop.", new DoubleValue(0.0)));93 51 } 94 52 95 53 [StorableConstructor] 96 private I ACompiledExpressionBoundsEstimator(StorableConstructorFlag _) : base(_) { }97 98 private I ACompiledExpressionBoundsEstimator(IACompiledExpressionBoundsEstimator original, Cloner cloner) : base(original, cloner) { }54 private IntervalArithCompiledExpressionBoundsEstimator(StorableConstructorFlag _) : base(_) { } 55 56 private IntervalArithCompiledExpressionBoundsEstimator(IntervalArithCompiledExpressionBoundsEstimator original, Cloner cloner) : base(original, cloner) { } 99 57 100 58 public override IDeepCloneable Clone(Cloner cloner) { 101 return new IACompiledExpressionBoundsEstimator(this, cloner); 102 } 103 104 105 106 public double CheckConstraint(ISymbolicExpressionTree tree, IntervalCollection variableRanges, ShapeConstraint constraint) { 107 if (!UseIntervalSplitting) { 108 var modelBound = GetModelBound(tree, variableRanges); 109 if (constraint.Interval.Contains(modelBound)) return 0.0; 110 return Math.Abs(modelBound.LowerBound - constraint.Interval.LowerBound) + 111 Math.Abs(modelBound.UpperBound - constraint.Interval.UpperBound); 112 } 113 114 if (double.IsNegativeInfinity(constraint.Interval.LowerBound) && 115 double.IsPositiveInfinity(constraint.Interval.UpperBound)) { 116 return 0.0; 117 } 118 119 //ContainsVariableMultipleTimes(tree, out var variables); 120 121 lock (syncRoot) { EvaluatedSolutions++; } 122 123 double upperBound; 124 if (double.IsNegativeInfinity(constraint.Interval.LowerBound)) { 125 upperBound = EstimateUpperBound(tree, variableRanges.GetReadonlyDictionary(), MaxSplit, MinWidth); 126 127 return upperBound <= constraint.Interval.UpperBound 128 ? 0.0 129 : Math.Abs(upperBound - constraint.Interval.UpperBound); 130 } 131 132 double lowerBound; 133 if (double.IsPositiveInfinity(constraint.Interval.UpperBound)) { 134 lowerBound = EstimateLowerBound(tree, variableRanges.GetReadonlyDictionary(), MaxSplit, MinWidth); 135 136 return lowerBound <= constraint.Interval.LowerBound 137 ? 0.0 138 : Math.Abs(lowerBound - constraint.Interval.LowerBound); 139 } 140 141 var ranges = variableRanges.GetReadonlyDictionary(); 142 lowerBound = EstimateLowerBound(tree, ranges, MaxSplit, MinWidth); 143 upperBound = EstimateUpperBound(tree, ranges, MaxSplit, MinWidth); 144 145 var res = 0.0; 146 147 res += upperBound <= constraint.Interval.UpperBound ? 0.0 : Math.Abs(upperBound - constraint.Interval.UpperBound); 148 res += lowerBound <= constraint.Interval.LowerBound ? 0.0 : Math.Abs(lowerBound - constraint.Interval.LowerBound); 149 150 return res; 59 return new IntervalArithCompiledExpressionBoundsEstimator(this, cloner); 60 } 61 62 public double GetConstraintViolation(ISymbolicExpressionTree tree, IntervalCollection variableRanges, ShapeConstraint constraint) { 63 var modelBound = GetModelBound(tree, variableRanges); 64 if (constraint.Interval.Contains(modelBound)) return 0.0; 65 return Math.Abs(modelBound.LowerBound - constraint.Interval.LowerBound) + 66 Math.Abs(modelBound.UpperBound - constraint.Interval.UpperBound); 151 67 } 152 68 … … 157 73 public Interval GetModelBound(ISymbolicExpressionTree tree, IntervalCollection variableRanges) { 158 74 lock (syncRoot) { EvaluatedSolutions++; } 159 var resultInterval = UseIntervalSplitting 160 ? EstimateBounds(tree, variableRanges.GetReadonlyDictionary(), MaxSplit, MinWidth) 161 : EstimateBounds(tree, variableRanges.GetReadonlyDictionary()); 75 var resultInterval = EstimateBounds(tree, variableRanges.GetReadonlyDictionary()); 162 76 163 77 if (resultInterval.IsInfiniteOrUndefined || resultInterval.LowerBound <= resultInterval.UpperBound) … … 298 212 } 299 213 } 300 Array.Resize <Interval>(ref inputIntervals, count);214 Array.Resize(ref inputIntervals, count); 301 215 return variableIndices; 302 216 } … … 309 223 } 310 224 311 public static Interval EstimateBounds(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges , int n = 0, double w = 1e-5) {225 public static Interval EstimateBounds(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges) { 312 226 var variableIndices = GetVariableIndices(tree, variableRanges, out Interval[] x); 313 227 var f = Compile(tree, variableRanges, variableIndices); 314 if (n == 0) return f(x); 315 var inf = EstimateBound(x, f, true, n, w); 316 var sup = EstimateBound(x, f, false, n, w); 317 return inf < sup ? new Interval(inf, sup) : new Interval(sup, inf); 318 } 319 public double EstimateLowerBound(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges, int n = 1000, double w = 1e-5) { 320 var variableIndices = GetVariableIndices(tree, variableRanges, out Interval[] x); 321 var f = Compile(tree, variableRanges, variableIndices); 322 var inf = EstimateBound(x, f, true, n, w); 323 return inf; 324 } 325 326 public double EstimateUpperBound(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges, int n = 1000, double w = 1e-5) { 327 var variableIndices = GetVariableIndices(tree, variableRanges, out Interval[] x); 328 var f = Compile(tree, variableRanges, variableIndices); 329 var sup = EstimateBound(x, f, false, n, w); 330 return sup; 331 } 332 333 static double EstimateBound(Interval[] x, Func<Interval[], Interval> f, bool m = false, int n = 1000, double w = 1e-4) { 334 double getBound(Interval iv) => m ? iv.LowerBound : -iv.UpperBound; 335 double getVolume(Interval[] box) => box.Aggregate(1.0, (acc, iv) => acc * iv.Width); 336 337 var splits = Enumerable.Range(0, x.Length).Select(_ => new List<Interval>()).ToArray(); 338 var newbox = new Interval[x.Length]; 339 340 int compare(Tuple<double, double, Interval[]> a, Tuple<double, double, Interval[]> b) { 341 var res = a.Item1.CompareTo(b.Item1); 342 if (res == 0) { 343 res = b.Item2.CompareTo(a.Item2); 344 } 345 return res; 346 } 347 348 var q = new SortedSet<Tuple<double, double, Interval[]>>(Comparer<Tuple<double, double, Interval[]>>.Create(compare)) { 349 Tuple.Create(getBound(f(x)), getVolume(x), x) 350 }; 351 352 353 var bestBound = double.MaxValue; 354 355 // examine all the ordered pairs in the cartesian product 356 void next_pair(int i) { 357 if (i == splits.Length) { 358 var tmp = newbox.ToArray(); // make a copy to put in the queue 359 q.Add(Tuple.Create(getBound(f(tmp)), getVolume(tmp), tmp)); 360 return; 361 } 362 363 foreach (var iv in splits[i]) { 364 newbox[i] = iv; 365 next_pair(i + 1); 366 } 367 } 368 369 while (q.Count > 0 && n-- > 0) { 370 var currentBound = q.Min; q.Remove(currentBound); 371 var bound = currentBound.Item1; 372 var box = currentBound.Item3; 373 374 if (!box.Any(b => b.Width > w)) { 375 bestBound = Math.Min(bestBound, bound); 376 continue; 377 } 378 379 // do the splits 380 for (int i = 0; i < box.Length; ++i) { 381 splits[i].Clear(); 382 var iv = box[i]; 383 if (iv.Width > w) { 384 var t = iv.Split(); 385 splits[i].Add(t.Item1); 386 splits[i].Add(t.Item2); 387 } else { 388 splits[i].Add(iv); 389 } 390 } 391 next_pair(0); 392 } 393 if (q.Count > 0) { 394 bestBound = Math.Min(bestBound, q.First().Item1); 395 } 396 return m ? bestBound : -bestBound; 228 return f(x); 397 229 } 398 230 #endregion
Note: See TracChangeset
for help on using the changeset viewer.