Free cookie consent management tool by TermsFeed Policy Generator

Ticket #2281: resultparameter.patch

File resultparameter.patch, 34.5 KB (added by abeham, 9 years ago)

Patching the trunk to include the result parameter, also adapts QualityDistributionAnalyzer to use this new parameter

  • HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDistributionAnalyzer.cs

     
    3737    public IScopeTreeLookupParameter<DoubleValue> QualityParameter {
    3838      get { return (IScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
    3939    }
    40     public IValueLookupParameter<ResultCollection> ResultsParameter {
    41       get { return (IValueLookupParameter<ResultCollection>)Parameters["Results"]; }
     40    public IResultParameter<DataTable> QualityDistributionParameter {
     41      get { return (IResultParameter<DataTable>)Parameters["Quality Distribution"]; }
    4242    }
    43     private ValueParameter<StringValue> HistogramNameParameter {
    44       get { return (ValueParameter<StringValue>)Parameters["HistogramName"]; }
     43    public IResultParameter<DataTableHistory> QualityDistributionHistoryParameter {
     44      get { return (IResultParameter<DataTableHistory>)Parameters["Quality Distribution History"]; }
    4545    }
    46     private ValueParameter<BoolValue> StoreHistoryParameter {
    47       get { return (ValueParameter<BoolValue>)Parameters["StoreHistory"]; }
    48     }
    4946    public ILookupParameter<IntValue> IterationsParameter {
    5047      get { return (ILookupParameter<IntValue>)Parameters["Iterations"]; }
    5148    }
     
    5249    public IValueLookupParameter<IntValue> MaximumIterationsParameter {
    5350      get { return (IValueLookupParameter<IntValue>)Parameters["MaximumIterations"]; }
    5451    }
     52    private ValueParameter<BoolValue> StoreHistoryParameter {
     53      get { return (ValueParameter<BoolValue>)Parameters["StoreHistory"]; }
     54    }
    5555    #endregion
    5656
    5757    public virtual bool EnabledByDefault {
     
    5858      get { return true; }
    5959    }
    6060
    61     public string HistogramName {
    62       get { return HistogramNameParameter.Value.Value; }
    63       set { HistogramNameParameter.Value.Value = value; }
    64     }
    65 
    6661    public bool StoreHistory {
    6762      get { return StoreHistoryParameter.Value.Value; }
    6863      set { StoreHistoryParameter.Value.Value = value; }
     
    7671    public QualityDistributionAnalyzer()
    7772      : base() {
    7873      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The value which represents the quality of a solution."));
    79       Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The results collection where the analysis values should be stored."));
    80       Parameters.Add(new FixedValueParameter<StringValue>("HistogramName", "The name of the histogram that gets injected in to the results collection.", new StringValue("Quality Distribution")));
     74      Parameters.Add(new ResultParameter<DataTable>("Quality Distribution", "Shows the quality distributions in the current population."));
     75      Parameters.Add(new ResultParameter<DataTableHistory>("Quality Distribution History", "Maintains the history of the quality distributions of each iteration."));
    8176      Parameters.Add(new FixedValueParameter<BoolValue>("StoreHistory", "True if the history should be stored in addition to the current distribution", new BoolValue(false)));
    8277      Parameters.Add(new LookupParameter<IntValue>("Iterations", "Optional: A value indicating the current iteration."));
    8378      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "Unused", new IntValue(-1)));
    8479
    8580      QualityParameter.Hidden = true;
    86       ResultsParameter.Hidden = true;
    8781      IterationsParameter.Hidden = true;
    8882      MaximumIterationsParameter.Hidden = true;
     83
     84      var table = new DataTable("Population Quality Distribution", QualityDistributionParameter.Description) {
     85        VisualProperties = { XAxisTitle = "Quality", YAxisTitle = "Frequency" }
     86      };
     87      var row = new DataRow("QualityDistribution") {
     88        VisualProperties = { ChartType = DataRowVisualProperties.DataRowChartType.Histogram }
     89      };
     90      table.Rows.Add(row);
     91      QualityDistributionParameter.DefaultValue = table;
     92
     93      QualityDistributionHistoryParameter.DefaultValue = new DataTableHistory();
    8994    }
    9095
    9196    public override IDeepCloneable Clone(Cloner cloner) {
     
    9398    }
    9499
    95100    public override IOperation Apply() {
    96       DataTable qualityDistribution = null;
    97       ResultCollection results = ResultsParameter.ActualValue;
    98       string description = "Shows the quality distributions in the current population.";
    99       if (results.ContainsKey(HistogramName)) {
    100         qualityDistribution = results[HistogramName].Value as DataTable;
    101       } else {
    102         qualityDistribution = new DataTable("Population Quality Distribution", description);
    103         qualityDistribution.VisualProperties.XAxisTitle = QualityParameter.ActualName;
    104         qualityDistribution.VisualProperties.YAxisTitle = "Frequency";
    105         results.Add(new Result(HistogramName, description, qualityDistribution));
    106       }
    107       DataRow row;
    108       if (!qualityDistribution.Rows.TryGetValue("QualityDistribution", out row)) {
    109         row = new DataRow("QualityDistribution");
    110         row.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Histogram;
    111         qualityDistribution.Rows.Add(row);
    112       }
     101      var qualityDistribution = QualityDistributionParameter.ActualValue;
     102      var row = qualityDistribution.Rows.First();
     103
    113104      var qualities = QualityParameter.ActualValue;
    114105      row.Values.Replace(qualities.Select(x => x.Value));
    115106
    116107      if (StoreHistory) {
    117         string historyResultName = HistogramName + " History";
    118         DataTableHistory qdHistory = null;
    119         if (results.ContainsKey(historyResultName)) {
    120           qdHistory = results[historyResultName].Value as DataTableHistory;
    121         } else {
    122           qdHistory = new DataTableHistory();
    123           results.Add(new Result(historyResultName, qdHistory));
    124         }
    125         DataTable table = (DataTable)qualityDistribution.Clone();
    126         IntValue iteration = IterationsParameter.ActualValue;
     108        var qdHistory = QualityDistributionHistoryParameter.ActualValue;
     109        var table = (DataTable)qualityDistribution.Clone();
     110        var iteration = IterationsParameter.ActualValue;
    127111        if (iteration != null) {
    128           string iterationName = IterationsParameter.ActualName;
     112          var iterationName = IterationsParameter.ActualName;
    129113          if (iterationName.EndsWith("s")) iterationName = iterationName.Remove(iterationName.Length - 1);
    130           string appendix = " at " + iterationName + " " + iteration.Value.ToString();
     114          var appendix = " at " + iterationName + " " + iteration.Value;
    131115          table.Name += appendix;
    132           table.Rows["QualityDistribution"].VisualProperties.DisplayName += appendix;
     116          table.Rows.First().VisualProperties.DisplayName += appendix;
    133117        }
    134118        qdHistory.Add(table);
    135119      }
  • HeuristicLab.Core/3.3/HeuristicLab.Core-3.3.csproj

     
    161161    <Compile Include="Interfaces\DirectedGraph\IVertex.cs" />
    162162    <Compile Include="Interfaces\ICheckedMultiOperator.cs" />
    163163    <Compile Include="Interfaces\IConstrainedValueParameter.cs" />
     164    <Compile Include="Interfaces\IContextualParameter.cs" />
    164165    <Compile Include="Interfaces\IInstrumentedOperator.cs" />
     166    <Compile Include="Interfaces\IResultParameter.cs" />
    165167    <Compile Include="Interfaces\IMultiOperator.cs" />
    166168    <Compile Include="Interfaces\IFixedValueParameter.cs" />
    167169    <Compile Include="Interfaces\IOperatorGraphOperator.cs" />
  • HeuristicLab.Core/3.3/Interfaces/IContextualParameter.cs

     
     1#region License Information
     2/* HeuristicLab
     3 * Copyright (C) 2002-2015 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
     22namespace HeuristicLab.Core {
     23  public interface IContextualParameter : IParameter {
     24    IExecutionContext ExecutionContext { get; set; }
     25  }
     26}
  • HeuristicLab.Core/3.3/Interfaces/ILookupParameter.cs

     
    2222using System;
    2323
    2424namespace HeuristicLab.Core {
    25   public interface ILookupParameter : IParameter {
     25  public interface ILookupParameter : IContextualParameter {
    2626    string ActualName { get; set; }
    2727    string TranslatedName { get; }
    28     IExecutionContext ExecutionContext { get; set; }
    2928    event EventHandler ActualNameChanged;
    3029  }
    3130
  • HeuristicLab.Core/3.3/Interfaces/IResultParameter.cs

     
     1#region License Information
     2/* HeuristicLab
     3 * Copyright (C) 2002-2015 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;
     23
     24namespace HeuristicLab.Core {
     25  public interface IResultParameter : IContextualParameter {
     26    string ResultName { get; set; }
     27    string ResultCollectionName { get; set; }
     28    event EventHandler ResultNameChanged;
     29    event EventHandler ResultCollectionNameChanged;
     30  }
     31
     32  public interface IResultParameter<T> : IResultParameter where T : class, IItem, new() {
     33    T DefaultValue { get; set; }
     34    new T ActualValue { get; set; }
     35  }
     36}
  • HeuristicLab.Operators/3.3/Operator.cs

     
    119119      try {
    120120        ExecutionContext = context;
    121121        this.cancellationToken = cancellationToken;
    122         foreach (ILookupParameter param in Parameters.OfType<ILookupParameter>())
     122        foreach (var param in Parameters.OfType<IContextualParameter>())
    123123          param.ExecutionContext = context;
    124124        IOperation next = Apply();
    125125        OnExecuted();
    126126        return next;
    127       }
    128       finally {
    129         foreach (ILookupParameter param in Parameters.OfType<ILookupParameter>())
     127      } finally {
     128        foreach (var param in Parameters.OfType<IContextualParameter>())
    130129          param.ExecutionContext = null;
    131130        ExecutionContext = null;
    132131      }
  • HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj

     
    164164    <Compile Include="Interfaces\ISolutionSimilarityCalculator.cs" />
    165165    <Compile Include="MetaOptimizers\BatchRun.cs" />
    166166    <Compile Include="MetaOptimizers\Experiment.cs" />
     167    <Compile Include="Parameters\ResultParameter.cs" />
    167168    <Compile Include="RunCollectionModification\RunCollectionRunRemover.cs" />
    168169    <Compile Include="Plugin.cs" />
    169170    <Compile Include="RunCollectionModification\RunCollectionDiscretizer.cs" />
  • HeuristicLab.Optimization/3.3/Parameters/ResultParameter.cs

     
     1#region License Information
     2/* HeuristicLab
     3 * Copyright (C) 2002-2015 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.Threading;
     24using HeuristicLab.Common;
     25using HeuristicLab.Core;
     26using HeuristicLab.Parameters;
     27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     28
     29namespace HeuristicLab.Optimization {
     30  [Item("ResultParameter", "A parameter whose value is written to a result collection.")]
     31  [StorableClass]
     32  public sealed class ResultParameter<T> : Parameter, IResultParameter<T>, IStatefulItem where T : class, IItem, new() {
     33
     34    [Storable]
     35    private string resultName;
     36    public string ResultName {
     37      get { return resultName; }
     38      set {
     39        if (value == null) throw new ArgumentNullException();
     40        if (string.IsNullOrWhiteSpace(value)) {
     41          resultName = Name;
     42          OnResultNameChanged();
     43        } else if (!resultName.Equals(value)) {
     44          resultName = value;
     45          OnResultNameChanged();
     46        }
     47      }
     48    }
     49
     50    [Storable]
     51    private string resultCollectionName;
     52    public string ResultCollectionName {
     53      get { return resultCollectionName; }
     54      set {
     55        if (value == null) throw new ArgumentNullException("value");
     56        if (string.IsNullOrWhiteSpace(value)) {
     57          resultCollectionName = "Results";
     58          OnResultCollectionNameChanged();
     59        } else if (!resultCollectionName.Equals(value)) {
     60          resultCollectionName = value;
     61          OnResultCollectionNameChanged();
     62        }
     63      }
     64    }
     65
     66    [Storable]
     67    private T defaultValue;
     68    public T DefaultValue {
     69      get { return defaultValue; }
     70      set {
     71        if (value != defaultValue) {
     72          defaultValue = value;
     73          OnDefaultValueChanged();
     74        }
     75      }
     76    }
     77
     78    public new T ActualValue {
     79      get { return (T)base.ActualValue; }
     80      set { base.ActualValue = value; }
     81    }
     82
     83    private Lazy<ThreadLocal<IItem>> cachedActualValues;
     84    private IItem CachedActualValue {
     85      get { return cachedActualValues.Value.Value; }
     86    }
     87
     88    private Lazy<ThreadLocal<IExecutionContext>> executionContexts;
     89    public IExecutionContext ExecutionContext {
     90      get { return executionContexts.Value.Value; }
     91      set {
     92        executionContexts.Value.Value = value;
     93        cachedActualValues.Value.Value = null;
     94      }
     95    }
     96
     97    [StorableConstructor]
     98    private ResultParameter(bool deserializing) : base(deserializing) { }
     99    private ResultParameter(ResultParameter<T> original, Cloner cloner)
     100      : base(original, cloner) {
     101      resultName = original.resultName;
     102      resultCollectionName = original.resultCollectionName;
     103      defaultValue = cloner.Clone(original.defaultValue);
     104      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     105      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     106    }
     107    public override IDeepCloneable Clone(Cloner cloner) {
     108      return new ResultParameter<T>(this, cloner);
     109    }
     110    public ResultParameter() : this("Anonymous") { }
     111    public ResultParameter(string name)
     112      : base(name, typeof(T)) {
     113      resultName = Name;
     114      resultCollectionName = "Results";
     115      defaultValue = new T();
     116      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     117      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     118    }
     119    public ResultParameter(string name, string description) : this(name, description, new T()) { }
     120    public ResultParameter(string name, string description, T defaultValue)
     121      : base(name, description, typeof(T)) {
     122      if (defaultValue == null) throw new ArgumentNullException("defaultValue");
     123      resultName = Name;
     124      resultCollectionName = "Results";
     125      this.defaultValue = defaultValue;
     126      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     127      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     128    }
     129    public ResultParameter(string name, string description, string resultName) : this(name, description, new T(), resultName) { }
     130    public ResultParameter(string name, string description, T defaultValue, string resultName)
     131      : base(name, description, typeof(T)) {
     132      if (defaultValue == null) throw new ArgumentNullException("defaultValue");
     133      this.resultName = string.IsNullOrWhiteSpace(resultName) ? Name : resultName;
     134      resultCollectionName = "Results";
     135      this.defaultValue = defaultValue;
     136      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     137      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     138    }
     139    public ResultParameter(string name, string description, string resultName, string resultCollectionName) : this(name, description, new T(), resultName, resultCollectionName) { }
     140    public ResultParameter(string name, string description, T defaultValue, string resultName, string resultCollectionName)
     141      : base(name, description, typeof(T)) {
     142      if (defaultValue == null) throw new ArgumentNullException("defaultValue");
     143      this.resultName = string.IsNullOrWhiteSpace(resultName) ? Name : resultName;
     144      this.resultCollectionName = string.IsNullOrWhiteSpace(resultCollectionName) ? "Results" : resultCollectionName;
     145      this.defaultValue = defaultValue;
     146      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     147      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     148    }
     149
     150    public override string ToString() {
     151      if (Name.Equals(ResultName)) return Name;
     152      return Name + ": " + ResultName;
     153    }
     154
     155
     156    private ResultCollection LookupResultCollection() {
     157      var scope = ExecutionContext.Scope;
     158      while ((scope != null) && !scope.Variables.ContainsKey(ResultCollectionName)
     159        && !(scope.Variables[ResultCollectionName].Value is ResultCollection))
     160        scope = scope.Parent;
     161      return scope != null ? (ResultCollection)scope.Variables[ResultCollectionName].Value : null;
     162    }
     163
     164    protected override IItem GetActualValue() {
     165      if (CachedActualValue != null) return CachedActualValue;
     166
     167      var results = LookupResultCollection();
     168      if (results == null)
     169        throw new InvalidOperationException("ResultParameter (" + Name + "): ResultCollection " + ResultCollectionName + " not found.");
     170
     171      if (!results.ContainsKey(ResultName)) results.Add(new Result(ResultName, (T)DefaultValue.Clone()));
     172      var resultValue = results[ResultName].Value;
     173      if (!(resultValue is T))
     174        throw new InvalidOperationException(string.Format("Type mismatch. Result \"{0}\" does not contain a \"{1}\".", ResultName, typeof(T).GetPrettyName()));
     175
     176      cachedActualValues.Value.Value = resultValue;
     177      return resultValue;
     178    }
     179
     180    protected override void SetActualValue(IItem value) {
     181      if (!(value is T)) throw new InvalidOperationException(string.Format("Type mismatch. Result is not a \"{0}\".", typeof(T).GetPrettyName()));
     182
     183      var results = LookupResultCollection();
     184      if (results == null)
     185        throw new InvalidOperationException("ResultParameter (" + Name + "): ResultCollection " + ResultCollectionName + " not found.");
     186
     187      if (!results.ContainsKey(ResultName))
     188        results.Add(new Result(ResultName, value));
     189      else results[ResultName].Value = value;
     190
     191      cachedActualValues.Value.Value = value;
     192    }
     193
     194    public event EventHandler ResultNameChanged;
     195    private void OnResultNameChanged() {
     196      var handler = ResultNameChanged;
     197      if (handler != null) handler(this, EventArgs.Empty);
     198      OnToStringChanged();
     199    }
     200
     201    public event EventHandler ResultCollectionNameChanged;
     202    private void OnResultCollectionNameChanged() {
     203      var handler = ResultCollectionNameChanged;
     204      if (handler != null) handler(this, EventArgs.Empty);
     205    }
     206
     207    public event EventHandler DefaultValueChanged;
     208    private void OnDefaultValueChanged() {
     209      EventHandler handler = DefaultValueChanged;
     210      if (handler != null) handler(this, EventArgs.Empty);
     211      OnItemImageChanged();
     212    }
     213
     214    #region IStatefulItem members
     215    public void InitializeState() {
     216    }
     217
     218    public void ClearState() {
     219      if (cachedActualValues.IsValueCreated) {
     220        cachedActualValues.Value.Dispose();
     221        cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     222      }
     223      if (executionContexts.IsValueCreated) {
     224        executionContexts.Value.Dispose();
     225        executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     226      }
     227    }
     228    #endregion
     229  }
     230}
  • HeuristicLab.Optimization/3.3/Parameters/ResultParameter.cs

     
     1#region License Information
     2/* HeuristicLab
     3 * Copyright (C) 2002-2015 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.Threading;
     24using HeuristicLab.Common;
     25using HeuristicLab.Core;
     26using HeuristicLab.Parameters;
     27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     28
     29namespace HeuristicLab.Optimization {
     30  [Item("ResultParameter", "A parameter whose value is written to a result collection.")]
     31  [StorableClass]
     32  public sealed class ResultParameter<T> : Parameter, IResultParameter<T>, IStatefulItem where T : class, IItem, new() {
     33
     34    [Storable]
     35    private string resultName;
     36    public string ResultName {
     37      get { return resultName; }
     38      set {
     39        if (value == null) throw new ArgumentNullException();
     40        if (string.IsNullOrWhiteSpace(value)) {
     41          resultName = Name;
     42          OnResultNameChanged();
     43        } else if (!resultName.Equals(value)) {
     44          resultName = value;
     45          OnResultNameChanged();
     46        }
     47      }
     48    }
     49
     50    [Storable]
     51    private string resultCollectionName;
     52    public string ResultCollectionName {
     53      get { return resultCollectionName; }
     54      set {
     55        if (value == null) throw new ArgumentNullException("value");
     56        if (string.IsNullOrWhiteSpace(value)) {
     57          resultCollectionName = "Results";
     58          OnResultCollectionNameChanged();
     59        } else if (!resultCollectionName.Equals(value)) {
     60          resultCollectionName = value;
     61          OnResultCollectionNameChanged();
     62        }
     63      }
     64    }
     65
     66    [Storable]
     67    private T defaultValue;
     68    public T DefaultValue {
     69      get { return defaultValue; }
     70      set {
     71        if (value != defaultValue) {
     72          defaultValue = value;
     73          OnDefaultValueChanged();
     74        }
     75      }
     76    }
     77
     78    public new T ActualValue {
     79      get { return (T)base.ActualValue; }
     80      set { base.ActualValue = value; }
     81    }
     82
     83    private Lazy<ThreadLocal<IItem>> cachedActualValues;
     84    private IItem CachedActualValue {
     85      get { return cachedActualValues.Value.Value; }
     86    }
     87
     88    private Lazy<ThreadLocal<IExecutionContext>> executionContexts;
     89    public IExecutionContext ExecutionContext {
     90      get { return executionContexts.Value.Value; }
     91      set {
     92        executionContexts.Value.Value = value;
     93        cachedActualValues.Value.Value = null;
     94      }
     95    }
     96
     97    [StorableConstructor]
     98    private ResultParameter(bool deserializing) : base(deserializing) { }
     99    private ResultParameter(ResultParameter<T> original, Cloner cloner)
     100      : base(original, cloner) {
     101      resultName = original.resultName;
     102      resultCollectionName = original.resultCollectionName;
     103      defaultValue = cloner.Clone(original.defaultValue);
     104      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     105      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     106    }
     107    public override IDeepCloneable Clone(Cloner cloner) {
     108      return new ResultParameter<T>(this, cloner);
     109    }
     110    public ResultParameter() : this("Anonymous") { }
     111    public ResultParameter(string name)
     112      : base(name, typeof(T)) {
     113      resultName = Name;
     114      resultCollectionName = "Results";
     115      defaultValue = new T();
     116      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     117      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     118    }
     119    public ResultParameter(string name, string description) : this(name, description, new T()) { }
     120    public ResultParameter(string name, string description, T defaultValue)
     121      : base(name, description, typeof(T)) {
     122      if (defaultValue == null) throw new ArgumentNullException("defaultValue");
     123      resultName = Name;
     124      resultCollectionName = "Results";
     125      this.defaultValue = defaultValue;
     126      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     127      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     128    }
     129    public ResultParameter(string name, string description, string resultName) : this(name, description, new T(), resultName) { }
     130    public ResultParameter(string name, string description, T defaultValue, string resultName)
     131      : base(name, description, typeof(T)) {
     132      if (defaultValue == null) throw new ArgumentNullException("defaultValue");
     133      this.resultName = string.IsNullOrWhiteSpace(resultName) ? Name : resultName;
     134      resultCollectionName = "Results";
     135      this.defaultValue = defaultValue;
     136      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     137      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     138    }
     139    public ResultParameter(string name, string description, string resultName, string resultCollectionName) : this(name, description, new T(), resultName, resultCollectionName) { }
     140    public ResultParameter(string name, string description, T defaultValue, string resultName, string resultCollectionName)
     141      : base(name, description, typeof(T)) {
     142      if (defaultValue == null) throw new ArgumentNullException("defaultValue");
     143      this.resultName = string.IsNullOrWhiteSpace(resultName) ? Name : resultName;
     144      this.resultCollectionName = string.IsNullOrWhiteSpace(resultCollectionName) ? "Results" : resultCollectionName;
     145      this.defaultValue = defaultValue;
     146      cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     147      executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     148    }
     149
     150    public override string ToString() {
     151      if (Name.Equals(ResultName)) return Name;
     152      return Name + ": " + ResultName;
     153    }
     154
     155
     156    private ResultCollection LookupResultCollection() {
     157      var scope = ExecutionContext.Scope;
     158      while ((scope != null) && !scope.Variables.ContainsKey(ResultCollectionName)
     159        && !(scope.Variables[ResultCollectionName].Value is ResultCollection))
     160        scope = scope.Parent;
     161      return scope != null ? (ResultCollection)scope.Variables[ResultCollectionName].Value : null;
     162    }
     163
     164    protected override IItem GetActualValue() {
     165      if (CachedActualValue != null) return CachedActualValue;
     166
     167      var results = LookupResultCollection();
     168      if (results == null)
     169        throw new InvalidOperationException("ResultParameter (" + Name + "): ResultCollection " + ResultCollectionName + " not found.");
     170
     171      if (!results.ContainsKey(ResultName)) results.Add(new Result(ResultName, (T)DefaultValue.Clone()));
     172      var resultValue = results[ResultName].Value;
     173      if (!(resultValue is T))
     174        throw new InvalidOperationException(string.Format("Type mismatch. Result \"{0}\" does not contain a \"{1}\".", ResultName, typeof(T).GetPrettyName()));
     175
     176      cachedActualValues.Value.Value = resultValue;
     177      return resultValue;
     178    }
     179
     180    protected override void SetActualValue(IItem value) {
     181      if (!(value is T)) throw new InvalidOperationException(string.Format("Type mismatch. Result is not a \"{0}\".", typeof(T).GetPrettyName()));
     182
     183      var results = LookupResultCollection();
     184      if (results == null)
     185        throw new InvalidOperationException("ResultParameter (" + Name + "): ResultCollection " + ResultCollectionName + " not found.");
     186
     187      if (!results.ContainsKey(ResultName))
     188        results.Add(new Result(ResultName, value));
     189      else results[ResultName].Value = value;
     190
     191      cachedActualValues.Value.Value = value;
     192    }
     193
     194    public event EventHandler ResultNameChanged;
     195    private void OnResultNameChanged() {
     196      var handler = ResultNameChanged;
     197      if (handler != null) handler(this, EventArgs.Empty);
     198      OnToStringChanged();
     199    }
     200
     201    public event EventHandler ResultCollectionNameChanged;
     202    private void OnResultCollectionNameChanged() {
     203      var handler = ResultCollectionNameChanged;
     204      if (handler != null) handler(this, EventArgs.Empty);
     205    }
     206
     207    public event EventHandler DefaultValueChanged;
     208    private void OnDefaultValueChanged() {
     209      EventHandler handler = DefaultValueChanged;
     210      if (handler != null) handler(this, EventArgs.Empty);
     211      OnItemImageChanged();
     212    }
     213
     214    #region IStatefulItem members
     215    public void InitializeState() {
     216    }
     217
     218    public void ClearState() {
     219      if (cachedActualValues.IsValueCreated) {
     220        cachedActualValues.Value.Dispose();
     221        cachedActualValues = new Lazy<ThreadLocal<IItem>>(() => { return new ThreadLocal<IItem>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     222      }
     223      if (executionContexts.IsValueCreated) {
     224        executionContexts.Value.Dispose();
     225        executionContexts = new Lazy<ThreadLocal<IExecutionContext>>(() => { return new ThreadLocal<IExecutionContext>(); }, LazyThreadSafetyMode.ExecutionAndPublication);
     226      }
     227    }
     228    #endregion
     229  }
     230}