using System; using System.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Random; namespace HeuristicLab.Problems.ProgramSynthesis { [StorableClass] public abstract class PushProblemBase : SingleObjectiveBasicProblem where T : class, IEncoding { [Storable] public readonly PushConfiguration Config; protected PushInterpreterPool Pool; protected readonly SeededRandomPool RandomPool = new SeededRandomPool(); [Storable] protected readonly IPushEvaluator PushEvaluator; private const string BEST_TRAINING_SOLUTION_RESULT_NAME = "Best Solution"; private const string TEST_QUALITY_RESULT_NAME = "Test Quality"; private const string PUSH_CONFIGURATION_PARAMETER_NAME = "PushConfiguration"; public const string CasesScopeParameterName = "CaseQualities"; public const string CaseQualitiesScopeParameterName = "CaseQualities"; public const string SeedScopeParameterName = "Seed"; protected PushProblemBase(IPushEvaluator evaluator) { Config = new PushConfiguration(); PushEvaluator = evaluator; InitData(); InitParameters(); } [StorableConstructor] protected PushProblemBase(bool deserializing) : base(deserializing) { } protected PushProblemBase(PushProblemBase original, Cloner cloner) : base(original, cloner) { Config = cloner.Clone(original.Config); PushEvaluator = cloner.Clone(original.PushEvaluator); InitData(); } [StorableHook(HookType.AfterDeserialization)] // ReSharper disable once UnusedMember.Local private void AfterDeserialization() { InitData(); InitParameters(); } private void InitData() { Pool = new PushInterpreterPool(Environment.ProcessorCount * 2, 4096, 1024, Config); } private void InitParameters() { foreach (var paramater in Config.Parameters) { if (!Parameters.ContainsKey(paramater.Name)) { Parameters.Add(paramater); } } if (!Parameters.ContainsKey(PUSH_CONFIGURATION_PARAMETER_NAME)) Parameters.Add(new ValueParameter(PUSH_CONFIGURATION_PARAMETER_NAME, Config) { Hidden = true }); if (!Parameters.ContainsKey(CasesScopeParameterName)) Parameters.Add(new LookupParameter(CasesScopeParameterName, "The training cases that have been successfully executed.")); if (!Parameters.ContainsKey(CaseQualitiesScopeParameterName)) Parameters.Add(new LookupParameter(CaseQualitiesScopeParameterName, "The quality of every single training case for each individual")); } public override bool Maximization { get { return false; } } public override void Analyze(Individual[] individuals, double[] qualities, ResultCollection results, IRandom random) { var bestQuality = Maximization ? qualities.Max() : qualities.Min(); var bestIdx = Array.IndexOf(qualities, bestQuality); var bestIndividual = individuals[bestIdx]; var seed = (IntValue)bestIndividual[SeedScopeParameterName]; var program = MapIndividual(bestIndividual); var rand = new FastRandom(seed.Value); var isIndividualBetter = AnalyzeBestTrainingSolution(program, bestQuality, results, rand); if (isIndividualBetter) { rand.Reset(seed.Value); AnalyzeBestTestSolution(program, results, rand); } } protected void AnalyzeBestTestSolution(PushProgram program, ResultCollection results, IRandom random) { var testResult = PushEvaluator.EvaluateTest(Pool, program, random); if (!results.ContainsKey(TEST_QUALITY_RESULT_NAME)) { results.Add(new Result(TEST_QUALITY_RESULT_NAME, new DoubleValue(testResult.AvgQuality))); } else { ((DoubleValue)results[TEST_QUALITY_RESULT_NAME].Value).Value = testResult.AvgQuality; } } protected bool AnalyzeBestTrainingSolution(PushProgram program, double bestQuality, ResultCollection results, IRandom random) { var solution = CreatePushSolution( program, bestQuality, random, // is already cloned (IReadOnlyPushConfiguration)Config.Clone()); if (!results.ContainsKey(BEST_TRAINING_SOLUTION_RESULT_NAME)) { results.Add(new Result(BEST_TRAINING_SOLUTION_RESULT_NAME, solution)); return true; } var currentBestQuality = ((PushSolution)results[BEST_TRAINING_SOLUTION_RESULT_NAME].Value).Quality; if ((!Maximization && currentBestQuality > bestQuality) || (Maximization && currentBestQuality < bestQuality)) { results[BEST_TRAINING_SOLUTION_RESULT_NAME].Value = solution; return true; } return false; } public override double Evaluate(Individual individual, IRandom random) { var program = MapIndividual(individual); var seed = random.Next(); var rand = new FastRandom(seed); var result = PushEvaluator.EvaluateTraining(Pool, program, rand); individual[CaseQualitiesScopeParameterName] = new DoubleArray(result.ExampleQualities); individual[SeedScopeParameterName] = new IntValue(seed); return result.AvgQuality; } protected abstract PushProgram MapIndividual(Individual individual); protected abstract PushSolution CreatePushSolution( PushProgram program, double bestQuality, IRandom random, IReadOnlyPushConfiguration config); } }