|
92 | 92 | <li><b>Generic problem divide/conquer</b>: Applies the <em>divide/conquer</em> pattern to a generic problem and returns a solution.</li>
|
93 | 93 | </ul>
|
94 | 94 | <h2>Key elements in divide/conquer</h2>
|
95 |
| -<p>The key elements of the <b>divide/conquer</b> pattern are: a <b>Divider</b> operation that divides a problem into subproblems, a <b>Solver</b> operation that is used to solve a subproblem, and a <b>Combiner</b> operation that is used to merge results of subproblems.</p> |
| 95 | +<p>The key elements of the <b>divide/conquer</b> pattern are: a <b>Divider</b> operation that divides a problem into subproblems, a <b>Predicate</b> that signals if a problem is already an elemental problem, a <b>Solver</b> operation that is used to solve a subproblem, and a <b>Combiner</b> operation that is used to merge results of subproblems.</p> |
96 | 96 | <p>A <b>Divider</b> is any C++ callable entity that takes a problem and returns a collection of subproblems. The returned collection of subproblems must be iterable. This allows returning any standard C++ sequence container, or even a plain array. When a problem cannot be divided into subproblems, the divider returns a collection with a single subproblem.</p>
|
| 97 | +<p>A <b>Predicate</b> is any C++ callable entity that takes a problem and returns a boolean value. Returning <em>true</em> means that the problem is already elemental and should be solved using the <b>Solver</b>. Returning <em>false</em> means that the problem needs to be divided into subproblems by the <b>Divider</b>.</p> |
97 | 98 | <p>The <b>Solver</b> is any C++ callable entity that takes a problem and turns it into a solution. The signature of the solver takes as argument a problem and returns the corresponding solution.</p>
|
98 | 99 | <p>The <b>Combiner</b> is any C++ callable entity capable to combine two solutions. The signature of the combiner takes two solutions and returns a new combined solution.</p>
|
99 | 100 | <h2>Details on divide/conquer variants</h2>
|
100 | 101 | <h3>Generic divide/conquer</h3>
|
101 | 102 | <p>The <b>divide/conquer</b> pattern takes an input problem and generates an output problem. </p><hr/>
|
102 |
| -<p> <b>Example</b>: Merge sort of an array. </p><div class="fragment"><div class="line">vector<int> v{1,3,5,7,2,4,6,8};</div><div class="line"></div><div class="line"><span class="keyword">struct </span>range {</div><div class="line"> std::vector<int>::iterator first, last;</div><div class="line"> <span class="keyword">auto</span> size()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> distance(first,last); }</div><div class="line">};</div><div class="line"></div><div class="line">std::vector<range> divide(range r) {</div><div class="line"> <span class="keyword">auto</span> mid = r.first + distance(r.first,r.last)/2;</div><div class="line"> <span class="keywordflow">return</span> { {r.first,mid} , {mid, r.last} };</div><div class="line">}</div><div class="line"></div><div class="line">range problem{begin(v), end(v)};</div><div class="line"></div><div class="line"><span class="keyword">auto</span> res = <a class="code" href="group__divide__conquer__pattern.html#gac2ebc10ffc0be3d2f8170e621dbdbca2">grppi::divide_conquer</a>(exec,</div><div class="line"> problem,</div><div class="line"> [](<span class="keyword">auto</span> r) -> vector<range> {</div><div class="line"> <span class="keywordflow">if</span> (1>=r.size()) { <span class="keywordflow">return</span> {r}; }</div><div class="line"> <span class="keywordflow">else</span> { <span class="keywordflow">return</span> divide(r); }</div><div class="line"> },</div><div class="line"> [](<span class="keyword">auto</span> x) { <span class="keywordflow">return</span> x; },</div><div class="line"> [](<span class="keyword">auto</span> r1, <span class="keyword">auto</span> r2) {</div><div class="line"> std::inplace_merge(r1.first, r1.last, r2.last);</div><div class="line"> <span class="keywordflow">return</span> range{r1.first, r2.last};</div><div class="line"> }</div><div class="line">);</div></div><!-- fragment --><hr/> |
| 103 | +<p> <b>Example</b>: Merge sort of an array. </p><div class="fragment"><div class="line">vector<int> v{1,3,5,7,2,4,6,8};</div><div class="line"></div><div class="line"><span class="keyword">struct </span>range {</div><div class="line"> std::vector<int>::iterator first, last;</div><div class="line"> <span class="keyword">auto</span> size()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> distance(first,last); }</div><div class="line">};</div><div class="line"></div><div class="line">std::vector<range> divide(range r) {</div><div class="line"> <span class="keyword">auto</span> mid = r.first + distance(r.first,r.last)/2;</div><div class="line"> <span class="keywordflow">return</span> { {r.first,mid} , {mid, r.last} };</div><div class="line">}</div><div class="line"></div><div class="line">range problem{begin(v), end(v)};</div><div class="line"></div><div class="line"><span class="keyword">auto</span> res = <a class="code" href="group__divide__conquer__pattern.html#gac2ebc10ffc0be3d2f8170e621dbdbca2">grppi::divide_conquer</a>(exec,</div><div class="line"> problem,</div><div class="line"> [](<span class="keyword">auto</span> r) -> vector<range> { <span class="keywordflow">return</span> divide(r); },</div><div class="line"> [](<span class="keyword">auto</span> r) { <span class="keywordflow">return</span> r.size()<=1; },</div><div class="line"> [](<span class="keyword">auto</span> x) { <span class="keywordflow">return</span> x; },</div><div class="line"> [](<span class="keyword">auto</span> r1, <span class="keyword">auto</span> r2) {</div><div class="line"> std::inplace_merge(r1.first, r1.last, r2.last);</div><div class="line"> <span class="keywordflow">return</span> range{r1.first, r2.last};</div><div class="line"> }</div><div class="line">);</div></div><!-- fragment --><hr/> |
103 | 104 | </div></div><!-- contents -->
|
104 | 105 | <!-- start footer part -->
|
105 | 106 | <hr class="footer"/><address class="footer"><small>
|
|
0 commit comments