Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 17749 was 17655, checked in by abeham, 4 years ago

#2521: adapted readonly of reference parameters

File size: 8.4 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 names
44    private const string NumberOfBitsParameterName = "NumberOfBits";
45    #endregion
46
47    #region Parameter Properties
48    public IFixedValueParameter<IntValue> NumberOfBitsParameter {
49      get { return (IFixedValueParameter<IntValue>)Parameters[NumberOfBitsParameterName]; }
50    }
51    #endregion
52
53    #region Properties
54    public int NumberOfBits {
55      get { return NumberOfBitsParameter.Value.Value; }
56      set { NumberOfBitsParameter.Value.Value = value; }
57    }
58    #endregion
59
60    #region item cloning and persistence
61    // persistence
62    [StorableConstructor]
63    private MultiplexerProblem(StorableConstructorFlag _) : base(_) { }
64    [StorableHook(HookType.AfterDeserialization)]
65    private void AfterDeserialization() {
66      RegisterEventHandlers();
67    }
68
69    // cloning
70    private MultiplexerProblem(MultiplexerProblem original, Cloner cloner)
71      : base(original, cloner) {
72      RegisterEventHandlers();
73    }
74    public override IDeepCloneable Clone(Cloner cloner) {
75      return new MultiplexerProblem(this, cloner);
76    }
77    #endregion
78
79
80    public MultiplexerProblem()
81      : base(new SymbolicExpressionTreeEncoding()) {
82      Maximization = true;
83      Parameters.Add(new FixedValueParameter<IntValue>(NumberOfBitsParameterName,
84        "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",
85        new IntValue(11)));
86
87      Encoding.TreeLength = 100;
88      Encoding.TreeDepth = 17;
89
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      Encoding.GrammarParameter.ReadOnly = GrammarRefParameter.ReadOnly = true;
113
114      BestKnownQuality = Math.Pow(2, NumberOfBits); // this is a benchmark problem (the best achievable quality is known for a given number of bits)
115      BestKnownQualityParameter.ReadOnly = true;
116    }
117
118
119    public override ISingleObjectiveEvaluationResult Evaluate(ISymbolicExpressionTree tree, IRandom random, CancellationToken cancellationToken) {
120      if (NumberOfBits <= 0) throw new NotSupportedException("Number of bits must be larger than zero.");
121      if (NumberOfBits > 37) throw new NotSupportedException("Multiplexer does not support problems with number of bits > 37.");
122      var bs = Enumerable.Range(0, (int)Math.Pow(2, NumberOfBits));
123      var addrBits = (int)Math.Log(NumberOfBits, 2); // largest power of two that fits into the number of bits
124      var inputBits = NumberOfBits - addrBits;
125      var targets = bs.Select(b => CalcTarget(b, addrBits, inputBits));
126      var pred = Interpret(tree, bs, (byte)addrBits);
127      var quality = targets.Zip(pred, (t, p) => t == p ? 1 : 0).Sum(); // count number of correct predictions
128
129      return new SingleObjectiveEvaluationResult(quality);
130    }
131
132    private bool CalcTarget(int b, int addrBits, int inputBits) {
133      Contract.Assert(addrBits > 0);
134      // calc addr
135      int addr = 0;
136      for (int i = addrBits - 1; i >= 0; i--) {
137        addr = addr << 1;
138        if (GetBits(b, (byte)i)) addr += 1;
139      }
140      if (addr <= inputBits)
141        return GetBits(b, (byte)(addrBits + addr));
142      else return false; // in case the number of bits is smaller then necessary we assume that the remaining lines are false
143    }
144
145    private static IEnumerable<bool> Interpret(ISymbolicExpressionTree tree, IEnumerable<int> bs, byte addrBits) {
146      // skip programRoot and startSymbol
147      return InterpretRec(tree.Root.GetSubtree(0).GetSubtree(0), bs, addrBits);
148    }
149
150
151    private static IEnumerable<bool> InterpretRec(ISymbolicExpressionTreeNode node, IEnumerable<int> bs, byte addrBits) {
152      Func<ISymbolicExpressionTreeNode, Func<bool, bool>, IEnumerable<bool>> unaryEval =
153        (child, f) => InterpretRec(child, bs, addrBits).Select(f);
154      Func<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode, Func<bool, bool, bool>, IEnumerable<bool>> binaryEval =
155        (left, right, f) => InterpretRec(left, bs, addrBits).Zip(InterpretRec(right, bs, addrBits), f);
156
157      switch (node.Symbol.Name) {
158        case "AND": return binaryEval(node.GetSubtree(0), node.GetSubtree(1), (x, y) => x & y);
159        case "OR": return binaryEval(node.GetSubtree(0), node.GetSubtree(1), (x, y) => x | y);
160        case "NOT": return unaryEval(node.GetSubtree(0), (x) => !x);
161        case "IF": return EvalIf(node.GetSubtree(0), node.GetSubtree(1), node.GetSubtree(2), bs, addrBits);
162        default: {
163            if (node.Symbol.Name[0] == 'a') {
164              byte bitPos;
165              if (byte.TryParse(node.Symbol.Name.Substring(1), out bitPos)) {
166                return bs.Select(b => GetBits(b, bitPos));
167              }
168            } else if (node.Symbol.Name[0] == 'd') {
169              byte bitPos;
170              if (byte.TryParse(node.Symbol.Name.Substring(1), out bitPos)) {
171                return bs.Select(b => GetBits(b, (byte)(bitPos + addrBits))); // offset of input line bits
172              }
173            }
174
175            throw new NotSupportedException(string.Format("Found unexpected symbol {0}", node.Symbol.Name));
176          }
177      }
178    }
179
180    private static IEnumerable<bool> EvalIf(ISymbolicExpressionTreeNode pred, ISymbolicExpressionTreeNode trueBranch, ISymbolicExpressionTreeNode falseBranch, IEnumerable<int> bs, byte addrBits) {
181      var preds = InterpretRec(pred, bs, addrBits).GetEnumerator();
182      var tB = InterpretRec(trueBranch, bs, addrBits).GetEnumerator();
183      var fB = InterpretRec(falseBranch, bs, addrBits).GetEnumerator();
184      // start enumerators
185
186      while (preds.MoveNext() & tB.MoveNext() & fB.MoveNext()) {
187        if (preds.Current) yield return tB.Current;
188        else yield return fB.Current;
189      }
190    }
191
192    private static bool GetBits(int b, byte bitPos) {
193      return (b & (1 << bitPos)) != 0;
194    }
195
196    #region events
197    private void RegisterEventHandlers() {
198      NumberOfBitsParameter.Value.ValueChanged += (sender, args) => UpdateGrammar();
199    }
200    #endregion
201  }
202}
Note: See TracBrowser for help on using the repository browser.