Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 16813 was 16813, checked in by mkommend, 5 years ago

#2521: Changed base ctor call in all GeneticProgrammingProblems.

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