Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2521_ProblemRefactoring/HeuristicLab.Problems.GeneticProgramming/3.3/Boolean/MultiplexerProblem.cs

Last change on this file was 17778, checked in by abeham, 4 years ago

#2521: working on refactoring

File size: 8.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 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.Diagnostics.Contracts;
25using System.Linq;
26using System.Threading;
27using HEAL.Attic;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30using HeuristicLab.Data;
31using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
32using HeuristicLab.Optimization;
33using HeuristicLab.Parameters;
34
35
36namespace HeuristicLab.Problems.GeneticProgramming.Boolean {
37  [Item("Multiplexer Problem (MUX)",
38    "The Boolean multiplexer genetic programming problem. See Koza 1992, page 171, section 7.4.1 11-multiplexer.")]
39  [Creatable(CreatableAttribute.Categories.GeneticProgrammingProblems, Priority = 900)]
40  [StorableType("6DFE64E4-3968-446F-AE3D-FAF13C18930C")]
41  public sealed class MultiplexerProblem : SymbolicExpressionTreeProblem {
42
43    #region Parameter Properties
44    [Storable] public IFixedValueParameter<IntValue> NumberOfBitsParameter { get; private set; }
45    #endregion
46
47    #region Properties
48    public int NumberOfBits {
49      get { return NumberOfBitsParameter.Value.Value; }
50      set { NumberOfBitsParameter.Value.Value = value; }
51    }
52    #endregion
53
54    #region item cloning and persistence
55    // persistence
56    [StorableConstructor]
57    private MultiplexerProblem(StorableConstructorFlag _) : base(_) { }
58    [StorableHook(HookType.AfterDeserialization)]
59    private void AfterDeserialization() {
60      RegisterEventHandlers();
61    }
62
63    // cloning
64    private MultiplexerProblem(MultiplexerProblem original, Cloner cloner)
65      : base(original, cloner) {
66      NumberOfBitsParameter = cloner.Clone(original.NumberOfBitsParameter);
67      RegisterEventHandlers();
68    }
69    public override IDeepCloneable Clone(Cloner cloner) {
70      return new MultiplexerProblem(this, cloner);
71    }
72    #endregion
73
74
75    public MultiplexerProblem()
76      : base(new SymbolicExpressionTreeEncoding()) {
77      Maximization = true;
78      Parameters.Add(NumberOfBitsParameter = new FixedValueParameter<IntValue>("NumberOfBits",
79        "The number of bits for the input parameter for the multiplexer function. This is the sum of the number of address bits and the number of input lines. E.g. the 11-MUX has 3 address bits and 8 input lines",
80        new IntValue(11)));
81
82      Encoding.TreeLength = 100;
83      Encoding.TreeDepth = 17;
84
85      UpdateGrammar();
86      RegisterEventHandlers();
87    }
88
89    private void UpdateGrammar() {
90      var g = new SimpleSymbolicExpressionGrammar();
91      g.AddSymbols(new[] { "AND", "OR" }, 2, 2); // See Koza 1992, page 171, section 7.4.1 11-multiplexer
92      g.AddSymbols(new[] { "NOT" }, 1, 1);
93      g.AddSymbols(new[] { "IF" }, 3, 3);
94
95      // find the number of address lines and input lines
96      // e.g. 11-MUX: 3 addrBits + 8 input bits
97
98      var addrBits = (int)Math.Log(NumberOfBits, 2); // largest power of two that fits into the number of bits
99      var inputBits = NumberOfBits - addrBits;
100
101      for (int i = 0; i < addrBits; i++)
102        g.AddTerminalSymbol(string.Format("a{0}", i));
103      for (int i = 0; i < inputBits; i++)
104        g.AddTerminalSymbol(string.Format("d{0}", i));
105
106      Encoding.Grammar = g;
107      Encoding.GrammarParameter.ReadOnly = GrammarRefParameter.ReadOnly = true;
108
109      BestKnownQuality = Math.Pow(2, NumberOfBits); // this is a benchmark problem (the best achievable quality is known for a given number of bits)
110      BestKnownQualityParameter.ReadOnly = true;
111    }
112
113
114    public override ISingleObjectiveEvaluationResult Evaluate(ISymbolicExpressionTree tree, IRandom random, CancellationToken cancellationToken) {
115      if (NumberOfBits <= 0) throw new NotSupportedException("Number of bits must be larger than zero.");
116      if (NumberOfBits > 37) throw new NotSupportedException("Multiplexer does not support problems with number of bits > 37.");
117      var bs = Enumerable.Range(0, (int)Math.Pow(2, NumberOfBits));
118      var addrBits = (int)Math.Log(NumberOfBits, 2); // largest power of two that fits into the number of bits
119      var inputBits = NumberOfBits - addrBits;
120      var targets = bs.Select(b => CalcTarget(b, addrBits, inputBits));
121      var pred = Interpret(tree, bs, (byte)addrBits);
122      var quality = targets.Zip(pred, (t, p) => t == p ? 1 : 0).Sum(); // count number of correct predictions
123
124      return new SingleObjectiveEvaluationResult(quality);
125    }
126
127    private bool CalcTarget(int b, int addrBits, int inputBits) {
128      Contract.Assert(addrBits > 0);
129      // calc addr
130      int addr = 0;
131      for (int i = addrBits - 1; i >= 0; i--) {
132        addr = addr << 1;
133        if (GetBits(b, (byte)i)) addr += 1;
134      }
135      if (addr <= inputBits)
136        return GetBits(b, (byte)(addrBits + addr));
137      else return false; // in case the number of bits is smaller then necessary we assume that the remaining lines are false
138    }
139
140    private static IEnumerable<bool> Interpret(ISymbolicExpressionTree tree, IEnumerable<int> bs, byte addrBits) {
141      // skip programRoot and startSymbol
142      return InterpretRec(tree.Root.GetSubtree(0).GetSubtree(0), bs, addrBits);
143    }
144
145
146    private static IEnumerable<bool> InterpretRec(ISymbolicExpressionTreeNode node, IEnumerable<int> bs, byte addrBits) {
147      Func<ISymbolicExpressionTreeNode, Func<bool, bool>, IEnumerable<bool>> unaryEval =
148        (child, f) => InterpretRec(child, bs, addrBits).Select(f);
149      Func<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode, Func<bool, bool, bool>, IEnumerable<bool>> binaryEval =
150        (left, right, f) => InterpretRec(left, bs, addrBits).Zip(InterpretRec(right, bs, addrBits), f);
151
152      switch (node.Symbol.Name) {
153        case "AND": return binaryEval(node.GetSubtree(0), node.GetSubtree(1), (x, y) => x & y);
154        case "OR": return binaryEval(node.GetSubtree(0), node.GetSubtree(1), (x, y) => x | y);
155        case "NOT": return unaryEval(node.GetSubtree(0), (x) => !x);
156        case "IF": return EvalIf(node.GetSubtree(0), node.GetSubtree(1), node.GetSubtree(2), bs, addrBits);
157        default: {
158            if (node.Symbol.Name[0] == 'a') {
159              byte bitPos;
160              if (byte.TryParse(node.Symbol.Name.Substring(1), out bitPos)) {
161                return bs.Select(b => GetBits(b, bitPos));
162              }
163            } else if (node.Symbol.Name[0] == 'd') {
164              byte bitPos;
165              if (byte.TryParse(node.Symbol.Name.Substring(1), out bitPos)) {
166                return bs.Select(b => GetBits(b, (byte)(bitPos + addrBits))); // offset of input line bits
167              }
168            }
169
170            throw new NotSupportedException(string.Format("Found unexpected symbol {0}", node.Symbol.Name));
171          }
172      }
173    }
174
175    private static IEnumerable<bool> EvalIf(ISymbolicExpressionTreeNode pred, ISymbolicExpressionTreeNode trueBranch, ISymbolicExpressionTreeNode falseBranch, IEnumerable<int> bs, byte addrBits) {
176      var preds = InterpretRec(pred, bs, addrBits).GetEnumerator();
177      var tB = InterpretRec(trueBranch, bs, addrBits).GetEnumerator();
178      var fB = InterpretRec(falseBranch, bs, addrBits).GetEnumerator();
179      // start enumerators
180
181      while (preds.MoveNext() & tB.MoveNext() & fB.MoveNext()) {
182        if (preds.Current) yield return tB.Current;
183        else yield return fB.Current;
184      }
185    }
186
187    private static bool GetBits(int b, byte bitPos) {
188      return (b & (1 << bitPos)) != 0;
189    }
190
191    #region events
192    private void RegisterEventHandlers() {
193      NumberOfBitsParameter.Value.ValueChanged += (sender, args) => UpdateGrammar();
194    }
195    #endregion
196  }
197}
Note: See TracBrowser for help on using the repository browser.