Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2895_PushGP_GenealogyAnalysis/HeuristicLab.Problems.ProgramSynthesis/Push/Interpreter/PushInterpreter.cs

Last change on this file was 15771, checked in by bburlacu, 7 years ago

#2895: Add solution skeleton for PushGP with genealogy analysis.

File size: 14.8 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Runtime.CompilerServices;
5using System.Threading;
6using System.Threading.Tasks;
7using HeuristicLab.Core;
8using HeuristicLab.Random;
9
10namespace HeuristicLab.Problems.ProgramSynthesis {
11  public class PushInterpreter : IInternalPushInterpreter, IDisposable {
12    private Task currentTask;
13    private int evalPushLimit;
14
15    /// <summary>
16    /// An interpreter for Push
17    /// </summary>
18    /// <param name="config">Determines the runtime behavior of the interpreter</param>
19    /// <param name="random">Note that random may be reseted</param>
20    /// <param name="poolContainer">Used to save resources used by the interpreter</param>
21    public PushInterpreter(IReadOnlyPushConfiguration config = null, IRandom random = null, InterpreterPoolContainer poolContainer = null) {
22      randomOrigin = random ?? new MersenneTwister();
23      Random = (IRandom)randomOrigin.Clone();
24      Configuration = config ?? new PushConfiguration();
25
26      ExecStack = new PushStack<Expression>(Configuration.MaxProgramLength);
27      CodeStack = new PushStack<Expression>();
28      NameStack = new PushStack<string>();
29      BooleanStack = new PushStack<bool>();
30      IntegerStack = new PushStack<long>();
31      FloatStack = new PushStack<double>();
32      CharStack = new PushStack<char>();
33      StringStack = new PushStack<string>();
34      IntegerVectorStack = new PushStack<IReadOnlyList<long>>();
35      FloatVectorStack = new PushStack<IReadOnlyList<double>>();
36      BooleanVectorStack = new PushStack<IReadOnlyList<bool>>();
37      StringVectorStack = new PushStack<IReadOnlyList<string>>();
38      PrintStack = new PrintStack();
39
40      Stacks = new Dictionary<StackTypes, IPushStack> {
41        { StackTypes.Exec, ExecStack },
42        { StackTypes.Code, CodeStack },
43        { StackTypes.Integer, IntegerStack },
44        { StackTypes.Float, FloatStack },
45        { StackTypes.Boolean, BooleanStack },
46        { StackTypes.Char, CharStack },
47        { StackTypes.String, StringStack },
48        { StackTypes.Name, NameStack },
49        { StackTypes.Print, PrintStack },
50        { StackTypes.IntegerVector, IntegerVectorStack },
51        { StackTypes.FloatVector, FloatVectorStack },
52        { StackTypes.BooleanVector, BooleanVectorStack },
53        { StackTypes.StringVector, StringVectorStack },
54      };
55
56      supportedStackTypes = Stacks.Keys.ToArray();
57
58      CustomExpressions = new Dictionary<string, Expression>();
59      PoolContainer = poolContainer ?? new InterpreterPoolContainer();
60
61      InitEvalPushLimit();
62      ConfigureStacks();
63    }
64
65    public PushInterpreter(int seed, IReadOnlyPushConfiguration config = null)
66      : this(config, new FastRandom(seed)) {
67    }
68
69    private readonly StackTypes[] supportedStackTypes;
70    public IReadOnlyDictionary<StackTypes, IPushStack> Stacks { get; private set; }
71
72    private IRandom randomOrigin;
73    public IRandom Random { get; private set; }
74
75    public long ExecCounter { get; private set; }
76
77    public bool IsPaused { get; private set; }
78
79    public bool IsAborted { get; private set; }
80
81    public bool IsRunning {
82      get {
83        return !ExecStack.IsEmpty &&
84               !IsPaused &&
85               !IsAborted &&
86               (ExecCounter < evalPushLimit);
87      }
88    }
89
90    public bool IsCompleted {
91      get {
92        return ExecStack.IsEmpty || ExecCounter >= Configuration.EvalPushLimit;
93      }
94    }
95
96    public bool CanStep {
97      get {
98        return !IsCompleted && !IsAborted && IsPaused;
99      }
100    }
101
102    public InterpreterPoolContainer PoolContainer { get; private set; }
103
104    public IReadOnlyPushConfiguration Configuration { get; protected set; }
105    [PushStack(StackTypes.Code)]
106    public IPushStack<Expression> CodeStack { get; private set; }
107    [PushStack(StackTypes.Exec)]
108    public IPushStack<Expression> ExecStack { get; private set; }
109    [PushStack(StackTypes.Name)]
110    public IPushStack<string> NameStack { get; private set; }
111    [PushStack(StackTypes.Boolean)]
112    public IPushStack<bool> BooleanStack { get; private set; }
113    [PushStack(StackTypes.Integer)]
114    public IPushStack<long> IntegerStack { get; private set; }
115    [PushStack(StackTypes.Float)]
116    public IPushStack<double> FloatStack { get; private set; }
117    [PushStack(StackTypes.Char)]
118    public IPushStack<char> CharStack { get; private set; }
119    [PushStack(StackTypes.String)]
120    public IPushStack<string> StringStack { get; private set; }
121    [PushStack(StackTypes.IntegerVector)]
122    public IPushStack<IReadOnlyList<long>> IntegerVectorStack { get; private set; }
123    [PushStack(StackTypes.FloatVector)]
124    public IPushStack<IReadOnlyList<double>> FloatVectorStack { get; private set; }
125    [PushStack(StackTypes.BooleanVector)]
126    public IPushStack<IReadOnlyList<bool>> BooleanVectorStack { get; private set; }
127    [PushStack(StackTypes.StringVector)]
128    public IPushStack<IReadOnlyList<string>> StringVectorStack { get; private set; }
129    [PushStack(StackTypes.Print)]
130    public IPrintStack PrintStack { get; private set; }
131
132    public IDictionary<string, Expression> CustomExpressions { get; private set; }
133
134    public bool IsNameQuoteFlagSet { get; set; }
135
136    private readonly List<Expression> inputExpressions = new List<Expression>();
137    IReadOnlyList<Expression> IInternalPushInterpreter.InputExpressions { get { return inputExpressions; } }
138
139    public void SetInput(
140      IReadOnlyList<long> integers = null,
141      IReadOnlyList<double> floats = null,
142      IReadOnlyList<bool> booleans = null,
143      IReadOnlyList<char> chars = null,
144      IReadOnlyList<string> strings = null,
145      IReadOnlyList<IReadOnlyList<long>> integerVectors = null,
146      IReadOnlyList<IReadOnlyList<double>> floatVectors = null,
147      IReadOnlyList<IReadOnlyList<string>> stringVectors = null) {
148
149      // Integer
150      if (integers != null && integers.Count > 0) {
151        var integerPushExpressionPool = PoolContainer.GetStatefulExpressionPool<IntegerPushExpression>();
152
153        for (var i = 0; i < integers.Count; i++) {
154          var expression = IntegerPushExpression.Create(integerPushExpressionPool, integers[i]);
155          inputExpressions.Add(expression);
156        }
157      }
158
159      // Float
160      if (floats != null && floats.Count > 0) {
161        var floatPushExpressionPool = PoolContainer.GetStatefulExpressionPool<FloatPushExpression>();
162
163        for (var i = 0; i < floats.Count; i++) {
164          var expression = FloatPushExpression.Create(floatPushExpressionPool, floats[i]);
165          inputExpressions.Add(expression);
166        }
167      }
168
169      // Booleans
170      if (booleans != null && booleans.Count > 0) {
171        var booleanPushExpressionPool = PoolContainer.GetStatefulExpressionPool<BooleanPushExpression>();
172
173        for (var i = 0; i < booleans.Count; i++) {
174          var expression = BooleanPushExpression.Create(booleanPushExpressionPool, booleans[i]);
175          inputExpressions.Add(expression);
176        }
177      }
178
179      // Char
180      if (chars != null && chars.Count > 0) {
181        var charPushExpressionPool = PoolContainer.GetStatefulExpressionPool<CharPushExpression>();
182
183        for (var i = 0; i < chars.Count; i++) {
184          var expression = CharPushExpression.Create(charPushExpressionPool, chars[i]);
185          inputExpressions.Add(expression);
186        }
187      }
188
189      // String
190      if (strings != null && strings.Count > 0) {
191        var stringPushExpressionPool = PoolContainer.GetStatefulExpressionPool<StringPushExpression>();
192
193        for (var i = 0; i < strings.Count; i++) {
194          var expression = StringPushExpression.Create(stringPushExpressionPool, strings[i]);
195          inputExpressions.Add(expression);
196        }
197      }
198
199      // IntegerVector
200      if (integerVectors != null && integerVectors.Count > 0) {
201        var integerVectorPushExpressionPool = PoolContainer.GetStatefulExpressionPool<IntegerVectorPushExpression>();
202
203        for (var i = 0; i < integerVectors.Count; i++) {
204          var expression = IntegerVectorPushExpression.Create(integerVectorPushExpressionPool, integerVectors[i]);
205          inputExpressions.Add(expression);
206        }
207      }
208
209      // FloatVector
210      if (floatVectors != null && floatVectors.Count > 0) {
211        var floatVectorPushExpressionPool = PoolContainer.GetStatefulExpressionPool<FloatVectorPushExpression>();
212
213        for (var i = 0; i < floatVectors.Count; i++) {
214          var expression = FloatVectorPushExpression.Create(floatVectorPushExpressionPool, floatVectors[i]);
215          inputExpressions.Add(expression);
216        }
217      }
218
219      // StringVector
220      if (stringVectors != null && stringVectors.Count > 0) {
221        var stringVectorPushExpressionPool = PoolContainer.GetStatefulExpressionPool<StringVectorPushExpression>();
222
223        for (var i = 0; i < stringVectors.Count; i++) {
224          var expression = StringVectorPushExpression.Create(stringVectorPushExpressionPool, stringVectors[i]);
225          inputExpressions.Add(expression);
226        }
227      }
228    }
229
230
231    public Task RunAsync(string code, CancellationToken token = default(CancellationToken)) {
232      var program = PushParser.Parse(code);
233      currentTask = RunAsync(program, token);
234      return currentTask;
235    }
236    public async Task RunAsync(Expression expression, CancellationToken token = default(CancellationToken)) {
237      await Task.Run(() => Run(expression), token);
238    }
239
240    public void Run(string code, bool stepwise = false) {
241      var program = PushParser.Parse(code);
242      Run(program, stepwise);
243    }
244
245    public void Run(bool stepwise) {
246      Run(PushProgram.Empty, stepwise);
247    }
248
249    public void Run(Expression expression, bool stepwise = false) {
250      IsPaused = stepwise;
251
252      /* Push top expression so the loop is able to enter
253       * If the top expression is a single statement it gets evaluated in Run.
254       * Otherwise the push program will be evaluated and the expressions of the program are pushed onto the EXEC stack.
255       * Expanding the initial program is not counted in ExecCount */
256      InitRun(expression);
257
258      if (Configuration.TopLevelPushCode && CodeStack.IsEnabled)
259        CodeStack.Push(expression);
260
261      Run();
262    }
263
264    public bool CanRun(int count) {
265      return ExecStack.Count >= count &&
266             !IsPaused &&
267             !IsAborted &&
268             ExecCounter + count < Configuration.EvalPushLimit;
269    }
270
271    public async Task AbortAsync() {
272      if (IsAborted || IsCompleted) return;
273
274      IsAborted = true;
275
276      PoolContainer.DisposePools();
277
278      if (currentTask != null) await currentTask;
279    }
280
281    public async Task AbortAndResetAsync() {
282      await AbortAsync();
283      Reset();
284    }
285
286    public async Task PauseAsync() {
287      if (IsPaused || IsCompleted) return;
288
289      IsPaused = true;
290
291      if (currentTask != null) await currentTask;
292    }
293
294    public async Task ResumeAsync() {
295      if (IsPaused || !IsAborted) {
296        IsPaused = false;
297        await InterpretAsync();
298      } else await currentTask;
299    }
300
301    public void Resume() {
302      if (!IsPaused && IsAborted)
303        return;
304
305      IsPaused = false;
306      Run();
307    }
308
309    [MethodImpl(MethodImplOptions.AggressiveInlining)]
310    public bool Step() {
311      if (!CanStep) return false;
312
313      var successful = DoStep();
314
315      if (IsCompleted)
316        Finally();
317
318      return successful;
319    }
320
321    [MethodImpl(MethodImplOptions.AggressiveInlining)]
322    public void Step(int count) {
323      for (var i = 0u; i < count; i++) Step();
324    }
325
326    /// <summary>
327    /// Reset interpreter which clears and reconfigures stacks and local variables
328    /// </summary>
329    public void Reset(IRandom random = null) {
330      if (random != null)
331        randomOrigin = random;
332
333      // Reset Random
334      Random = (IRandom)randomOrigin.Clone();
335
336      InitEvalPushLimit();
337
338      ExecCounter = 0;
339      IsAborted = false;
340      IsPaused = false;
341      currentTask = null;
342
343      inputExpressions.Clear();
344      ClearStacks();
345      ConfigureStacks();
346    }
347
348    private void InitEvalPushLimit() {
349      // evalPushLimit is accessed very often and using the getter of the configuration object is rather expensive as the values is capsuled within a parameter
350      evalPushLimit = Configuration.EvalPushLimit;
351    }
352
353    private void EvalPushLimitChanged(object sender, EventArgs e) {
354      this.evalPushLimit = Configuration.EvalPushLimit;
355    }
356
357    private void ConfigureStacks() {
358      for (var i = 0u; i < supportedStackTypes.Length; i++) {
359        var key = supportedStackTypes[i];
360        Stacks[key].IsEnabled = Configuration.IsStackEnabled(key);
361      }
362
363      // exec stack must always be enabled
364      this.ExecStack.IsEnabled = true;
365    }
366
367    /// <summary>
368    /// Clears Stacks and custom expressions
369    /// </summary>
370    public void ClearStacks() {
371      for (var i = 0u; i < supportedStackTypes.Length; i++) {
372        var key = supportedStackTypes[i];
373        Stacks[key].Clear();
374      }
375
376      CustomExpressions.Clear();
377    }
378
379    [MethodImpl(MethodImplOptions.AggressiveInlining)]
380    private void Run() {
381      // if no stack which is modifies the exec stack is enabled, unroll loop due to performance reasons
382      if (!Configuration.IsStackEnabled(StackTypes.Exec)) {
383        while (CanRun(10))
384          DoTenSteps();
385      }
386
387      while (IsRunning)
388        DoStep();
389
390      if (IsCompleted)
391        Finally();
392    }
393
394    [MethodImpl(MethodImplOptions.AggressiveInlining)]
395    private void Finally() {
396      if (Configuration.TopLevelPopCode && !CodeStack.IsEmpty && CodeStack.IsEnabled)
397        CodeStack.Pop();
398
399      PoolContainer.DisposePools();
400    }
401
402    private void InitRun(Expression expression) {
403      ExecStack.Push(expression);
404
405      if (!expression.IsProgram)
406        return;
407
408      DoStep();
409      ExecCounter--;   // unpacking the initial program is not counted
410    }
411
412    [MethodImpl(MethodImplOptions.AggressiveInlining)]
413    private bool DoStep() {
414      ExecCounter++;
415      return ExecStack.Pop().TryEval(this);
416    }
417
418    [MethodImpl(MethodImplOptions.AggressiveInlining)]
419    private void DoTenSteps() {
420      ExecStack[0].TryEval(this);
421      ExecStack[1].TryEval(this);
422      ExecStack[2].TryEval(this);
423      ExecStack[3].TryEval(this);
424      ExecStack[4].TryEval(this);
425      ExecStack[5].TryEval(this);
426      ExecStack[6].TryEval(this);
427      ExecStack[7].TryEval(this);
428      ExecStack[8].TryEval(this);
429      ExecStack[9].TryEval(this);
430
431      ExecStack.Remove(10);
432      ExecCounter += 10;
433    }
434
435    private Task InterpretAsync() {
436      currentTask = Task.Run(() => Run());
437
438      return currentTask;
439    }
440
441    public virtual void Dispose() {
442      PoolContainer.DisposePools();
443    }
444  }
445}
Note: See TracBrowser for help on using the repository browser.