Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.GeneticProgramming/3.3/Boolean/MultiplexerProblem.cs @ 13163

Last change on this file since 13163 was 13163, checked in by gkronber, 8 years ago

#2472: adapted the multiplexer sample to use the specific implementation of the multiplexer problem instead of symbolic regression. Added best known solutions for the Boolean benchmark problems

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