Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PushGP/HeuristicLab.PushGP/HeuristicLab.Problems.ProgramSynthesis/Push/Expressions/PushProgram.cs @ 14952

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

#2665 Added IsNoop to Expression, Made Expressions storable, Fixed Debugger, Fixed and improved problem data and result visualisation, Added custom ErcOption view, Added problem difficulty to problem data name

File size: 10.1 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4
5namespace HeuristicLab.Problems.ProgramSynthesis.Push.Expressions {
6  using System.Diagnostics;
7
8  using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
9  using HeuristicLab.Problems.ProgramSynthesis.Push.Data.Pool;
10
11  using Interpreter;
12
13  public interface IMutablePushProgram {
14    void SetAtIndex(int index, Expression expression);
15  }
16
17  [Serializable]
18  [StorableClass]
19  public sealed class PushProgram : Expression, IPooledObject, IMutablePushProgram {
20#if DEBUG
21    private const int StringRepresentationCountBeforeAggregate = 50;
22#else
23    private const int StringRepresentationCountBeforeAggregate = 10;
24#endif
25
26    private static readonly Expression[] EmptyExpressions = new Expression[0];
27    public static readonly PushProgram Empty = new PushProgram();
28
29    private const string Prefix = "(";
30    private const string PrefixReduced = "[";
31    private const string Postfix = ")";
32    private const string PostfixReduced = "]";
33    private const string Delimiter = " ";
34
35    [Storable]
36    private IReadOnlyList<Expression> expressions;
37
38    public PushProgram() : this(EmptyExpressions) { }
39
40    [StorableConstructor]
41    public PushProgram(bool deserializing) : this(EmptyExpressions) { }
42
43    public PushProgram(IReadOnlyList<Expression> expressions) {
44      this.expressions = expressions;
45    }
46
47    public bool IsEmpty { get { return Count == 0; } }
48    public int Count { get { return expressions.Count; } }
49
50    public IReadOnlyList<Expression> Expressions { get { return expressions; } }
51
52    public static PushProgram Create(IManagedPool<PushProgram> pool, IReadOnlyList<Expression> expressions) {
53      var program = pool.Get();
54      program.expressions = expressions;
55      return program;
56    }
57
58    void IPooledObject.Reset() {
59      expressions = null;
60      stringRepresentation = null;
61      depth = null;
62      treeIndex = null;
63      hashCode = null;
64    }
65
66    public static PushProgram Merge(IManagedPool<PushProgram> pool, IManagedPool<PooledList<Expression>> expressionListPool,
67      PushProgram first, Expression second) {
68      var program = pool.Get();
69      var list = expressionListPool.Get();
70
71      list.AddRange(first.Expressions);
72      list.Add(second);
73
74      program.expressions = list;
75
76      return program;
77    }
78
79    public static PushProgram Merge(IManagedPool<PushProgram> pool, IManagedPool<PooledList<Expression>> expressionListPool,
80      Expression first, PushProgram second) {
81      var program = pool.Get();
82      var list = expressionListPool.Get();
83
84      list.Add(first);
85      list.AddRange(second.Expressions);
86
87      program.expressions = list;
88
89      return program;
90    }
91
92    public static PushProgram Merge(IManagedPool<PushProgram> pool, IManagedPool<PooledList<Expression>> expressionListPool,
93      PushProgram first, PushProgram second) {
94      var program = pool.Get();
95      var list = expressionListPool.Get();
96
97      list.AddRange(first.Expressions);
98      list.AddRange(second.Expressions);
99
100      program.expressions = list;
101
102      return program;
103    }
104
105    public int IndexOf(Expression expression) {
106      var max = expressions.Count - 1;
107      for (var i = max; i >= 0; i--) {
108        if (expression.Equals(expressions[i])) return max - i;
109      }
110
111      return -1;
112    }
113
114    private string stringRepresentation;
115    public override string StringRepresentation
116    {
117      get
118      {
119        if (stringRepresentation == null) stringRepresentation = BuildString();
120        return stringRepresentation;
121      }
122    }
123
124
125    private int? depth;
126    public int Depth
127    {
128      get
129      {
130        if (depth == null) depth = CalcDepth();
131        return depth.Value;
132      }
133    }
134
135    private int[] treeIndex;
136    private int[] TreeIndex
137    {
138      get
139      {
140        if (treeIndex == null) treeIndex = BuildTreeIndex();
141        return treeIndex;
142      }
143    }
144
145    private int? hashCode;
146    public override int GetHashCode() {
147      if (hashCode == null) hashCode = HashExpressions();
148      return hashCode.Value;
149    }
150
151    void IMutablePushProgram.SetAtIndex(int index, Expression expression) {
152
153    }
154
155    public override bool Equals(object obj) {
156      if (ReferenceEquals(this, obj))
157        return true;
158
159      if (GetType() != obj.GetType())
160        return false;
161
162      var other = (PushProgram)obj;
163
164      return ReferenceEquals(expressions, other.expressions) ||
165             GetHashCode() == other.GetHashCode();
166    }
167
168    public bool Equals(PushProgram other) {
169      return ReferenceEquals(this, other) ||
170             ReferenceEquals(expressions, other.expressions) ||
171             GetHashCode() == other.GetHashCode();
172    }
173
174    public override bool IsNoop(IInternalPushInterpreter interpreter) {
175      return IsEmpty;
176    }
177
178    public override void Eval(IInternalPushInterpreter interpreter) {
179      interpreter.ExecStack.Push(expressions);
180    }
181
182    public override string ToString() {
183      return StringRepresentation;
184    }
185
186    /// <summary>
187    /// Returns the amount of elements in the whole tree
188    /// </summary>
189    /// <returns></returns>
190    public int TotalCount
191    {
192      get
193      {
194        return IsEmpty
195            ? 1
196            // + 1 because "this" is also counted
197            : TreeIndex[0] + 1;
198      }
199    }
200
201    public IEnumerable<Expression> DepthLast() {
202      foreach (var expr in expressions) {
203        if (expr.IsProgram)
204          foreach (var sub in ((PushProgram)expr).DepthLast())
205            yield return sub;
206        else yield return expr;
207      }
208    }
209
210    public PushProgram Copy() {
211      if (IsEmpty) return this;
212
213      return new PushProgram(expressions) {
214        stringRepresentation = stringRepresentation,
215        hashCode = hashCode,
216        depth = depth,
217        treeIndex = treeIndex
218      };
219    }
220
221    public PushProgram Copy(IManagedPool<PushProgram> pool) {
222      if (IsEmpty) return this;
223
224      var program = pool.Get(reset: false);
225
226      program.expressions = expressions;
227      program.stringRepresentation = stringRepresentation;
228      program.hashCode = hashCode;
229      program.depth = depth;
230      program.treeIndex = treeIndex;
231
232      return program;
233    }
234
235    public IList<Expression> CopyExpressions() {
236      return new List<Expression>(expressions);
237    }
238
239    public IList<Expression> CopyExpressions(IManagedPool<PooledList<Expression>> expressionListPool) {
240      if (IsEmpty) return EmptyExpressions;
241
242      var copy = expressionListPool.Get();
243      copy.AddRange(expressions);
244
245      return copy;
246    }
247
248    private int CalcDepth() {
249      var maxDepth = 1;
250      for (var i = 0; i < Count; i++) {
251        var expression = expressions[i];
252        if (!expression.IsProgram) continue;
253        var expandExpression = (PushProgram)expression;
254
255        if (expandExpression.Depth > maxDepth)
256          maxDepth = expandExpression.Depth;
257      }
258
259      return maxDepth + 1;
260    }
261
262    private string BuildString() {
263      // prevent too big string
264      return TotalCount > StringRepresentationCountBeforeAggregate
265        ? PrefixReduced + Count + PostfixReduced
266        : Prefix + string.Join(Delimiter, expressions) + Postfix;
267    }
268
269    private int[] BuildTreeIndex() {
270      var local_treeIndex = new int[Count];
271
272      var next = 1;
273
274      for (var i = Count - 1; i >= 0; i--) {
275        var subExpression = expressions[i];
276
277        local_treeIndex[i] = next;
278
279        if (subExpression.IsProgram) {
280          next += ((PushProgram)subExpression).TotalCount;
281        } else {
282          next++;
283        }
284      }
285
286      return local_treeIndex;
287    }
288
289    private int HashExpressions() {
290      var hash = 19 * 31 + typeof(PushProgram).GetHashCode();
291
292      for (var i = 0; i < Count; i++) {
293        hash = hash * 31 + expressions[i].GetHashCode();
294      }
295
296      return hash;
297    }
298
299    private static void CheckIfNested(int level, PushProgram target, PushProgram current,
300        IList<PushProgram> visited) {
301      if (visited.Any(x => ReferenceEquals(x, current)))
302        Debugger.Break();
303
304      visited.Add(current);
305      if (level <= 0) {
306        // hierarchy depth > level
307        Debugger.Break();
308        return;
309      }
310
311      for (var i = 0; i < current.Count; i++) {
312        if (current.expressions[i].IsProgram)
313          continue;
314
315        var subExpression = current.expressions[i] as PushProgram;
316
317        if (ReferenceEquals(target, subExpression)) {
318          // Endless recursion dedected
319          Debugger.Break();
320        }
321
322        CheckIfNested(level - 1, target, subExpression, visited);
323      }
324
325      visited.RemoveAt(visited.Count - 1);
326    }
327
328    /// <summary>
329    ///     Returns the element with the given index whereby the tree is indexed in depth first manner
330    /// </summary>
331    /// <param name="index">The index of the required element</param>
332    /// <returns>The required element</returns>
333    public Expression GetFromTree(int index) {
334      return GetFromTree(index, (root, parent, child, childIndex, parentIndex) => child);
335    }
336
337    /// <returns>The required element</returns>
338    public T GetFromTree<T>(int index,
339        Func<PushProgram, PushProgram, Expression, int, int, T> resolver) {
340      return GetFromTree(index, 0, null, resolver);
341    }
342
343    private T GetFromTree<T>(int index, int parentIndex, PushProgram parent,
344        Func<PushProgram, PushProgram, Expression, int, int, T> resolver) {
345      if (index == 0) return resolver(parent, parent, this, 0, parentIndex);
346
347      var min = Count - 1;
348      var max = 0;
349      var mid = (min + max) / 2;
350
351      while ((max <= min) && (TreeIndex[mid] != index)) {
352        if (TreeIndex[mid] > index) max = mid + 1;
353        else min = mid - 1;
354
355        mid = (min + max) / 2;
356      }
357
358      return TreeIndex[mid] == index
359          ? resolver(parent, this, expressions[mid], mid, parentIndex)
360          : (expressions[mid + 1] as PushProgram).GetFromTree(index - TreeIndex[mid + 1], mid + 1,
361              this, resolver);
362    }
363  }
364}
Note: See TracBrowser for help on using the repository browser.