Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.GoalSeekingProblem/HeuristicLab.GoalSeekingProblem/3.4/MultiObjectiveGoalSeekingProblem.cs @ 14325

Last change on this file since 14325 was 14325, checked in by bburlacu, 8 years ago

#2679: Fix accidental code.

File size: 30.9 KB
Line 
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
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using System.Windows.Forms;
26using HeuristicLab.Collections;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29using HeuristicLab.Data;
30using HeuristicLab.Encodings.RealVectorEncoding;
31using HeuristicLab.Optimization;
32using HeuristicLab.Parameters;
33using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
34using HeuristicLab.Problems.DataAnalysis;
35
36namespace HeuristicLab.GoalSeeking {
37  [Item("Goal seeking problem (multi-objective)", "Represents a single objective optimization problem which uses configurable regression models to evaluate targets from a given dataset.")]
38  [Creatable("Problems")]
39  [StorableClass]
40  public sealed class MultiObjectiveGoalSeekingProblem : MultiObjectiveBasicProblem<RealVectorEncoding>, IGoalSeekingProblem {
41    private const string ModifiableDatasetParameterName = "Dataset";
42    private const string ProblemDataParameterName = "ProblemData";
43    private const string ControllableParametersParameterName = "ControllableParameters";
44    private const string ControllableParameterBoundsParameterName = "ControllableParameterBounds";
45    private const string TargetGoalsParameterName = "TargetGoals";
46    private const string TargetsParameterName = "Targets";
47    private const string ModelCollectionParameterName = "ModelCollection";
48    private const string RowParameterName = "Row";
49    // these parameters are used by the pareto folding analyzer
50    private const string QualitySumCutoffParameterName = "QualitySumCutoff";
51
52    #region parameters
53    public IFixedValueParameter<DoubleValue> QualitySumCutoffParameter {
54      get { return (IFixedValueParameter<DoubleValue>)Parameters[QualitySumCutoffParameterName]; }
55    }
56    public IValueParameter<IRegressionProblemData> ProblemDataParameter {
57      get { return (IValueParameter<IRegressionProblemData>)Parameters[ProblemDataParameterName]; }
58    }
59    public IValueParameter<CheckedItemList<StringValue>> ControllableParametersParameter {
60      get { return (IValueParameter<CheckedItemList<StringValue>>)Parameters[ControllableParametersParameterName]; }
61    }
62    public IValueParameter<DoubleMatrix> ControllableParameterBoundsParameter {
63      get { return (IValueParameter<DoubleMatrix>)Parameters[ControllableParameterBoundsParameterName]; }
64    }
65    public IFixedValueParameter<ItemCollection<IRegressionModel>> ModelCollectionParameter {
66      get { return (IFixedValueParameter<ItemCollection<IRegressionModel>>)Parameters[ModelCollectionParameterName]; }
67    }
68    public IValueParameter<CheckedItemList<StringValue>> TargetsParameter {
69      get { return (IValueParameter<CheckedItemList<StringValue>>)Parameters[TargetsParameterName]; }
70    }
71    public IValueParameter<DoubleMatrix> TargetGoalsParameter {
72      get { return (IValueParameter<DoubleMatrix>)Parameters[TargetGoalsParameterName]; }
73    }
74    public IFixedValueParameter<IntValue> RowParameter {
75      get { return (IFixedValueParameter<IntValue>)Parameters[RowParameterName]; }
76    }
77    #endregion
78
79    #region parameter properties
80    private IItemCollection<IRegressionModel> ModelCollection {
81      get { return ModelCollectionParameter.Value; }
82    }
83    public DoubleMatrix TargetGoals {
84      get { return TargetGoalsParameter.Value; }
85      set { TargetGoalsParameter.Value = value; }
86    }
87    public double QualitySumCutoff {
88      get { return QualitySumCutoffParameter.Value.Value; }
89      set { QualitySumCutoffParameter.Value.Value = value; }
90    }
91    #endregion
92
93    #region IProcessParameterOptimizationProblem properties
94    [Storable]
95    private IRegressionProblemData problemData;
96    public IRegressionProblemData ProblemData {
97      get { return problemData; }
98      set {
99        if (value == null || value == problemData) return;
100        var variables = value.Dataset.DoubleVariables.ToList();
101        if (Models.Any()) {
102          var targets = Models.Select(x => x.TargetVariable);
103          var hashset = new HashSet<string>(variables);
104          foreach (var target in targets) {
105            if (!hashset.Contains(target)) {
106              throw new ArgumentException(string.Format("Incompatible problem data. Target \"{0}\" is missing.", target));
107            }
108          }
109        }
110        problemData = value;
111        dataset = new ModifiableDataset(variables, variables.Select(x => new List<double> { ProblemData.Dataset.GetDoubleValue(x, Row) }));
112        ProblemDataParameter.Value = ProblemData;
113        UpdateControllableParameters();
114        UpdateTargetList();
115      }
116    }
117
118    public int Row {
119      get { return RowParameter.Value.Value; }
120      set { RowParameter.Value.Value = value; }
121    }
122
123    public IEnumerable<IRegressionModel> Models {
124      get { return ModelCollectionParameter.Value; }
125    }
126
127    #region targets
128    public ICheckedItemList<StringValue> TargetList {
129      get { return TargetsParameter.Value; }
130      set { TargetsParameter.Value = (CheckedItemList<StringValue>)value; }
131    }
132    // convenience method
133    private IEnumerable<string> ActiveTargets {
134      get { return TargetList.CheckedItems.Select(x => x.Value.Value); }
135    }
136    #endregion
137
138    #region parameters
139    public ICheckedItemList<StringValue> ControllableParameters {
140      get { return ControllableParametersParameter.Value; }
141      set { ControllableParametersParameter.Value = (CheckedItemList<StringValue>)value; }
142    }
143    // convenience method
144    private IEnumerable<string> ActiveParameters {
145      get { return ControllableParameters.CheckedItems.Select(x => x.Value.Value); }
146    }
147    public DoubleMatrix ControllableParameterBounds {
148      get { return ControllableParameterBoundsParameter.Value; }
149      set { ControllableParameterBoundsParameter.Value = value; }
150    }
151    #endregion
152    #endregion
153
154    #region IProcessParameterOptimizationProblem methods
155    #region models
156    public IEnumerable<double> GetEstimatedGoalValues(IEnumerable<double> parameterValues, bool round = false) {
157      var ds = (ModifiableDataset)dataset.Clone();
158      foreach (var parameter in ActiveParameters.Zip(parameterValues, (p, v) => new { Name = p, Value = v })) {
159        ds.SetVariableValue(parameter.Value, parameter.Name, 0);
160      }
161      var rows = new[] { 0 }; // actually just one row
162
163      var estimatedValues =
164        round ? ActiveTargets.Select(t => RoundToNearestStepMultiple(GetModels(t).Average(m => m.GetEstimatedValues(ds, rows).Single()), GetTargetStepSize(t)))
165              : ActiveTargets.Select(t => GetModels(t).Average(m => m.GetEstimatedValues(ds, rows).Single()));
166      return estimatedValues;
167    }
168
169    public void AddModel(IRegressionModel model) {
170      var target = model.TargetVariable;
171      CheckIfDatasetContainsTarget(target);
172      ModelCollection.Add(model);
173      OnModelsChanged(this, EventArgs.Empty);
174    }
175
176    // method which throws an exception that can be caught in the event handler if the check fails
177    private void CheckIfDatasetContainsTarget(string target) {
178      if (dataset.DoubleVariables.All(x => x != target))
179        throw new ArgumentException(string.Format("Model target \"{0}\" does not exist in the dataset.", target));
180    }
181
182    public void RemoveModel(IRegressionModel model) {
183      ModelCollection.Remove(model);
184      OnModelsChanged(this, EventArgs.Empty);
185    }
186
187    public event EventHandler ModelsChanged;
188    private void OnModelsChanged(object sender, EventArgs args) {
189      var changed = ModelsChanged;
190      if (changed == null) return;
191      changed(sender, args);
192    }
193    #endregion
194
195    #region targets
196    public bool GetTargetActive(string target) {
197      var item = TargetList.SingleOrDefault(x => x.Value == target);
198      if (item == null)
199        throw new ArgumentException(string.Format("SetTargetActive: Invalid target name {0}", target));
200      return TargetList.ItemChecked(item);
201    }
202
203    public void SetTargetActive(string target, bool active) {
204      var item = TargetList.SingleOrDefault(x => x.Value == target);
205      if (item == null)
206        throw new ArgumentException(string.Format("SetTargetActive: Invalid target name {0}", target));
207      TargetList.SetItemCheckedState(item, active);
208      OnTargetsChanged(this, EventArgs.Empty);
209    }
210
211    public double GetTargetGoal(string target) {
212      if (!IsValidTarget(target))
213        throw new ArgumentException(string.Format("The target variable name \"{0}\" does not exist in the dataset.", target));
214      int i = TargetGoals.RowNames.TakeWhile(x => x != target).Count();
215      return TargetGoals[i, 0];
216    }
217
218    public void SetTargetGoal(string target, double goal) {
219      if (!IsValidTarget(target))
220        throw new ArgumentException(string.Format("The target variable name \"{0}\" does not exist in the dataset.", target));
221      int i = TargetGoals.RowNames.TakeWhile(x => x != target).Count();
222      TargetGoals[i, 0] = goal;
223      OnTargetsChanged(this, EventArgs.Empty);
224    }
225
226    public double GetTargetWeight(string target) {
227      if (!IsValidTarget(target))
228        throw new ArgumentException(string.Format("The target variable name \"{0}\" does not exist in the dataset.", target));
229      int i = TargetGoals.RowNames.TakeWhile(x => x != target).Count();
230      return TargetGoals[i, 1];
231    }
232
233    public void SetTargetWeight(string target, double weight) {
234      if (!IsValidTarget(target))
235        throw new ArgumentException(string.Format("The target variable name \"{0}\" does not exist in the dataset.", target));
236      int i = TargetGoals.RowNames.TakeWhile(x => x != target).Count();
237      TargetGoals[i, 1] = weight;
238      OnTargetsChanged(this, EventArgs.Empty);
239    }
240
241    public double GetTargetVariance(string target) {
242      if (!IsValidTarget(target))
243        throw new ArgumentException(string.Format("The target variable name \"{0}\" does not exist in the dataset.", target));
244      int i = TargetGoals.RowNames.TakeWhile(x => x != target).Count();
245      return TargetGoals[i, 2];
246    }
247
248    public void SetTargetVariance(string target, double variance) {
249      if (!IsValidTarget(target))
250        throw new ArgumentException(string.Format("The target variable name \"{0}\" does not exist in the dataset.", target));
251      int i = TargetGoals.RowNames.TakeWhile(x => x != target).Count();
252      TargetGoals[i, 2] = variance;
253      OnTargetsChanged(this, EventArgs.Empty);
254    }
255
256    public double GetTargetStepSize(string target) {
257      if (!IsValidTarget(target))
258        throw new ArgumentException(string.Format("The target variable name \"{0}\" does not exist in the dataset.", target));
259      int i = TargetGoals.RowNames.TakeWhile(x => x != target).Count();
260      return TargetGoals[i, 3];
261    }
262
263    public void SetTargetStepSize(string target, double stepSize) {
264      if (!IsValidTarget(target))
265        throw new ArgumentException(string.Format("The target variable name \"{0}\" does not exist in the dataset.", target));
266      int i = TargetGoals.RowNames.TakeWhile(x => x != target).Count();
267      TargetGoals[i, 3] = stepSize;
268      OnTargetsChanged(this, EventArgs.Empty);
269    }
270
271    public event EventHandler TargetsChanged;
272    private void OnTargetsChanged(object sender, EventArgs args) {
273      var changed = TargetsChanged;
274      if (changed == null) return;
275      changed(sender, args);
276    }
277    #endregion // targets
278
279    #region process parameters
280    /// <summary>
281    /// Returns the parameter bounds (min and max) and the step size for the specified parameter
282    /// </summary>
283    /// <param name="parameterName"></param>
284    /// <returns>A double array containing the values (min, max, step) in this order</returns>
285    public double[] GetParameterBounds(string parameterName) {
286      var index = ControllableParameters.TakeWhile(x => x.Value != parameterName).Count();
287      if (index < ControllableParameters.Count) {
288        var min = ControllableParameterBounds[index, 0];
289        var max = ControllableParameterBounds[index, 1];
290        var step = ControllableParameterBounds[index, 2];
291        return new[] { min, max, step };
292      }
293      throw new ArgumentException(string.Format("GetParameterBounds: Unknown parameter {0}.", parameterName));
294    }
295
296    public void SetParameterBounds(string parameterName, double min, double max, double step) {
297      int i = ControllableParameterBounds.RowNames.TakeWhile(x => x != parameterName).Count();
298      if (i < ControllableParameterBounds.Rows) {
299        ControllableParameterBounds[i, 0] = min;
300        ControllableParameterBounds[i, 1] = max;
301        ControllableParameterBounds[i, 2] = step;
302        UpdateEncoding();
303        OnParametersChanged(this, EventArgs.Empty);
304      } else {
305        throw new ArgumentException(string.Format("SetParameterBounds: Invalid parameter name {0}", parameterName));
306      }
307
308    }
309
310    public double GetParameterStepSize(string parameter) {
311      int i = ControllableParameterBounds.RowNames.TakeWhile(x => x != parameter).Count();
312      if (i < ControllableParameterBounds.Rows)
313        return ControllableParameterBounds[i, 2];
314      throw new ArgumentException(string.Format("GetParameterStepSize: Invalid parameter name {0}", parameter));
315    }
316
317    public void SetParameterStepSize(string parameter, double stepSize) {
318      int i = ControllableParameterBounds.RowNames.TakeWhile(x => x != parameter).Count();
319      if (i < ControllableParameterBounds.Rows) {
320        ControllableParameterBounds[i, 2] = stepSize;
321        OnParametersChanged(this, EventArgs.Empty);
322        return;
323      }
324      throw new ArgumentException(string.Format("SetParameterStepSize: Invalid parameter name {0}", parameter));
325    }
326
327    public bool GetParameterActive(string parameter) {
328      var item = ControllableParameters.SingleOrDefault(x => x.Value == parameter);
329      if (item == null)
330        throw new ArgumentException(string.Format("GetParameterActive: Invalid target name {0}", parameter));
331      return ControllableParameters.ItemChecked(item);
332    }
333
334    public void SetParameterActive(string parameter, bool active) {
335      var item = ControllableParameters.SingleOrDefault(x => x.Value == parameter);
336      if (item == null)
337        throw new ArgumentException(string.Format("SetParameterActive: Invalid target name {0}", parameter));
338      ControllableParameters.SetItemCheckedState(item, active);
339      OnParametersChanged(this, EventArgs.Empty);
340    }
341
342    public void SetControllableParameters(IEnumerable<string> parameterNames) {
343      ControllableParameters = new CheckedItemList<StringValue>();
344      foreach (var v in parameterNames) {
345        ControllableParameters.Add(new StringValue(v), false);
346      }
347      ControllableParameters.CheckedItemsChanged += ControllableParameters_OnItemsChanged;
348      ControllableParameterBounds = new DoubleMatrix(ControllableParameters.Count, 3);
349      ControllableParameterBounds.RowNames = GetControllableParameters();
350      ControllableParameterBounds.ColumnNames = new[] { "Min", "Max", "Step" };
351
352      for (int i = 0; i < ControllableParameters.Count; ++i) {
353        var itemName = ControllableParameters[i].Value;
354        var values = ProblemData.Dataset.GetReadOnlyDoubleValues(itemName).Where(x => !double.IsNaN(x) && !double.IsInfinity(x)).ToList();
355        if (!values.Any()) continue;
356
357        // add a 20% margin to allow the optimization algorithm more freedom of exploration
358        ControllableParameterBounds[i, 0] = 0.8 * values.Min(); // min
359        ControllableParameterBounds[i, 1] = 1.2 * values.Max(); // max
360        ControllableParameterBounds[i, 2] = 1e-6;               // step
361      }
362      OnParametersChanged(this, EventArgs.Empty);
363    }
364
365    public IEnumerable<string> GetControllableParameters() {
366      return ControllableParameters.Select(x => x.Value);
367    }
368
369    public event EventHandler ParametersChanged;
370    private void OnParametersChanged(object sender, EventArgs args) {
371      var changed = ParametersChanged;
372      if (changed == null) return;
373      changed(sender, args);
374    }
375    #endregion // process parameters
376    #endregion // IGoalSeekingProblem methods
377
378    #region data members
379    [Storable]
380    private ModifiableDataset dataset; // modifiable dataset
381
382    [Storable]
383    private bool[] maximization;
384    public override bool[] Maximization {
385      get { return maximization ?? new bool[] { false }; }
386    }
387
388    public ValueParameter<BoolArray> MaximizationParameter {
389      get { return (ValueParameter<BoolArray>)Parameters["Maximization"]; }
390    }
391    #endregion
392
393    #region constructors
394    [StorableConstructor]
395    private MultiObjectiveGoalSeekingProblem(bool deserializing) : base(deserializing) { }
396
397    private MultiObjectiveGoalSeekingProblem(MultiObjectiveGoalSeekingProblem original, Cloner cloner) : base(original, cloner) {
398      this.dataset = cloner.Clone(original.dataset);
399      this.problemData = cloner.Clone(original.problemData);
400
401      RegisterEvents();
402    }
403
404    public override IDeepCloneable Clone(Cloner cloner) {
405      return new MultiObjectiveGoalSeekingProblem(this, cloner);
406    }
407
408    [StorableHook(HookType.AfterDeserialization)]
409    private void AfterDeserialization() {
410      if (Parameters.ContainsKey("Accuracy"))
411        Parameters.Remove("Accuracy");
412
413      if (!Parameters.ContainsKey(QualitySumCutoffParameterName)) {
414        Parameters.Add(new FixedValueParameter<DoubleValue>(QualitySumCutoffParameterName, new DoubleValue(0.2)));
415        QualitySumCutoffParameter.Hidden = true;
416      }
417
418      if (ProblemData == null && Parameters.ContainsKey(ProblemDataParameterName)) {
419        ProblemData = ProblemDataParameter.Value;
420      }
421
422      if (!Parameters.ContainsKey(ModifiableDatasetParameterName)) {
423        Parameters.Add(new ValueParameter<IDataset>(ModifiableDatasetParameterName, dataset) { Hidden = true });
424      }
425
426      // backwards-compatibility
427      if (Parameters.ContainsKey("Models")) {
428        var solutions = ((IFixedValueParameter<ItemCollection<IRegressionSolution>>)Parameters["Models"]).Value;
429        var models = new ItemCollection<IRegressionModel>();
430        foreach (var solution in solutions) {
431          var model = solution.Model;
432          model.TargetVariable = solution.ProblemData.TargetVariable;
433          models.Add(model);
434        }
435        if (Parameters.ContainsKey(ModelCollectionParameterName))
436          Parameters.Remove(ModelCollectionParameterName);
437        Parameters.Add(new FixedValueParameter<ItemCollection<IRegressionModel>>(ModelCollectionParameterName, models));
438      }
439
440      RegisterEvents();
441    }
442
443    public MultiObjectiveGoalSeekingProblem() {
444      Parameters.Add(new ValueParameter<IRegressionProblemData>(ProblemDataParameterName, new RegressionProblemData()));
445      Parameters.Add(new ValueParameter<IDataset>(ModifiableDatasetParameterName, dataset) { Hidden = true });
446      Parameters.Add(new ValueParameter<CheckedItemList<StringValue>>(ControllableParametersParameterName));
447      Parameters.Add(new ValueParameter<CheckedItemList<StringValue>>(TargetsParameterName));
448      Parameters.Add(new ValueParameter<DoubleMatrix>(ControllableParameterBoundsParameterName));
449      Parameters.Add(new FixedValueParameter<ItemCollection<IRegressionModel>>(ModelCollectionParameterName, new ItemCollection<IRegressionModel>()));
450      Parameters.Add(new ValueParameter<DoubleMatrix>(TargetGoalsParameterName)); // model target weights
451      Parameters.Add(new FixedValueParameter<IntValue>(RowParameterName));
452      Parameters.Add(new FixedValueParameter<DoubleValue>(QualitySumCutoffParameterName, new DoubleValue(0.2)));
453
454      QualitySumCutoffParameter.Hidden = true;
455
456      // when the problem is created, the problem data parameter will be set to a default value
457      // set the internal property to the same value
458      ProblemData = ProblemDataParameter.Value;
459
460      UpdateControllableParameters();
461      UpdateTargetList();
462      RegisterEvents();
463    }
464    #endregion
465
466    public override double[] Evaluate(Individual individual, IRandom random) {
467      var vector = individual.RealVector();
468      vector.ElementNames = ActiveParameters;
469
470      int i = 0;
471      // round vector according to parameter step sizes
472      foreach (var parameter in ControllableParameters.CheckedItems) {
473        var step = ControllableParameterBounds[parameter.Index, 2];
474        vector[i] = RoundToNearestStepMultiple(vector[i], step);
475        ++i;
476      }
477      var estimatedValues = GetEstimatedGoalValues(vector, round: true);
478      var qualities = TargetList.CheckedItems.Zip(estimatedValues, (t, v) => new { Name = t.Value.Value, Index = t.Index, EstimatedValue = v })
479                                .Select(target => {
480                                  var goal = TargetGoals[target.Index, 0];
481                                  var weight = TargetGoals[target.Index, 1];
482                                  var variance = TargetGoals[target.Index, 2];
483                                  return weight * Math.Pow(target.EstimatedValue - goal, 2) / variance;
484                                });
485      return qualities.ToArray();
486    }
487
488    public override void Analyze(Individual[] individuals, double[][] qualities, ResultCollection results, IRandom random) {
489      var matrix = FilterFrontsByQualitySum(individuals, qualities, Math.Max(QualitySumCutoff, qualities.Min(x => x.Sum())));
490      const string resultName = "Pareto Front Solutions"; // disclaimer: not really a pareto front
491      if (!results.ContainsKey(resultName)) {
492        results.Add(new Result(resultName, matrix));
493      } else {
494        results[resultName].Value = matrix;
495      }
496      base.Analyze(individuals, qualities, results, random);
497    }
498
499    private DoubleMatrix FilterFrontsByQualitySum(Individual[] individuals, double[][] qualities, double qualitySumCutoff) {
500      var activeParameters = ActiveParameters.ToList();
501      var activeTargets = ActiveTargets.ToList();
502      var filteredModels = new List<double[]>();
503      var rowNames = new List<string>();
504      // build list of column names by combining target and parameter names (with their respective original and estimated values)
505      var columnNames = new List<string> { "Quality Sum" };
506      foreach (var target in activeTargets) {
507        columnNames.Add(target);
508        columnNames.Add(target + " (estimated)");
509      }
510      foreach (var controllableParameter in activeParameters) {
511        columnNames.Add(controllableParameter);
512        columnNames.Add(controllableParameter + " (estimated)");
513        columnNames.Add(controllableParameter + " (deviation)");
514      }
515      // filter models based on their quality sum; remove duplicate models
516      var dec = new DoubleEqualityComparer(); // comparer which uses the IsAlmost method for comparing floating point numbers
517      for (int i = 0; i < individuals.Length; ++i) {
518        var qualitySum = qualities[i].Sum();
519        if (qualitySum > qualitySumCutoff)
520          continue;
521        var vector = individuals[i].RealVector();
522        var estimatedValues = GetEstimatedGoalValues(vector).ToList();
523        var rowValues = new double[columnNames.Count];
524        rowValues[0] = qualitySum;
525        int offset = 1;
526        for (int j = 0; j < activeTargets.Count * 2; j += 2) {
527          int k = j + offset;
528          var goal = GetTargetGoal(activeTargets[j / 2]);
529          rowValues[k] = goal; // original value
530          rowValues[k + 1] = estimatedValues[j / 2]; // estimated value
531        }
532        offset += activeTargets.Count * 2;
533        for (int j = 0; j < activeParameters.Count * 3; j += 3) {
534          int k = j + offset;
535          rowValues[k] = problemData.Dataset.GetDoubleValue(columnNames[k], Row);
536          rowValues[k + 1] = vector[j / 3];
537          rowValues[k + 2] = rowValues[k + 1] - rowValues[k];
538        }
539        if (!filteredModels.Any(x => x.SequenceEqual(rowValues, dec))) {
540          rowNames.Add((i + 1).ToString());
541          filteredModels.Add(rowValues);
542        }
543      }
544      var matrix = new DoubleMatrix(filteredModels.Count, columnNames.Count) { RowNames = rowNames, ColumnNames = columnNames, SortableView = true };
545      for (int i = 0; i < filteredModels.Count; ++i) {
546        for (int j = 0; j < filteredModels[i].Length; ++j) {
547          matrix[i, j] = filteredModels[i][j];
548        }
549      }
550      return matrix;
551    }
552
553    #region event handlers
554    private void RegisterEvents() {
555      ProblemDataParameter.ValueChanged += OnProblemDataChanged;
556      ModelCollectionParameter.Value.ItemsAdded += ModelCollection_OnItemsAdded;
557      ModelCollectionParameter.Value.ItemsRemoved += ModelCollection_OnItemsRemoved;
558      RowParameter.Value.ValueChanged += OnRowChanged;
559      ControllableParameters.CheckedItemsChanged += ControllableParameters_OnItemsChanged;
560      ControllableParameterBounds.ItemChanged += ControllableParameterBounds_ItemChanged;
561    }
562
563    private void OnRowChanged(object o, EventArgs e) {
564      // set variables in the modifiable dataset according to the new row
565      foreach (var v in dataset.DoubleVariables)
566        dataset.SetVariableValue(ProblemData.Dataset.GetDoubleValue(v, Row), v, 0);
567      // set the correct targets
568      UpdateTargetList();
569    }
570
571    private void OnProblemDataChanged(object o, EventArgs e) {
572      try {
573        ProblemData = ProblemDataParameter.Value;
574      }
575      catch (ArgumentException exception) {
576        MessageBox.Show(exception.Message, "Update Problem Data", MessageBoxButtons.OK, MessageBoxIcon.Error);
577        ProblemDataParameter.Value = problemData;
578      }
579    }
580
581    private void ModelCollection_OnItemsAdded(object sender, CollectionItemsChangedEventArgs<IRegressionModel> e) {
582      if (e.Items == null) return;
583
584      var collection = (IObservableCollection<IRegressionModel>)sender;
585      var newItems = e.Items.ToList();
586
587      foreach (var model in e.Items) {
588        try {
589          CheckIfDatasetContainsTarget(model.TargetVariable);
590        }
591        catch (ArgumentException exception) {
592          MessageBox.Show(exception.Message, "Add Model", MessageBoxButtons.OK, MessageBoxIcon.Error);
593          newItems.Remove(model);
594          collection.Remove(model);
595        }
596      }
597      UpdateTargetList();
598      OnModelsChanged(this, EventArgs.Empty);
599    }
600
601    private void ModelCollection_OnItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRegressionModel> e) {
602      if (e.Items == null) return;
603      UpdateTargetList();
604      OnModelsChanged(this, EventArgs.Empty);
605    }
606
607    private void ControllableParameters_OnItemsChanged(object o, CollectionItemsChangedEventArgs<IndexedItem<StringValue>> e) {
608      UpdateEncoding();
609    }
610
611    private void ControllableParameterBounds_ItemChanged(object o, EventArgs e) {
612      UpdateEncoding();
613    }
614    #endregion
615
616    #region helper methods
617    private void UpdateControllableParameters() {
618      if (ProblemData == null) return;
619      var variablesUsedForPrediction = ModelCollection.Any()
620        ? ModelCollection.SelectMany(x => x.VariablesUsedForPrediction).Distinct()
621        : ProblemData.Dataset.DoubleVariables;
622      SetControllableParameters(variablesUsedForPrediction);
623    }
624
625    private void UpdateTargetList() {
626      if (ProblemData == null) return;
627      if (!Models.Any()) {
628        TargetGoals = new DoubleMatrix();
629        maximization = new[] { false };
630        MaximizationParameter.Value = (BoolArray)new BoolArray(maximization).AsReadOnly();
631        TargetList = new CheckedItemList<StringValue>();
632        return;
633      }
634
635      var targetNames = Models.Select(x => x.TargetVariable).Distinct().ToList();
636      var oldTargetGoals = (DoubleMatrix)TargetGoals.Clone();
637      var oldRowIndices = oldTargetGoals.RowNames.Select((x, i) => new { x, i }).ToDictionary(x => x.x, x => x.i);
638      TargetGoals = new DoubleMatrix(targetNames.Count, 4);
639      TargetGoals.RowNames = targetNames;
640      TargetGoals.ColumnNames = new[] { "Goal", "Weight", "Variance", "Step size" };
641
642      TargetList = new CheckedItemList<StringValue>();
643      for (int i = 0; i < targetNames.Count; ++i) {
644        TargetList.Add(new StringValue(targetNames[i]), true);
645        int rowIndex;
646        if (oldRowIndices.TryGetValue(targetNames[i], out rowIndex)) {
647          for (int j = 0; j < TargetGoals.Columns; ++j)
648            TargetGoals[i, j] = oldTargetGoals[rowIndex, j];
649        } else {
650          TargetGoals[i, 0] = ProblemData.Dataset.GetDoubleValue(targetNames[i], Row);
651          TargetGoals[i, 1] = 1.0;
652          TargetGoals[i, 2] = ProblemData.Dataset.GetReadOnlyDoubleValues(targetNames[i]).Variance();
653          TargetGoals[i, 3] = 1e-6;
654        }
655      }
656      maximization = new bool[targetNames.Count];
657      MaximizationParameter.Value = (BoolArray)new BoolArray(maximization).AsReadOnly();
658    }
659
660    private void UpdateEncoding() {
661      var activeParameters = ActiveParameters.ToList();
662      if (Encoding == null)
663        Encoding = new RealVectorEncoding(activeParameters.Count);
664      else
665        Encoding.Length = activeParameters.Count;
666
667      Encoding.Bounds = new DoubleMatrix(activeParameters.Count, 2); // only two columns: min and max
668      Encoding.Bounds.RowNames = activeParameters;
669      Encoding.Bounds.ColumnNames = new[] { "Min.", "Max." };
670
671      int i = 0;
672      foreach (var item in ControllableParameters.CheckedItems) {
673        var index = item.Index;
674        Encoding.Bounds[i, 0] = ControllableParameterBounds[index, 0];
675        Encoding.Bounds[i, 1] = ControllableParameterBounds[index, 1];
676        ++i;
677      }
678    }
679
680    private bool IsValidTarget(string target) {
681      return TargetList.Any(x => x.Value == target);
682    }
683    private static double RoundToNearestStepMultiple(double value, double step) {
684      return step * (long)Math.Round(value / step);
685    }
686    private IEnumerable<IRegressionModel> GetModels(string target) {
687      return ModelCollection.Where(x => x.TargetVariable == target);
688    }
689    private class DoubleEqualityComparer : IEqualityComparer<double> {
690      public bool Equals(double x, double y) { return x.IsAlmost(y); }
691      public int GetHashCode(double obj) { return obj.GetHashCode(); }
692    }
693    #endregion
694  }
695}
Note: See TracBrowser for help on using the repository browser.