Free cookie consent management tool by TermsFeed Policy Generator

source: addons/HeuristicLab.PushGP/HeuristicLab.Problems.ProgramSynthesis/Push/Interpreter/PushInterpreter.cs

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

#2665 Testet Problems, Improved Performance

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