1 | using System;
|
---|
2 | using System.Collections.Generic;
|
---|
3 | using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
|
---|
4 |
|
---|
5 | namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
|
---|
6 | public sealed class IntervalEvaluator : InterpreterBase<AlgebraicInterval> {
|
---|
7 | [ThreadStatic]
|
---|
8 | private IDictionary<string, Interval> intervals;
|
---|
9 |
|
---|
10 | public Interval Evaluate(ISymbolicExpressionTree tree, IDictionary<string, Interval> intervals) {
|
---|
11 | this.intervals = intervals;
|
---|
12 | var code = Compile(tree);
|
---|
13 | Evaluate(code);
|
---|
14 | if (code[0].value.LowerBound.Value.Value > code[0].value.UpperBound.Value.Value) throw new InvalidProgramException($"lower: {code[0].value.LowerBound.Value.Value} > upper: {code[0].value.UpperBound.Value.Value}");
|
---|
15 | return new Interval(code[0].value.LowerBound.Value.Value, code[0].value.UpperBound.Value.Value);
|
---|
16 | }
|
---|
17 |
|
---|
18 | public Interval Evaluate(ISymbolicExpressionTree tree, IDictionary<string, Interval> intervals, ISymbolicExpressionTreeNode[] paramNodes, out double[] lowerGradient, out double[] upperGradient) {
|
---|
19 | this.intervals = intervals;
|
---|
20 | var code = Compile(tree);
|
---|
21 | Evaluate(code);
|
---|
22 | lowerGradient = new double[paramNodes.Length];
|
---|
23 | upperGradient = new double[paramNodes.Length];
|
---|
24 | var l = code[0].value.LowerBound;
|
---|
25 | var u = code[0].value.UpperBound;
|
---|
26 | for (int i = 0; i < paramNodes.Length; ++i) {
|
---|
27 | if (paramNodes[i] == null) continue;
|
---|
28 | if (l.Gradient.Elements.TryGetValue(paramNodes[i], out AlgebraicDouble value)) lowerGradient[i] = value;
|
---|
29 | if (u.Gradient.Elements.TryGetValue(paramNodes[i], out value)) upperGradient[i] = value;
|
---|
30 | }
|
---|
31 | return new Interval(code[0].value.LowerBound.Value.Value, code[0].value.UpperBound.Value.Value);
|
---|
32 | }
|
---|
33 |
|
---|
34 | protected override void InitializeInternalInstruction(ref Instruction instruction, ISymbolicExpressionTreeNode node) {
|
---|
35 | instruction.value = new AlgebraicInterval(0, 0);
|
---|
36 | }
|
---|
37 |
|
---|
38 |
|
---|
39 | protected override void InitializeTerminalInstruction(ref Instruction instruction, ConstantTreeNode constant) {
|
---|
40 | instruction.dblVal = constant.Value;
|
---|
41 | instruction.value = new AlgebraicInterval(
|
---|
42 | new MultivariateDual<AlgebraicDouble>(instruction.dblVal, constant, 1.0),
|
---|
43 | new MultivariateDual<AlgebraicDouble>(instruction.dblVal, constant, 1.0) // use node as key
|
---|
44 | );
|
---|
45 | }
|
---|
46 |
|
---|
47 | protected override void InitializeTerminalInstruction(ref Instruction instruction, VariableTreeNode variable) {
|
---|
48 | instruction.dblVal = variable.Weight;
|
---|
49 | var v1 = instruction.dblVal * intervals[variable.VariableName].LowerBound;
|
---|
50 | var v2 = instruction.dblVal * intervals[variable.VariableName].UpperBound;
|
---|
51 | var lower = Math.Min(v1, v2);
|
---|
52 | var upper = Math.Max(v1, v2);
|
---|
53 | // we assume that the for variable nodes ( v(x,w) = w * x ) the gradient is returned for parameter w
|
---|
54 | instruction.value = new AlgebraicInterval(
|
---|
55 | low: new MultivariateDual<AlgebraicDouble>(v: lower, key: variable, dv: intervals[variable.VariableName].LowerBound),
|
---|
56 | high: new MultivariateDual<AlgebraicDouble>(v: upper, key: variable, dv: intervals[variable.VariableName].UpperBound)
|
---|
57 | );
|
---|
58 | }
|
---|
59 |
|
---|
60 | protected override void LoadVariable(Instruction a) {
|
---|
61 | // nothing to do
|
---|
62 | }
|
---|
63 | }
|
---|
64 | } |
---|