Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2665 BenchmarkSuite, all examples, partially tested, VectorExpressions added

File size: 16.3 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.Base.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<ProblemData> {
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    private const string BestTrainingSolutionResultName = "Best Solution";
35    private const string TestQualityResultName = "Test Quality";
36
37    public PushProblem() {
38      config = new PushConfiguration();
39
40      InitData();
41      InitEvents();
42      InitParameters();
43    }
44
45    [StorableConstructor]
46    public PushProblem(bool deserializing)
47      : base(deserializing) {
48    }
49
50    public PushProblem(PushProblem original, Cloner cloner)
51      : base(original, cloner) {
52      config = cloner.Clone(original.config);
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      this.Encoding.Bounds[0, 1] = config.EnabledExpressions.Count;
75      this.Encoding.BoundsParameter.Value[0, 1] = config.EnabledExpressions.Count;
76    }
77
78    #region Parameters
79
80    private const string DataBoundsParameterName = "DataBounds";
81    private const string DataParameterName = "Data";
82    private const string DataParameterDescription = "Program Synthesis";
83    private const string InstructionsParameterName = "Instructions";
84    private const string InstructionsParameterDescription = "Enables/Disables Instructions";
85    private const string EvalPushLimitParameterName = "EvalPushLimit";
86    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).";
87    private const string MaxPointsInProgramParameterName = "MaxProgramLength";
88    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.";
89    private const string TopLevelPushCodeParameterName = "TopLevelPushCode";
90    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.";
91    private const string TopLevelPopCodeParameterName = "TopLevelPopCode";
92    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.";
93    private const string MaxPointsInRandomInstructionParameterName = "MaxPointsInRandomInstruction";
94    private const string MaxPointsInRandomInstructionParameterDescription = "MaxPointsInRandomInstruction";
95    private const string ErcOptionsParameterName = "ERC options";
96    private const string MaxStringLengthParameterName = "Max. string length";
97    private const string MaxDepthParameterName = "Max. program recursion";
98
99    private void InitParameters() {
100      Parameters.Add(new FixedValueParameter<DataBounds>(DataBoundsParameterName));
101
102      Parameters.Add(new ValueParameter<IEnabledExpressionsConfiguration>(
103        InstructionsParameterName,
104        InstructionsParameterDescription,
105        config));
106
107      Parameters.Add(new ValueParameter<ProblemData>(
108        DataParameterName,
109        DataParameterDescription));
110
111      Parameters.Add(new ValueParameter<ErcOptions>(ErcOptionsParameterName, config.ErcOptions));
112
113      Parameters.Add(new FixedValueParameter<IntValue>(
114        EvalPushLimitParameterName,
115        EvalPushLimitParameterDescription,
116        new IntValue(config.EvalPushLimit)));
117
118      Parameters.Add(new FixedValueParameter<IntValue>(
119        MaxPointsInProgramParameterName,
120        MaxProgramLengthParameterDescription,
121        new IntValue(config.MaxPointsInProgram)));
122      Encoding.LengthParameter = Parameters[MaxPointsInProgramParameterName] as IFixedValueParameter<IntValue>;
123
124      Parameters.Add(new FixedValueParameter<BoolValue>(
125        TopLevelPushCodeParameterName,
126        TopLevelPushCodeParameterDescription,
127        new BoolValue(config.TopLevelPushCode)) { Hidden = true });
128
129      Parameters.Add(new FixedValueParameter<BoolValue>(
130        TopLevelPopCodeParameterName,
131        TopLevelPopCodeParameterDescription,
132        new BoolValue(config.TopLevelPopCode)) { Hidden = true });
133
134      Parameters.Add(new FixedValueParameter<IntValue>(
135        MaxPointsInRandomInstructionParameterName,
136        MaxPointsInRandomInstructionParameterDescription,
137        new IntValue(config.MaxPointsInRandomExpression)) { Hidden = true });
138
139      Parameters.Add(new FixedValueParameter<IntValue>(
140        MaxStringLengthParameterName,
141        new IntValue(config.MaxStringLength)) { Hidden = true });
142
143      Parameters.Add(new FixedValueParameter<IntValue>(
144        MaxDepthParameterName,
145        new IntValue(config.MaxDepth)) { Hidden = true });
146
147      Parameters.Add(new LookupParameter<BoolArray>("Cases", "The training cases that have been successfully executed."));
148      Parameters.Add(new LookupParameter<DoubleArray>(CaseQualitiesScopeParameterName, "The quality of every single training case for each individual"));
149
150      Encoding.Bounds[0, 0] = 0;
151      Encoding.Bounds[0, 1] = config.EnabledExpressions.Count;
152      Encoding.Length = config.MaxPointsInProgram;
153    }
154
155    public IValueParameter<DataBounds> DataBoundsParameter
156    {
157      get { return (IValueParameter<DataBounds>)Parameters[DataBoundsParameterName]; }
158    }
159
160    public DataBounds DataBounds
161    {
162      get { return DataBoundsParameter.Value; }
163      set { DataBoundsParameter.Value = value; }
164    }
165
166
167    public IValueParameter<IEnabledExpressionsConfiguration> InstructionsParameter
168    {
169      get { return (IValueParameter<IEnabledExpressionsConfiguration>)Parameters[InstructionsParameterName]; }
170    }
171
172    public IEnabledExpressionsConfiguration Instructions
173    {
174      get { return InstructionsParameter.Value; }
175      set { InstructionsParameter.Value = value; }
176    }
177
178    public IValueParameter<ProblemData> DataParameter
179    {
180      get { return (IValueParameter<ProblemData>)Parameters[DataParameterName]; }
181    }
182
183    public ProblemData Data
184    {
185      get { return DataParameter.Value; }
186      set { DataParameter.Value = value; }
187    }
188
189    public IValueParameter<ErcOptions> ErcOptionsParameter
190    {
191      get { return (IValueParameter<ErcOptions>)Parameters[ErcOptionsParameterName]; }
192    }
193
194    public ErcOptions ErcOptions
195    {
196      get { return config.ErcOptions; }
197      set
198      {
199        ErcOptionsParameter.Value = value;
200        config.ErcOptions = value;
201      }
202    }
203
204    /// <summary>
205    ///     This is the maximum allowed number of "executions" in a single top-level call to the interpreter.
206    ///     The execution of a single Push instruction counts as one execution, as does the processing of a single literal,
207    ///     as does the descent into one layer of parentheses (that is, the processing of the "(" counts as one execution).
208    ///     When this limit is exceeded the interpreter aborts immediately, leaving its stacks in the states they were in prior
209    ///     to the abort (so they may still be examined by a calling program). Whether or not this counts as an "abnormal"
210    ///     termination
211    ///     is up to the calling program.
212    /// </summary>
213    public IValueParameter<IntValue> EvalPushLimitParameter
214    {
215      get { return (IValueParameter<IntValue>)Parameters[EvalPushLimitParameterName]; }
216    }
217
218    public int EvalPushLimit
219    {
220      get { return config.EvalPushLimit; }
221      set
222      {
223        EvalPushLimitParameter.Value.Value = value;
224        config.EvalPushLimit = value;
225      }
226    }
227
228    /// <summary>
229    /// This is the maximum of depth a push program can have. Expressions, which lead to exceed this limit are interpreted as NOOP.
230    /// </summary>
231    public IValueParameter<IntValue> MaxDepthParameter
232    {
233      get { return (IValueParameter<IntValue>)Parameters[MaxDepthParameterName]; }
234    }
235
236    public int MaxDepth
237    {
238      get { return config.MaxDepth; }
239      set
240      {
241        MaxDepthParameter.Value.Value = value;
242        config.MaxDepth = value;
243      }
244    }
245
246    /// <summary>
247    ///     This is the maximum size of an item on the CODE stack, expressed as a number of points.
248    ///     A point is an instruction, a literal, or a pair of parentheses. Any instruction that would cause this limit to be
249    ///     exceeded
250    ///     should instead act as a NOOP, leaving all stacks in the states that they were in before the execution of the
251    ///     instruction.
252    /// </summary>
253    public IValueParameter<IntValue> MaxPointsInProgramParameter
254    {
255      get { return (IValueParameter<IntValue>)this.Parameters[MaxPointsInProgramParameterName]; }
256    }
257
258    public int MaxPointsInProgram
259    {
260      get { return config.MaxPointsInProgram; }
261      set
262      {
263        MaxPointsInProgramParameter.Value.Value = value;
264        config.MaxPointsInProgram = value;
265      }
266    }
267
268    /// <summary>
269    ///     The maximum number of points in an expression produced by the CODE.RAND instruction.
270    /// </summary>
271    public IValueParameter<IntValue> MaxPointsInRandomExpressionParameter
272    {
273      get { return (IValueParameter<IntValue>)Parameters[MaxPointsInRandomInstructionParameterName]; }
274    }
275
276    public int MaxPointsInRandomExpression
277    {
278      get { return config.MaxPointsInRandomExpression; }
279      set
280      {
281        MaxPointsInRandomExpressionParameter.Value.Value = value;
282        config.MaxPointsInRandomExpression = value;
283      }
284    }
285
286    /// <summary>
287    ///     When TRUE (which is the default), code passed to the top level of the interpreter
288    ///     will be pushed onto the CODE stack prior to execution.
289    /// </summary>
290    public IValueParameter<BoolValue> TopLevelPushCodeParameter
291    {
292      get { return (IValueParameter<BoolValue>)this.Parameters[TopLevelPushCodeParameterName]; }
293    }
294
295    public bool TopLevelPushCode
296    {
297      get { return config.TopLevelPushCode; }
298      set
299      {
300        TopLevelPushCodeParameter.Value.Value = value;
301        config.TopLevelPushCode = value;
302      }
303    }
304
305    /// <summary>
306    ///     When TRUE, the CODE stack will be popped at the end of top level calls to the interpreter. The default is FALSE.
307    /// </summary>
308    public IValueParameter<BoolValue> TopLevelPopCodeParameter
309    {
310      get { return (IValueParameter<BoolValue>)this.Parameters[TopLevelPopCodeParameterName]; }
311    }
312
313    public bool TopLevelPopCode
314    {
315      get { return config.TopLevelPopCode; }
316      set
317      {
318        TopLevelPopCodeParameter.Value.Value = value;
319        config.TopLevelPopCode = value;
320      }
321    }
322
323    public IValueParameter<IntValue> MaxStringLengthParameter
324    {
325      get { return (IValueParameter<IntValue>)Parameters[MaxStringLengthParameterName]; }
326    }
327
328    public int MaxStringLength
329    {
330      get { return config.MaxStringLength; }
331      set
332      {
333        MaxStringLengthParameter.Value.Value = value;
334        config.MaxStringLength = value;
335      }
336    }
337    #endregion
338
339    public override bool Maximization { get { return false; } }
340
341    public override IDeepCloneable Clone(Cloner cloner) {
342      return new PushProblem(this, cloner);
343    }
344
345    public override void Analyze(Individual[] individuals, double[] qualities, ResultCollection results, IRandom random) {
346      var bestQuality = Maximization ? qualities.Max() : qualities.Min();
347      var bestIdx = Array.IndexOf(qualities, bestQuality);
348      var bestIndividual = individuals[bestIdx].IntegerVector();
349
350      var isIndividualBetter = AnalyzeBestTrainingSolution(bestIndividual, bestQuality, results, random);
351
352      if (isIndividualBetter) {
353        AnalyzeBestTestSolution(bestIndividual, results, random);
354      }
355    }
356
357    private void AnalyzeBestTestSolution(IntegerVector bestIndividual, ResultCollection results, IRandom random) {
358      var program = bestIndividual.ToPushProgram(config, randomPool);
359      var trainingResult = PushEvaluator.Evaluate(program, pool, random, Data, DataBounds.TestRange.Start, DataBounds.TestRange.End);
360
361      if (!results.ContainsKey(TestQualityResultName)) {
362        results.Add(new Result(TestQualityResultName, new DoubleValue(trainingResult.TotalQuality)));
363      } else {
364        ((DoubleValue)results[TestQualityResultName].Value).Value = trainingResult.TotalQuality;
365      }
366    }
367
368    private bool AnalyzeBestTrainingSolution(IntegerVector bestIndividual, double bestQuality, ResultCollection results, IRandom random) {
369      var solution = new PushSolution(bestIndividual, bestQuality, Data, random, config, DataBounds.TrainingRange.Start, DataBounds.TrainingRange.End);
370
371      if (!results.ContainsKey(BestTrainingSolutionResultName)) {
372        results.Add(new Result(BestTrainingSolutionResultName, solution));
373        return true;
374      }
375
376      var currentBestQuality = ((PushSolution)results[BestTrainingSolutionResultName].Value).Quality;
377
378      if (Maximization && currentBestQuality < bestQuality ||
379         !Maximization && currentBestQuality > bestQuality) {
380        results[BestTrainingSolutionResultName].Value = solution;
381        return true;
382      }
383
384      return false;
385    }
386
387    public override double Evaluate(Individual individual, IRandom random) {
388      var program = individual.ToPushProgram(config, randomPool);
389      var result = PushEvaluator.Evaluate(
390        program,
391        pool,
392        random,
393        Data,
394        DataBounds.TrainingRange.Start,
395        DataBounds.TrainingRange.End);
396
397      individual.SetScopeValue(CaseQualitiesScopeParameterName, new DoubleArray(result.ExampleQualities));
398
399      return result.TotalQuality;
400    }
401
402    public void Load(ProblemData data) {
403      Data = data;
404      BestKnownQuality = data.BestResult;
405      MaxPointsInProgram = data.MaxSize;
406      EvalPushLimit = data.EvalLimit;
407      ErcOptions = data.ErcOptions;
408
409      config.EnabledExpressions = (IList<string>)ExpressionTable.GetExpressionsByStackTypes((StackTypes)data.EnabledDataTypes);
410
411      // update enabled stack types
412      foreach (var stackType in ExpressionTable.StackTypeToNamesTable.Keys) {
413        var enable = config.EnabledExpressions.Intersect(ExpressionTable.StackTypeToNamesTable[stackType]).Any();
414        config.SetStack(stackType, enable);
415      }
416
417      Encoding.Bounds[0, 0] = 0;
418      Encoding.Bounds[0, 1] = config.EnabledExpressions.Count;
419      Encoding.Length = config.MaxPointsInProgram;
420
421      DataBounds.TrainingRange.Start = 0;
422      DataBounds.TrainingRange.End = Data.TrainingCount;
423      DataBounds.TestRange.Start = Data.TrainingCount;
424      DataBounds.TestRange.End = Data.TrainingCount + Data.TestCount;
425    }
426  }
427}
Note: See TracBrowser for help on using the repository browser.