1  #region License Information


2  /* HeuristicLab


3  * Copyright (C) 20022019 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.Common;


26  using HeuristicLab.Core;


27  using HeuristicLab.Data;


28  using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;


29  using HeuristicLab.Parameters;


30  using HEAL.Attic;


31 


32 


33  namespace HeuristicLab.Problems.GeneticProgramming.Boolean {


34  [Item("Even Parity Problem", "The Boolean even parity genetic programming problem. See Koza, 1992, page 529 section 20.2 Symbolic Regression of EvenParity Functions")]


35  [Creatable(CreatableAttribute.Categories.GeneticProgrammingProblems, Priority = 900)]


36  [StorableType("76D6001D135F45FBBC79061EDAEE33A9")]


37  public sealed class EvenParityProblem : SymbolicExpressionTreeProblem {


38 


39  #region parameter names


40  private const string NumberOfBitsParameterName = "NumberOfBits";


41  #endregion


42 


43  #region Parameter Properties


44  public IFixedValueParameter<IntValue> NumberOfBitsParameter {


45  get { return (IFixedValueParameter<IntValue>)Parameters[NumberOfBitsParameterName]; }


46  }


47  #endregion


48 


49  #region Properties


50  public int NumberOfBits {


51  get { return NumberOfBitsParameter.Value.Value; }


52  set { NumberOfBitsParameter.Value.Value = value; }


53  }


54  #endregion


55 


56  public override bool Maximization {


57  get { return true; }


58  }


59 


60  #region item cloning and persistence


61  // persistence


62  [StorableConstructor]


63  private EvenParityProblem(StorableConstructorFlag _) : base(_) { }


64  [StorableHook(HookType.AfterDeserialization)]


65  private void AfterDeserialization() {


66  RegisterEventHandlers();


67  }


68 


69  // cloning


70  private EvenParityProblem(EvenParityProblem original, Cloner cloner)


71  : base(original, cloner) {


72  RegisterEventHandlers();


73  }


74  public override IDeepCloneable Clone(Cloner cloner) {


75  return new EvenParityProblem(this, cloner);


76  }


77  #endregion


78 


79  public EvenParityProblem()


80  : base() {


81  Parameters.Add(new FixedValueParameter<IntValue>(NumberOfBitsParameterName, "The number of bits for the input parameter for the even parity function", new IntValue(4)));


82 


83  var g = new SimpleSymbolicExpressionGrammar(); // will be replaced in update grammar


84  Encoding = new SymbolicExpressionTreeEncoding(g, 100, 17);


85 


86  UpdateGrammar();


87  RegisterEventHandlers();


88  }


89 


90  private void UpdateGrammar() {


91  var g = new SimpleSymbolicExpressionGrammar();


92  g.AddSymbols(new[] { "AND", "OR", "NAND", "NOR" }, 2, 2); // see Koza, 1992, page 529 section 20.2 Symbolic Regression of EvenParity Functions


93 


94  // add one terminal symbol for each bit


95  for (int i = 0; i < NumberOfBits; i++)


96  g.AddTerminalSymbol(string.Format("{0}", i));


97 


98  Encoding.Grammar = g;


99 


100  BestKnownQuality = Math.Pow(2, NumberOfBits); // this is a benchmark problem (the best achievable quality is known for a given number of bits)


101  }


102 


103 


104  public override double Evaluate(ISymbolicExpressionTree tree, IRandom random) {


105  if (NumberOfBits <= 0) throw new NotSupportedException("Number of bits must be larger than zero.");


106  if (NumberOfBits > 10) throw new NotSupportedException("Even parity does not support problems with number of bits > 10.");


107  var bs = Enumerable.Range(0, (int)Math.Pow(2, NumberOfBits));


108  var targets = bs.Select(b => CalcTarget(b, NumberOfBits));


109  var pred = Interpret(tree, bs);


110  return targets.Zip(pred, (t, p) => t == p ? 1 : 0).Sum(); // count number of correct predictions


111  }


112 


113  private static bool CalcTarget(int b, int numBits) {


114  bool res = GetBits(b, 0);


115  for (byte i = 1; i < numBits; i++)


116  res = res ^ GetBits(b, i); // XOR


117  return res;


118  }


119 


120  private static IEnumerable<bool> Interpret(ISymbolicExpressionTree tree, IEnumerable<int> bs) {


121  // skip programRoot and startSymbol


122  return InterpretRec(tree.Root.GetSubtree(0).GetSubtree(0), bs);


123  }


124 


125  private static IEnumerable<bool> InterpretRec(ISymbolicExpressionTreeNode node, IEnumerable<int> bs) {


126  Func<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode, Func<bool, bool, bool>, IEnumerable<bool>> binaryEval =


127  (left, right, f) => InterpretRec(left, bs).Zip(InterpretRec(right, bs), f);


128 


129  switch (node.Symbol.Name) {


130  case "AND": return binaryEval(node.GetSubtree(0), node.GetSubtree(1), (x, y) => x & y);


131  case "OR": return binaryEval(node.GetSubtree(0), node.GetSubtree(1), (x, y) => x  y);


132  case "NAND": return binaryEval(node.GetSubtree(0), node.GetSubtree(1), (x, y) => !(x & y));


133  case "NOR": return binaryEval(node.GetSubtree(0), node.GetSubtree(1), (x, y) => !(x  y));


134  default: {


135  byte bitPos;


136  if (byte.TryParse(node.Symbol.Name, out bitPos)) {


137  return bs.Select(b => GetBits(b, bitPos));


138  } else throw new NotSupportedException(string.Format("Found unexpected symbol {0}", node.Symbol.Name));


139  }


140  }


141  }


142 


143  private static bool GetBits(int b, byte bitPos) {


144  return (b & (1 << bitPos)) != 0;


145  }


146 


147  #region events


148  private void RegisterEventHandlers() {


149  NumberOfBitsParameter.Value.ValueChanged += (sender, args) => UpdateGrammar();


150  }


151  #endregion


152  }


153  }

