source: branches/2994-AutoDiffForIntervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/Interpreter.cs @ 17295

Last change on this file since 17295 was 17295, checked in by gkronber, 3 years ago

#2994: refactoring: moved types into separate files

File size: 5.3 KB
Line 
1using System;
2using HeuristicLab.Common;
3using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
4
5namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
6  public abstract class Interpreter<T> where T : IAlgebraicType<T> {
7    public struct Instruction {
8      public byte opcode;
9      public ushort narg;
10      public int childIndex;
11      public double dblVal;
12      public object data; // any kind of data you want to store in instructions
13      public T value;
14    }
15
16    public T Evaluate(Instruction[] code) {
17      for (int i = code.Length - 1; i >= 0; --i) {
18        var instr = code[i];
19        var c = instr.childIndex;
20        var n = instr.narg;
21
22        switch (instr.opcode) {
23          case OpCodes.Variable: {
24              LoadVariable(instr);
25              break;
26            }
27          case OpCodes.Constant: { break; }  // we initialize constants in Compile. The value never changes afterwards
28          case OpCodes.Add: {
29              instr.value.Assign(code[c].value);
30              for (int j = 1; j < n; ++j) {
31                instr.value.Add(code[c + j].value);
32              }
33              break;
34            }
35
36          case OpCodes.Sub: {
37              if (n == 1) {
38                instr.value.AssignNeg(code[c].value);
39              } else {
40                instr.value.Assign(code[c].value);
41                for (int j = 1; j < n; ++j) {
42                  instr.value.Sub(code[c + j].value);
43                }
44              }
45              break;
46            }
47
48          case OpCodes.Mul: {
49              instr.value.Assign(code[c].value);
50              for (int j = 1; j < n; ++j) {
51                instr.value.Mul(code[c + j].value);
52              }
53              break;
54            }
55
56          case OpCodes.Div: {
57              if (n == 1) {
58                instr.value.AssignInv(code[c].value);
59              } else {
60                instr.value.Assign(code[c].value);
61                for (int j = 1; j < n; ++j) {
62                  instr.value.Div(code[c + j].value);
63                }
64              }
65              break;
66            }
67          case OpCodes.Square: {
68              instr.value.AssignIntPower(code[c].value, 2);
69              break;
70            }
71          case OpCodes.SquareRoot: {
72              instr.value.AssignIntRoot(code[c].value, 2);
73              break;
74            }
75          case OpCodes.Cube: {
76              instr.value.AssignIntPower(code[c].value, 3);
77              break;
78            }
79          case OpCodes.CubeRoot: {
80              instr.value.AssignIntRoot(code[c].value, 3);
81              break;
82            }
83          case OpCodes.Exp: {
84              instr.value.AssignExp(code[c].value);
85              break;
86            }
87          case OpCodes.Log: {
88              instr.value.AssignLog(code[c].value);
89              break;
90            }
91          case OpCodes.Sin: {
92              instr.value.AssignSin(code[c].value);
93              break;
94            }
95          case OpCodes.Cos: {
96              instr.value.AssignCos(code[c].value);
97              break;
98            }
99          case OpCodes.Absolute: {
100              instr.value.AssignAbs(code[c].value);
101              break;
102            }
103          case OpCodes.AnalyticQuotient: {
104              instr.value.Assign(code[c].value);
105              for (int j = 1; j < n; ++j) {
106                var t = instr.value.One;
107                t.Add(code[c + j].value.Clone().IntPower(2));
108                instr.value.Div(t.IntRoot(2));
109              }
110              break;
111            }
112          case OpCodes.Tanh: {
113              instr.value.AssignTanh(code[c].value);
114              break;
115            }
116
117          default: throw new ArgumentException($"Unknown opcode {instr.opcode}");
118        }
119      }
120      return code[0].value;
121    }
122
123    protected Instruction[] Compile(ISymbolicExpressionTree tree) {
124      var root = tree.Root.GetSubtree(0).GetSubtree(0);
125      var code = new Instruction[root.GetLength()];
126      if (root.SubtreeCount > ushort.MaxValue) throw new ArgumentException("Number of subtrees is too big (>65.535)");
127      int c = 1, i = 0;
128      foreach (var node in root.IterateNodesBreadth()) {
129        if (node.SubtreeCount > ushort.MaxValue) throw new ArgumentException("Number of subtrees is too big (>65.535)");
130        code[i] = new Instruction {
131          opcode = OpCodes.MapSymbolToOpCode(node),
132          narg = (ushort)node.SubtreeCount,
133          childIndex = c
134        };
135        if (node is VariableTreeNode variable) {
136          InitializeTerminalInstruction(ref code[i], variable);
137        } else if (node is ConstantTreeNode constant) {
138          InitializeTerminalInstruction(ref code[i], constant);
139        } else {
140          InitializeInternalInstruction(ref code[i], node);
141        }
142        c += node.SubtreeCount;
143        ++i;
144      }
145      return code;
146    }
147
148    protected abstract void InitializeTerminalInstruction(ref Instruction instruction, ConstantTreeNode constant);
149    protected abstract void InitializeTerminalInstruction(ref Instruction instruction, VariableTreeNode variable);
150    protected abstract void InitializeInternalInstruction(ref Instruction instruction, ISymbolicExpressionTreeNode node);
151
152    protected abstract void LoadVariable(Instruction a);
153
154  }
155}
Note: See TracBrowser for help on using the repository browser.