Free cookie consent management tool by TermsFeed Policy Generator

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

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

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

File size: 14.8 KB
RevLine 
[15771]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 {
[14834]11  public class PushInterpreter : IInternalPushInterpreter, IDisposable {
[14744]12    private Task currentTask;
[15341]13    private int evalPushLimit;
[14744]14
[15273]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>
[14777]21    public PushInterpreter(IReadOnlyPushConfiguration config = null, IRandom random = null, InterpreterPoolContainer poolContainer = null) {
[15273]22      randomOrigin = random ?? new MersenneTwister();
23      Random = (IRandom)randomOrigin.Clone();
[14744]24      Configuration = config ?? new PushConfiguration();
25
[15334]26      ExecStack = new PushStack<Expression>(Configuration.MaxProgramLength);
[15032]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>>();
[15189]38      PrintStack = new PrintStack();
[14744]39
[14914]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 },
[15017]49        { StackTypes.Print, PrintStack },
[14914]50        { StackTypes.IntegerVector, IntegerVectorStack },
51        { StackTypes.FloatVector, FloatVectorStack },
52        { StackTypes.BooleanVector, BooleanVectorStack },
53        { StackTypes.StringVector, StringVectorStack },
54      };
55
[15189]56      supportedStackTypes = Stacks.Keys.ToArray();
57
[14744]58      CustomExpressions = new Dictionary<string, Expression>();
[14777]59      PoolContainer = poolContainer ?? new InterpreterPoolContainer();
[15032]60
[15341]61      InitEvalPushLimit();
[15032]62      ConfigureStacks();
[14744]63    }
64
[14777]65    public PushInterpreter(int seed, IReadOnlyPushConfiguration config = null)
[14744]66      : this(config, new FastRandom(seed)) {
67    }
68
[15189]69    private readonly StackTypes[] supportedStackTypes;
[14914]70    public IReadOnlyDictionary<StackTypes, IPushStack> Stacks { get; private set; }
71
[15273]72    private IRandom randomOrigin;
73    public IRandom Random { get; private set; }
[14744]74
[14875]75    public long ExecCounter { get; private set; }
[14744]76
77    public bool IsPaused { get; private set; }
78
79    public bool IsAborted { get; private set; }
80
[15771]81    public bool IsRunning {
82      get {
[14744]83        return !ExecStack.IsEmpty &&
84               !IsPaused &&
85               !IsAborted &&
[15341]86               (ExecCounter < evalPushLimit);
[14744]87      }
88    }
89
[15771]90    public bool IsCompleted {
91      get {
[14834]92        return ExecStack.IsEmpty || ExecCounter >= Configuration.EvalPushLimit;
[14744]93      }
94    }
95
[15771]96    public bool CanStep {
97      get {
[14744]98        return !IsCompleted && !IsAborted && IsPaused;
99      }
100    }
101
[14777]102    public InterpreterPoolContainer PoolContainer { get; private set; }
[14746]103
[14777]104    public IReadOnlyPushConfiguration Configuration { get; protected set; }
[14834]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)]
[15017]122    public IPushStack<IReadOnlyList<long>> IntegerVectorStack { get; private set; }
[14834]123    [PushStack(StackTypes.FloatVector)]
[15017]124    public IPushStack<IReadOnlyList<double>> FloatVectorStack { get; private set; }
[14834]125    [PushStack(StackTypes.BooleanVector)]
[15017]126    public IPushStack<IReadOnlyList<bool>> BooleanVectorStack { get; private set; }
[14834]127    [PushStack(StackTypes.StringVector)]
[15017]128    public IPushStack<IReadOnlyList<string>> StringVectorStack { get; private set; }
[14897]129    [PushStack(StackTypes.Print)]
[15189]130    public IPrintStack PrintStack { get; private set; }
[14897]131
[14744]132    public IDictionary<string, Expression> CustomExpressions { get; private set; }
133
134    public bool IsNameQuoteFlagSet { get; set; }
135
[15189]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
[14834]231    public Task RunAsync(string code, CancellationToken token = default(CancellationToken)) {
[14744]232      var program = PushParser.Parse(code);
[14834]233      currentTask = RunAsync(program, token);
[14744]234      return currentTask;
235    }
[14834]236    public async Task RunAsync(Expression expression, CancellationToken token = default(CancellationToken)) {
[14875]237      await Task.Run(() => Run(expression), token);
[14744]238    }
239
[14745]240    public void Run(string code, bool stepwise = false) {
241      var program = PushParser.Parse(code);
242      Run(program, stepwise);
[14744]243    }
244
[15017]245    public void Run(bool stepwise) {
246      Run(PushProgram.Empty, stepwise);
247    }
248
[14834]249    public void Run(Expression expression, bool stepwise = false) {
[14777]250      IsPaused = stepwise;
[14744]251
[14777]252      /* Push top expression so the loop is able to enter
[14952]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);
[14744]257
[14952]258      if (Configuration.TopLevelPushCode && CodeStack.IsEnabled)
259        CodeStack.Push(expression);
[14744]260
[14834]261      Run();
[14744]262    }
263
[14875]264    public bool CanRun(int count) {
265      return ExecStack.Count >= count &&
266             !IsPaused &&
267             !IsAborted &&
268             ExecCounter + count < Configuration.EvalPushLimit;
269    }
270
[14744]271    public async Task AbortAsync() {
272      if (IsAborted || IsCompleted) return;
273
274      IsAborted = true;
275
[14777]276      PoolContainer.DisposePools();
[14747]277
[14744]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;
[14908]306      Run();
[14744]307    }
308
309    [MethodImpl(MethodImplOptions.AggressiveInlining)]
310    public bool Step() {
311      if (!CanStep) return false;
312
313      var successful = DoStep();
314
[14834]315      if (IsCompleted)
316        Finally();
317
[14744]318      return successful;
319    }
320
321    [MethodImpl(MethodImplOptions.AggressiveInlining)]
322    public void Step(int count) {
[14875]323      for (var i = 0u; i < count; i++) Step();
[14744]324    }
325
326    /// <summary>
[15273]327    /// Reset interpreter which clears and reconfigures stacks and local variables
[14744]328    /// </summary>
[15273]329    public void Reset(IRandom random = null) {
330      if (random != null)
331        randomOrigin = random;
332
333      // Reset Random
334      Random = (IRandom)randomOrigin.Clone();
335
[15341]336      InitEvalPushLimit();
337
[14834]338      ExecCounter = 0;
[14744]339      IsAborted = false;
340      IsPaused = false;
341      currentTask = null;
342
[15189]343      inputExpressions.Clear();
[15273]344      ClearStacks();
[15032]345      ConfigureStacks();
[14744]346    }
347
[15341]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
[15032]357    private void ConfigureStacks() {
[15189]358      for (var i = 0u; i < supportedStackTypes.Length; i++) {
359        var key = supportedStackTypes[i];
360        Stacks[key].IsEnabled = Configuration.IsStackEnabled(key);
[15032]361      }
362
363      // exec stack must always be enabled
364      this.ExecStack.IsEnabled = true;
365    }
366
[14744]367    /// <summary>
[14914]368    /// Clears Stacks and custom expressions
[14744]369    /// </summary>
[15273]370    public void ClearStacks() {
[15189]371      for (var i = 0u; i < supportedStackTypes.Length; i++) {
372        var key = supportedStackTypes[i];
373        Stacks[key].Clear();
374      }
[14744]375
376      CustomExpressions.Clear();
377    }
378
379    [MethodImpl(MethodImplOptions.AggressiveInlining)]
[14834]380    private void Run() {
[14875]381      // if no stack which is modifies the exec stack is enabled, unroll loop due to performance reasons
[15032]382      if (!Configuration.IsStackEnabled(StackTypes.Exec)) {
[14875]383        while (CanRun(10))
384          DoTenSteps();
385      }
386
[14834]387      while (IsRunning)
[14744]388        DoStep();
389
[14834]390      if (IsCompleted)
391        Finally();
[14744]392    }
393
394    [MethodImpl(MethodImplOptions.AggressiveInlining)]
395    private void Finally() {
[14952]396      if (Configuration.TopLevelPopCode && !CodeStack.IsEmpty && CodeStack.IsEnabled)
[14834]397        CodeStack.Pop();
[14744]398
[14834]399      PoolContainer.DisposePools();
[14744]400    }
401
[14952]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
[14744]412    [MethodImpl(MethodImplOptions.AggressiveInlining)]
413    private bool DoStep() {
[14834]414      ExecCounter++;
[14952]415      return ExecStack.Pop().TryEval(this);
[14744]416    }
417
[14875]418    [MethodImpl(MethodImplOptions.AggressiveInlining)]
419    private void DoTenSteps() {
[14952]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);
[14875]430
431      ExecStack.Remove(10);
432      ExecCounter += 10;
433    }
434
[14744]435    private Task InterpretAsync() {
[14908]436      currentTask = Task.Run(() => Run());
[14744]437
438      return currentTask;
439    }
440
[14834]441    public virtual void Dispose() {
442      PoolContainer.DisposePools();
[14744]443    }
444  }
445}
Note: See TracBrowser for help on using the repository browser.