Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HLScript/HeuristicLab.Operators/3.3/DataReducer.cs @ 10971

Last change on this file since 10971 was 10196, checked in by mkommend, 11 years ago

#2123: Implemented reduction operations for BoolValues in the DataReducer.

File size: 12.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Data;
28using HeuristicLab.Parameters;
29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
30
31namespace HeuristicLab.Operators {
32  [Item("DataReducer", "An operator to reduce values of sub scopes.")]
33  [StorableClass]
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    }
42    public ValueParameter<ReductionOperation> ReductionOperation {
43      get { return (ValueParameter<ReductionOperation>)Parameters["ReductionOperation"]; }
44    }
45    public ValueParameter<ReductionOperation> TargetOperation {
46      get { return (ValueParameter<ReductionOperation>)Parameters["TargetOperation"]; }
47    }
48    #endregion
49
50    [StorableConstructor]
51    private DataReducer(bool deserializing) : base(deserializing) { }
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."));
60      Parameters.Add(new ValueParameter<ReductionOperation>("ReductionOperation", "The operation which is applied on the parameters to reduce."));
61      Parameters.Add(new ValueParameter<ReductionOperation>("TargetOperation", "The operation used to apply the reduced value to the target variable."));
62      #endregion
63    }
64
65    public override IDeepCloneable Clone(Cloner cloner) {
66      return new DataReducer(this, cloner);
67    }
68
69    public override IOperation Apply() {
70      var values = ParameterToReduce.ActualValue;
71      if (!values.Any()) return base.Apply();
72
73      if (values.All(x => x is IntValue)) {
74        CalculateResult(values.OfType<IntValue>().Select(x => x.Value), values.First().GetType());
75      } else if (values.All(x => x is DoubleValue)) {
76        CalculateResult(values.OfType<DoubleValue>().Select(x => x.Value), values.First().GetType());
77      } else if (values.All(x => x is TimeSpanValue)) {
78        CalculateResult(values.OfType<TimeSpanValue>().Select(x => x.Value), values.First().GetType());
79      } else if (values.All(x => x is BoolValue)) {
80        CalculateResult(values.OfType<BoolValue>().Select(x => x.Value), values.First().GetType());
81      } else {
82        throw new ArgumentException(string.Format("Type {0} is not supported by the DataReducer.", values.First().GetType()));
83      }
84
85      return base.Apply();
86    }
87
88    #region integer reduction
89    private void CalculateResult(IEnumerable<int> values, Type targetType) {
90      int result;
91      switch (ReductionOperation.Value.Value) {
92        case ReductionOperations.Sum:
93          result = values.Sum();
94          break;
95        case ReductionOperations.Product:
96          result = values.Aggregate(1, (x, y) => x * y);
97          break;
98        case ReductionOperations.Count:
99          result = values.Count();
100          break;
101        case ReductionOperations.Min:
102          result = values.Min();
103          break;
104        case ReductionOperations.Max:
105          result = values.Max();
106          break;
107        case ReductionOperations.Avg:
108          result = (int)Math.Round(values.Average());
109          break;
110        case ReductionOperations.Assign:
111          result = values.Last();
112          break;
113        default:
114          throw new InvalidOperationException(string.Format("Operation {0} is not supported as ReductionOperation for type: {1}.", ReductionOperation.Value.Value, targetType));
115      }
116
117      IntValue target;
118      switch (TargetOperation.Value.Value) {
119        case ReductionOperations.Sum:
120          target = InitializeTarget<IntValue, int>(targetType, 0);
121          target.Value += result;
122          break;
123        case ReductionOperations.Product:
124          target = InitializeTarget<IntValue, int>(targetType, 1);
125          target.Value = target.Value * result;
126          break;
127        case ReductionOperations.Min:
128          target = InitializeTarget<IntValue, int>(targetType, int.MaxValue);
129          target.Value = Math.Min(target.Value, result);
130          break;
131        case ReductionOperations.Max:
132          target = InitializeTarget<IntValue, int>(targetType, int.MinValue);
133          target.Value = Math.Max(target.Value, result);
134          break;
135        case ReductionOperations.Avg:
136          target = InitializeTarget<IntValue, int>(targetType, result);
137          target.Value = (int)Math.Round((target.Value + result) / 2.0);
138          break;
139        case ReductionOperations.Assign:
140          target = InitializeTarget<IntValue, int>(targetType, 0);
141          target.Value = result;
142          break;
143        default:
144          throw new InvalidOperationException(string.Format("Operation {0} is not supported as TargetOperation for type: {1}.", TargetOperation.Value.Value, targetType));
145      }
146    }
147    #endregion
148    #region double reduction
149    private void CalculateResult(IEnumerable<double> values, Type targetType) {
150      double result;
151      switch (ReductionOperation.Value.Value) {
152        case ReductionOperations.Sum:
153          result = values.Sum();
154          break;
155        case ReductionOperations.Product:
156          result = values.Aggregate(1.0, (x, y) => x * y);
157          break;
158        case ReductionOperations.Count:
159          result = values.Count();
160          break;
161        case ReductionOperations.Min:
162          result = values.Min();
163          break;
164        case ReductionOperations.Max:
165          result = values.Max();
166          break;
167        case ReductionOperations.Avg:
168          result = values.Average();
169          break;
170        case ReductionOperations.Assign:
171          result = values.Last();
172          break;
173        default:
174          throw new InvalidOperationException(string.Format("Operation {0} is not supported as ReductionOperation for type: {1}.", ReductionOperation.Value.Value, targetType));
175      }
176
177      DoubleValue target;
178      switch (TargetOperation.Value.Value) {
179        case ReductionOperations.Sum:
180          target = InitializeTarget<DoubleValue, double>(targetType, 0.0);
181          target.Value += result;
182          break;
183        case ReductionOperations.Product:
184          target = InitializeTarget<DoubleValue, double>(targetType, 1.0);
185          target.Value = target.Value * result;
186          break;
187        case ReductionOperations.Min:
188          target = InitializeTarget<DoubleValue, double>(targetType, double.MaxValue);
189          target.Value = Math.Min(target.Value, result);
190          break;
191        case ReductionOperations.Max:
192          target = InitializeTarget<DoubleValue, double>(targetType, double.MinValue);
193          target.Value = Math.Max(target.Value, result);
194          break;
195        case ReductionOperations.Avg:
196          target = InitializeTarget<DoubleValue, double>(targetType, result);
197          target.Value = (target.Value + result) / 2.0;
198          break;
199        case ReductionOperations.Assign:
200          target = InitializeTarget<DoubleValue, double>(targetType, 0.0);
201          target.Value = result;
202          break;
203        default:
204          throw new InvalidOperationException(string.Format("Operation {0} is not supported as TargetOperation for type: {1}.", TargetOperation.Value.Value, targetType));
205      }
206    }
207    #endregion
208    #region TimeSpan reduction
209    private void CalculateResult(IEnumerable<TimeSpan> values, Type targetType) {
210      TimeSpan result;
211      switch (ReductionOperation.Value.Value) {
212        case ReductionOperations.Sum:
213          result = values.Aggregate(new TimeSpan(), (x, y) => x + y);
214          break;
215        case ReductionOperations.Min:
216          result = values.Min();
217          break;
218        case ReductionOperations.Max:
219          result = values.Max();
220          break;
221        case ReductionOperations.Avg:
222          result = TimeSpan.FromMilliseconds(values.Average(x => x.TotalMilliseconds));
223          break;
224        case ReductionOperations.Assign:
225          result = values.Last();
226          break;
227        default:
228          throw new InvalidOperationException(string.Format("Operation {0} is not supported as ReductionOperation for type: {1}.", ReductionOperation.Value.Value, targetType));
229      }
230
231      TimeSpanValue target;
232      switch (TargetOperation.Value.Value) {
233        case ReductionOperations.Sum:
234          target = InitializeTarget<TimeSpanValue, TimeSpan>(targetType, new TimeSpan());
235          target.Value += result;
236          break;
237        case ReductionOperations.Min:
238          target = InitializeTarget<TimeSpanValue, TimeSpan>(targetType, TimeSpan.MaxValue);
239          target.Value = target.Value < result ? target.Value : result;
240          break;
241        case ReductionOperations.Max:
242          target = InitializeTarget<TimeSpanValue, TimeSpan>(targetType, TimeSpan.MinValue);
243          target.Value = target.Value > result ? target.Value : result;
244          break;
245        case ReductionOperations.Avg:
246          target = InitializeTarget<TimeSpanValue, TimeSpan>(targetType, result);
247          target.Value = TimeSpan.FromMilliseconds((target.Value.TotalMilliseconds + result.TotalMilliseconds) / 2);
248          break;
249        case ReductionOperations.Assign:
250          target = InitializeTarget<TimeSpanValue, TimeSpan>(targetType, new TimeSpan());
251          target.Value = result;
252          break;
253        default:
254          throw new InvalidOperationException(string.Format("Operation {0} is not supported as TargetOperation for type: {1}.", TargetOperation.Value.Value, targetType));
255      }
256    }
257    #endregion
258    #region bool reduction
259    private void CalculateResult(IEnumerable<bool> values, Type targetType) {
260      bool result;
261      switch (ReductionOperation.Value.Value) {
262        case ReductionOperations.All:
263          result = values.All(x => x);
264          break;
265        case ReductionOperations.Any:
266          result = values.Any(x => x);
267          break;
268        default:
269          throw new InvalidOperationException(string.Format("Operation {0} is not supported as ReductionOperation for type: {1}.", ReductionOperation.Value.Value, targetType));
270      }
271
272      BoolValue target;
273      switch (TargetOperation.Value.Value) {
274        case ReductionOperations.Assign:
275          target = InitializeTarget<BoolValue, bool>(targetType, true);
276          target.Value = result;
277          break;
278        default:
279          throw new InvalidOperationException(string.Format("Operation {0} is not supported as TargetOperation for type: {1}.", TargetOperation.Value.Value, targetType));
280      }
281    }
282    #endregion
283
284    #region helpers
285    private T1 InitializeTarget<T1, T2>(Type targetType, T2 initialValue)
286      where T1 : ValueTypeValue<T2>
287      where T2 : struct {
288      T1 target = (T1)TargetParameter.ActualValue;
289      if (target == null) {
290        target = (T1)Activator.CreateInstance(targetType);
291        TargetParameter.ActualValue = target;
292        target.Value = initialValue;
293      }
294      return target;
295    }
296    #endregion
297  }
298}
Note: See TracBrowser for help on using the repository browser.