mc2lib
mcversi.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-2016, Marco Elver
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the
15  * distribution.
16  *
17  * * Neither the name of the software nor the names of its contributors
18  * may be used to endorse or promote products derived from this
19  * software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 #ifndef MC2LIB_MCVERSI_HPP_
35 #define MC2LIB_MCVERSI_HPP_
36 
37 #include <cassert>
38 #include <cstddef>
39 #include <random>
40 
41 #include "simplega.hpp"
42 
43 namespace mc2lib {
44 
49 namespace mcversi {
50 
54 template <class URNG, class RandInstTest, class MemOperation>
56  public:
57  explicit CrossoverMutate(double P_USEL, double P_BFA)
58  : P_USEL_(P_USEL), P_BFA_(P_BFA) {}
59 
60  void operator()(
61  URNG& urng, const RandInstTest& test1, const RandInstTest& test2,
62  float mutation_rate,
64  assert(test1.get().size() == test2.get().size());
65 
66  // Probability with which we unconditionally select a particular gene. We
67  // don't always just want to pick fitaddr operations, as surrounding
68  // operations may contribute to coverage or other timing effects.
69  std::bernoulli_distribution mem_unconditional_select(P_USEL_);
70 
71  const double faf1 = FitaddrFraction(test1);
72  const double faf2 = FitaddrFraction(test2);
73 
74  // Same rate as selecting a memory-operation.
75  std::bernoulli_distribution nonmem_select1(faf1 + P_USEL_ -
76  (faf1 * P_USEL_));
77  std::bernoulli_distribution nonmem_select2(faf2 + P_USEL_ -
78  (faf2 * P_USEL_));
79 
80  // Tiebreaker: If both are valid, pick one consistently and do not break up
81  // a good genome's dominant genes as they may interact in an imporant way.
82  const bool prefer_test2 = std::bernoulli_distribution(0.5)(urng);
83 
84  // In case both operations are invalid, probability with which we make a
85  // new operation with the address-set restricted to fitaddrs.
86  std::bernoulli_distribution new_from_fitaddrs(P_BFA_);
87  const auto all_fitaddrs = test1.fitaddrs() | test2.fitaddrs();
88 
89  auto child = test1.get();
90  std::size_t mutations = 0;
91 
92  for (std::size_t i = 0; i < child.size(); ++i) {
93  bool select1 = false;
94  bool select2 = false;
95 
96  auto mem_op1 = dynamic_cast<MemOperation*>(test1.get()[i].get());
97  auto mem_op2 = dynamic_cast<MemOperation*>(test2.get()[i].get());
98 
99  // Decide validity of genes
100  if (mem_op1 != nullptr) {
101  select1 = test1.fitaddrs().Contains(mem_op1->addr()) ||
102  mem_unconditional_select(urng);
103  } else {
104  select1 = nonmem_select1(urng);
105  }
106 
107  if (mem_op2 != nullptr) {
108  select2 = test2.fitaddrs().Contains(mem_op2->addr()) ||
109  mem_unconditional_select(urng);
110  } else {
111  select2 = nonmem_select2(urng);
112  }
113 
114  // Pick gene
115  if (select1 && select2) {
116  if (prefer_test2) {
117  child[i] = test2.get()[i];
118  }
119  } else if (!select1 && select2) {
120  child[i] = test2.get()[i];
121  } else if (!select1 && !select2) {
122  ++mutations;
123 
124  if (new_from_fitaddrs(urng)) {
125  // Make new random operation, but only select from set of
126  // fitaddrs.
127  child[i] = test1.MakeRandom(all_fitaddrs);
128  } else {
129  // By deciding to discard fit addresses, we control where the
130  // tests mutate, so that in the initial phases the good
131  // operations do not get mutated away.
132  //
133  child[i] = test1.MakeRandom();
134  }
135  } else {
136  assert(select1);
137  // child[i] is valid, don't do anything.
138  }
139  }
140 
141  auto result = RandInstTest(test1, test2, child);
142 
143  float cur_mutation =
144  static_cast<float>(mutations) / static_cast<float>(child.size());
145  if (cur_mutation < mutation_rate) {
146  // cur_mutation is the fraction of newly generated instructions, i.e.
147  // replaced non-dominant genes. We must mutate full mutation_rate
148  // again, as newly generated instructions are considered for mutation
149  // as well (redundant).
150  result.Mutate(mutation_rate);
151  } else {
152  // No mutation neccessary.
153  }
154 
155  container->push_back(std::move(result));
156  }
157 
158  private:
159  double P_USEL_;
160  double P_BFA_;
161 
162  double FitaddrFraction(const RandInstTest& rit) {
163  std::size_t mem_ops = 0;
164  std::size_t fitaddr_ops = 0;
165 
166  for (const auto& op : rit.get()) {
167  auto mem_op = dynamic_cast<MemOperation*>(op.get());
168  if (mem_op != nullptr) {
169  ++mem_ops;
170  if (rit.fitaddrs().Contains(mem_op->addr())) {
171  ++fitaddr_ops;
172  }
173  }
174  }
175 
176  return static_cast<double>(fitaddr_ops) / static_cast<double>(mem_ops);
177  }
178 };
179 
180 } // namespace mcversi
181 } // namespace mc2lib
182 
183 #endif /* MCVERSI_HPP_ */
184 
185 /* vim: set ts=2 sts=2 sw=2 et : */
double P_USEL_
Definition: mcversi.hpp:159
double P_BFA_
Definition: mcversi.hpp:160
Definition: cats.hpp:47
void operator()(URNG &urng, const RandInstTest &test1, const RandInstTest &test2, float mutation_rate, typename simplega::GenePool< RandInstTest >::Population *container)
Definition: mcversi.hpp:60
std::list< GenomeT > Population
Definition: simplega.hpp:232
MemOp< Backend, EvtStateCats > MemOperation
Definition: armv7.hpp:212
Definition: mcversi.hpp:55
CrossoverMutate(double P_USEL, double P_BFA)
Definition: mcversi.hpp:57
double FitaddrFraction(const RandInstTest &rit)
Definition: mcversi.hpp:162