1  #region License Information


2  /* HeuristicLab


3  * Copyright (C) 20022012 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 


22  using System;


23  using System.Collections.Generic;


24  using System.Linq;


25  using HeuristicLab.Collections;


26  using HeuristicLab.Common;


27  using HeuristicLab.Core;


28  using HeuristicLab.Data;


29  using HeuristicLab.Parameters;


30  using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;


31 


32  namespace HeuristicLab.Operators {


33  /// <summary>


34  /// Selects one of its branches (if there are any) given a list of relative probabilities.


35  /// </summary>


36  [Item("StochasticMultiBranch", "Selects one of its branches (if there are any) given a list of relative probabilities.")]


37  [StorableClass]


38  public abstract class StochasticMultiBranch<T> : CheckedMultiOperator<T> where T : class, IOperator {


39  /// <summary>


40  /// Should return true if the StochasticMultiOperator should create a new child operation with the selected successor


41  /// or if it should create a new operation. If you need to shield the parameters of the successor you should return true here.


42  /// </summary>


43  protected abstract bool CreateChildOperation { get; }


44 


45  public ValueLookupParameter<DoubleArray> ProbabilitiesParameter {


46  get { return (ValueLookupParameter<DoubleArray>)Parameters["Probabilities"]; }


47  }


48  public ILookupParameter<IRandom> RandomParameter {


49  get { return (ILookupParameter<IRandom>)Parameters["Random"]; }


50  }


51  public ValueParameter<BoolValue> TraceSelectedOperatorParameter {


52  get { return (ValueParameter<BoolValue>)Parameters["TraceSelectedOperator"]; }


53  }


54  public LookupParameter<StringValue> SelectedOperatorParameter {


55  get { return (LookupParameter<StringValue>)Parameters["SelectedOperator"]; }


56  }


57 


58  public DoubleArray Probabilities {


59  get { return ProbabilitiesParameter.Value; }


60  set { ProbabilitiesParameter.Value = value; }


61  }


62 


63  [StorableHook(HookType.AfterDeserialization)]


64  private void AfterDeserializationHook() {


65  #region Backwards Compatibility


66  if (!Parameters.ContainsKey("SelectedOperator")) {


67  Parameters.Add(new LookupParameter<StringValue>("SelectedOperator", "If the TraceSelectedOperator flag is set, the name of the operator is traced in this parameter."));


68  SelectedOperatorParameter.Hidden = false;


69  }


70  if (!Parameters.ContainsKey("TraceSelectedOperator")) {


71  Parameters.Add(new ValueParameter<BoolValue>("TraceSelectedOperator", "Indicates, if the selected operator should be traced.", new BoolValue(false)));


72  }


73  #endregion


74  }


75 


76  [StorableConstructor]


77  protected StochasticMultiBranch(bool deserializing) : base(deserializing) { }


78  protected StochasticMultiBranch(StochasticMultiBranch<T> original, Cloner cloner)


79  : base(original, cloner) {


80  }


81  /// <summary>


82  /// Initializes a new instance of <see cref="StochasticMultiOperator"/> with two parameters


83  /// (<c>Probabilities</c> and <c>Random</c>).


84  /// </summary>


85  public StochasticMultiBranch()


86  : base() {


87  Parameters.Add(new ValueLookupParameter<DoubleArray>("Probabilities", "The array of relative probabilities for each operator.", new DoubleArray()));


88  Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator to use."));


89  Parameters.Add(new LookupParameter<StringValue>("SelectedOperator", "If the TraceSelectedOperator flag is set, the name of the operator is traced in this parameter."));


90  Parameters.Add(new ValueParameter<BoolValue>("TraceSelectedOperator", "Indicates, if the selected operator should be traced.", new BoolValue(false)));


91  SelectedOperatorParameter.Hidden = false;


92  }


93 


94  protected override void Operators_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<T>> e) {


95  base.Operators_ItemsRemoved(sender, e);


96  if (Probabilities != null && Probabilities.Length > Operators.Count) {


97  List<double> probs = new List<double>(Probabilities.Cast<double>());


98  var sorted = e.Items.OrderByDescending(x => x.Index);


99  foreach (IndexedItem<T> item in sorted)


100  if (probs.Count > item.Index) probs.RemoveAt(item.Index);


101  Probabilities = new DoubleArray(probs.ToArray());


102  }


103  }


104 


105  protected override void Operators_ItemsAdded(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs<IndexedItem<T>> e) {


106  base.Operators_ItemsAdded(sender, e);


107  if (Probabilities != null && Probabilities.Length < Operators.Count) {


108  double avg = (Probabilities.Where(x => x > 0).Count() > 0) ? (Probabilities.Where(x => x > 0).Average()) : (1);


109  // add the average of all probabilities in the respective places (the new operators)


110  var added = e.Items.OrderBy(x => x.Index).ToList();


111  int insertCount = 0;


112  DoubleArray probs = new DoubleArray(Operators.Count);


113  for (int i = 0; i < Operators.Count; i++) {


114  if (insertCount < added.Count && i == added[insertCount].Index) {


115  probs[i] = avg;


116  insertCount++;


117  } else if (i  insertCount < Probabilities.Length) {


118  probs[i] = Probabilities[i  insertCount];


119  } else probs[i] = avg;


120  }


121  Probabilities = probs;


122  }


123  }


124 


125  /// <summary>


126  /// Applies an operator of the branches to the current scope with a


127  /// specific probability.


128  /// </summary>


129  /// <exception cref="InvalidOperationException">Thrown when the list of probabilites does not


130  /// match the number of operators, the list of selected operators is empty,


131  /// or all selected operators have zero probabitlity.</exception>


132  /// <returns>A new operation with the operator that was selected followed by the current operator's successor.</returns>


133  public override IOperation Apply() {


134  IRandom random = RandomParameter.ActualValue;


135  DoubleArray probabilities = ProbabilitiesParameter.ActualValue;


136  if (probabilities.Length != Operators.Count) {


137  throw new InvalidOperationException(Name + ": The list of probabilities has to match the number of operators");


138  }


139  IOperator successor = null;


140  int index = 1;


141  var checkedOperators = Operators.CheckedItems;


142  if (checkedOperators.Count() > 0) {


143  // select a random operator from the checked operators


144  double sum = (from indexedItem in checkedOperators select probabilities[indexedItem.Index]).Sum();


145  if (sum == 0) throw new InvalidOperationException(Name + ": All selected operators have zero probability.");


146  double r = random.NextDouble() * sum;


147  sum = 0;


148  foreach (var indexedItem in checkedOperators) {


149  sum += probabilities[indexedItem.Index];


150  if (sum > r) {


151  successor = indexedItem.Value;


152  index = indexedItem.Index;


153  break;


154  }


155  }


156  }


157  OperationCollection next = new OperationCollection(base.Apply());


158  if (successor != null) {


159  if (TraceSelectedOperatorParameter.Value.Value)


160  SelectedOperatorParameter.ActualValue = new StringValue(index + ": " + successor.Name);


161 


162  if (CreateChildOperation)


163  next.Insert(0, ExecutionContext.CreateChildOperation(successor));


164  else next.Insert(0, ExecutionContext.CreateOperation(successor));


165  } else {


166  if (TraceSelectedOperatorParameter.Value.Value)


167  SelectedOperatorParameter.ActualValue = new StringValue("");


168  }


169  return next;


170  }


171  }


172 


173  /// <summary>


174  /// Selects one of its branches (if there are any) given a list of relative probabilities.


175  /// </summary>


176  [Item("StochasticMultiBranch", "Selects one of its branches (if there are any) given a list of relative probabilities.")]


177  [StorableClass]


178  public class StochasticMultiBranch : StochasticMultiBranch<IOperator> {


179  [StorableConstructor]


180  protected StochasticMultiBranch(bool deserializing) : base(deserializing) { }


181  protected StochasticMultiBranch(StochasticMultiBranch original, Cloner cloner)


182  : base(original, cloner) {


183  }


184  public StochasticMultiBranch() { }


185 


186  public override IDeepCloneable Clone(Cloner cloner) {


187  return new StochasticMultiBranch(this, cloner);


188  }


189 


190  protected override bool CreateChildOperation {


191  get { return false; }


192  }


193  }


194  }

