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

Last change on this file since 14834 was 14834, checked in by pkimmesw, 3 years ago

#2665 LexicaseSelector, Performance improvements, UI Fixes, Debugger only shows used stacks, fixed Debugger stepping, Added vector expressions, ERCOptions,

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