GENEIAL  0.2=/
 All Classes Pages
MultiValueChromosomeNPointCrossover.hpp
1 #pragma once
2 
3 #include <geneial/core/operations/crossover/MultiValueChromosomeNPointCrossover.h>
4 #include <geneial/utility/Random.h>
5 
6 #include <set>
7 #include <algorithm>
8 #include <iterator>
9 
10 geneial_private_namespace(geneial)
11 {
12 geneial_private_namespace(operation)
13 {
14 geneial_private_namespace(crossover)
15 {
16 using ::geneial::population::Population;
17 using ::geneial::population::chromosome::MultiValueChromosome;
18 using ::geneial::operation::coupling::BaseCouplingOperation;
19 using ::geneial::utility::Random;
20 
21 geneial_export_namespace
22 {
23 
24 //TODO (bewo): reduce cyclomatic complexity...
25 template<typename VALUE_TYPE, typename FITNESS_TYPE>
26 typename BaseCrossoverOperation<FITNESS_TYPE>::crossover_result_set MultiValueChromosomeNPointCrossover<VALUE_TYPE,
27  FITNESS_TYPE>::doMultiValueCrossover(
28  const typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::const_ptr &mommy,
29  const typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::const_ptr &daddy) const
30 {
31 
32  typename BaseCouplingOperation<FITNESS_TYPE>::offspring_result_set resultset;
33 
34 
35  const unsigned int crossoverPoints = this->getCrossoverSettings().getCrossOverPoints();
36  const unsigned int totalWidth = this->getBuilderFactory().getSettings().getNum();
37 
38  //std::set<unsigned int> crossoverPositions;
39 
40  std::vector<unsigned int> crossoverPositions;
41  crossoverPositions.reserve(crossoverPoints);
42 
43 
44 
45  if (this->getCrossoverSettings().getWidthSetting()
46  == MultiValueChromosomeNPointCrossoverSettings::EQUIDISTANT_WIDTH)
47  {
48  const unsigned int equidistantwidth = totalWidth / (crossoverPoints + 1);
49 
50  for (unsigned int i = 0; i < crossoverPoints; i++)
51  {
52  crossoverPositions.emplace_back(i * equidistantwidth);
53  }
54 
55  }
56  else if (this->getCrossoverSettings().getWidthSetting()
57  == MultiValueChromosomeNPointCrossoverSettings::RANDOM_WIDTH
58  || this->getCrossoverSettings().getWidthSetting()
59  == MultiValueChromosomeNPointCrossoverSettings::RANDOM_MIN_WIDTH)
60  {
61 
62  unsigned int minWidth;
63  if (this->getCrossoverSettings().getWidthSetting()
64  == MultiValueChromosomeNPointCrossoverSettings::RANDOM_WIDTH)
65  {
66  minWidth = 1;
67  }
68  else
69  {
70  minWidth = this->getCrossoverSettings().getMinWidth();
71  }
72 
73  //TODO(bewo) make some assertions about minwidth, crossoverPositions and size
74 
75  const auto max = this->getBuilderFactory().getSettings().getNum();
76  while (crossoverPositions.size() < crossoverPoints)
77  {
78  const unsigned int rnd_pos = Random::generate<int>(0, max);
79  bool valid = true;
80 
81  valid &= rnd_pos >= minWidth; //ensure there is enough space on the interval boundaries
82  if (!valid)
83  {
84  continue;
85  }
86 
87  valid &= rnd_pos <= totalWidth - minWidth;
88  if (!valid)
89  {
90  continue;
91  }
92 
93  const auto pos = std::find(crossoverPositions.begin(), crossoverPositions.end(), rnd_pos);
94  valid &= pos == crossoverPositions.end(); //element is not contained within the set
95  if (!valid)
96  {
97  continue;
98  }
99 
100  const auto itlow = std::lower_bound(crossoverPositions.begin(), crossoverPositions.end(), rnd_pos);
101  const auto itup = std::upper_bound(crossoverPositions.begin(), crossoverPositions.end(), rnd_pos);
102  //is the picked element too near to another element already contained?
103  //ensure between two values there is enough width, i.e. either we have a lower or upper neighbor and the distance is correct or not.
104  valid &= itlow == crossoverPositions.end()
105  || (itlow != crossoverPositions.end() && rnd_pos - *itlow >= minWidth);
106  if (!valid)
107  {
108  continue;
109  }
110 
111  valid &= itup == crossoverPositions.end()
112  || (itup != crossoverPositions.end() && *itup - rnd_pos >= minWidth);
113  if (!valid)
114  {
115  continue;
116  }
117  crossoverPositions.emplace_back(rnd_pos);
118  }
119 
120  std::sort(crossoverPositions.begin(),crossoverPositions.end());
121  }
122 
123 
124  assert(crossoverPositions.size() == crossoverPoints);
125 
126  auto child_candidate = this->createChildCandidate();
127 
128  const auto &daddy_container = daddy->getContainer();
129  const auto &mommy_container = mommy->getContainer();
130  auto &child_container = child_candidate->getContainer();
131 
132  assert(daddy_container.size() == mommy_container.size());
133 
134  bool flip = true; //copy from ladies first.
135 
136  //push back to end so its ok, does not destroy sortedness
137  crossoverPositions.push_back(daddy_container.size());
138 
139  auto widthIterator = crossoverPositions.cbegin();
140 
141  unsigned int i = 0;
142 
143  for (; widthIterator != crossoverPositions.end(); ++widthIterator)
144  {
145  if (flip)
146  {
147  std::copy(mommy_container.begin() + i, mommy_container.begin() + *widthIterator, child_container.begin()+i);
148  }
149  else
150  {
151  std::copy(daddy_container.begin() + i, daddy_container.begin() + *widthIterator, child_container.begin()+i);
152  }
153  i = *widthIterator;
154  flip = !flip;
155  }
156  assert(child_container.size() == mommy_container.size());
157 
158  resultset.emplace_back(std::move(child_candidate));
159 
160  return std::move(resultset);
161 }
162 
163 } /* geneial_export_namespace */
164 } /* private namespace crossover */
165 } /* private namespace operation */
166 } /* private namespace geneial */