1 | namespace HeuristicLab.Problems.ProgramSynthesis.Push.Interpreter {
|
---|
2 | using System;
|
---|
3 | using System.Collections.Generic;
|
---|
4 | using System.Runtime.CompilerServices;
|
---|
5 | using System.Threading;
|
---|
6 | using System.Threading.Tasks;
|
---|
7 | using Attributes;
|
---|
8 | using Configuration;
|
---|
9 | using Core;
|
---|
10 | using Expressions;
|
---|
11 | using Parser;
|
---|
12 | using Random;
|
---|
13 | using Stack;
|
---|
14 |
|
---|
15 | #if DEBUG
|
---|
16 | using System.Diagnostics;
|
---|
17 | using System.Linq;
|
---|
18 | #endif
|
---|
19 |
|
---|
20 | public class PushInterpreter : IInternalPushInterpreter, IDisposable {
|
---|
21 | private Task currentTask;
|
---|
22 |
|
---|
23 | public PushInterpreter(IReadOnlyPushConfiguration config = null, IRandom random = null, InterpreterPoolContainer poolContainer = null) {
|
---|
24 | Random = random ?? new FastRandom();
|
---|
25 |
|
---|
26 | Configuration = config ?? new PushConfiguration();
|
---|
27 |
|
---|
28 | // setting the capacity of the stacks to max points ensures that there will be enough memory at runtime
|
---|
29 | ExecStack = new PushStack<Expression>(Configuration.MaxPointsInProgram);
|
---|
30 |
|
---|
31 | CodeStack = new PushStack<Expression> {
|
---|
32 | IsEnabled = Configuration.EnabledStacks[StackTypes.Code]
|
---|
33 | };
|
---|
34 |
|
---|
35 | NameStack = new PushStack<string> {
|
---|
36 | IsEnabled = Configuration.EnabledStacks[StackTypes.Code]
|
---|
37 | };
|
---|
38 |
|
---|
39 | BooleanStack = new PushStack<bool> {
|
---|
40 | IsEnabled = Configuration.EnabledStacks[StackTypes.Boolean]
|
---|
41 | };
|
---|
42 |
|
---|
43 | IntegerStack = new PushStack<long> {
|
---|
44 | IsEnabled = Configuration.EnabledStacks[StackTypes.Integer]
|
---|
45 | };
|
---|
46 |
|
---|
47 | FloatStack = new PushStack<double> {
|
---|
48 | IsEnabled = Configuration.EnabledStacks[StackTypes.Float]
|
---|
49 | };
|
---|
50 |
|
---|
51 | CharStack = new PushStack<char> {
|
---|
52 | IsEnabled = Configuration.EnabledStacks[StackTypes.Char]
|
---|
53 | };
|
---|
54 |
|
---|
55 | StringStack = new PushStack<string> {
|
---|
56 | IsEnabled = Configuration.EnabledStacks[StackTypes.String]
|
---|
57 | };
|
---|
58 |
|
---|
59 | IntegerVectorStack = new PushStack<List<long>> {
|
---|
60 | IsEnabled = Configuration.EnabledStacks[StackTypes.IntegerVector]
|
---|
61 | };
|
---|
62 |
|
---|
63 | FloatVectorStack = new PushStack<List<double>> {
|
---|
64 | IsEnabled = Configuration.EnabledStacks[StackTypes.FloatVector]
|
---|
65 | };
|
---|
66 |
|
---|
67 | BooleanVectorStack = new PushStack<List<bool>> {
|
---|
68 | IsEnabled = Configuration.EnabledStacks[StackTypes.BooleanVector]
|
---|
69 | };
|
---|
70 |
|
---|
71 | StringVectorStack = new PushStack<List<string>> {
|
---|
72 | IsEnabled = Configuration.EnabledStacks[StackTypes.StringVector]
|
---|
73 | };
|
---|
74 |
|
---|
75 | CustomExpressions = new Dictionary<string, Expression>();
|
---|
76 | PoolContainer = poolContainer ?? new InterpreterPoolContainer();
|
---|
77 | }
|
---|
78 |
|
---|
79 | public PushInterpreter(int seed, IReadOnlyPushConfiguration config = null)
|
---|
80 | : this(config, new FastRandom(seed)) {
|
---|
81 | }
|
---|
82 |
|
---|
83 | public IRandom Random { get; set; }
|
---|
84 |
|
---|
85 | public long ExecCounter { get; private set; }
|
---|
86 |
|
---|
87 | public bool IsPaused { get; private set; }
|
---|
88 |
|
---|
89 | public bool IsAborted { get; private set; }
|
---|
90 |
|
---|
91 | public bool IsRunning
|
---|
92 | {
|
---|
93 | get
|
---|
94 | {
|
---|
95 | return !ExecStack.IsEmpty &&
|
---|
96 | !IsPaused &&
|
---|
97 | !IsAborted &&
|
---|
98 | (ExecCounter < Configuration.EvalPushLimit);
|
---|
99 | }
|
---|
100 | }
|
---|
101 |
|
---|
102 | public bool IsCompleted
|
---|
103 | {
|
---|
104 | get
|
---|
105 | {
|
---|
106 | return ExecStack.IsEmpty || ExecCounter >= Configuration.EvalPushLimit;
|
---|
107 | }
|
---|
108 | }
|
---|
109 |
|
---|
110 | public bool CanStep
|
---|
111 | {
|
---|
112 | get
|
---|
113 | {
|
---|
114 | return !IsCompleted && !IsAborted && IsPaused;
|
---|
115 | }
|
---|
116 | }
|
---|
117 |
|
---|
118 | public InterpreterPoolContainer PoolContainer { get; private set; }
|
---|
119 |
|
---|
120 | public IReadOnlyPushConfiguration Configuration { get; protected set; }
|
---|
121 |
|
---|
122 | [PushStack(StackTypes.Code)]
|
---|
123 | public IPushStack<Expression> CodeStack { get; private set; }
|
---|
124 |
|
---|
125 | [PushStack(StackTypes.Exec)]
|
---|
126 | public IPushStack<Expression> ExecStack { get; private set; }
|
---|
127 |
|
---|
128 | [PushStack(StackTypes.Name)]
|
---|
129 | public IPushStack<string> NameStack { get; private set; }
|
---|
130 |
|
---|
131 | [PushStack(StackTypes.Boolean)]
|
---|
132 | public IPushStack<bool> BooleanStack { get; private set; }
|
---|
133 |
|
---|
134 | [PushStack(StackTypes.Integer)]
|
---|
135 | public IPushStack<long> IntegerStack { get; private set; }
|
---|
136 |
|
---|
137 | [PushStack(StackTypes.Float)]
|
---|
138 | public IPushStack<double> FloatStack { get; private set; }
|
---|
139 |
|
---|
140 | [PushStack(StackTypes.Char)]
|
---|
141 | public IPushStack<char> CharStack { get; private set; }
|
---|
142 |
|
---|
143 | [PushStack(StackTypes.String)]
|
---|
144 | public IPushStack<string> StringStack { get; private set; }
|
---|
145 |
|
---|
146 | [PushStack(StackTypes.IntegerVector)]
|
---|
147 | public IPushStack<List<long>> IntegerVectorStack { get; private set; }
|
---|
148 |
|
---|
149 | [PushStack(StackTypes.FloatVector)]
|
---|
150 | public IPushStack<List<double>> FloatVectorStack { get; private set; }
|
---|
151 |
|
---|
152 | [PushStack(StackTypes.BooleanVector)]
|
---|
153 | public IPushStack<List<bool>> BooleanVectorStack { get; private set; }
|
---|
154 |
|
---|
155 | [PushStack(StackTypes.StringVector)]
|
---|
156 | public IPushStack<List<string>> StringVectorStack { get; private set; }
|
---|
157 |
|
---|
158 | public IDictionary<string, Expression> CustomExpressions { get; private set; }
|
---|
159 |
|
---|
160 | public bool IsNameQuoteFlagSet { get; set; }
|
---|
161 |
|
---|
162 | public Task RunAsync(string code, CancellationToken token = default(CancellationToken)) {
|
---|
163 | var program = PushParser.Parse(code);
|
---|
164 | currentTask = RunAsync(program, token);
|
---|
165 | return currentTask;
|
---|
166 | }
|
---|
167 | public async Task RunAsync(Expression expression, CancellationToken token = default(CancellationToken)) {
|
---|
168 | await Task.Run(() => Run(expression), token);
|
---|
169 | }
|
---|
170 |
|
---|
171 | public void Run(string code, bool stepwise = false) {
|
---|
172 | var program = PushParser.Parse(code);
|
---|
173 | Run(program, stepwise);
|
---|
174 | }
|
---|
175 |
|
---|
176 | public void Run(Expression expression, bool stepwise = false) {
|
---|
177 | IsPaused = stepwise;
|
---|
178 |
|
---|
179 | /* Push top expression so the loop is able to enter
|
---|
180 | * If the top expression is a single statement then the loop has nothing to do.
|
---|
181 | * Otherwise the expand expression will be evaluated and pushes code onto the EXEC stack.
|
---|
182 | * Expanding the initial program is not counted */
|
---|
183 | ExecStack.Push(expression);
|
---|
184 |
|
---|
185 | if (Configuration.TopLevelPushCode) CodeStack.Push(expression);
|
---|
186 |
|
---|
187 | // expand if program
|
---|
188 | if (expression.IsProgram)
|
---|
189 | DoStep();
|
---|
190 |
|
---|
191 | Run();
|
---|
192 | }
|
---|
193 |
|
---|
194 | public bool CanRun(int count) {
|
---|
195 | return ExecStack.Count >= count &&
|
---|
196 | !IsPaused &&
|
---|
197 | !IsAborted &&
|
---|
198 | ExecCounter + count < Configuration.EvalPushLimit;
|
---|
199 | }
|
---|
200 |
|
---|
201 | public async Task AbortAsync() {
|
---|
202 | if (IsAborted || IsCompleted) return;
|
---|
203 |
|
---|
204 | IsAborted = true;
|
---|
205 |
|
---|
206 | PoolContainer.DisposePools();
|
---|
207 |
|
---|
208 | if (currentTask != null) await currentTask;
|
---|
209 | }
|
---|
210 |
|
---|
211 | public async Task AbortAndResetAsync() {
|
---|
212 | await AbortAsync();
|
---|
213 | Reset();
|
---|
214 | }
|
---|
215 |
|
---|
216 | public async Task PauseAsync() {
|
---|
217 | if (IsPaused || IsCompleted) return;
|
---|
218 |
|
---|
219 | IsPaused = true;
|
---|
220 |
|
---|
221 | if (currentTask != null) await currentTask;
|
---|
222 | }
|
---|
223 |
|
---|
224 | public async Task ResumeAsync() {
|
---|
225 | if (IsPaused || !IsAborted) {
|
---|
226 | IsPaused = false;
|
---|
227 | await InterpretAsync();
|
---|
228 | } else await currentTask;
|
---|
229 | }
|
---|
230 |
|
---|
231 | public void Resume() {
|
---|
232 | if (!IsPaused && IsAborted)
|
---|
233 | return;
|
---|
234 |
|
---|
235 | IsPaused = false;
|
---|
236 | this.Run();
|
---|
237 | }
|
---|
238 |
|
---|
239 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
---|
240 | public bool Step() {
|
---|
241 | if (!CanStep) return false;
|
---|
242 |
|
---|
243 | var successful = DoStep();
|
---|
244 |
|
---|
245 | if (IsCompleted)
|
---|
246 | Finally();
|
---|
247 |
|
---|
248 | return successful;
|
---|
249 | }
|
---|
250 |
|
---|
251 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
---|
252 | public void Step(int count) {
|
---|
253 | for (var i = 0u; i < count; i++) Step();
|
---|
254 | }
|
---|
255 |
|
---|
256 | /// <summary>
|
---|
257 | /// Reset while interpreter
|
---|
258 | /// </summary>
|
---|
259 | public void Reset() {
|
---|
260 | ExecCounter = 0;
|
---|
261 |
|
---|
262 | IsAborted = false;
|
---|
263 | IsPaused = false;
|
---|
264 | currentTask = null;
|
---|
265 |
|
---|
266 | Clear();
|
---|
267 | }
|
---|
268 |
|
---|
269 | /// <summary>
|
---|
270 | /// Clears stacks and custom expressions
|
---|
271 | /// </summary>
|
---|
272 | public void Clear() {
|
---|
273 | ExecStack.Clear();
|
---|
274 | CodeStack.Clear();
|
---|
275 | NameStack.Clear();
|
---|
276 | BooleanStack.Clear();
|
---|
277 | IntegerStack.Clear();
|
---|
278 | FloatStack.Clear();
|
---|
279 |
|
---|
280 | CustomExpressions.Clear();
|
---|
281 | }
|
---|
282 |
|
---|
283 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
---|
284 | private void Run() {
|
---|
285 | // if no stack which is modifies the exec stack is enabled, unroll loop due to performance reasons
|
---|
286 | if (!Configuration.EnabledStacks[StackTypes.Exec] &&
|
---|
287 | !Configuration.EnabledStacks[StackTypes.Code]) {
|
---|
288 | while (CanRun(10))
|
---|
289 | DoTenSteps();
|
---|
290 | }
|
---|
291 |
|
---|
292 | while (IsRunning)
|
---|
293 | DoStep();
|
---|
294 |
|
---|
295 | if (IsCompleted)
|
---|
296 | Finally();
|
---|
297 | }
|
---|
298 |
|
---|
299 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
---|
300 | private void Finally() {
|
---|
301 | if (Configuration.TopLevelPopCode && !CodeStack.IsEmpty)
|
---|
302 | CodeStack.Pop();
|
---|
303 |
|
---|
304 | PoolContainer.DisposePools();
|
---|
305 | }
|
---|
306 |
|
---|
307 | #if DEBUG
|
---|
308 | private Expression last;
|
---|
309 | private bool DoStep() {
|
---|
310 | double[] bk;
|
---|
311 | if (!FloatStack.IsEmpty) {
|
---|
312 | bk = FloatStack.Peek(Math.Min(FloatStack.Count, 3));
|
---|
313 | }
|
---|
314 |
|
---|
315 | var expression = ExecStack.Pop();
|
---|
316 | var succ = expression.Eval(this);
|
---|
317 |
|
---|
318 | if ((ExecStack.Count > 0 && ExecStack.Top == null) ||
|
---|
319 | (CodeStack.Count > 0 && CodeStack.Top == null) ||
|
---|
320 | FloatStack.Any(x => double.IsNaN(x) || double.IsInfinity(x)) ||
|
---|
321 | StringStack.Count > 0 && StringStack.Any(x => x == null)) {
|
---|
322 | Debugger.Break();
|
---|
323 | }
|
---|
324 |
|
---|
325 | ExecCounter++;
|
---|
326 | last = expression;
|
---|
327 | return succ;
|
---|
328 | }
|
---|
329 | #else
|
---|
330 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
---|
331 | private bool DoStep() {
|
---|
332 | ExecCounter++;
|
---|
333 | return ExecStack.Pop().Eval(this);
|
---|
334 | }
|
---|
335 | #endif
|
---|
336 |
|
---|
337 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
---|
338 | private void DoTenSteps() {
|
---|
339 | ExecStack[0].Eval(this);
|
---|
340 | ExecStack[1].Eval(this);
|
---|
341 | ExecStack[2].Eval(this);
|
---|
342 | ExecStack[3].Eval(this);
|
---|
343 | ExecStack[4].Eval(this);
|
---|
344 | ExecStack[5].Eval(this);
|
---|
345 | ExecStack[6].Eval(this);
|
---|
346 | ExecStack[7].Eval(this);
|
---|
347 | ExecStack[8].Eval(this);
|
---|
348 | ExecStack[9].Eval(this);
|
---|
349 |
|
---|
350 | ExecStack.Remove(10);
|
---|
351 | ExecCounter += 10;
|
---|
352 | }
|
---|
353 |
|
---|
354 | private Task InterpretAsync() {
|
---|
355 | currentTask = Task.Run(() => this.Run());
|
---|
356 |
|
---|
357 | return currentTask;
|
---|
358 | }
|
---|
359 |
|
---|
360 | public virtual void Dispose() {
|
---|
361 | PoolContainer.DisposePools();
|
---|
362 | }
|
---|
363 | }
|
---|
364 | } |
---|