Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PushGP/HeuristicLab.Algorithms.PushGP/HeuristicLab.Algorithms.PushGP/Expressions/ExecExpressions.cs @ 14602

Last change on this file since 14602 was 14602, checked in by pkimmesw, 7 years ago

#2665 PushGP HL Integration

File size: 8.9 KB
Line 
1using System.Threading;
2
3namespace HeuristicLab.Algorithms.PushGP.Expressions {
4  using System;
5  using System.Collections.Generic;
6  using System.Diagnostics;
7  using System.Linq;
8  using System.Text;
9  using Interpreter;
10
11  public class ExecExpandExpression : WrapperExpression<Expression[]> {
12    private const string Prefix = "( ";
13    private const string PrefixReduced = "[";
14    private const string Postfix = ")";
15    private const string PostfixReduced = "]";
16    private const string Delimiter = " ";
17
18    public static readonly ExecExpandExpression Empty = new ExecExpandExpression();
19
20    private readonly Lazy<string> _stringValue;
21    private readonly int[] _treeIndex;
22    public readonly int Depth;
23
24    private readonly int _hashCode;
25
26    public ExecExpandExpression(params Expression[] state) : base(state) {
27      IsEmpty = State.Length == 0;
28
29      Depth = CalcDepth();
30      _treeIndex = BuildTreeIndex();
31      _hashCode = HashExpressions();
32
33      _stringValue = new Lazy<string>(BuildString, LazyThreadSafetyMode.ExecutionAndPublication);
34    }
35
36    public ExecExpandExpression(IEnumerable<Expression> state) : this(state.ToArray()) {
37      // TODO: lazy evaluation of ToArray()
38    }
39
40#if DEBUG
41
42    private static void CheckIfNested(int level, ExecExpandExpression target, ExecExpandExpression current,
43        IList<ExecExpandExpression> visited) {
44      if (visited.Any(x => ReferenceEquals(x, current)))
45        Debugger.Break();
46
47      visited.Add(current);
48      if (level <= 0) {
49        // hirarchy depth > level
50        Debugger.Break();
51        return;
52      }
53
54      for (var i = 0; i < current.State.Length; i++) {
55        if (current.State[i].GetType() != typeof(ExecExpandExpression))
56          continue;
57
58        var subExpression = current.State[i] as ExecExpandExpression;
59
60        if (ReferenceEquals(target, subExpression)) {
61          // Endless recursion dedected
62          Debugger.Break();
63        }
64
65        CheckIfNested(level - 1, target, subExpression, visited);
66      }
67
68      visited.RemoveAt(visited.Count - 1);
69    }
70
71#endif
72
73    public IReadOnlyList<Expression> Expressions
74    {
75      get { return State; }
76    }
77
78    public bool IsEmpty { get; private set; }
79
80    /// <summary>
81    /// Returns the amount of elements in the whole tree
82    /// </summary>
83    /// <returns></returns>
84    public int TotalCount
85    {
86      get
87      {
88        return IsEmpty
89            ? 1
90            // + 1 because this is also counted
91            : _treeIndex[0] + 1;
92      }
93    }
94
95    public override string ToString() {
96      return _stringValue.Value;
97    }
98
99    private int HashExpressions() {
100      var hash = 19 * 31 + this.GetType().GetHashCode();
101
102      for (var i = 0; i < this.State.Length; i++) {
103        hash = hash * 31 + this.State[i].GetHashCode();
104      }
105
106      return hash;
107    }
108
109    protected override int CalcHashCode() {
110      return _hashCode;
111    }
112
113    public ExecExpandExpression Copy() {
114      // as the empty list is a static stateless expression, no copy required
115      return this == Empty || IsEmpty ? Empty : new ExecExpandExpression(State);
116    }
117
118    public Expression[] CopyExpressions() {
119      var copy = new Expression[State.Length];
120      Array.Copy(State, copy, State.Length);
121
122      return copy;
123    }
124
125    public override void Eval(IPushGpInterpreter interpreter) {
126      interpreter.ExecStack.Push(State);
127    }
128
129    private int CalcDepth() {
130      var subExpressions = State.Where(e => e.GetType() == typeof(ExecExpandExpression));
131      var depth = subExpressions.Any()
132          ? subExpressions.Select(e => e as ExecExpandExpression).Max(e => e.Depth) + 1
133          : 1;
134
135      return depth;
136    }
137
138    private string BuildString() {
139      // prevent stack overflow
140      if (this.TotalCount > 50)
141        return PrefixReduced + this.State.Length + PostfixReduced;
142
143      var sb = new StringBuilder();
144
145      sb.Append(Prefix);
146      for (var i = this.State.Length - 1; i >= 0; i--) sb.Append(this.State[i] + Delimiter);
147      sb.Append(Postfix);
148      return sb.ToString();
149    }
150
151    private int[] BuildTreeIndex() {
152      var treeIndex = new int[State.Length];
153
154      var next = 1;
155
156      for (var i = State.Length - 1; i >= 0; i--) {
157        var subExpression = State[i];
158
159        treeIndex[i] = next;
160
161        if (subExpression.GetType() == typeof(ExecExpandExpression)) {
162          next += (subExpression as ExecExpandExpression).TotalCount;
163        } else {
164          next++;
165        }
166      }
167
168      return treeIndex;
169    }
170
171    /// <summary>
172    ///     Returns the element with the given index whereby the tree is indexed in depth first manner
173    /// </summary>
174    /// <param name="index">The index of the required element</param>
175    /// <returns>The required element</returns>
176    public Expression GetFromTree(int index) {
177      return GetFromTree(index, (root, parent, child, childIndex, parentIndex) => child);
178    }
179
180    /// <returns>The required element</returns>
181    public T GetFromTree<T>(int index,
182        Func<ExecExpandExpression, ExecExpandExpression, Expression, int, int, T> resolver) {
183      return GetFromTree(index, 0, null, resolver);
184    }
185
186    private T GetFromTree<T>(int index, int parentIndex, ExecExpandExpression parent,
187        Func<ExecExpandExpression, ExecExpandExpression, Expression, int, int, T> resolver) {
188      if (index == 0) return resolver(parent, parent, this, 0, parentIndex);
189
190      var min = State.Length - 1;
191      var max = 0;
192      var mid = (min + max) / 2;
193
194      while ((max <= min) && (_treeIndex[mid] != index)) {
195        if (_treeIndex[mid] > index) max = mid + 1;
196        else min = mid - 1;
197
198        mid = (min + max) / 2;
199      }
200
201      return _treeIndex[mid] == index
202          ? resolver(parent, this, State[mid], mid, parentIndex)
203          : (State[mid + 1] as ExecExpandExpression).GetFromTree(index - _treeIndex[mid + 1], mid + 1,
204              this, resolver);
205    }
206  }
207
208  /// <summary>
209  /// If the top item of the BOOLEAN stack is TRUE then this removes the second item on the EXEC stack, leaving the first
210  /// item to be executed. If it is false then it removes the first item, leaving the second to be executed. This is similar to
211  /// CODE.IF except that it operates on the EXEC stack. This acts as a NOOP unless there are at least two items on the EXEC stack and
212  /// one item on the BOOLEAN stack.
213  /// </summary>
214  public class ExecIfExpression : StatelessExpression {
215    public ExecIfExpression() : base("EXEC.IF") {
216    }
217
218    public override void Eval(IPushGpInterpreter interpreter) {
219      // not enough arguments on stack
220      if ((interpreter.BooleanStack.Count == 0) || (interpreter.ExecStack.Count < 2)) return;
221
222      var condition = interpreter.BooleanStack.Pop();
223
224      if (condition) interpreter.ExecStack.RemoveAt(interpreter.ExecStack.Count - 2);
225      else interpreter.ExecStack.RemoveTop();
226    }
227  }
228
229  /// <summary>
230  ///     Inserts beneath the top item of the EXEC stack a new item of the form
231  ///     "( EXEC.Y <TopItem> )".
232  /// </summary>
233  public class ExecYExpression : StatelessExpression {
234    public ExecYExpression() : base("EXEC.Y") {
235    }
236
237    public override void Eval(IPushGpInterpreter interpreter) {
238      // not enough arguments on stack
239      if ((interpreter.ExecStack.Count == 0) || (interpreter.Configuration.MaxPointsInProgram < 2)) return;
240
241      var top = interpreter.ExecStack.Top;
242      var result = new ExecExpandExpression(top, new ExecYExpression());
243
244      interpreter.ExecStack.Insert(interpreter.ExecStack.Count - 1, result);
245    }
246  }
247
248  /// <summary>
249  ///     Removes the second item on the EXEC stack.
250  /// </summary>
251  public class ExecKExpression : StatelessExpression {
252    public ExecKExpression() : base("EXEC.K") {
253    }
254
255    public override void Eval(IPushGpInterpreter interpreter) {
256      if (interpreter.ExecStack.Count < 2) return;
257
258      var top = interpreter.ExecStack.Pop();
259      interpreter.ExecStack.SetTop(top);
260    }
261  }
262
263  /// <summary>
264  ///     Pops 3 items from the EXEC stack, which we will call A, B, and C
265  ///     (with A being the first one popped). Then pushes a list containing B and C back onto the EXEC stack, followed by
266  ///     another instance of C, followed by another instance of A.
267  /// </summary>
268  public class ExecSExpression : StatelessExpression {
269    public ExecSExpression() : base("EXEC.S") {
270    }
271
272    public override void Eval(IPushGpInterpreter interpreter) {
273      if (interpreter.ExecStack.Count < 3) return;
274
275      var expression = interpreter.ExecStack.Pop(2);
276      var a = expression[1];
277      var b = expression[0];
278      var c = interpreter.ExecStack.Top;
279
280      var newTop = new ExecExpandExpression(c, b);
281
282      interpreter.ExecStack.SetTop(newTop);
283      interpreter.ExecStack.Push(c, a);
284    }
285  }
286}
Note: See TracBrowser for help on using the repository browser.