Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Operators/3.3/DataReducer.cs @ 17102

Last change on this file since 17102 was 16565, checked in by gkronber, 6 years ago

#2520: merged changes from PersistenceOverhaul branch (r16451:16564) into trunk

File size: 13.5 KB
RevLine 
[7395]1#region License Information
2/* HeuristicLab
[16565]3 * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[7395]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 HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Data;
28using HeuristicLab.Parameters;
[16565]29using HEAL.Attic;
[7395]30
31namespace HeuristicLab.Operators {
32  [Item("DataReducer", "An operator to reduce values of sub scopes.")]
[16565]33  [StorableType("87DC7AB9-4C8D-4FF9-B0B0-70B7E7F32C3C")]
[7395]34  public sealed class DataReducer : SingleSuccessorOperator {
35    #region Parameter Properties
36    public ScopeTreeLookupParameter<IItem> ParameterToReduce {
37      get { return (ScopeTreeLookupParameter<IItem>)Parameters["ParameterToReduce"]; }
38    }
39    public LookupParameter<IItem> TargetParameter {
40      get { return (LookupParameter<IItem>)Parameters["TargetParameter"]; }
41    }
[12072]42    public ValueLookupParameter<ReductionOperation> ReductionOperation {
43      get { return (ValueLookupParameter<ReductionOperation>)Parameters["ReductionOperation"]; }
[7395]44    }
[12072]45    public ValueLookupParameter<ReductionOperation> TargetOperation {
46      get { return (ValueLookupParameter<ReductionOperation>)Parameters["TargetOperation"]; }
[7395]47    }
48    #endregion
49
50    [StorableConstructor]
[16565]51    private DataReducer(StorableConstructorFlag _) : base(_) { }
[7395]52    private DataReducer(DataReducer original, Cloner cloner)
53      : base(original, cloner) {
54    }
55    public DataReducer()
56      : base() {
57      #region Create parameters
58      Parameters.Add(new ScopeTreeLookupParameter<IItem>("ParameterToReduce", "The parameter on which the reduction operation should be applied."));
59      Parameters.Add(new LookupParameter<IItem>("TargetParameter", "The target variable in which the reduced value should be stored."));
[12072]60      Parameters.Add(new ValueLookupParameter<ReductionOperation>("ReductionOperation", "The operation which is applied on the parameters to reduce.", new ReductionOperation()));
61      Parameters.Add(new ValueLookupParameter<ReductionOperation>("TargetOperation", "The operation used to apply the reduced value to the target variable.", new ReductionOperation()));
[7395]62      #endregion
63    }
64
65    public override IDeepCloneable Clone(Cloner cloner) {
66      return new DataReducer(this, cloner);
67    }
68
[12072]69    [StorableHook(HookType.AfterDeserialization)]
70    private void AfterDeserialization() {
71      // BackwardsCompatibility3.3
72      var oldReductionOperation = Parameters["ReductionOperation"] as ValueParameter<ReductionOperation>;
73      if (oldReductionOperation != null) {
74        Parameters.Remove("ReductionOperation");
75        Parameters.Add(new ValueLookupParameter<ReductionOperation>("ReductionOperation", "The operation which is applied on the parameters to reduce.", oldReductionOperation.Value));
76      }
77      var oldTargetOperation = Parameters["TargetOperation"] as ValueParameter<ReductionOperation>;
78      if (oldTargetOperation != null) {
79        Parameters.Remove("TargetOperation");
80        Parameters.Add(new ValueLookupParameter<ReductionOperation>("TargetOperation", "The operation used to apply the reduced value to the target variable.", oldTargetOperation.Value));
81      }
82    }
83
[7395]84    public override IOperation Apply() {
85      var values = ParameterToReduce.ActualValue;
[10196]86      if (!values.Any()) return base.Apply();
87
88      if (values.All(x => x is IntValue)) {
89        CalculateResult(values.OfType<IntValue>().Select(x => x.Value), values.First().GetType());
90      } else if (values.All(x => x is DoubleValue)) {
91        CalculateResult(values.OfType<DoubleValue>().Select(x => x.Value), values.First().GetType());
92      } else if (values.All(x => x is TimeSpanValue)) {
93        CalculateResult(values.OfType<TimeSpanValue>().Select(x => x.Value), values.First().GetType());
94      } else if (values.All(x => x is BoolValue)) {
95        CalculateResult(values.OfType<BoolValue>().Select(x => x.Value), values.First().GetType());
96      } else {
97        throw new ArgumentException(string.Format("Type {0} is not supported by the DataReducer.", values.First().GetType()));
[7395]98      }
[10196]99
[7395]100      return base.Apply();
101    }
102
[8252]103    #region integer reduction
104    private void CalculateResult(IEnumerable<int> values, Type targetType) {
105      int result;
[12072]106      switch (ReductionOperation.ActualValue.Value) {
[7395]107        case ReductionOperations.Sum:
[8252]108          result = values.Sum();
[7395]109          break;
[8252]110        case ReductionOperations.Product:
111          result = values.Aggregate(1, (x, y) => x * y);
[7395]112          break;
[8252]113        case ReductionOperations.Count:
114          result = values.Count();
[7395]115          break;
116        case ReductionOperations.Min:
[8252]117          result = values.Min();
[7395]118          break;
119        case ReductionOperations.Max:
[8252]120          result = values.Max();
[7395]121          break;
[8252]122        case ReductionOperations.Avg:
123          result = (int)Math.Round(values.Average());
124          break;
125        case ReductionOperations.Assign:
126          result = values.Last();
127          break;
[7395]128        default:
[12072]129          throw new InvalidOperationException(string.Format("Operation {0} is not supported as ReductionOperation for type: {1}.", ReductionOperation.ActualValue.Value, targetType));
[7395]130      }
131
[8252]132      IntValue target;
[12072]133      switch (TargetOperation.ActualValue.Value) {
[7395]134        case ReductionOperations.Sum:
[8252]135          target = InitializeTarget<IntValue, int>(targetType, 0);
[7395]136          target.Value += result;
137          break;
[8252]138        case ReductionOperations.Product:
139          target = InitializeTarget<IntValue, int>(targetType, 1);
140          target.Value = target.Value * result;
[7395]141          break;
[8252]142        case ReductionOperations.Min:
143          target = InitializeTarget<IntValue, int>(targetType, int.MaxValue);
144          target.Value = Math.Min(target.Value, result);
145          break;
146        case ReductionOperations.Max:
147          target = InitializeTarget<IntValue, int>(targetType, int.MinValue);
148          target.Value = Math.Max(target.Value, result);
149          break;
150        case ReductionOperations.Avg:
151          target = InitializeTarget<IntValue, int>(targetType, result);
152          target.Value = (int)Math.Round((target.Value + result) / 2.0);
153          break;
154        case ReductionOperations.Assign:
155          target = InitializeTarget<IntValue, int>(targetType, 0);
156          target.Value = result;
157          break;
[7395]158        default:
[12072]159          throw new InvalidOperationException(string.Format("Operation {0} is not supported as TargetOperation for type: {1}.", TargetOperation.ActualValue.Value, targetType));
[7395]160      }
161    }
[8252]162    #endregion
163    #region double reduction
164    private void CalculateResult(IEnumerable<double> values, Type targetType) {
165      double result;
[12072]166      switch (ReductionOperation.ActualValue.Value) {
[7395]167        case ReductionOperations.Sum:
[8252]168          result = values.Sum();
[7395]169          break;
[8252]170        case ReductionOperations.Product:
171          result = values.Aggregate(1.0, (x, y) => x * y);
[7395]172          break;
[8252]173        case ReductionOperations.Count:
174          result = values.Count();
[7395]175          break;
176        case ReductionOperations.Min:
[8252]177          result = values.Min();
[7395]178          break;
179        case ReductionOperations.Max:
[8252]180          result = values.Max();
[7395]181          break;
[8252]182        case ReductionOperations.Avg:
183          result = values.Average();
184          break;
185        case ReductionOperations.Assign:
186          result = values.Last();
187          break;
[7395]188        default:
[12072]189          throw new InvalidOperationException(string.Format("Operation {0} is not supported as ReductionOperation for type: {1}.", ReductionOperation.ActualValue.Value, targetType));
[7395]190      }
191
[8252]192      DoubleValue target;
[12072]193      switch (TargetOperation.ActualValue.Value) {
[7395]194        case ReductionOperations.Sum:
[8252]195          target = InitializeTarget<DoubleValue, double>(targetType, 0.0);
[7395]196          target.Value += result;
197          break;
[8252]198        case ReductionOperations.Product:
199          target = InitializeTarget<DoubleValue, double>(targetType, 1.0);
200          target.Value = target.Value * result;
[7395]201          break;
[8252]202        case ReductionOperations.Min:
203          target = InitializeTarget<DoubleValue, double>(targetType, double.MaxValue);
204          target.Value = Math.Min(target.Value, result);
205          break;
206        case ReductionOperations.Max:
207          target = InitializeTarget<DoubleValue, double>(targetType, double.MinValue);
208          target.Value = Math.Max(target.Value, result);
209          break;
210        case ReductionOperations.Avg:
211          target = InitializeTarget<DoubleValue, double>(targetType, result);
212          target.Value = (target.Value + result) / 2.0;
213          break;
214        case ReductionOperations.Assign:
215          target = InitializeTarget<DoubleValue, double>(targetType, 0.0);
216          target.Value = result;
217          break;
[7395]218        default:
[12072]219          throw new InvalidOperationException(string.Format("Operation {0} is not supported as TargetOperation for type: {1}.", TargetOperation.ActualValue.Value, targetType));
[7395]220      }
221    }
[8252]222    #endregion
223    #region TimeSpan reduction
224    private void CalculateResult(IEnumerable<TimeSpan> values, Type targetType) {
225      TimeSpan result;
[12072]226      switch (ReductionOperation.ActualValue.Value) {
[7395]227        case ReductionOperations.Sum:
[8252]228          result = values.Aggregate(new TimeSpan(), (x, y) => x + y);
[7395]229          break;
230        case ReductionOperations.Min:
[8252]231          result = values.Min();
[7395]232          break;
233        case ReductionOperations.Max:
[8252]234          result = values.Max();
[7395]235          break;
[8252]236        case ReductionOperations.Avg:
237          result = TimeSpan.FromMilliseconds(values.Average(x => x.TotalMilliseconds));
238          break;
239        case ReductionOperations.Assign:
240          result = values.Last();
241          break;
[7395]242        default:
[12072]243          throw new InvalidOperationException(string.Format("Operation {0} is not supported as ReductionOperation for type: {1}.", ReductionOperation.ActualValue.Value, targetType));
[7395]244      }
245
[8252]246      TimeSpanValue target;
[12072]247      switch (TargetOperation.ActualValue.Value) {
[8252]248        case ReductionOperations.Sum:
249          target = InitializeTarget<TimeSpanValue, TimeSpan>(targetType, new TimeSpan());
250          target.Value += result;
251          break;
252        case ReductionOperations.Min:
253          target = InitializeTarget<TimeSpanValue, TimeSpan>(targetType, TimeSpan.MaxValue);
254          target.Value = target.Value < result ? target.Value : result;
255          break;
256        case ReductionOperations.Max:
257          target = InitializeTarget<TimeSpanValue, TimeSpan>(targetType, TimeSpan.MinValue);
258          target.Value = target.Value > result ? target.Value : result;
259          break;
260        case ReductionOperations.Avg:
261          target = InitializeTarget<TimeSpanValue, TimeSpan>(targetType, result);
262          target.Value = TimeSpan.FromMilliseconds((target.Value.TotalMilliseconds + result.TotalMilliseconds) / 2);
263          break;
[7395]264        case ReductionOperations.Assign:
[8252]265          target = InitializeTarget<TimeSpanValue, TimeSpan>(targetType, new TimeSpan());
[7395]266          target.Value = result;
267          break;
268        default:
[12072]269          throw new InvalidOperationException(string.Format("Operation {0} is not supported as TargetOperation for type: {1}.", TargetOperation.ActualValue.Value, targetType));
[7395]270      }
271    }
[8252]272    #endregion
[10196]273    #region bool reduction
274    private void CalculateResult(IEnumerable<bool> values, Type targetType) {
275      bool result;
[12072]276      switch (ReductionOperation.ActualValue.Value) {
[10196]277        case ReductionOperations.All:
278          result = values.All(x => x);
279          break;
280        case ReductionOperations.Any:
281          result = values.Any(x => x);
282          break;
283        default:
[12072]284          throw new InvalidOperationException(string.Format("Operation {0} is not supported as ReductionOperation for type: {1}.", ReductionOperation.ActualValue.Value, targetType));
[10196]285      }
[8252]286
[10196]287      BoolValue target;
[12072]288      switch (TargetOperation.ActualValue.Value) {
[10196]289        case ReductionOperations.Assign:
290          target = InitializeTarget<BoolValue, bool>(targetType, true);
291          target.Value = result;
292          break;
293        default:
[12072]294          throw new InvalidOperationException(string.Format("Operation {0} is not supported as TargetOperation for type: {1}.", TargetOperation.ActualValue.Value, targetType));
[10196]295      }
296    }
297    #endregion
298
[8252]299    #region helpers
300    private T1 InitializeTarget<T1, T2>(Type targetType, T2 initialValue)
301      where T1 : ValueTypeValue<T2>
302      where T2 : struct {
303      T1 target = (T1)TargetParameter.ActualValue;
304      if (target == null) {
305        target = (T1)Activator.CreateInstance(targetType);
306        TargetParameter.ActualValue = target;
307        target.Value = initialValue;
308      }
309      return target;
310    }
311    #endregion
[7395]312  }
313}
Note: See TracBrowser for help on using the repository browser.