<ahref="find__graph__symmetries_8cc.html">Go to the documentation of this file.</a><divclass="fragment"><divclass="line"><aid="l00001"name="l00001"></a><spanclass="lineno"> 1</span><spanclass="comment">// Copyright 2010-2021 Google LLC</span></div>
<divclass="line"><aid="l00002"name="l00002"></a><spanclass="lineno"> 2</span><spanclass="comment">// Licensed under the Apache License, Version 2.0 (the "License");</span></div>
<divclass="line"><aid="l00003"name="l00003"></a><spanclass="lineno"> 3</span><spanclass="comment">// you may not use this file except in compliance with the License.</span></div>
<divclass="line"><aid="l00004"name="l00004"></a><spanclass="lineno"> 4</span><spanclass="comment">// You may obtain a copy of the License at</span></div>
<divclass="line"><aid="l00008"name="l00008"></a><spanclass="lineno"> 8</span><spanclass="comment">// Unless required by applicable law or agreed to in writing, software</span></div>
<divclass="line"><aid="l00009"name="l00009"></a><spanclass="lineno"> 9</span><spanclass="comment">// distributed under the License is distributed on an "AS IS" BASIS,</span></div>
<divclass="line"><aid="l00010"name="l00010"></a><spanclass="lineno"> 10</span><spanclass="comment">// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div>
<divclass="line"><aid="l00011"name="l00011"></a><spanclass="lineno"> 11</span><spanclass="comment">// See the License for the specific language governing permissions and</span></div>
<divclass="line"><aid="l00012"name="l00012"></a><spanclass="lineno"> 12</span><spanclass="comment">// limitations under the License.</span></div>
<divclass="line"><aid="l00042"name="l00042"></a><spanclass="lineno"> 42</span><spanclass="stringliteral">"Tweak the algorithm to try and minimize the support size"</span></div>
<divclass="line"><aid="l00043"name="l00043"></a><spanclass="lineno"> 43</span><spanclass="stringliteral">" of the generators produced. This may negatively impact the"</span></div>
<divclass="line"><aid="l00044"name="l00044"></a><spanclass="lineno"> 44</span><spanclass="stringliteral">" performance, but works great on the sat_holeXXX benchmarks"</span></div>
<divclass="line"><aid="l00045"name="l00045"></a><spanclass="lineno"> 45</span><spanclass="stringliteral">" to reduce the support size."</span>);</div>
<divclass="line"><aid="l00072"name="l00072"></a><spanclass="lineno"> 72</span><spanclass="comment">// Whether the "l1" list maps to "l2" under the permutation "permutation".</span></div>
<divclass="line"><aid="l00073"name="l00073"></a><spanclass="lineno"> 73</span><spanclass="comment">// This method uses a transient bitmask on all the elements, which</span></div>
<divclass="line"><aid="l00074"name="l00074"></a><spanclass="lineno"> 74</span><spanclass="comment">// should be entirely false before the call (and will be restored as such</span></div>
<divclass="line"><aid="l00075"name="l00075"></a><spanclass="lineno"> 75</span><spanclass="comment">// after it).</span></div>
<divclass="line"><aid="l00077"name="l00077"></a><spanclass="lineno"> 77</span><spanclass="comment">// TODO(user): Make this method support multi-elements (i.e. an element may</span></div>
<divclass="line"><aid="l00078"name="l00078"></a><spanclass="lineno"> 78</span><spanclass="comment">// be repeated in the list), and see if that's sufficient to make the whole</span></div>
<divclass="line"><aid="l00079"name="l00079"></a><spanclass="lineno"> 79</span><spanclass="comment">// graph symmetry finder support multi-arcs.</span></div>
<divclass="line"><aid="l00085"name="l00085"></a><spanclass="lineno"> 85</span><spanclass="keywordtype">bool</span> match = <spanclass="keyword">true</span>;</div>
<divclass="line"><aid="l00114"name="l00114"></a><spanclass="lineno"> 114</span><spanclass="comment">// Set up an "unlimited" time limit by default.</span></div>
<divclass="line"><aid="l00120"name="l00120"></a><spanclass="lineno"> 120</span><spanclass="comment">// Compute the reverse adjacency lists.</span></div>
<divclass="line"><aid="l00121"name="l00121"></a><spanclass="lineno"> 121</span><spanclass="comment">// First pass: compute the total in-degree of all nodes and put it in</span></div>
<divclass="line"><aid="l00122"name="l00122"></a><spanclass="lineno"> 122</span><spanclass="comment">// reverse_adj_list_index (shifted by two; see below why).</span></div>
<divclass="line"><aid="l00129"name="l00129"></a><spanclass="lineno"> 129</span><spanclass="comment">// Second pass: apply a cumulative sum over reverse_adj_list_index.</span></div>
<divclass="line"><aid="l00130"name="l00130"></a><spanclass="lineno"> 130</span><spanclass="comment">// After that, reverse_adj_list contains:</span></div>
<divclass="line"><aid="l00135"name="l00135"></a><spanclass="lineno"> 135</span><spanclass="comment">// Third pass: populate "flattened_reverse_adj_lists", using</span></div>
<divclass="line"><aid="l00136"name="l00136"></a><spanclass="lineno"> 136</span><spanclass="comment">// reverse_adj_list_index[i] as a dynamic pointer to the yet-unpopulated</span></div>
<divclass="line"><aid="l00137"name="l00137"></a><spanclass="lineno"> 137</span><spanclass="comment">// area of the reverse adjacency list of node #i.</span></div>
<divclass="line"><aid="l00146"name="l00146"></a><spanclass="lineno"> 146</span><spanclass="comment">// The last pass shifted reverse_adj_list_index, so it's now as we want it:</span></div>
<divclass="line"><aid="l00166"name="l00166"></a><spanclass="lineno"> 166</span><spanclass="comment">// The graph was not symmetric: we must also check the incoming arcs</span></div>
<divclass="line"><aid="l00167"name="l00167"></a><spanclass="lineno"> 167</span><spanclass="comment">// to displaced nodes.</span></div>
<divclass="line"><aid="l00168"name="l00168"></a><spanclass="lineno"> 168</span><spanclass="keywordflow">for</span> (<spanclass="keyword">const</span><spanclass="keywordtype">int</span> base : permutation.<aclass="code hl_function"href="classoperations__research_1_1_dynamic_permutation.html#afc48707ddd63d0978b9cfcd17c704694">AllMappingsSrc</a>()) {</div>
<divclass="line"><aid="l00182"name="l00182"></a><spanclass="lineno"> 182</span><spanclass="comment">// Specialized subroutine, to avoid code duplication: see its call site</span></div>
<divclass="line"><aid="l00183"name="l00183"></a><spanclass="lineno"> 183</span><spanclass="comment">// and its self-explanatory code.</span></div>
<divclass="line"><aid="l00201"name="l00201"></a><spanclass="lineno"> 201</span><spanclass="comment">// Rename, for readability of the code below.</span></div>
<divclass="line"><aid="l00204"name="l00204"></a><spanclass="lineno"> 204</span><spanclass="comment">// This function is the main bottleneck of the whole algorithm. We count the</span></div>
<divclass="line"><aid="l00205"name="l00205"></a><spanclass="lineno"> 205</span><spanclass="comment">// number of blocks in the inner-most loops in num_operations. At the end we</span></div>
<divclass="line"><aid="l00206"name="l00206"></a><spanclass="lineno"> 206</span><spanclass="comment">// will multiply it by a factor to have some deterministic time that we will</span></div>
<divclass="line"><aid="l00207"name="l00207"></a><spanclass="lineno"> 207</span><spanclass="comment">// append to the deterministic time counter.</span></div>
<divclass="line"><aid="l00209"name="l00209"></a><spanclass="lineno"> 209</span><spanclass="comment">// TODO(user): We are really imprecise in our counting, but it is fine. We</span></div>
<divclass="line"><aid="l00210"name="l00210"></a><spanclass="lineno"> 210</span><spanclass="comment">// just need a way to enforce a deterministic limit on the computation effort.</span></div>
<divclass="line"><aid="l00213"name="l00213"></a><spanclass="lineno"> 213</span><spanclass="comment">// Assuming that the partition was refined based on the adjacency on</span></div>
<divclass="line"><aid="l00214"name="l00214"></a><spanclass="lineno"> 214</span><spanclass="comment">// parts [0 .. first_unrefined_part_index) already, we simply need to</span></div>
<divclass="line"><aid="l00215"name="l00215"></a><spanclass="lineno"> 215</span><spanclass="comment">// refine parts first_unrefined_part_index ... NumParts()-1, the latter bound</span></div>
<divclass="line"><aid="l00216"name="l00216"></a><spanclass="lineno"> 216</span><spanclass="comment">// being a moving target:</span></div>
<divclass="line"><aid="l00217"name="l00217"></a><spanclass="lineno"> 217</span><spanclass="comment">// When a part #p < first_unrefined_part_index gets modified, it's always</span></div>
<divclass="line"><aid="l00218"name="l00218"></a><spanclass="lineno"> 218</span><spanclass="comment">// split in two: itself, and a new part #p'. Since #p was already refined</span></div>
<divclass="line"><aid="l00219"name="l00219"></a><spanclass="lineno"> 219</span><spanclass="comment">// on, we only need to further refine on *one* of its two split parts.</span></div>
<divclass="line"><aid="l00220"name="l00220"></a><spanclass="lineno"> 220</span><spanclass="comment">// And this will be done because p'> first_unrefined_part_index.</span></div>
<divclass="line"><aid="l00222"name="l00222"></a><spanclass="lineno"> 222</span><spanclass="comment">// Thus, the following loop really does the full recursive refinement as</span></div>
<divclass="line"><aid="l00226"name="l00226"></a><spanclass="lineno"> 226</span> adjacency_directions.push_back(<spanclass="keyword">false</span>); <spanclass="comment">// Also look at incoming arcs.</span></div>
<divclass="line"><aid="l00232"name="l00232"></a><spanclass="lineno"> 232</span><spanclass="comment">// Count the aggregated degree of all nodes, only looking at arcs that</span></div>
<divclass="line"><aid="l00233"name="l00233"></a><spanclass="lineno"> 233</span><spanclass="comment">// come from/to the current part.</span></div>
<divclass="line"><aid="l00247"name="l00247"></a><spanclass="lineno"> 247</span><spanclass="comment">// Group the nodes by (nonzero) degree. Remember the maximum degree.</span></div>
<divclass="line"><aid="l00252"name="l00252"></a><spanclass="lineno"> 252</span> tmp_degree_[node] = 0; <spanclass="comment">// To clean up after us.</span></div>
<divclass="line"><aid="l00256"name="l00256"></a><spanclass="lineno"> 256</span> tmp_nodes_with_nonzero_degree.clear(); <spanclass="comment">// To clean up after us.</span></div>
<divclass="line"><aid="l00257"name="l00257"></a><spanclass="lineno"> 257</span><spanclass="comment">// For each degree, refine the partition by the set of nodes with that</span></div>
<divclass="line"><aid="l00260"name="l00260"></a><spanclass="lineno"> 260</span><spanclass="comment">// We use a manually tuned factor 3 because Refine() does quite a bit of</span></div>
<divclass="line"><aid="l00261"name="l00261"></a><spanclass="lineno"> 261</span><spanclass="comment">// operations for each node in its argument.</span></div>
<divclass="line"><aid="l00264"name="l00264"></a><spanclass="lineno"> 264</span> tmp_nodes_with_degree_[degree].clear(); <spanclass="comment">// To clean up after us.</span></div>
<divclass="line"><aid="l00269"name="l00269"></a><spanclass="lineno"> 269</span><spanclass="comment">// The coefficient was manually tuned (only on a few instances) so that the</span></div>
<divclass="line"><aid="l00270"name="l00270"></a><spanclass="lineno"> 270</span><spanclass="comment">// time is roughly correlated with seconds on a fast desktop computer from</span></div>
<divclass="line"><aid="l00282"name="l00282"></a><spanclass="lineno"> 282</span><spanclass="comment">// Explore the newly refined parts to gather all the new singletons.</span></div>
<divclass="line"><aid="l00287"name="l00287"></a><spanclass="lineno"> 287</span><spanclass="comment">// We may see the same singleton parent several times, so we guard them</span></div>
<divclass="line"><aid="l00288"name="l00288"></a><spanclass="lineno"> 288</span><spanclass="comment">// with the tmp_node_mask_ boolean vector.</span></div>
<divclass="line"><aid="l00309"name="l00309"></a><spanclass="lineno"> 309</span><spanclass="keywordflow">for</span> (<spanclass="keywordtype">int</span> c = 0; c < perm.<aclass="code hl_function"href="classoperations__research_1_1_sparse_permutation.html#a8c5fc5af6e649a82d169f61e4dab5e33">NumCycles</a>(); ++c) {</div>
<divclass="line"><aid="l00310"name="l00310"></a><spanclass="lineno"> 310</span><spanclass="comment">// TODO(user): use the global element->image iterator when it exists.</span></div>
<divclass="line"><aid="l00325"name="l00325"></a><spanclass="lineno"> 325</span><spanclass="comment">// Subroutine used by FindSymmetries(); see its call site. This finds and</span></div>
<divclass="line"><aid="l00326"name="l00326"></a><spanclass="lineno"> 326</span><spanclass="comment">// outputs (in "pruned_other_nodes") the list of all representatives (under</span></div>
<divclass="line"><aid="l00327"name="l00327"></a><spanclass="lineno"> 327</span><spanclass="comment">// "node_equivalence_classes") that are in the same part as</span></div>
<divclass="line"><aid="l00328"name="l00328"></a><spanclass="lineno"> 328</span><spanclass="comment">// "representative_node" in "partition"; other than "representative_node"</span></div>
<divclass="line"><aid="l00330"name="l00330"></a><spanclass="lineno"> 330</span><spanclass="comment">// "node_equivalence_classes" must be compatible with "partition", i.e. two</span></div>
<divclass="line"><aid="l00331"name="l00331"></a><spanclass="lineno"> 331</span><spanclass="comment">// nodes that are in the same equivalence class must also be in the same part.</span></div>
<divclass="line"><aid="l00333"name="l00333"></a><spanclass="lineno"> 333</span><spanclass="comment">// To do this in O(output size), we also need the</span></div>
<divclass="line"><aid="l00334"name="l00334"></a><spanclass="lineno"> 334</span><spanclass="comment">// "representatives_sorted_by_index_in_partition" data structure: the</span></div>
<divclass="line"><aid="l00335"name="l00335"></a><spanclass="lineno"> 335</span><spanclass="comment">// representatives of the nodes of the targeted part are contiguous in that</span></div>
<divclass="line"><aid="l00340"name="l00340"></a><spanclass="lineno"> 340</span> MergingPartition* node_equivalence_classes, <spanclass="comment">// Only for debugging.</span></div>
<divclass="line"><aid="l00344"name="l00344"></a><spanclass="lineno"> 344</span><spanclass="comment">// Iterate on all contiguous representatives after the initial one...</span></div>
<divclass="line"><aid="l00352"name="l00352"></a><spanclass="lineno"> 352</span><spanclass="comment">// ... and then on all contiguous representatives *before* it.</span></div>
<divclass="line"><aid="l00361"name="l00361"></a><spanclass="lineno"> 361</span><spanclass="comment">// This code is a bit tricky, so we check that we're doing it right, by</span></div>
<divclass="line"><aid="l00362"name="l00362"></a><spanclass="lineno"> 362</span><spanclass="comment">// comparing its output to the brute-force, O(Part size) version.</span></div>
<divclass="line"><aid="l00363"name="l00363"></a><spanclass="lineno"> 363</span><spanclass="comment">// This also (partly) verifies that</span></div>
<divclass="line"><aid="l00364"name="l00364"></a><spanclass="lineno"> 364</span><spanclass="comment">// "representatives_sorted_by_index_in_partition" is what it claims it is.</span></div>
<divclass="line"><aid="l00373"name="l00373"></a><spanclass="lineno"> 373</span><spanclass="keywordflow">for</span> (<spanclass="keywordtype">int</span>& x : expected_output) x = node_equivalence_classes->GetRoot(x);</div>
<divclass="line"><aid="l00398"name="l00398"></a><spanclass="lineno"> 398</span><spanclass="comment">// Break all inherent asymmetries in the graph.</span></div>
<divclass="line"><aid="l00406"name="l00406"></a><spanclass="lineno"> 406</span><spanclass="stringliteral">"During the initial refinement."</span>);</div>
<divclass="line"><aid="l00416"name="l00416"></a><spanclass="lineno"> 416</span><spanclass="comment">// To find all permutations of the Graph that satisfy the current partition,</span></div>
<divclass="line"><aid="l00417"name="l00417"></a><spanclass="lineno"> 417</span><spanclass="comment">// we pick an element v that is not in a singleton part, and we</span></div>
<divclass="line"><aid="l00418"name="l00418"></a><spanclass="lineno"> 418</span><spanclass="comment">// split the search in two phases:</span></div>
<divclass="line"><aid="l00419"name="l00419"></a><spanclass="lineno"> 419</span><spanclass="comment">// 1) Find (the generators of) all permutations that keep v invariant.</span></div>
<divclass="line"><aid="l00420"name="l00420"></a><spanclass="lineno"> 420</span><spanclass="comment">// 2) For each w in PartOf(v) such that w != v:</span></div>
<divclass="line"><aid="l00421"name="l00421"></a><spanclass="lineno"> 421</span><spanclass="comment">// find *one* permutation that maps v to w, if it exists.</span></div>
<divclass="line"><aid="l00422"name="l00422"></a><spanclass="lineno"> 422</span><spanclass="comment">// if it does exists, add this to the generators.</span></div>
<divclass="line"><aid="l00426"name="l00426"></a><spanclass="lineno"> 426</span><spanclass="comment">// Since we can't really use true recursion because it will be too deep for</span></div>
<divclass="line"><aid="l00427"name="l00427"></a><spanclass="lineno"> 427</span><spanclass="comment">// the stack, we implement it iteratively. To do that, we unroll 1):</span></div>
<divclass="line"><aid="l00428"name="l00428"></a><spanclass="lineno"> 428</span><spanclass="comment">// the "invariant dive" is a single pass that successively refines the node</span></div>
<divclass="line"><aid="l00429"name="l00429"></a><spanclass="lineno"> 429</span><spanclass="comment">// base_partition with elements from non-singleton parts (the 'invariant</span></div>
<divclass="line"><aid="l00430"name="l00430"></a><spanclass="lineno"> 430</span><spanclass="comment">// node'), until all parts are singletons.</span></div>
<divclass="line"><aid="l00431"name="l00431"></a><spanclass="lineno"> 431</span><spanclass="comment">// We remember which nodes we picked as invariants, and also the successive</span></div>
<divclass="line"><aid="l00432"name="l00432"></a><spanclass="lineno"> 432</span><spanclass="comment">// partition sizes as we refine it, to allow us to backtrack.</span></div>
<divclass="line"><aid="l00433"name="l00433"></a><spanclass="lineno"> 433</span><spanclass="comment">// Then we'll perform 2) in the reverse order, backtracking the stack from 1)</span></div>
<divclass="line"><aid="l00434"name="l00434"></a><spanclass="lineno"> 434</span><spanclass="comment">// as using another dedicated stack for the search (see below).</span></div>
<divclass="line"><aid="l00444"name="l00444"></a><spanclass="lineno"> 444</span><spanclass="comment">// TODO(user): experiment with, and briefly describe the results of various</span></div>
<divclass="line"><aid="l00445"name="l00445"></a><spanclass="lineno"> 445</span><spanclass="comment">// algorithms for picking the invariant node:</span></div>
<divclass="line"><aid="l00446"name="l00446"></a><spanclass="lineno"> 446</span><spanclass="comment">// - random selection</span></div>
<divclass="line"><aid="l00448"name="l00448"></a><spanclass="lineno"> 448</span><spanclass="comment">// - enumerate by part index; or by part size</span></div>
<divclass="line"><aid="l00462"name="l00462"></a><spanclass="lineno"> 462</span><spanclass="stringliteral">"During the invariant dive."</span>);</div>
<divclass="line"><aid="l00469"name="l00469"></a><spanclass="lineno"> 469</span><spanclass="comment">// Now we've dived to the bottom: we're left with the identity permutation,</span></div>
<divclass="line"><aid="l00470"name="l00470"></a><spanclass="lineno"> 470</span><spanclass="comment">// which we don't need as a generator. We move on to phase 2).</span></div>
<divclass="line"><aid="l00475"name="l00475"></a><spanclass="lineno"> 475</span><spanclass="comment">// Backtrack the last step of 1) (the invariant dive).</span></div>
<divclass="line"><aid="l00487"name="l00487"></a><spanclass="lineno"> 487</span><spanclass="comment">// Now we'll try to map "root_node" to all image nodes that seem compatible</span></div>
<divclass="line"><aid="l00488"name="l00488"></a><spanclass="lineno"> 488</span><spanclass="comment">// and that aren't "root_node" itself.</span></div>
<divclass="line"><aid="l00490"name="l00490"></a><spanclass="lineno"> 490</span><spanclass="comment">// Doing so, we're able to detect potential bad (or good) matches by</span></div>
<divclass="line"><aid="l00491"name="l00491"></a><spanclass="lineno"> 491</span><spanclass="comment">// refining the 'base' partition with "root_node"; and refining the</span></div>
<divclass="line"><aid="l00492"name="l00492"></a><spanclass="lineno"> 492</span><spanclass="comment">// 'image' partition (which represents the partition of images nodes,</span></div>
<divclass="line"><aid="l00493"name="l00493"></a><spanclass="lineno"> 493</span><spanclass="comment">// i.e. the nodes after applying the currently implicit permutation)</span></div>
<divclass="line"><aid="l00494"name="l00494"></a><spanclass="lineno"> 494</span><spanclass="comment">// with that candidate image node: if the two partitions don't match, then</span></div>
<divclass="line"><aid="l00495"name="l00495"></a><spanclass="lineno"> 495</span><spanclass="comment">// the candidate image isn't compatible.</span></div>
<divclass="line"><aid="l00496"name="l00496"></a><spanclass="lineno"> 496</span><spanclass="comment">// If the partitions do match, we might either find the underlying</span></div>
<divclass="line"><aid="l00497"name="l00497"></a><spanclass="lineno"> 497</span><spanclass="comment">// permutation directly, or we might need to further try and map other</span></div>
<divclass="line"><aid="l00498"name="l00498"></a><spanclass="lineno"> 498</span><spanclass="comment">// nodes to their image: this is a recursive search with backtracking.</span></div>
<divclass="line"><aid="l00500"name="l00500"></a><spanclass="lineno"> 500</span><spanclass="comment">// The potential images of root_node are the nodes in its part. They can be</span></div>
<divclass="line"><aid="l00501"name="l00501"></a><spanclass="lineno"> 501</span><spanclass="comment">// pruned by the already computed equivalence classes.</span></div>
<divclass="line"><aid="l00502"name="l00502"></a><spanclass="lineno"> 502</span><spanclass="comment">// TODO(user): better elect the representative of each equivalence class</span></div>
<divclass="line"><aid="l00503"name="l00503"></a><spanclass="lineno"> 503</span><spanclass="comment">// in order to reduce the permutation support down the line</span></div>
<divclass="line"><aid="l00504"name="l00504"></a><spanclass="lineno"> 504</span><spanclass="comment">// TODO(user): Don't build a list; but instead use direct, inline iteration</span></div>
<divclass="line"><aid="l00505"name="l00505"></a><spanclass="lineno"> 505</span><spanclass="comment">// on the representatives in the while() loop below, to benefit from the</span></div>
<divclass="line"><aid="l00506"name="l00506"></a><spanclass="lineno"> 506</span><spanclass="comment">// incremental merging of the equivalence classes.</span></div>
<divclass="line"><aid="l00514"name="l00514"></a><spanclass="lineno"> 514</span><spanclass="comment">// Try to map "root_node" to all of its potential images. For each image,</span></div>
<divclass="line"><aid="l00515"name="l00515"></a><spanclass="lineno"> 515</span><spanclass="comment">// we only care about finding a single compatible permutation, if it exists.</span></div>
<divclass="line"><aid="l00531"name="l00531"></a><spanclass="lineno"> 531</span><spanclass="comment">// We found a permutation. We store it in the list of generators, and</span></div>
<divclass="line"><aid="l00532"name="l00532"></a><spanclass="lineno"> 532</span><spanclass="comment">// further prune out the remaining 'root' image candidates, taking into</span></div>
<divclass="line"><aid="l00533"name="l00533"></a><spanclass="lineno"> 533</span><spanclass="comment">// account the permutation we just found.</span></div>
<divclass="line"><aid="l00537"name="l00537"></a><spanclass="lineno"> 537</span><spanclass="comment">// HACK(user): to make sure that we keep root_image_node as the</span></div>
<divclass="line"><aid="l00538"name="l00538"></a><spanclass="lineno"> 538</span><spanclass="comment">// representant of its part, we temporarily move it to the front</span></div>
<divclass="line"><aid="l00539"name="l00539"></a><spanclass="lineno"> 539</span><spanclass="comment">// of the vector, then move it again to the back so that it gets</span></div>
<divclass="line"><aid="l00540"name="l00540"></a><spanclass="lineno"> 540</span><spanclass="comment">// deleted by the pop_back() below.</span></div>
<divclass="line"><aid="l00546"name="l00546"></a><spanclass="lineno"> 546</span><spanclass="comment">// Register it onto the permutations_displacing_node vector.</span></div>
<divclass="line"><aid="l00552"name="l00552"></a><spanclass="lineno"> 552</span><spanclass="comment">// Move the permutation to the generator list (this also transfers</span></div>
<divclass="line"><aid="l00560"name="l00560"></a><spanclass="lineno"> 560</span><spanclass="comment">// We keep track of the size of the orbit of 'root_node' under the</span></div>
<divclass="line"><aid="l00561"name="l00561"></a><spanclass="lineno"> 561</span><spanclass="comment">// current subgroup: this is one of the factors of the total group size.</span></div>
<divclass="line"><aid="l00562"name="l00562"></a><spanclass="lineno"> 562</span><spanclass="comment">// TODO(user): better, more complete explanation.</span></div>
<divclass="line"><aid="l00572"name="l00572"></a><spanclass="lineno"> 572</span><spanclass="stringliteral">"Some automorphisms were found, but probably not all."</span>);</div>
<divclass="line"><aid="l00578"name="l00578"></a><spanclass="lineno"> 578</span><spanclass="comment">// This method can be easily understood in the context of</span></div>
<divclass="line"><aid="l00579"name="l00579"></a><spanclass="lineno"> 579</span><spanclass="comment">// ConfirmFullMatchOrFindNextMappingDecision(): see its call sites.</span></div>
<divclass="line"><aid="l00580"name="l00580"></a><spanclass="lineno"> 580</span><spanclass="comment">// Knowing that we want to map some element of part #part_index of</span></div>
<divclass="line"><aid="l00581"name="l00581"></a><spanclass="lineno"> 581</span><spanclass="comment">// "base_partition" to part #part_index of "image_partition", pick the "best"</span></div>
<divclass="line"><aid="l00582"name="l00582"></a><spanclass="lineno"> 582</span><spanclass="comment">// such mapping, for the global search algorithm.</span></div>
<divclass="line"><aid="l00586"name="l00586"></a><spanclass="lineno"> 586</span><spanclass="comment">// As of pending CL 66620435, we've loosely tried three variants of</span></div>
<divclass="line"><aid="l00588"name="l00588"></a><spanclass="lineno"> 588</span><spanclass="comment">// 1) Just take the first element of the base part, map it to the first</span></div>
<divclass="line"><aid="l00589"name="l00589"></a><spanclass="lineno"> 589</span><spanclass="comment">// element of the image part.</span></div>
<divclass="line"><aid="l00590"name="l00590"></a><spanclass="lineno"> 590</span><spanclass="comment">// 2) Just take the first element of the base part, and map it to itself if</span></div>
<divclass="line"><aid="l00591"name="l00591"></a><spanclass="lineno"> 591</span><spanclass="comment">// possible, else map it to the first element of the image part</span></div>
<divclass="line"><aid="l00592"name="l00592"></a><spanclass="lineno"> 592</span><spanclass="comment">// 3) Scan all elements of the base parts until we find one that can map to</span></div>
<divclass="line"><aid="l00593"name="l00593"></a><spanclass="lineno"> 593</span><spanclass="comment">// itself. If there isn't one; we just fall back to the strategy 1).</span></div>
<divclass="line"><aid="l00595"name="l00595"></a><spanclass="lineno"> 595</span><spanclass="comment">// Variant 2) gives the best results on most benchmarks, in terms of speed,</span></div>
<divclass="line"><aid="l00596"name="l00596"></a><spanclass="lineno"> 596</span><spanclass="comment">// but 3) yields much smaller supports for the sat_holeXXX benchmarks, as</span></div>
<divclass="line"><aid="l00597"name="l00597"></a><spanclass="lineno"> 597</span><spanclass="comment">// long as it's combined with the other tweak enabled by</span></div>
<divclass="line"><aid="l00622"name="l00622"></a><spanclass="lineno"> 622</span><spanclass="comment">// TODO(user): refactor this method and its submethods into a dedicated class</span></div>
<divclass="line"><aid="l00623"name="l00623"></a><spanclass="lineno"> 623</span><spanclass="comment">// whose members will be ominously accessed by all the class methods; most</span></div>
<divclass="line"><aid="l00624"name="l00624"></a><spanclass="lineno"> 624</span><spanclass="comment">// notably the search state stack. This may improve readability.</span></div>
<divclass="line"><aid="l00639"name="l00639"></a><spanclass="lineno"> 639</span><spanclass="comment">// These will be used during the search. See their usage.</span></div>
<divclass="line"><aid="l00647"name="l00647"></a><spanclass="lineno"> 647</span><spanclass="comment">// Initialize the search: we can already distinguish "root_node" in the base</span></div>
<divclass="line"><aid="l00648"name="l00648"></a><spanclass="lineno"> 648</span><spanclass="comment">// partition. See the comment below.</span></div>
<divclass="line"><aid="l00653"name="l00653"></a><spanclass="lineno"> 653</span><spanclass="comment">// We inject the image node directly as the "remaining_pruned_image_nodes".</span></div>
<divclass="line"><aid="l00661"name="l00661"></a><spanclass="lineno"> 661</span><spanclass="comment">// When exploring a SearchState "ss", we're supposed to have:</span></div>
<divclass="line"><aid="l00662"name="l00662"></a><spanclass="lineno"> 662</span><spanclass="comment">// - A base_partition that has already been refined on ss->base_node.</span></div>
<divclass="line"><aid="l00663"name="l00663"></a><spanclass="lineno"> 663</span><spanclass="comment">// (base_singleton is the list of singletons created on the base</span></div>
<divclass="line"><aid="l00664"name="l00664"></a><spanclass="lineno"> 664</span><spanclass="comment">// partition during that refinement).</span></div>
<divclass="line"><aid="l00665"name="l00665"></a><spanclass="lineno"> 665</span><spanclass="comment">// - A non-empty list of potential image nodes (we'll try them in reverse</span></div>
<divclass="line"><aid="l00667"name="l00667"></a><spanclass="lineno"> 667</span><spanclass="comment">// - An image partition that hasn't been refined yet.</span></div>
<divclass="line"><aid="l00669"name="l00669"></a><spanclass="lineno"> 669</span><spanclass="comment">// Also, one should note that the base partition (before its refinement on</span></div>
<divclass="line"><aid="l00670"name="l00670"></a><spanclass="lineno"> 670</span><spanclass="comment">// base_node) was deemed compatible with the image partition as it is now.</span></div>
<divclass="line"><aid="l00671"name="l00671"></a><spanclass="lineno"> 671</span><spanclass="keyword">const</span> SearchState& ss = search_states_.back();</div>
<divclass="line"><aid="l00681"name="l00681"></a><spanclass="lineno"> 681</span><spanclass="comment">// Apply the decision: map base_node to image_node. Since base_partition</span></div>
<divclass="line"><aid="l00682"name="l00682"></a><spanclass="lineno"> 682</span><spanclass="comment">// was already refined on base_node, we just need to refine image_partition.</span></div>
<divclass="line"><aid="l00692"name="l00692"></a><spanclass="lineno"> 692</span><spanclass="comment">// Run some diagnoses on the two partitions. There are many outcomes, so</span></div>
<divclass="line"><aid="l00693"name="l00693"></a><spanclass="lineno"> 693</span><spanclass="comment">// it's a bit complicated:</span></div>
<divclass="line"><aid="l00694"name="l00694"></a><spanclass="lineno"> 694</span><spanclass="comment">// 1) The partitions are incompatible</span></div>
<divclass="line"><aid="l00695"name="l00695"></a><spanclass="lineno"> 695</span><spanclass="comment">// - Because of a straightfoward criterion (size mismatch).</span></div>
<divclass="line"><aid="l00696"name="l00696"></a><spanclass="lineno"> 696</span><spanclass="comment">// - Because they are both fully refined (i.e. singletons only), yet the</span></div>
<divclass="line"><aid="l00697"name="l00697"></a><spanclass="lineno"> 697</span><spanclass="comment">// permutation induced by them is not a graph automorpshim.</span></div>
<divclass="line"><aid="l00698"name="l00698"></a><spanclass="lineno"> 698</span><spanclass="comment">// 2) The partitions induce a permutation (all their non-singleton parts are</span></div>
<divclass="line"><aid="l00699"name="l00699"></a><spanclass="lineno"> 699</span><spanclass="comment">// identical), and this permutation is a graph automorphism.</span></div>
<divclass="line"><aid="l00700"name="l00700"></a><spanclass="lineno"> 700</span><spanclass="comment">// 3) The partitions need further refinement:</span></div>
<divclass="line"><aid="l00701"name="l00701"></a><spanclass="lineno"> 701</span><spanclass="comment">// - Because some non-singleton parts aren't equal in the base and image</span></div>
<divclass="line"><aid="l00703"name="l00703"></a><spanclass="lineno"> 703</span><spanclass="comment">// - Or because they are a full match (i.e. may induce a permutation,</span></div>
<divclass="line"><aid="l00704"name="l00704"></a><spanclass="lineno"> 704</span><spanclass="comment">// like in 2)), but the induced permutation isn't a graph automorphism.</span></div>
<divclass="line"><aid="l00735"name="l00735"></a><spanclass="lineno"> 735</span><spanclass="comment">// We have a permutation candidate!</span></div>
<divclass="line"><aid="l00736"name="l00736"></a><spanclass="lineno"> 736</span><spanclass="comment">// Note(user): we also deal with (extremely rare) false positives for</span></div>
<divclass="line"><aid="l00737"name="l00737"></a><spanclass="lineno"> 737</span><spanclass="comment">// "partitions_are_full_match" here: in case they aren't a full match,</span></div>
<divclass="line"><aid="l00738"name="l00738"></a><spanclass="lineno"> 738</span><spanclass="comment">// IsGraphAutomorphism() will catch that; and we'll simply deepen the</span></div>
<divclass="line"><aid="l00749"name="l00749"></a><spanclass="lineno"> 749</span><spanclass="comment">// We found a valid permutation. We can return it, but first we</span></div>
<divclass="line"><aid="l00750"name="l00750"></a><spanclass="lineno"> 750</span><spanclass="comment">// must restore the partitions to their original state.</span></div>
<divclass="line"><aid="l00765"name="l00765"></a><spanclass="lineno"> 765</span><spanclass="comment">// The permutation isn't a valid automorphism. Either the partitions were</span></div>
<divclass="line"><aid="l00766"name="l00766"></a><spanclass="lineno"> 766</span><spanclass="comment">// fully refined, and we deem them incompatible, or they weren't, and we</span></div>
<divclass="line"><aid="l00767"name="l00767"></a><spanclass="lineno"> 767</span><spanclass="comment">// consider them as 'not a full match'.</span></div>
<divclass="line"><aid="l00768"name="l00768"></a><spanclass="lineno"> 768</span><aclass="code hl_define"href="base_2logging_8h.html#afcaa7cadd41741bb855c2ada1d2ef927">VLOG</a>(4) <<<spanclass="stringliteral">"Permutation candidate isn't a valid automorphism."</span>;</div>
<divclass="line"><aid="l00770"name="l00770"></a><spanclass="lineno"> 770</span><spanclass="comment">// Fully refined: the partitions are incompatible.</span></div>
<divclass="line"><aid="l00776"name="l00776"></a><spanclass="lineno"> 776</span><spanclass="comment">// TODO(user, viger): try to get the non-singleton part from</span></div>
<divclass="line"><aid="l00777"name="l00777"></a><spanclass="lineno"> 777</span><spanclass="comment">// DynamicPermutation in O(1). On some graphs like the symmetry of the</span></div>
<divclass="line"><aid="l00778"name="l00778"></a><spanclass="lineno"> 778</span><spanclass="comment">// mip problem lectsched-4-obj.mps.gz, this take the majority of the</span></div>
<divclass="line"><aid="l00791"name="l00791"></a><spanclass="lineno"> 791</span><spanclass="comment">// The partitions are compatible, but we'll deepen the search on some</span></div>
<divclass="line"><aid="l00792"name="l00792"></a><spanclass="lineno"> 792</span><spanclass="comment">// non-singleton part. We can pick any base and image node in this case.</span></div>
<divclass="line"><aid="l00798"name="l00798"></a><spanclass="lineno"> 798</span><spanclass="comment">// Now we've fully diagnosed our partitions, and have already dealt with</span></div>
<divclass="line"><aid="l00799"name="l00799"></a><spanclass="lineno"> 799</span><spanclass="comment">// case 2). We're left to deal with 1) and 3).</span></div>
<divclass="line"><aid="l00801"name="l00801"></a><spanclass="lineno"> 801</span><spanclass="comment">// Case 1): partitions are incompatible.</span></div>
<divclass="line"><aid="l00804"name="l00804"></a><spanclass="lineno"> 804</span><spanclass="comment">// We invalidate the current image node, and prune the remaining image</span></div>
<divclass="line"><aid="l00805"name="l00805"></a><spanclass="lineno"> 805</span><spanclass="comment">// nodes. We might be left with no other image nodes, which means that</span></div>
<divclass="line"><aid="l00806"name="l00806"></a><spanclass="lineno"> 806</span><spanclass="comment">// we'll backtrack, i.e. pop our current SearchState and invalidate the</span></div>
<divclass="line"><aid="l00807"name="l00807"></a><spanclass="lineno"> 807</span><spanclass="comment">// 'current' image node of the upper SearchState (which might lead to us</span></div>
<divclass="line"><aid="l00808"name="l00808"></a><spanclass="lineno"> 808</span><spanclass="comment">// backtracking it, and so on).</span></div>
<divclass="line"><aid="l00814"name="l00814"></a><spanclass="lineno"> 814</span><spanclass="comment">// Find out and prune the remaining potential image nodes: there is</span></div>
<divclass="line"><aid="l00815"name="l00815"></a><spanclass="lineno"> 815</span><spanclass="comment">// no permutation that maps base_node -> image_node that is</span></div>
<divclass="line"><aid="l00816"name="l00816"></a><spanclass="lineno"> 816</span><spanclass="comment">// compatible with the current partition, so there can't be a</span></div>
<divclass="line"><aid="l00817"name="l00817"></a><spanclass="lineno"> 817</span><spanclass="comment">// permutation that maps base_node -> X either, for all X in the orbit</span></div>
<divclass="line"><aid="l00818"name="l00818"></a><spanclass="lineno"> 818</span><spanclass="comment">// of 'image_node' under valid permutations compatible with the</span></div>
<divclass="line"><aid="l00819"name="l00819"></a><spanclass="lineno"> 819</span><spanclass="comment">// current partition. Ditto for other potential image nodes.</span></div>
<divclass="line"><aid="l00821"name="l00821"></a><spanclass="lineno"> 821</span><spanclass="comment">// TODO(user): fix this: we should really be collecting all</span></div>
<divclass="line"><aid="l00822"name="l00822"></a><spanclass="lineno"> 822</span><spanclass="comment">// permutations displacing any node in "image_part", for the pruning</span></div>
<divclass="line"><aid="l00823"name="l00823"></a><spanclass="lineno"> 823</span><spanclass="comment">// to be really exhaustive. We could also consider alternative ways,</span></div>
<divclass="line"><aid="l00824"name="l00824"></a><spanclass="lineno"> 824</span><spanclass="comment">// like incrementally maintaining the list of permutations compatible</span></div>
<divclass="line"><aid="l00825"name="l00825"></a><spanclass="lineno"> 825</span><spanclass="comment">// with the partition so far.</span></div>
<divclass="line"><aid="l00826"name="l00826"></a><spanclass="lineno"> 826</span><spanclass="keyword">const</span><spanclass="keywordtype">int</span> part = image_partition->PartOf(last_ss->first_image_node);</div>
<divclass="line"><aid="l00854"name="l00854"></a><spanclass="lineno"> 854</span><spanclass="comment">// If this was the root search state (i.e. we fully backtracked and</span></div>
<divclass="line"><aid="l00855"name="l00855"></a><spanclass="lineno"> 855</span><spanclass="comment">// will exit the search after that), we don't have mappings to undo.</span></div>
<divclass="line"><aid="l00856"name="l00856"></a><spanclass="lineno"> 856</span><spanclass="comment">// We run UndoLastMappings() anyway, because it's a no-op in that case.</span></div>
<divclass="line"><aid="l00864"name="l00864"></a><spanclass="lineno"> 864</span><spanclass="comment">// Case 3): we deepen the search.</span></div>
<divclass="line"><aid="l00865"name="l00865"></a><spanclass="lineno"> 865</span><spanclass="comment">// Since the search loop starts from an already-refined base_partition,</span></div>
<divclass="line"><aid="l00866"name="l00866"></a><spanclass="lineno"> 866</span><spanclass="comment">// we must do it here.</span></div>
<divclass="line"><aid="l00867"name="l00867"></a><spanclass="lineno"> 867</span><aclass="code hl_define"href="base_2logging_8h.html#afcaa7cadd41741bb855c2ada1d2ef927">VLOG</a>(4) <<<spanclass="stringliteral">" Deepening the search."</span>;</div>
<divclass="line"><aid="l00878"name="l00878"></a><spanclass="lineno"> 878</span><spanclass="comment">// We exhausted the search; we didn't find any permutation.</span></div>
<divclass="line"><aid="l00895"name="l00895"></a><spanclass="lineno"> 895</span><spanclass="comment">// TODO(user): apply a smarter test to decide whether to do the pruning</span></div>
<divclass="line"><aid="l00896"name="l00896"></a><spanclass="lineno"> 896</span><spanclass="comment">// or not: we can accurately estimate the cost of pruning (iterate through</span></div>
<divclass="line"><aid="l00897"name="l00897"></a><spanclass="lineno"> 897</span><spanclass="comment">// all generators found so far) and its estimated benefit (the cost of</span></div>
<divclass="line"><aid="l00898"name="l00898"></a><spanclass="lineno"> 898</span><spanclass="comment">// the search below the state that we're currently in, times the expected</span></div>
<divclass="line"><aid="l00899"name="l00899"></a><spanclass="lineno"> 899</span><spanclass="comment">// number of pruned nodes). Sometimes it may be better to skip the</span></div>
<divclass="line"><aid="l00903"name="l00903"></a><spanclass="lineno"> 903</span><spanclass="comment">// Iterate on all targeted permutations. If they are compatible, apply</span></div>
<divclass="line"><aid="l00904"name="l00904"></a><spanclass="lineno"> 904</span><spanclass="comment">// them to tmp_partition_ which will contain the incrementally merged</span></div>
<divclass="line"><aid="l00909"name="l00909"></a><spanclass="lineno"> 909</span><spanclass="comment">// TODO(user): investigate further optimizations: maybe it's possible</span></div>
<divclass="line"><aid="l00910"name="l00910"></a><spanclass="lineno"> 910</span><spanclass="comment">// to incrementally maintain the set of permutations that is compatible</span></div>
<divclass="line"><aid="l00911"name="l00911"></a><spanclass="lineno"> 911</span><spanclass="comment">// with the current partition, instead of recomputing it here?</span></div>
<divclass="line"><aid="l00912"name="l00912"></a><spanclass="lineno"> 912</span><spanclass="keywordflow">for</span> (<spanclass="keyword">const</span><spanclass="keywordtype">int</span> p : permutation_indices) {</div>
<divclass="line"><aid="l00914"name="l00914"></a><spanclass="lineno"> 914</span><spanclass="comment">// First, a quick compatibility check: the permutation's cycles must be</span></div>
<divclass="line"><aid="l00915"name="l00915"></a><spanclass="lineno"> 915</span><spanclass="comment">// smaller or equal to the size of the part that they are included in.</span></div>
<divclass="line"><aid="l00926"name="l00926"></a><spanclass="lineno"> 926</span><spanclass="comment">// Now the full compatibility check: each cycle of the permutation must</span></div>
<divclass="line"><aid="l00927"name="l00927"></a><spanclass="lineno"> 927</span><spanclass="comment">// be fully included in an image part.</span></div>
<divclass="line"><aid="l00928"name="l00928"></a><spanclass="lineno"> 928</span><spanclass="keywordflow">for</span> (<spanclass="keywordtype">int</span> c = 0; c < permutation.NumCycles(); ++c) {</div>
<divclass="line"><aid="l00929"name="l00929"></a><spanclass="lineno"> 929</span><spanclass="keywordtype">int</span> part = -1;</div>
<divclass="line"><aid="l00936"name="l00936"></a><spanclass="lineno"> 936</span> part = partition.PartOf(node); <spanclass="comment">// Initialization of 'part'.</span></div>
<divclass="line"><aid="l00941"name="l00941"></a><spanclass="lineno"> 941</span><spanclass="comment">// The permutation is fully compatible!</span></div>
<divclass="line"><aid="l00942"name="l00942"></a><spanclass="lineno"> 942</span><spanclass="comment">// TODO(user): ignore cycles that are outside of image_part.</span></div>
<divclass="line"><aid="l00974"name="l00974"></a><spanclass="lineno"> 974</span><spanclass="comment">// The following clause should be true most of the times, except in some</span></div>
<divclass="line"><aid="l00975"name="l00975"></a><spanclass="lineno"> 975</span><spanclass="comment">// specific use cases.</span></div>
<divclass="line"><aid="l00977"name="l00977"></a><spanclass="lineno"> 977</span><spanclass="comment">// First, we try to map the loose ends of the current permutations: these</span></div>
<divclass="line"><aid="l00978"name="l00978"></a><spanclass="lineno"> 978</span><spanclass="comment">// loose ends can't be mapped to themselves, so we'll have to map them to</span></div>
<divclass="line"><aid="l00986"name="l00986"></a><spanclass="lineno"> 986</span><spanclass="comment">// We prioritize mapping a loose end to its own root (i.e. close a</span></div>
<divclass="line"><aid="l00987"name="l00987"></a><spanclass="lineno"> 987</span><spanclass="comment">// cycle), if possible, like here: we exit immediately.</span></div>
<divclass="line"><aid="l00993"name="l00993"></a><spanclass="lineno"> 993</span><spanclass="comment">// We found loose ends, but none that mapped to its own root. Just pick</span></div>
<divclass="line"><aid="l00994"name="l00994"></a><spanclass="lineno"> 994</span><spanclass="comment">// any valid image.</span></div>
<divclass="line"><aid="l01003"name="l01003"></a><spanclass="lineno"> 1003</span><spanclass="comment">// If there is no loose node (i.e. the current permutation only has closed</span></div>
<divclass="line"><aid="l01004"name="l01004"></a><spanclass="lineno"> 1004</span><spanclass="comment">// cycles), we fall back to picking any part that is different in the base and</span></div>
<divclass="line"><aid="l01005"name="l01005"></a><spanclass="lineno"> 1005</span><spanclass="comment">// image partitions; because we know that some mapping decision will have to</span></div>
<divclass="line"><aid="l01006"name="l01006"></a><spanclass="lineno"> 1006</span><spanclass="comment">// be made there.</span></div>
<divclass="line"><aid="l01007"name="l01007"></a><spanclass="lineno"> 1007</span><spanclass="comment">// SUBTLE: we use "min_potential_mismatching_part_index_io" to incrementally</span></div>
<divclass="line"><aid="l01008"name="l01008"></a><spanclass="lineno"> 1008</span><spanclass="comment">// keep running this search (for a mismatching part) from where we left off.</span></div>
<divclass="line"><aid="l01009"name="l01009"></a><spanclass="lineno"> 1009</span><spanclass="comment">// TODO(user): implement a simpler search for a mismatching part: it's</span></div>
<divclass="line"><aid="l01010"name="l01010"></a><spanclass="lineno"> 1010</span><spanclass="comment">// trivially possible if the base partition maintains a hash set of all</span></div>
<divclass="line"><aid="l01011"name="l01011"></a><spanclass="lineno"> 1011</span><spanclass="comment">// Fprints of its parts, and if the image partition uses that to maintain the</span></div>
<divclass="line"><aid="l01012"name="l01012"></a><spanclass="lineno"> 1012</span><spanclass="comment">// list of 'different' non-singleton parts.</span></div>
<divclass="line"><aid="l01017"name="l01017"></a><spanclass="lineno"> 1017</span><spanclass="keyword">const</span><spanclass="keywordtype">int</span> p = *min_potential_mismatching_part_index_io;</div>
<divclass="line"><aid="l01036"name="l01036"></a><spanclass="lineno"> 1036</span><spanclass="comment">// We didn't find an unequal part. DCHECK that our "incremental" check was</span></div>
<divclass="line"><aid="l01037"name="l01037"></a><spanclass="lineno"> 1037</span><spanclass="comment">// actually correct and that all non-singleton parts are indeed equal.</span></div>
<divclass="ttc"id="aclassoperations__research_1_1_dynamic_partition_html_a32f3aa9643111b05108d1120e48c1e13"><divclass="ttname"><ahref="classoperations__research_1_1_dynamic_partition.html#a32f3aa9643111b05108d1120e48c1e13">operations_research::DynamicPartition::Refine</a></div><divclass="ttdeci">void Refine(const std::vector< int >&distinguished_subset)</div><divclass="ttdef"><b>Definition:</b><ahref="dynamic__partition_8cc_source.html#l00097">dynamic_partition.cc:97</a></div></div>
<divclass="ttc"id="aclassoperations__research_1_1_dynamic_partition_html_ad8a3eb5fa76f501ec96f1664fc899c3b"><divclass="ttname"><ahref="classoperations__research_1_1_dynamic_partition.html#ad8a3eb5fa76f501ec96f1664fc899c3b">operations_research::DynamicPartition::ElementsInHierarchicalOrder</a></div><divclass="ttdeci">const std::vector< int >& ElementsInHierarchicalOrder() const</div><divclass="ttdef"><b>Definition:</b><ahref="dynamic__partition_8h_source.html#l00137">dynamic_partition.h:137</a></div></div>
<divclass="ttc"id="aclassoperations__research_1_1_dynamic_partition_html_ae91b7d9b6c4f0675b9ad3f38e5761853"><divclass="ttname"><ahref="classoperations__research_1_1_dynamic_partition.html#ae91b7d9b6c4f0675b9ad3f38e5761853">operations_research::DynamicPartition::NumParts</a></div><divclass="ttdeci">const int NumParts() const</div><divclass="ttdef"><b>Definition:</b><ahref="dynamic__partition_8h_source.html#l00062">dynamic_partition.h:62</a></div></div>
<divclass="ttc"id="aclassoperations__research_1_1_dynamic_permutation_html_ae8f61c84a06024a7d6343902f44e7e59"><divclass="ttname"><ahref="classoperations__research_1_1_dynamic_permutation.html#ae8f61c84a06024a7d6343902f44e7e59">operations_research::DynamicPermutation::UndoLastMappings</a></div><divclass="ttdeci">void UndoLastMappings(std::vector< int > *undone_mapping_src)</div><divclass="ttdef"><b>Definition:</b><ahref="dynamic__permutation_8cc_source.html#l00049">dynamic_permutation.cc:49</a></div></div>
<divclass="ttc"id="aclassoperations__research_1_1_dynamic_permutation_html_aeb46445d022e7bc495f212704791824a"><divclass="ttname"><ahref="classoperations__research_1_1_dynamic_permutation.html#aeb46445d022e7bc495f212704791824a">operations_research::DynamicPermutation::AddMappings</a></div><divclass="ttdeci">void AddMappings(const std::vector< int >&src, const std::vector< int >&dst)</div><divclass="ttdef"><b>Definition:</b><ahref="dynamic__permutation_8cc_source.html#l00027">dynamic_permutation.cc:27</a></div></div>
<divclass="ttc"id="aclassoperations__research_1_1_dynamic_permutation_html_afc48707ddd63d0978b9cfcd17c704694"><divclass="ttname"><ahref="classoperations__research_1_1_dynamic_permutation.html#afc48707ddd63d0978b9cfcd17c704694">operations_research::DynamicPermutation::AllMappingsSrc</a></div><divclass="ttdeci">const std::vector< int >& AllMappingsSrc() const</div><divclass="ttdef"><b>Definition:</b><ahref="dynamic__permutation_8h_source.html#l00067">dynamic_permutation.h:67</a></div></div>
<divclass="ttc"id="aclassoperations__research_1_1_merging_partition_html_a612bd8d97219124a8d6fbac721bcdbc6"><divclass="ttname"><ahref="classoperations__research_1_1_merging_partition.html#a612bd8d97219124a8d6fbac721bcdbc6">operations_research::MergingPartition::MergePartsOf</a></div><divclass="ttdeci">int MergePartsOf(int node1, int node2)</div><divclass="ttdef"><b>Definition:</b><ahref="dynamic__partition_8cc_source.html#l00214">dynamic_partition.cc:214</a></div></div>
<divclass="ttc"id="aclassoperations__research_1_1_merging_partition_html_a62cb833403d7861c5badb4de3389e06e"><divclass="ttname"><ahref="classoperations__research_1_1_merging_partition.html#a62cb833403d7861c5badb4de3389e06e">operations_research::MergingPartition::FillEquivalenceClasses</a></div><divclass="ttdeci">int FillEquivalenceClasses(std::vector< int > *node_equivalence_classes)</div><divclass="ttdef"><b>Definition:</b><ahref="dynamic__partition_8cc_source.html#l00262">dynamic_partition.cc:262</a></div></div>
<divclass="ttc"id="aclassoperations__research_1_1_merging_partition_html_a80761f181b521aa284b7e687776b9fde"><divclass="ttname"><ahref="classoperations__research_1_1_merging_partition.html#a80761f181b521aa284b7e687776b9fde">operations_research::MergingPartition::KeepOnlyOneNodePerPart</a></div><divclass="ttdeci">void KeepOnlyOneNodePerPart(std::vector< int > *nodes)</div><divclass="ttdef"><b>Definition:</b><ahref="dynamic__partition_8cc_source.html#l00246">dynamic_partition.cc:246</a></div></div>
<divclass="ttc"id="aclassoperations__research_1_1_time_limit_html"><divclass="ttname"><ahref="classoperations__research_1_1_time_limit.html">operations_research::TimeLimit</a></div><divclass="ttdoc">A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...</div><divclass="ttdef"><b>Definition:</b><ahref="time__limit_8h_source.html#l00106">time_limit.h:106</a></div></div>
<divclass="ttc"id="aclassoperations__research_1_1_time_limit_html_a810d5f7aaf80cc09cf5a094e20c1aaca"><divclass="ttname"><ahref="classoperations__research_1_1_time_limit.html#a810d5f7aaf80cc09cf5a094e20c1aaca">operations_research::TimeLimit::LimitReached</a></div><divclass="ttdeci">bool LimitReached()</div><divclass="ttdoc">Returns true when the external limit is true, or the deterministic time is over the deterministic lim...</div><divclass="ttdef"><b>Definition:</b><ahref="time__limit_8h_source.html#l00546">time_limit.h:546</a></div></div>
<divclass="ttc"id="afind__graph__symmetries_8cc_html_a319b3c460e91c76ad49c4589748e4f0c"><divclass="ttname"><ahref="find__graph__symmetries_8cc.html#a319b3c460e91c76ad49c4589748e4f0c">ABSL_FLAG</a></div><divclass="ttdeci">ABSL_FLAG(bool, minimize_permutation_support_size, false, "Tweak the algorithm to try and minimize the support size"" of the generators produced. This may negatively impact the"" performance, but works great on the sat_holeXXX benchmarks"" to reduce the support size.")</div></div>
<divclass="ttc"id="alog__severity_8h_html_ab4a2cbab234914b320b7fae11b6e8cb9"><divclass="ttname"><ahref="log__severity_8h.html#ab4a2cbab234914b320b7fae11b6e8cb9">INFO</a></div><divclass="ttdeci">const int INFO</div><divclass="ttdef"><b>Definition:</b><ahref="log__severity_8h_source.html#l00031">log_severity.h:31</a></div></div>
<divclass="ttc"id="anamespaceoperations__research_1_1math__opt_html_a5de89a1f6e3f80a49a0d76136d8044e2"><divclass="ttname"><ahref="namespaceoperations__research_1_1math__opt.html#a5de89a1f6e3f80a49a0d76136d8044e2">operations_research::math_opt::swap</a></div><divclass="ttdeci">void swap(IdMap< K, V >&a, IdMap< K, V >&b)</div><divclass="ttdef"><b>Definition:</b><ahref="id__map_8h_source.html#l00262">id_map.h:262</a></div></div>
<divclass="ttc"id="anamespaceoperations__research_html"><divclass="ttname"><ahref="namespaceoperations__research.html">operations_research</a></div><divclass="ttdoc">Collection of objects used to extend the Constraint Solver library.</div><divclass="ttdef"><b>Definition:</b><ahref="dense__doubly__linked__list_8h_source.html#l00021">dense_doubly_linked_list.h:21</a></div></div>
<divclass="ttc"id="astructoperations__research_1_1_dynamic_partition_1_1_iterable_part_html_a895e8e66079521889215308182c5591b"><divclass="ttname"><ahref="structoperations__research_1_1_dynamic_partition_1_1_iterable_part.html#a895e8e66079521889215308182c5591b">operations_research::DynamicPartition::IterablePart::begin</a></div><divclass="ttdeci">std::vector< int >::const_iterator begin() const</div><divclass="ttdef"><b>Definition:</b><ahref="dynamic__partition_8h_source.html#l00185">dynamic_partition.h:185</a></div></div>