using System; using System.Linq; using HEAL.Attic; using HeuristicLab.Collections; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.IntegerVectorEncoding; using HeuristicLab.Optimization; using HeuristicLab.Parameters; namespace HeuristicLab.Problems.Modifiers { [StorableType("903EE850-62D5-4F3E-8F0D-8D9D5415A5F1")] [Creatable(CreatableAttribute.Categories.Problems, Priority = 90)] [Item("MultiObjectiveModifiedProblem", "A wrapper problem for multi-objective problems that should be evaluated using Hive.")] public class MultiObjectiveModifiedProblem : MultiObjectiveBasicProblem, IStatefulItem { private readonly MultiObjectiveEndPointProblemModifier endPoint = new MultiObjectiveEndPointProblemModifier(); private ProblemModifier activeStart; //this is to avoid attaching to multiple modifiers public override bool[] Maximization => Parameters.ContainsKey("Maximization") ? MaximizationParameter.Value.CloneAsArray() : new[] { false, false }; #region Parameter Names private const string ProblemParameterName = "Problem"; private const string ModifierParameterName = "Modifiers"; #endregion #region Parameters public IValueParameter> ProblemParameter => (IValueParameter>)Parameters[ProblemParameterName]; public IFixedValueParameter> ModifierParameter => (IFixedValueParameter>)Parameters[ModifierParameterName]; public IValueParameter MaximizationParameter => ((IValueParameter)Parameters["Maximization"]); #endregion #region Parameter Properties public MultiObjectiveBasicProblem Problem { get => ProblemParameter.Value; set => ProblemParameter.Value = value; } public CheckedItemList Modifiers => ModifierParameter.Value; #endregion #region Constructors & Cloning [StorableConstructor] protected MultiObjectiveModifiedProblem(StorableConstructorFlag _) : base(_) { } protected MultiObjectiveModifiedProblem(MultiObjectiveModifiedProblem original, Cloner cloner) : base(original, cloner) { Initialize(); } public MultiObjectiveModifiedProblem() { var defaultModifiers = new CheckedItemList { { new EvaluationCacheProblemModifier(), false }, { new EvaluationRepetitionProblemModifier(), false }, { new EvaluationLoggingProblemModifier(), false } }; Parameters.Add(new ValueParameter>(ProblemParameterName, "The actual problem that should be used to evaluate individuals.")); Parameters.Add(new FixedValueParameter>(ModifierParameterName, "The modifiers applied to the problem (order can be important)", defaultModifiers)); EncodingParameter.Hidden = true; MaximizationParameter.Hidden = true; SolutionCreatorParameter.Hidden = true; EvaluatorParameter.Hidden = true; Initialize(); } public override IDeepCloneable Clone(Cloner cloner) { return new MultiObjectiveModifiedProblem(this, cloner); } #endregion [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (Encoding == null) Encoding = new IntegerVectorEncoding("null-encoding"); Initialize(); } private void Initialize() { if (Problem != null) { Problem.OperatorsChanged -= Problem_OperatorsChanged; Problem.OperatorsChanged += Problem_OperatorsChanged; } ProblemParameter.ValueChanged -= ProblemParameter_ValueChanged; ProblemParameter.ValueChanged += ProblemParameter_ValueChanged; Modifiers.CheckedItemsChanged -= ActiveModifiersChanged; Modifiers.CheckedItemsChanged += ActiveModifiersChanged; Modifiers.ItemsMoved -= ActiveModifiersChanged; //This my fire unnecessarily but CheckedItemsChanged does not account for order ... Modifiers.ItemsMoved += ActiveModifiersChanged; Modifiers.ItemsAdded -= ActiveModifiersChanged; Modifiers.ItemsAdded += ActiveModifiersChanged; Modifiers.ItemsRemoved -= ActiveModifiersChanged; Modifiers.ItemsRemoved += ActiveModifiersChanged; Modifiers.ItemsReplaced -= ActiveModifiersChanged; Modifiers.ItemsReplaced += ActiveModifiersChanged; UpdateModifiers(); } public override double[] Evaluate(Individual individual, IRandom random) { return activeStart.ModifiedEvaluate(individual, random); } public override void Analyze(Individual[] individuals, double[][] qualities, ResultCollection results, IRandom random) { activeStart.ModifiedAnalyze(individuals, qualities, results, random); } private bool updating; private void UpdateModifiers() { if (Problem == null || updating) return; updating = true; var am = Modifiers.CheckedItems.Select(x => x.Value).ToArray(); //unwire modifiers to prevent cycles while setting and superfluous listeners foreach (var problemModifier in Modifiers) problemModifier.NextModifier = null; //wire modifiers for (var i = 0; i < am.Length - 1; i++) am[i].NextModifier = am[i + 1]; if (am.Length != 0) am[am.Length - 1].NextModifier = endPoint; endPoint.Problem = Problem; //listen to activeStart changes if (activeStart != null) { activeStart.EncodingChanged -= StartEncodingChanged; activeStart.MaximizationChanged -= StartMaximizationChanged; activeStart.SolutionCreatorChanged -= StartSolutionCreatorChanged; } activeStart = am.Length == 0 ? endPoint : am[0]; activeStart.EncodingChanged += StartEncodingChanged; activeStart.MaximizationChanged += StartMaximizationChanged; activeStart.SolutionCreatorChanged += StartSolutionCreatorChanged; foreach (var m in Modifiers) m.Initialize(); updating = false; if (Encoding == activeStart.Encoding || activeStart.Encoding == null) return; Encoding = activeStart.Encoding; } private void StartMaximizationChanged(object sender, EventArgs e) { if (activeStart.Maximization == null) return; MaximizationParameter.Value = (BoolArray)activeStart.Maximization.AsReadOnly(); } private void StartEncodingChanged(object sender, EventArgs e) { if (Encoding == activeStart.Encoding || activeStart.Encoding == null) return; Encoding = activeStart.Encoding; } private void StartSolutionCreatorChanged(object sender, EventArgs e) { if (SolutionCreator == activeStart.SolutionCreator || activeStart.SolutionCreator == null) return; SolutionCreator = activeStart.SolutionCreator; } private void ActiveModifiersChanged(object sender, CollectionItemsChangedEventArgs> e) { UpdateModifiers(); } private void ProblemParameter_ValueChanged(object sender, EventArgs e) { if (Problem != null) { Problem.OperatorsChanged -= Problem_OperatorsChanged; Problem.OperatorsChanged += Problem_OperatorsChanged; } endPoint.Problem = Problem; UpdateModifiers(); } private void Problem_OperatorsChanged(object sender, EventArgs e) { UpdateModifiers(); } void IStatefulItem.InitializeState() { UpdateModifiers(); } void IStatefulItem.ClearState() { UpdateModifiers(); } } }