Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
10/14/16 15:51:10 (8 years ago)
Author:
bburlacu
Message:

#2679: Refactor problems and extract common functionality in static util class.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/HeuristicLab.GoalSeekingProblem/HeuristicLab.GoalSeekingProblem/3.4/MultiObjectiveGoalSeekingProblem.cs

    r14325 r14333  
    2323using System.Collections.Generic;
    2424using System.Linq;
    25 using System.Windows.Forms;
    2625using HeuristicLab.Collections;
    2726using HeuristicLab.Common;
     
    3938  [StorableClass]
    4039  public sealed class MultiObjectiveGoalSeekingProblem : MultiObjectiveBasicProblem<RealVectorEncoding>, IGoalSeekingProblem {
     40    #region parameter names
    4141    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
     42    private const string InputsParameterName = "Inputs";
     43    private const string GoalsParameterName = "Goals";
     44    private const string ModelsParameterName = "Models";
    5045    private const string QualitySumCutoffParameterName = "QualitySumCutoff";
     46    #endregion
    5147
    5248    #region parameters
     49    public IValueParameter<CheckedItemList<InputParameter>> InputsParameter {
     50      get { return (IValueParameter<CheckedItemList<InputParameter>>)Parameters[InputsParameterName]; }
     51    }
     52    public IValueParameter<CheckedItemList<GoalParameter>> GoalsParameter {
     53      get { return (IValueParameter<CheckedItemList<GoalParameter>>)Parameters[GoalsParameterName]; }
     54    }
     55    public IFixedValueParameter<ItemCollection<IRegressionModel>> ModelsParameter {
     56      get { return (IFixedValueParameter<ItemCollection<IRegressionModel>>)Parameters[ModelsParameterName]; }
     57    }
    5358    public IFixedValueParameter<DoubleValue> QualitySumCutoffParameter {
    5459      get { return (IFixedValueParameter<DoubleValue>)Parameters[QualitySumCutoffParameterName]; }
    5560    }
    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 
     61    #endregion
     62
     63    #region IGoalSeekingProblem implementation
    12364    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
     65      get { return ModelsParameter.Value; }
     66    }
     67
     68    public IEnumerable<GoalParameter> Goals {
     69      get { return GoalsParameter.Value; }
     70    }
     71
     72    public IEnumerable<InputParameter> Inputs {
     73      get { return InputsParameter.Value; }
     74    }
     75
     76    public void AddModel(IRegressionModel model) {
     77      var models = ModelsParameter.Value;
     78      models.Add(model);
     79      GoalSeekingUtil.RaiseEvent(this, ModelsChanged);
     80    }
     81
     82    public void RemoveModel(IRegressionModel model) {
     83      var models = ModelsParameter.Value;
     84      models.Remove(model);
     85      GoalSeekingUtil.RaiseEvent(this, ModelsChanged);
     86    }
     87
     88    public void Configure(IRegressionProblemData problemData, int row) {
     89      GoalSeekingUtil.Configure(Goals, Inputs, problemData, row);
     90    }
     91
    15692    public IEnumerable<double> GetEstimatedGoalValues(IEnumerable<double> parameterValues, bool round = false) {
    15793      var ds = (ModifiableDataset)dataset.Clone();
    158       foreach (var parameter in ActiveParameters.Zip(parameterValues, (p, v) => new { Name = p, Value = v })) {
     94      foreach (var parameter in ActiveInputs.Zip(parameterValues, (p, v) => new { Name = p.Name, Value = v })) {
    15995        ds.SetVariableValue(parameter.Value, parameter.Name, 0);
    16096      }
    16197      var rows = new[] { 0 }; // actually just one row
    162 
    16398      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()));
     99        round ? ActiveGoals.Select(t => RoundToNearestStepMultiple(GetModels(t.Name).Average(m => m.GetEstimatedValues(ds, rows).Single()), t.Step))
     100              : ActiveGoals.Select(t => GetModels(t.Name).Average(m => m.GetEstimatedValues(ds, rows).Single()));
    166101      return estimatedValues;
    167102    }
    168103
    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 
    187104    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 
    271105    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 
    369106    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
     107    #endregion
     108
     109    private IEnumerable<GoalParameter> ActiveGoals {
     110      get { return Goals.Where(x => x.Active); }
     111    }
     112    private IEnumerable<InputParameter> ActiveInputs {
     113      get { return Inputs.Where(x => x.Active); }
     114    }
     115    private double QualitySumCutoff {
     116      get { return QualitySumCutoffParameter.Value.Value; }
     117    }
     118
    379119    [Storable]
    380120    private ModifiableDataset dataset; // modifiable dataset
     
    389129      get { return (ValueParameter<BoolArray>)Parameters["Maximization"]; }
    390130    }
    391     #endregion
    392131
    393132    #region constructors
     
    397136    private MultiObjectiveGoalSeekingProblem(MultiObjectiveGoalSeekingProblem original, Cloner cloner) : base(original, cloner) {
    398137      this.dataset = cloner.Clone(original.dataset);
    399       this.problemData = cloner.Clone(original.problemData);
    400138
    401139      RegisterEvents();
     
    408146    [StorableHook(HookType.AfterDeserialization)]
    409147    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 
    440148      RegisterEvents();
    441149    }
    442150
    443151    public MultiObjectiveGoalSeekingProblem() {
    444       Parameters.Add(new ValueParameter<IRegressionProblemData>(ProblemDataParameterName, new RegressionProblemData()));
     152      dataset = new ModifiableDataset();
    445153      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));
     154      Parameters.Add(new ValueParameter<CheckedItemList<InputParameter>>(InputsParameterName));
     155      Parameters.Add(new ValueParameter<CheckedItemList<GoalParameter>>(GoalsParameterName));
     156      Parameters.Add(new FixedValueParameter<ItemCollection<IRegressionModel>>(ModelsParameterName, new ItemCollection<IRegressionModel>()));
    452157      Parameters.Add(new FixedValueParameter<DoubleValue>(QualitySumCutoffParameterName, new DoubleValue(0.2)));
    453 
    454158      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();
     159      EncodingParameter.Hidden = true;
     160      EvaluatorParameter.Hidden = true;
     161      SolutionCreatorParameter.Hidden = true;
     162      MaximizationParameter.Hidden = true;
     163      GoalSeekingUtil.UpdateInputs(InputsParameter.Value, Models, InputParameterChanged);
     164      Encoding = GoalSeekingUtil.CreateEncoding(ActiveInputs);
     165      GoalSeekingUtil.UpdateTargets(GoalsParameter.Value, Models, GoalParameterChanged);
    462166      RegisterEvents();
    463167    }
     
    466170    public override double[] Evaluate(Individual individual, IRandom random) {
    467171      var vector = individual.RealVector();
    468       vector.ElementNames = ActiveParameters;
    469 
     172      vector.ElementNames = ActiveInputs.Select(x => x.Name);
    470173      int i = 0;
    471174      // 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);
     175      foreach (var parameter in ActiveInputs) {
     176        vector[i] = RoundToNearestStepMultiple(vector[i], parameter.Step);
    475177        ++i;
    476178      }
    477179      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                                 });
     180      var qualities = ActiveGoals.Zip(estimatedValues, (t, v) => new { Target = t, EstimatedValue = v })
     181                                 .Select(x => x.Target.Weight * Math.Pow(x.EstimatedValue - x.Target.Goal, 2) / x.Target.Variance);
    485182      return qualities.ToArray();
    486183    }
    487184
     185    #region pareto analyzer
    488186    public override void Analyze(Individual[] individuals, double[][] qualities, ResultCollection results, IRandom random) {
    489187      var matrix = FilterFrontsByQualitySum(individuals, qualities, Math.Max(QualitySumCutoff, qualities.Min(x => x.Sum())));
     
    498196
    499197    private DoubleMatrix FilterFrontsByQualitySum(Individual[] individuals, double[][] qualities, double qualitySumCutoff) {
    500       var activeParameters = ActiveParameters.ToList();
    501       var activeTargets = ActiveTargets.ToList();
     198      var activeParameters = ActiveInputs.ToList();
     199      var activeGoals = ActiveGoals.ToList();
    502200      var filteredModels = new List<double[]>();
    503201      var rowNames = new List<string>();
    504202      // build list of column names by combining target and parameter names (with their respective original and estimated values)
    505203      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)");
     204      foreach (var target in activeGoals) {
     205        columnNames.Add(target.Name);
     206        columnNames.Add(target.Name + " (estimated)");
     207      }
     208      foreach (var parameter in activeParameters) {
     209        columnNames.Add(parameter.Name);
     210        columnNames.Add(parameter.Name + " (estimated)");
     211        columnNames.Add(parameter.Name + " (deviation)");
    514212      }
    515213      // filter models based on their quality sum; remove duplicate models
     
    524222        rowValues[0] = qualitySum;
    525223        int offset = 1;
    526         for (int j = 0; j < activeTargets.Count * 2; j += 2) {
     224        for (int j = 0; j < activeGoals.Count * 2; j += 2) {
    527225          int k = j + offset;
    528           var goal = GetTargetGoal(activeTargets[j / 2]);
     226          var goal = activeGoals[j / 2].Goal;
    529227          rowValues[k] = goal; // original value
    530228          rowValues[k + 1] = estimatedValues[j / 2]; // estimated value
    531229        }
    532         offset += activeTargets.Count * 2;
     230        offset += activeGoals.Count * 2;
    533231        for (int j = 0; j < activeParameters.Count * 3; j += 3) {
    534232          int k = j + offset;
    535           rowValues[k] = problemData.Dataset.GetDoubleValue(columnNames[k], Row);
     233          rowValues[k] = 0; // TODO: figure this out and fix
    536234          rowValues[k + 1] = vector[j / 3];
    537235          rowValues[k + 2] = rowValues[k + 1] - rowValues[k];
     
    550248      return matrix;
    551249    }
     250    #endregion
    552251
    553252    #region event handlers
    554253    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();
     254      ModelsParameter.Value.ItemsAdded += ModelCollection_ItemsChanged;
     255      ModelsParameter.Value.ItemsRemoved += ModelCollection_ItemsChanged;
     256      GoalsParameter.Value.CheckedItemsChanged += GoalSeekingUtil.Goals_CheckedItemsChanged;
     257      InputsParameter.Value.CheckedItemsChanged += GoalSeekingUtil.Inputs_CheckedItemsChanged;
     258    }
     259
     260    private void ModelCollection_ItemsChanged(object sender, CollectionItemsChangedEventArgs<IRegressionModel> e) {
     261      if (e.Items == null || !e.Items.Any()) return;
     262      GoalSeekingUtil.UpdateInputs(InputsParameter.Value, Models, InputParameterChanged);
     263      Encoding = GoalSeekingUtil.CreateEncoding(ActiveInputs);
     264      GoalSeekingUtil.UpdateTargets(GoalsParameter.Value, Models, GoalParameterChanged);
     265      GoalSeekingUtil.RaiseEvent(this, ModelsChanged);
     266    }
     267
     268    private void InputParameterChanged(object sender, EventArgs args) {
     269      var inputParameter = (InputParameter)sender;
     270      var inputs = InputsParameter.Value;
     271      if (inputs.ItemChecked(inputParameter) != inputParameter.Active)
     272        inputs.SetItemCheckedState(inputParameter, inputParameter.Active);
     273      Encoding = GoalSeekingUtil.CreateEncoding(ActiveInputs);
     274    }
     275
     276    private void GoalParameterChanged(object sender, EventArgs args) {
     277      var goalParameter = (GoalParameter)sender;
     278      var goals = GoalsParameter.Value;
     279      if (goals.ItemChecked(goalParameter) != goalParameter.Active)
     280        goals.SetItemCheckedState(goalParameter, goalParameter.Active);
    613281    }
    614282    #endregion
    615283
    616284    #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);
     285    // method which throws an exception that can be caught in the event handler if the check fails
     286    private void CheckIfDatasetContainsTarget(string target) {
     287      if (dataset.DoubleVariables.All(x => x != target))
     288        throw new ArgumentException(string.Format("Model target \"{0}\" does not exist in the dataset.", target));
    682289    }
    683290    private static double RoundToNearestStepMultiple(double value, double step) {
     
    685292    }
    686293    private IEnumerable<IRegressionModel> GetModels(string target) {
    687       return ModelCollection.Where(x => x.TargetVariable == target);
     294      return Models.Where(x => x.TargetVariable == target);
    688295    }
    689296    private class DoubleEqualityComparer : IEqualityComparer<double> {
Note: See TracChangeset for help on using the changeset viewer.