Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2679_HeuristicLab.GoalSeekingProblem/HeuristicLab.GoalSeekingProblem/3.4/SingleObjectiveGoalSeekingProblem.cs @ 17607

Last change on this file since 17607 was 16901, checked in by bburlacu, 6 years ago

#2679: Update branch: framework version 4.6.1, use heal.attic for persistence, some minor refactoring.

File size: 10.7 KB
RevLine 
[14321]1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
[16901]22using HEAL.Attic;
[14321]23using HeuristicLab.Collections;
24using HeuristicLab.Common;
25using HeuristicLab.Core;
[14526]26using HeuristicLab.Data;
[14321]27using HeuristicLab.Encodings.RealVectorEncoding;
28using HeuristicLab.Optimization;
29using HeuristicLab.Parameters;
30using HeuristicLab.Problems.DataAnalysis;
[16901]31using System;
32using System.Collections.Generic;
33using System.Linq;
[14321]34
[14324]35namespace HeuristicLab.GoalSeeking {
36  [Item("Goal seeking problem (single-objective)", "Represents a single objective optimization problem which uses configurable regression solutions to evaluate targets from a given dataset.")]
[14321]37  [Creatable("Problems")]
[16901]38  [StorableType("DD67A460-1A32-414A-AB18-E0C773B46689")]
[14321]39  public sealed class SingleObjectiveGoalSeekingProblem : SingleObjectiveBasicProblem<RealVectorEncoding>, IGoalSeekingProblem {
[14324]40    #region parameter names
[14333]41    private const string InputsParameterName = "Inputs";
42    private const string GoalsParameterName = "Goals";
43    private const string ModelsParameterName = "Models";
[14324]44    #endregion
[14321]45
46    #region parameters
[14333]47    public IValueParameter<CheckedItemList<InputParameter>> InputsParameter {
48      get { return (IValueParameter<CheckedItemList<InputParameter>>)Parameters[InputsParameterName]; }
[14321]49    }
[14333]50    public IValueParameter<CheckedItemList<GoalParameter>> GoalsParameter {
51      get { return (IValueParameter<CheckedItemList<GoalParameter>>)Parameters[GoalsParameterName]; }
[14321]52    }
[14379]53    public IFixedValueParameter<ItemList<IRegressionModel>> ModelsParameter {
54      get { return (IFixedValueParameter<ItemList<IRegressionModel>>)Parameters[ModelsParameterName]; }
[14321]55    }
56    #endregion
57
[14333]58    #region IGoalSeekingProblem implementation
59    public IEnumerable<IRegressionModel> Models {
60      get { return ModelsParameter.Value; }
[14321]61    }
62
[14333]63    public IEnumerable<GoalParameter> Goals {
64      get { return GoalsParameter.Value; }
[14321]65    }
66
[14333]67    public IEnumerable<InputParameter> Inputs {
68      get { return InputsParameter.Value; }
[14321]69    }
70
[14333]71    public void AddModel(IRegressionModel model) {
72      var models = ModelsParameter.Value;
73      models.Add(model);
74      GoalSeekingUtil.RaiseEvent(this, ModelsChanged);
[14321]75    }
76
[14333]77    public void RemoveModel(IRegressionModel model) {
78      var models = ModelsParameter.Value;
79      models.Remove(model);
80      GoalSeekingUtil.RaiseEvent(this, ModelsChanged);
[14321]81    }
82
[14333]83    public void Configure(IRegressionProblemData problemData, int row) {
84      GoalSeekingUtil.Configure(Goals, Inputs, problemData, row);
[14321]85    }
86
[14324]87    public IEnumerable<double> GetEstimatedGoalValues(IEnumerable<double> parameterValues, bool round = false) {
[14321]88      var ds = (ModifiableDataset)dataset.Clone();
[14333]89      foreach (var parameter in ActiveInputs.Zip(parameterValues, (p, v) => new { Name = p.Name, Value = v })) {
[14324]90        ds.SetVariableValue(parameter.Value, parameter.Name, 0);
91      }
[14321]92      var rows = new[] { 0 }; // actually just one row
[16901]93      return round ? ActiveGoals.Select(t => RoundToNearestStepMultiple(GetModels(t.Name).Average(m => m.GetEstimatedValues(ds, rows).Single()), t.Step))
94                   : ActiveGoals.Select(t => GetModels(t.Name).Average(m => m.GetEstimatedValues(ds, rows).Single()));
[14321]95    }
96
97    public event EventHandler ModelsChanged;
[14333]98    public event EventHandler TargetsChanged;
99    public event EventHandler ParametersChanged;
[14321]100    #endregion
101
[14333]102    private IEnumerable<GoalParameter> ActiveGoals {
103      get { return Goals.Where(x => x.Active); }
[14321]104    }
[14333]105    private IEnumerable<InputParameter> ActiveInputs {
106      get { return Inputs.Where(x => x.Active); }
[14321]107    }
108
109    [Storable]
110    private ModifiableDataset dataset; // modifiable dataset
111
112    public override bool Maximization {
[14324]113      get { return false; }
[14321]114    }
115
116    #region constructors
117    [StorableConstructor]
[16901]118    private SingleObjectiveGoalSeekingProblem(StorableConstructorFlag _) : base(_) { }
[14321]119
[14324]120    private SingleObjectiveGoalSeekingProblem(SingleObjectiveGoalSeekingProblem original, Cloner cloner) : base(original, cloner) {
[14321]121      this.dataset = cloner.Clone(original.dataset);
122      RegisterEvents();
123    }
124
125    public override IDeepCloneable Clone(Cloner cloner) {
126      return new SingleObjectiveGoalSeekingProblem(this, cloner);
127    }
128
129    [StorableHook(HookType.AfterDeserialization)]
130    private void AfterDeserialization() {
131      RegisterEvents();
132    }
133
134    public SingleObjectiveGoalSeekingProblem() {
[14333]135      dataset = new ModifiableDataset();
136      Parameters.Add(new ValueParameter<CheckedItemList<InputParameter>>(InputsParameterName));
137      Parameters.Add(new ValueParameter<CheckedItemList<GoalParameter>>(GoalsParameterName));
[14379]138      Parameters.Add(new FixedValueParameter<ItemList<IRegressionModel>>(ModelsParameterName, new ItemList<IRegressionModel>()));
[14333]139      EncodingParameter.Hidden = true;
140      EvaluatorParameter.Hidden = true;
141      SolutionCreatorParameter.Hidden = true;
[14321]142      RegisterEvents();
143    }
144    #endregion
145
146    public override double Evaluate(Individual individual, IRandom random) {
147      var vector = individual.RealVector();
[14333]148      vector.ElementNames = ActiveInputs.Select(x => x.Name);
[14321]149      int i = 0;
150      // round vector according to parameter step sizes
[14333]151      foreach (var parameter in ActiveInputs) {
152        vector[i] = RoundToNearestStepMultiple(vector[i], parameter.Step);
[14321]153        ++i;
154      }
155      var estimatedValues = GetEstimatedGoalValues(vector, round: true);
[16901]156      return ActiveGoals.Zip(estimatedValues, (t, v) => new { Target = t, EstimatedValue = v })
157                        .Average(x => x.Target.Weight * Math.Pow(x.EstimatedValue - x.Target.Goal, 2) / x.Target.Variance);
[14321]158    }
[14526]159
160    public override void Analyze(Individual[] individuals, double[] qualities, ResultCollection results, IRandom random) {
161      var zipped = individuals.Zip(qualities, (ind, qual) => new { Individual = ind, Quality = qual }).OrderBy(x => x.Quality);
162      var best = Maximization ? zipped.Last() : zipped.First();
163      var realVector = best.Individual.RealVector();
164      const string resultName = "Best Solution";
165
166      var columnNames = new List<string>();
167      foreach (var goal in ActiveGoals) {
168        columnNames.Add(goal.Name);
169        columnNames.Add(goal.Name + " (estimated)");
170      }
171      foreach (var input in ActiveInputs) {
172        columnNames.Add(input.Name);
173        columnNames.Add(input.Name + " (estimated)");
174        columnNames.Add(input.Name + " (deviation)");
175      }
176
177      var m = new DoubleMatrix(1, columnNames.Count) { ColumnNames = columnNames };
178      int i = 0;
179
180      var goals = ActiveGoals.Zip(GetEstimatedGoalValues(realVector, round: true),
181        (goal, value) => new { TargetValue = goal.Goal, EstimatedValue = value });
182
183      foreach (var goal in goals) {
184        m[0, i] = goal.TargetValue;
185        m[0, i + 1] = goal.EstimatedValue;
186        i += 2;
187      }
188
189      var inputs = ActiveInputs.Zip(realVector,
190        (input, value) => new { ActualValue = input.Value, EstimatedValue = value });
191
192      foreach (var input in inputs) {
193        m[0, i] = input.ActualValue;
194        m[0, i + 1] = input.EstimatedValue;
195        m[0, i + 2] = m[0, i] - m[0, i + 1];
196        i += 3;
197      }
198
199      if (!results.ContainsKey(resultName)) {
200        results.Add(new Result(resultName, m));
201      } else {
202        results[resultName].Value = m;
203      }
204
205      base.Analyze(individuals, qualities, results, random);
206    }
207
[14333]208    #region event handlers
[14321]209    private void RegisterEvents() {
[14333]210      ModelsParameter.Value.ItemsAdded += ModelCollection_ItemsChanged;
211      ModelsParameter.Value.ItemsRemoved += ModelCollection_ItemsChanged;
212      GoalsParameter.Value.CheckedItemsChanged += GoalSeekingUtil.Goals_CheckedItemsChanged;
213      InputsParameter.Value.CheckedItemsChanged += GoalSeekingUtil.Inputs_CheckedItemsChanged;
[14338]214
215      foreach (var input in Inputs)
216        input.Changed += InputParameterChanged;
217
218      foreach (var goal in Goals)
219        goal.Changed += GoalParameterChanged;
[14321]220    }
221
[14379]222    private void ModelCollection_ItemsChanged(object sender, CollectionItemsChangedEventArgs<IndexedItem<IRegressionModel>> e) {
[14333]223      if (e.Items == null || !e.Items.Any()) return;
224      GoalSeekingUtil.UpdateInputs(InputsParameter.Value, Models, InputParameterChanged);
[14379]225      GoalSeekingUtil.UpdateEncoding(Encoding, ActiveInputs);
[14338]226      dataset = Inputs.Any() ? new ModifiableDataset(Inputs.Select(x => x.Name), Inputs.Select(x => new List<double> { x.Value })) : new ModifiableDataset();
[14333]227      GoalSeekingUtil.UpdateTargets(GoalsParameter.Value, Models, GoalParameterChanged);
228      GoalSeekingUtil.RaiseEvent(this, ModelsChanged);
[14321]229    }
230
[14333]231    private void InputParameterChanged(object sender, EventArgs args) {
232      var inputParameter = (InputParameter)sender;
233      var inputs = InputsParameter.Value;
234      if (inputs.ItemChecked(inputParameter) != inputParameter.Active)
235        inputs.SetItemCheckedState(inputParameter, inputParameter.Active);
[14379]236      GoalSeekingUtil.UpdateEncoding(Encoding, ActiveInputs);
[14321]237    }
238
[14333]239    private void GoalParameterChanged(object sender, EventArgs args) {
240      var goalParameter = (GoalParameter)sender;
241      var goals = GoalsParameter.Value;
242      if (goals.ItemChecked(goalParameter) != goalParameter.Active)
243        goals.SetItemCheckedState(goalParameter, goalParameter.Active);
[14321]244    }
245    #endregion
246
247    #region helper methods
[14333]248    // method which throws an exception that can be caught in the event handler if the check fails
249    private void CheckIfDatasetContainsTarget(string target) {
250      if (dataset.DoubleVariables.All(x => x != target))
251        throw new ArgumentException(string.Format("Model target \"{0}\" does not exist in the dataset.", target));
[14321]252    }
253
[14333]254    private IEnumerable<IRegressionModel> GetModels(string target) {
255      return Models.Where(x => x.TargetVariable == target);
[14321]256    }
257
258    private static double RoundToNearestStepMultiple(double value, double step) {
259      return step * (long)Math.Round(value / step);
260    }
261    #endregion
262  }
263}
Note: See TracBrowser for help on using the repository browser.