source: branches/PushGP/HeuristicLab.PushGP/HeuristicLab.Problems.ProgramSynthesis/Push/Problem/PushProblem.cs @ 14908

Last change on this file since 14908 was 14908, checked in by pkimmesw, 2 years ago

#2665 Removed "this" qualifier

File size: 15.5 KB
Line 
1using System;
2
3namespace HeuristicLab.Problems.ProgramSynthesis.Push.Problem {
4  using System.Linq;
5
6  using Common;
7  using Configuration;
8  using Core;
9  using Data.Pool;
10  using Encodings.IntegerVectorEncoding;
11  using HeuristicLab.Data;
12  using HeuristicLab.Problems.ProgramSynthesis.Base.Erc;
13  using HeuristicLab.Problems.ProgramSynthesis.Push.Problem.BenchmarkSuite;
14
15  using Interpreter;
16  using Optimization;
17  using Parameters;
18  using Persistence.Default.CompositeSerializers.Storable;
19  using Random;
20
21  [StorableClass]
22  public abstract class PushProblem : SingleObjectiveBasicProblem<IntegerVectorEncoding> {
23    [Storable]
24    protected readonly PushConfiguration config;
25    protected PushInterpreterPool pool;
26    protected readonly ObjectPool<IRandom> randomPool = new ObjectPool<IRandom>(() => new MersenneTwister());
27
28    [Storable]
29    protected readonly IPushEvaluator PushEvaluator;
30
31    public const string CaseQualitiesScopeParameterName = "CaseQualities";
32    private const string BestTrainingSolutionResultName = "Best Solution";
33    private const string TestQualityResultName = "Test Quality";
34
35    protected PushProblem(PushBenchmarkSuiteEvaluator evaluator) {
36      config = new PushConfiguration();
37      PushEvaluator = evaluator;
38
39      InitData();
40      InitEvents();
41      InitParameters();
42    }
43
44    [StorableConstructor]
45    protected PushProblem(bool deserializing)
46      : base(deserializing) {
47    }
48
49    protected PushProblem(PushProblem original, Cloner cloner)
50      : base(original, cloner) {
51      config = cloner.Clone(original.config);
52      PushEvaluator = cloner.Clone(original.PushEvaluator);
53
54      InitData();
55      InitEvents();
56    }
57
58    [StorableHook(HookType.AfterDeserialization)]
59    // ReSharper disable once UnusedMember.Local
60    private void AfterDeserialization() {
61      InitData();
62      InitEvents();
63    }
64
65    private void InitData() {
66      pool = new PushInterpreterPool(Environment.ProcessorCount * 2, 4096, 1024, config);
67    }
68
69    private void InitEvents() {
70      config.EnabledExpressionsChanged += EnabledExpressionsChanged;
71    }
72
73    private void EnabledExpressionsChanged(object sender, EnabledExpressionsChangedEventArgs e) {
74      Encoding.Bounds[0, 1] = config.EnabledExpressions.Count;
75      Encoding.BoundsParameter.Value[0, 1] = config.EnabledExpressions.Count;
76    }
77
78    #region Parameters
79
80    private const string InstructionsParameterName = "Instructions";
81    private const string InstructionsParameterDescription = "Enables/Disables Instructions";
82    private const string EvalPushLimitParameterName = "EvalPushLimit";
83    private const string EvalPushLimitParameterDescription = "This is the maximum allowed number of \"executions\" in a single top-level call to the interpreter. The execution of a single Push instruction counts as one execution, as does the processing of a single literal, as does the descent into one layer of parentheses (that is, the processing of the \"(\" counts as one execution).";
84    private const string MinPointsInProgramParameterName = "MinProgramLength";
85    private const string MinProgramLengthParameterDescription = "This is the minimum size of an item on the CODE/EXEC stack, expressed as a number of points. A point is an instruction, a literal, or a pair of parentheses.";
86    private const string MaxPointsInProgramParameterName = "MaxProgramLength";
87    private const string MaxProgramLengthParameterDescription = "This is the maximum size of an item on the CODE/EXEC stack, expressed as a number of points. A point is an instruction, a literal, or a pair of parentheses.";
88    private const string TopLevelPushCodeParameterName = "TopLevelPushCode";
89    private const string TopLevelPushCodeParameterDescription = "When TRUE (which is the default), code passed to the top level of the interpreter will be pushed onto the CODE stack prior to execution.";
90    private const string TopLevelPopCodeParameterName = "TopLevelPopCode";
91    private const string TopLevelPopCodeParameterDescription = "When TRUE, the CODE stack will be popped at the end of top level calls to the interpreter. The default is FALSE.";
92    private const string MaxPointsInRandomInstructionParameterName = "MaxPointsInRandomInstruction";
93    private const string MaxPointsInRandomInstructionParameterDescription = "MaxPointsInRandomInstruction";
94    private const string ErcOptionsParameterName = "ERC options";
95    private const string MaxStringLengthParameterName = "Max. string length";
96    private const string MaxDepthParameterName = "Max. program recursion";
97
98    private void InitParameters() {
99      Parameters.Add(new ValueParameter<IEnabledExpressionsConfiguration>(
100        InstructionsParameterName,
101        InstructionsParameterDescription,
102        config));
103
104      Parameters.Add(new ValueParameter<ErcOptions>(ErcOptionsParameterName, config.ErcOptions));
105
106      Parameters.Add(new FixedValueParameter<IntValue>(
107        EvalPushLimitParameterName,
108        EvalPushLimitParameterDescription,
109        new IntValue(config.EvalPushLimit)));
110
111      Parameters.Add(new FixedValueParameter<IntValue>(
112        MinPointsInProgramParameterName,
113        MinProgramLengthParameterDescription,
114        new IntValue(config.MinPointsInProgram)) { Hidden = true });
115
116      Parameters.Add(new FixedValueParameter<IntValue>(
117        MaxPointsInProgramParameterName,
118        MaxProgramLengthParameterDescription,
119        new IntValue(config.MaxPointsInProgram)));
120      Encoding.LengthParameter = MaxPointsInProgramParameter as IFixedValueParameter<IntValue>;
121
122      Parameters.Add(new FixedValueParameter<BoolValue>(
123        TopLevelPushCodeParameterName,
124        TopLevelPushCodeParameterDescription,
125        new BoolValue(config.TopLevelPushCode)) { Hidden = true });
126
127      Parameters.Add(new FixedValueParameter<BoolValue>(
128        TopLevelPopCodeParameterName,
129        TopLevelPopCodeParameterDescription,
130        new BoolValue(config.TopLevelPopCode)) { Hidden = true });
131
132      Parameters.Add(new FixedValueParameter<IntValue>(
133        MaxPointsInRandomInstructionParameterName,
134        MaxPointsInRandomInstructionParameterDescription,
135        new IntValue(config.MaxPointsInRandomExpression)) { Hidden = true });
136
137      Parameters.Add(new FixedValueParameter<IntValue>(
138        MaxStringLengthParameterName,
139        new IntValue(config.MaxStringLength)) { Hidden = true });
140
141      Parameters.Add(new FixedValueParameter<IntValue>(
142        MaxDepthParameterName,
143        new IntValue(config.MaxDepth)) { Hidden = true });
144
145      Parameters.Add(new LookupParameter<BoolArray>("Cases", "The training cases that have been successfully executed."));
146      Parameters.Add(new LookupParameter<DoubleArray>(CaseQualitiesScopeParameterName, "The quality of every single training case for each individual"));
147
148      Encoding.Bounds[0, 0] = 0;
149      Encoding.Bounds[0, 1] = config.EnabledExpressions.Count;
150      Encoding.Length = config.MaxPointsInProgram;
151    }
152
153    public IValueParameter<IEnabledExpressionsConfiguration> InstructionsParameter
154    {
155      get { return (IValueParameter<IEnabledExpressionsConfiguration>)Parameters[InstructionsParameterName]; }
156    }
157
158    public IEnabledExpressionsConfiguration Instructions
159    {
160      get { return InstructionsParameter.Value; }
161      set { InstructionsParameter.Value = value; }
162    }
163
164    public IValueParameter<ErcOptions> ErcOptionsParameter
165    {
166      get { return (IValueParameter<ErcOptions>)Parameters[ErcOptionsParameterName]; }
167    }
168
169    public ErcOptions ErcOptions
170    {
171      get { return config.ErcOptions; }
172      set
173      {
174        ErcOptionsParameter.Value = value;
175        config.ErcOptions = value;
176      }
177    }
178
179    /// <summary>
180    ///     This is the maximum allowed number of "executions" in a single top-level call to the interpreter.
181    ///     The execution of a single Push instruction counts as one execution, as does the processing of a single literal,
182    ///     as does the descent into one layer of parentheses (that is, the processing of the "(" counts as one execution).
183    ///     When this limit is exceeded the interpreter aborts immediately, leaving its stacks in the states they were in prior
184    ///     to the abort (so they may still be examined by a calling program). Whether or not this counts as an "abnormal"
185    ///     termination
186    ///     is up to the calling program.
187    /// </summary>
188    public IValueParameter<IntValue> EvalPushLimitParameter
189    {
190      get { return (IValueParameter<IntValue>)Parameters[EvalPushLimitParameterName]; }
191    }
192
193    public int EvalPushLimit
194    {
195      get { return config.EvalPushLimit; }
196      set
197      {
198        EvalPushLimitParameter.Value.Value = value;
199        config.EvalPushLimit = value;
200      }
201    }
202
203    /// <summary>
204    /// This is the maximum of depth a push program can have. Expressions, which lead to exceed this limit are interpreted as NOOP.
205    /// </summary>
206    public IValueParameter<IntValue> MaxDepthParameter
207    {
208      get { return (IValueParameter<IntValue>)Parameters[MaxDepthParameterName]; }
209    }
210
211    public int MaxDepth
212    {
213      get { return config.MaxDepth; }
214      set
215      {
216        MaxDepthParameter.Value.Value = value;
217        config.MaxDepth = value;
218      }
219    }
220
221    /// <summary>
222    ///     This is the maximum size of an item on the CODE stack, expressed as a number of points.
223    ///     A point is an instruction, a literal, or a pair of parentheses. Any instruction that would cause this limit to be
224    ///     exceeded
225    ///     should instead act as a NOOP, leaving all stacks in the states that they were in before the execution of the
226    ///     instruction.
227    /// </summary>
228    public IValueParameter<IntValue> MaxPointsInProgramParameter
229    {
230      get { return (IValueParameter<IntValue>)Parameters[MaxPointsInProgramParameterName]; }
231    }
232
233    public int MaxPointsInProgram
234    {
235      get { return config.MaxPointsInProgram; }
236      set
237      {
238        MaxPointsInProgramParameter.Value.Value = value;
239        config.MaxPointsInProgram = value;
240      }
241    }
242
243    /// <summary>
244    ///     This is the minimum size of an item on the CODE stack, expressed as a number of points.
245    ///     A point is an instruction, a literal, or a pair of parentheses. Any instruction that would cause this limit to be
246    ///     exceeded
247    ///     should instead act as a NOOP, leaving all stacks in the states that they were in before the execution of the
248    ///     instruction.
249    /// </summary>
250    public IValueParameter<IntValue> MinPointsInProgramParameter
251    {
252      get { return (IValueParameter<IntValue>)Parameters[MinPointsInProgramParameterName]; }
253    }
254
255    public int MinPointsInProgram
256    {
257      get { return config.MaxPointsInProgram; }
258      set
259      {
260        MinPointsInProgramParameter.Value.Value = value;
261        config.MinPointsInProgram = value;
262      }
263    }
264
265    /// <summary>
266    ///     The maximum number of points in an expression produced by the CODE.RAND instruction.
267    /// </summary>
268    public IValueParameter<IntValue> MaxPointsInRandomExpressionParameter
269    {
270      get { return (IValueParameter<IntValue>)Parameters[MaxPointsInRandomInstructionParameterName]; }
271    }
272
273    public int MaxPointsInRandomExpression
274    {
275      get { return config.MaxPointsInRandomExpression; }
276      set
277      {
278        MaxPointsInRandomExpressionParameter.Value.Value = value;
279        config.MaxPointsInRandomExpression = value;
280      }
281    }
282
283    /// <summary>
284    ///     When TRUE (which is the default), code passed to the top level of the interpreter
285    ///     will be pushed onto the CODE stack prior to execution.
286    /// </summary>
287    public IValueParameter<BoolValue> TopLevelPushCodeParameter
288    {
289      get { return (IValueParameter<BoolValue>)Parameters[TopLevelPushCodeParameterName]; }
290    }
291
292    public bool TopLevelPushCode
293    {
294      get { return config.TopLevelPushCode; }
295      set
296      {
297        TopLevelPushCodeParameter.Value.Value = value;
298        config.TopLevelPushCode = value;
299      }
300    }
301
302    /// <summary>
303    ///     When TRUE, the CODE stack will be popped at the end of top level calls to the interpreter. The default is FALSE.
304    /// </summary>
305    public IValueParameter<BoolValue> TopLevelPopCodeParameter
306    {
307      get { return (IValueParameter<BoolValue>)Parameters[TopLevelPopCodeParameterName]; }
308    }
309
310    public bool TopLevelPopCode
311    {
312      get { return config.TopLevelPopCode; }
313      set
314      {
315        TopLevelPopCodeParameter.Value.Value = value;
316        config.TopLevelPopCode = value;
317      }
318    }
319
320    public IValueParameter<IntValue> MaxStringLengthParameter
321    {
322      get { return (IValueParameter<IntValue>)Parameters[MaxStringLengthParameterName]; }
323    }
324
325    public int MaxStringLength
326    {
327      get { return config.MaxStringLength; }
328      set
329      {
330        MaxStringLengthParameter.Value.Value = value;
331        config.MaxStringLength = value;
332      }
333    }
334    #endregion
335
336    public override bool Maximization { get { return false; } }
337
338    public override void Analyze(Individual[] individuals, double[] qualities, ResultCollection results, IRandom random) {
339      var bestQuality = Maximization ? qualities.Max() : qualities.Min();
340      var bestIdx = Array.IndexOf(qualities, bestQuality);
341      var bestIndividual = individuals[bestIdx].IntegerVector();
342
343      var isIndividualBetter = AnalyzeBestTrainingSolution(bestIndividual, bestQuality, results, random);
344
345      if (isIndividualBetter) {
346        AnalyzeBestTestSolution(bestIndividual, results, random);
347      }
348    }
349
350    private void AnalyzeBestTestSolution(IntegerVector bestIndividual, ResultCollection results, IRandom random) {
351      var program = bestIndividual.ToPushProgram(config, randomPool);
352      var testResult = PushEvaluator.EvaluateTest(pool, program, random);
353
354      if (!results.ContainsKey(TestQualityResultName)) {
355        results.Add(new Result(TestQualityResultName, new DoubleValue(testResult.TotalQuality)));
356      } else {
357        ((DoubleValue)results[TestQualityResultName].Value).Value = testResult.TotalQuality;
358      }
359    }
360
361    private bool AnalyzeBestTrainingSolution(IntegerVector bestIndividual, double bestQuality, ResultCollection results, IRandom random) {
362      var solution = CreatePushSolution(
363        bestIndividual,
364        bestQuality,
365        random,
366        config,
367        PushEvaluator);
368
369      if (!results.ContainsKey(BestTrainingSolutionResultName)) {
370        results.Add(new Result(BestTrainingSolutionResultName, solution));
371        return true;
372      }
373
374      var currentBestQuality = ((PushSolution)results[BestTrainingSolutionResultName].Value).Quality;
375
376      if (Maximization && currentBestQuality < bestQuality ||
377         !Maximization && currentBestQuality > bestQuality) {
378        results[BestTrainingSolutionResultName].Value = solution;
379        return true;
380      }
381
382      return false;
383    }
384
385    protected abstract PushSolution CreatePushSolution(
386      IntegerVector vector,
387      double bestQuality,
388      IRandom random,
389      IReadOnlyPushConfiguration config,
390      IPushEvaluator evaluator);
391
392    public override double Evaluate(Individual individual, IRandom random) {
393      var program = individual.ToPushProgram(config, randomPool);
394      var result = PushEvaluator.EvaluateTraining(pool, program, random);
395
396      individual[CaseQualitiesScopeParameterName] = new DoubleArray(result.ExampleQualities);
397
398      return result.TotalQuality;
399    }
400  }
401}
Note: See TracBrowser for help on using the repository browser.