/* Default value for using "long prune" */
opt_use_long_prune = true; /* Default value for using failure recording */
opt_use_failure_recording = true; /* Default value for using component recursion */
opt_use_comprec = true;
void AbstractGraph::refine_to_equitable() { /* Start refinement from all cells -> push 'em all in the splitting queue */ for (Partition::Cell* cell = p.first_cell; cell; cell = cell->next)
p.splitting_queue_add(cell);
void AbstractGraph::long_prune_init() { constunsignedint N = get_nof_vertices();
long_prune_temp.clear();
long_prune_temp.resize(N); /* Of how many automorphisms we can store information in
the predefined, fixed amount of memory? */ constunsignedint nof_fitting_in_max_mem
= (long_prune_options_max_mem * 1024 * 1024) / (((N * 2) / 8) + 1);
long_prune_max_stored_autss = long_prune_options_max_stored_auts; /* Had some problems with g++ in using (a<b)?a:b when constants involved,
so had to make this in a stupid way... */ if (nof_fitting_in_max_mem < long_prune_options_max_stored_auts)
long_prune_max_stored_autss = nof_fitting_in_max_mem;
void AbstractGraph::long_prune_deallocate() { for (std::vector<std::vector<bool> >::iterator it
= long_prune_fixed.begin();
it < long_prune_fixed.end();
++it) {
it->clear();
} for (std::vector<std::vector<bool> >::iterator it = long_prune_mcrs.begin();
it < long_prune_mcrs.end();
++it) {
it->clear();
}
}
void AbstractGraph::update_orbit_information(Orbit& o,
uint_pointer_substitute perm) { constunsignedint N = get_nof_vertices(); for (unsignedint i = 0; i < N; i++) if (perm[i] != i)
o.merge_orbits(i, perm[i]);
}
/* Free old first path data structures */
first_path_labeling_vec.clear();
first_path_labeling_inv_vec.clear();
first_path_automorphism_vec.clear();
/* Free old best path data structures */
best_path_labeling_vec.clear();
best_path_labeling_inv_vec.clear();
best_path_automorphism_vec.clear();
if (N == 0) { /* Nothing to do, return... */ return;
}
/* Initialize the partition ... */
p.init(N); /* ... and the component recursion data structures in the partition */ if (opt_use_comprec)
p.cr_init();
neighbour_heap.init(N);
in_search = false; /* Do not compute certificate when building the initial partition */
refine_compare_certificate = false; /* The 'eqref_hash' hash value is not computed when building *theinitialpartitionasitisnotusedforanythingatthemoment.
* This saves some cycles. */
compute_eqref_hash = false;
Timer timer1;
make_initial_equitable_partition();
if (verbstr and verbose_level >= 2) {
fprintf(verbstr, "Initial partition computed in %.2f seconds\n",
timer1.get_duration());
fflush(verbstr);
}
/* *Istheinitialpartitiondiscrete?
*/ if (p.is_discrete()) { /* Make the best path labeling i.e. the canonical labeling */
update_labeling(best_path_labeling); /* Update statistics */
stats.nof_leaf_nodes = 1; return;
}
/* Save component recursion info for backtracking */
root.cr_level = cr_level;
root.cr_cep_stack_size = cr_cep_stack.size();
root.cr_cep_index = cr_cep_index;
search_stack.push_back(root);
}
/* *Setstatusandglobalflagsforsearchrelatedprocedures
*/
in_search = true; /* Do not compare certificates during refinement until the first path has
* been traversed to the leaf */
refine_compare_certificate = false;
/* *Updatelongpruneredundancysets
*/ if (opt_use_long_prune and current_level >= 1and !current_node.fp_on) { unsignedint begin = (current_node.long_prune_begin > long_prune_begin)
? current_node.long_prune_begin
: long_prune_begin; for (unsignedint i = begin; i < long_prune_end; i++) { const std::vector<bool>& fixed = long_prune_get_fixed(i); #ifdefined(BLISS_CONSISTENCY_CHECKS) for (unsignedint l = 0; l < search_stack.size() - 2; l++)
assert(fixed[search_stack[l].split_element]); #endif if (fixed[search_stack[search_stack.size() - 1 - 1].split_element]
== false) {
long_prune_swap(begin, i);
begin++;
current_node.long_prune_begin = begin; continue;
}
}
if (current_node.split_element == TreeNode::SPLIT_START) {
current_node.needs_long_prune = true;
} elseif (current_node.needs_long_prune) {
current_node.needs_long_prune = false;
begin = (current_node.long_prune_begin > long_prune_begin)
? current_node.long_prune_begin
: long_prune_begin; for (unsignedint i = begin; i < long_prune_end; i++) { const std::vector<bool>& fixed = long_prune_get_fixed(i); #ifdefined(BLISS_CONSISTENCY_CHECKS) for (unsignedint l = 0; l < search_stack.size() - 2; l++)
assert(fixed[search_stack[l].split_element]); #endif
assert(fixed[search_stack[current_level - 1].split_element]
== true); if (fixed[search_stack[current_level - 1].split_element] == false) {
long_prune_swap(begin, i);
begin++;
current_node.long_prune_begin = begin; continue;
} const std::vector<bool>& mcrs = long_prune_get_mcrs(i);
uint_pointer_substitute ep = p.elements + cell->first; for (unsignedint j = cell->length; j > 0; j--, ep++) { if (mcrs[*ep] == false)
current_node.long_prune_redundant.insert(*ep);
}
}
}
}
/* *Findthenextsmallest,non-isomorphicelementinthecelland *storeitincurrent_node.split_element
*/
{ unsignedint next_split_element = UINT_MAX;
uint_pointer_substitute next_split_element_pos;
uint_pointer_substitute ep = p.elements + cell->first; if (current_node.fp_on) { /* Find the next larger splitting element that is
* a minimal orbit representative w.r.t. first_path_orbits */ for (unsignedint i = cell->length; i > 0; i--, ep++) { if ((int) (*ep) > current_node.split_element and *ep < next_split_element and first_path_orbits.is_minimal_representative(*ep)) {
next_split_element = *ep;
next_split_element_pos = ep;
}
}
} elseif (current_node.in_best_path) { /* Find the next larger splitting element that is
* a minimal orbit representative w.r.t. best_path_orbits */ for (unsignedint i = cell->length; i > 0; i--, ep++) { if ((int) (*ep) > current_node.split_element and *ep < next_split_element and best_path_orbits.is_minimal_representative(*ep) and (!opt_use_long_prune or current_node.long_prune_redundant.find(*ep)
== current_node.long_prune_redundant.end())) {
next_split_element = *ep;
next_split_element_pos = ep;
}
}
} else { /* Find the next larger splitting element */ for (unsignedint i = cell->length; i > 0; i--, ep++) { if ((int) (*ep) > current_node.split_element and *ep < next_split_element and (!opt_use_long_prune or current_node.long_prune_redundant.find(*ep)
== current_node.long_prune_redundant.end())) {
next_split_element = *ep;
next_split_element_pos = ep;
}
}
} if (next_split_element == UINT_MAX) { /* No more (unexplored children) in the cell */
current_node.split_element = TreeNode::SPLIT_END; if (current_node.fp_on) { /* Update group size */ constunsignedint index = first_path_orbits.orbit_size(
first_path_info[search_stack.size() - 1].splitting_element);
stats.group_size.multiply(index);
stats.group_size_approx *= (longdouble) index; /* *Updateall_same_level
*/ if (index == cell->length and all_same_level == current_level + 1)
all_same_level = current_level; if (verbstr and verbose_level >= 2) {
fprintf(verbstr, "Level %u: orbits=%u, index=%u/%u, all_same_level=%u\n",
current_level,
first_path_orbits.nof_orbits(),
index,
cell->length,
all_same_level);
fflush(verbstr);
}
} continue;
}
/* Split on smallest */
current_node.split_element = next_split_element;
}
constunsignedint child_level = current_level + 1; /* Update some statistics */
stats.nof_nodes++; if (search_stack.size() > stats.max_level)
stats.max_level = search_stack.size();
/* Set flags and indices for the refiner certificate builder */
refine_equal_to_first = current_node.fp_cert_equal;
refine_cmp_to_best = current_node.cmp_to_best_path; if (!first_path_info.empty()) { if (refine_equal_to_first)
refine_first_path_subcertificate_end
= first_path_info[search_stack.size() - 1].certificate_index
+ first_path_info[search_stack.size() - 1]
.subcertificate_length; if (canonical) { if (refine_cmp_to_best == 0)
refine_best_path_subcertificate_end
= best_path_info[search_stack.size() - 1].certificate_index
+ best_path_info[search_stack.size() - 1]
.subcertificate_length;
} else
refine_cmp_to_best = -1;
}
/* Individualize, i.e. split the cell in two, the latter new cell
* will be a unit one containing info.split_element */
Partition::Cell* const new_cell
= p.individualize(cell, current_node.split_element);
/* *Refinethenewpartitiontoequitable
*/ if (cell->is_unit())
refine_to_equitable(cell, new_cell); else
refine_to_equitable(new_cell);
/* Update statistics */ if (p.is_discrete())
stats.nof_leaf_nodes++;
if (!first_path_info.empty()) { /* We are no longer on the first path */ constunsignedint subcertificate_length
= certificate_current_path.size() - certificate_index; if (refine_equal_to_first) { /* Was equal to the first path so far */
PathInfo& first_pinfo = first_path_info[current_level];
assert(first_pinfo.certificate_index == certificate_index); if (subcertificate_length != first_pinfo.subcertificate_length) {
refine_equal_to_first = false; if (opt_use_failure_recording)
failure_recording_fp_deviation = subcertificate_length;
} elseif (first_pinfo.eqref_hash.cmp(eqref_hash) != 0) {
refine_equal_to_first = false; if (opt_use_failure_recording)
failure_recording_fp_deviation = eqref_hash.get_value();
}
} if (canonical and (refine_cmp_to_best == 0)) { /* Was equal to the best path so far */
PathInfo& bestp_info = best_path_info[current_level];
assert(bestp_info.certificate_index == certificate_index); if (subcertificate_length < bestp_info.subcertificate_length) {
refine_cmp_to_best = -1;
} elseif (subcertificate_length > bestp_info.subcertificate_length) {
refine_cmp_to_best = 1;
} elseif (bestp_info.eqref_hash.cmp(eqref_hash) > 0) {
refine_cmp_to_best = -1;
} elseif (bestp_info.eqref_hash.cmp(eqref_hash) < 0) {
refine_cmp_to_best = 1;
}
}
if (opt_use_failure_recording and was_fp_cert_equal and !refine_equal_to_first) {
UintSeqHash k;
k.update(failure_recording_fp_deviation);
k.update(eqref_hash.get_value());
failure_recording_fp_deviation = k.get_value();
if (current_node.fp_on)
failure_recording_hashes[current_level].insert(
failure_recording_fp_deviation); else { for (unsignedint i = current_level; i > 0; i--) { if (search_stack[i].fp_on) break; const FailureRecordingSet& s = failure_recording_hashes[i]; if (i == current_level and s.find(failure_recording_fp_deviation) != s.end()) break; if (s.find(0) != s.end()) break;
search_stack[i].fp_extendable = TreeNode::NO;
}
}
}
/* Check if no longer equal to the first path and, *ifcanonicallabelingisdesired,alsoworsethanthe
* current best path */ if (refine_equal_to_first == false and (!canonical or (refine_cmp_to_best < 0))) { /* Yes, backtrack */
stats.nof_bad_nodes++; if (current_node.fp_cert_equal == true and current_level + 1 > all_same_level) {
assert(all_same_level >= 1); for (unsignedint i = all_same_level; i < search_stack.size();
i++) {
search_stack[i].fp_extendable = TreeNode::NO;
}
}
continue;
}
}
#ifdefined(BLISS_VERIFY_EQUITABLEDNESS) /* The new partition should be equitable */ if (!is_equitable())
fatal_error("consistency check failed - partition after refinement is " "not equitable"); #endif
if (p.is_discrete() and child_node.fp_cert_equal) { /* *Aleafnodethatisequaltothefirstone. *Anautomorphismfound:aut[i]=elements[first_path_labeling[i]]
*/ goto handle_first_path_automorphism;
}
if (!p.is_discrete()) {
Partition::Cell* next_split_cell = 0; /* *Aninternal,non-leafnode
*/ if (opt_use_comprec) {
assert(p.nof_discrete_cells()
<= cr_cep_stack[cr_cep_index].discrete_cell_limit);
assert(cr_level == child_node.cr_level);
if (p.nof_discrete_cells()
== cr_cep_stack[cr_cep_index].discrete_cell_limit) { /* We have reached the end of a component */
assert(cr_cep_index != 0);
CR_CEP& cep = cr_cep_stack[cr_cep_index];
/* First, compare with respect to the first path */ if (first_path_info.empty() or child_node.fp_cert_equal) { if (cep.first_checked == false) { /* First time, go to the next component */
cep.first_checked = true;
} else {
assert(!first_path_info.empty());
assert(cep.creation_level < search_stack.size());
TreeNode& old_info = search_stack[cep.creation_level]; /* If the component was found when on the first path, *handlethefoundautomorphismastheother
* first path automorphisms */ if (old_info.fp_on) goto handle_first_path_automorphism; /* Should never get here because of CR:FP */ //_INTERNAL_ERROR();
}
}
if (canonical and !first_path_info.empty() and child_node.cmp_to_best_path >= 0) { if (cep.best_checked == false) { /* First time, go to the next component */
cep.best_checked = true;
} else {
assert(cep.creation_level < search_stack.size());
TreeNode& old_info = search_stack[cep.creation_level]; if (child_node.cmp_to_best_path == 0) { /* If the component was found when on the best path, *handlethefoundautomorphismastheother
* best path automorphisms */ if (old_info.in_best_path) goto handle_best_path_automorphism; /* Otherwise, we do not remember the automorhism as *wedidn'tmemorizethepaththatwasinvariant *equaltothebestoneandpassedthroughthe *component.
* Thus we can only backtrack to the previous level */
child_node.cmp_to_best_path = -1; if (!child_node.fp_cert_equal) { continue;
}
} else {
assert(child_node.cmp_to_best_path > 0); if (old_info.in_best_path) {
stats.nof_canupdates++; /* *Updatecanonicallabelinganditsinverse
*/ for (unsignedint i = 0; i < N; i++) { if (p.get_cell(p.elements[i])->is_unit()) {
best_path_labeling[p.elements[i]] = i;
best_path_labeling_inv[i] = p.elements[i];
}
} // update_labeling_and_its_inverse(best_path_labeling, // best_path_labeling_inv); /* Reset best path automorphism */
reset_permutation(best_path_automorphism); /* Reset best path orbit structure */
best_path_orbits.reset(); /* Mark to be the best one and save prefix */ unsignedint postfix_start = cep.creation_level;
assert(postfix_start < best_path_info.size()); while (p.get_cell(
best_path_info[postfix_start].splitting_element)
->is_unit()) {
postfix_start++;
assert(postfix_start < best_path_info.size());
} unsignedint postfix_start_cert
= best_path_info[postfix_start].certificate_index;
std::vector<PathInfo> best_path_temp = best_path_info;
best_path_info.clear(); for (unsignedint i = 0; i < search_stack.size(); i++) {
TreeNode& ss_info = search_stack[i];
PathInfo bp_info;
ss_info.cmp_to_best_path = 0;
ss_info.in_best_path = true;
bp_info.splitting_element = ss_info.split_element;
bp_info.certificate_index = ss_info.certificate_index;
bp_info.subcertificate_length
= ss_info.subcertificate_length;
bp_info.eqref_hash = ss_info.eqref_hash;
best_path_info.push_back(bp_info);
} /* Copy the postfix of the previous best path */ for (unsignedint i = postfix_start;
i < best_path_temp.size();
i++) {
best_path_info.push_back(best_path_temp[i]);
best_path_info[best_path_info.size() - 1]
.certificate_index
= best_path_info[best_path_info.size() - 2]
.certificate_index
+ best_path_info[best_path_info.size() - 2]
.subcertificate_length;
}
std::vector<unsignedint> certificate_best_path_old
= certificate_best_path;
certificate_best_path = certificate_current_path; for (unsignedint i = postfix_start_cert;
i < certificate_best_path_old.size();
i++)
certificate_best_path.push_back(
certificate_best_path_old[i]);
assert(
certificate_best_path.size()
== best_path_info.back().certificate_index
+ best_path_info.back().subcertificate_length); /* Backtrack to the previous level */ continue;
}
}
}
}
/* No backtracking performed, go to next componenet */
cr_level = cep.next_cr_level;
cr_cep_index = cep.next_cep_index;
}
/* Check if the current component has been split into
* new non-uniformity subcomponents */ // if(nucr_find_first_component(cr_level) == true and // p.nof_discrete_cells() + cr_component_elements < // cr_cep_stack[cr_cep_index].discrete_cell_limit) if (nucr_find_first_component(cr_level,
cr_component,
cr_component_elements,
next_split_cell)
== true and p.nof_discrete_cells() + cr_component_elements
< cr_cep_stack[cr_cep_index].discrete_cell_limit) { constunsignedint next_cr_level
= p.cr_split_level(cr_level, cr_component);
CR_CEP cep;
cep.creation_level = search_stack.size();
cep.discrete_cell_limit
= p.nof_discrete_cells() + cr_component_elements;
cep.next_cr_level = cr_level;
cep.next_cep_index = cr_cep_index;
cep.first_checked = false;
cep.best_checked = false;
cr_cep_index = cr_cep_stack.size();
cr_cep_stack.push_back(cep);
cr_level = next_cr_level;
}
}
/* *Buildthenextnodeinfo
*/ /* Find the next cell to be splitted */ if (!next_split_cell)
next_split_cell = find_next_cell_to_be_splitted(
p.get_cell(p.elements[current_node.split_cell_first])); // Partition::Cell * const next_split_cell = // find_next_cell_to_be_splitted(p.get_cell(p.elements[current_node.split_cell_first]));
child_node.split_cell_first = next_split_cell->first;
child_node.split_element = TreeNode::SPLIT_START;
child_node.certificate_index = certificate_index;
child_node.partition_bt_point = p.set_backtrack_point();
child_node.long_prune_redundant.clear();
child_node.long_prune_begin = current_node.long_prune_begin;
/* Save component recursion info for backtracking */
child_node.cr_level = cr_level;
child_node.cr_cep_stack_size = cr_cep_stack.size();
child_node.cr_cep_index = cr_cep_index;
handle_best_path_automorphism: /* * *Bestpathautomorphismhandling *
*/
{ /* *Equaltothepreviousbestpath
*/ if (p.is_discrete()) { #ifdefined(BLISS_CONSISTENCY_CHECKS) /* Verify that the automorphism is correctly built */ for (unsignedint i = 0; i < N; i++)
assert(best_path_automorphism[i]
== p.elements[best_path_labeling[i]]); #endif
} else { /* An automorphism that was found before the partition was discrete.
* Set the image of all elements in non-disrete cells accordingly */ for (Partition::Cell* c = p.first_nonsingleton_cell; c;
c = c->next_nonsingleton) { for (unsignedint i = c->first; i < c->first + c->length; i++) if (p.get_cell(p.elements[best_path_labeling[p.elements[i]]])
->is_unit())
best_path_automorphism
[p.elements[best_path_labeling[p.elements[i]]]]
= p.elements[i]; else
best_path_automorphism[p.elements[i]] = p.elements[i];
}
}
#ifdefined(BLISS_VERIFY_AUTOMORPHISMS) /* Verify that it really is an automorphism */ if (!is_automorphism(best_path_automorphism))
fatal_error("Best path automorhism validation check failed"); #endif
unsignedint gca_level_with_first = 0; for (unsignedint i = search_stack.size(); i > 0; i--) { if ((int) first_path_info[gca_level_with_first].splitting_element
!= search_stack[gca_level_with_first].split_element) break;
gca_level_with_first++;
}
unsignedint gca_level_with_best = 0; for (unsignedint i = search_stack.size(); i > 0; i--) { if ((int) best_path_info[gca_level_with_best].splitting_element
!= search_stack[gca_level_with_best].split_element) break;
gca_level_with_best++;
}
if (opt_use_long_prune) { /* Record automorphism */
long_prune_add_automorphism(best_path_automorphism);
}
if (p.is_discrete()) { #ifdefined(BLISS_CONSISTENCY_CHECKS) /* Verify that the complete automorphism is correctly built */ for (unsignedint i = 0; i < N; i++)
assert(first_path_automorphism[i]
== p.elements[first_path_labeling[i]]); #endif
} else { /* An automorphism that was found before the partition was discrete.
* Set the image of all elements in non-disrete cells accordingly */ for (Partition::Cell* c = p.first_nonsingleton_cell; c;
c = c->next_nonsingleton) { for (unsignedint i = c->first; i < c->first + c->length; i++) if (p.get_cell(p.elements[first_path_labeling[p.elements[i]]])
->is_unit())
first_path_automorphism
[p.elements[first_path_labeling[p.elements[i]]]]
= p.elements[i]; else
first_path_automorphism[p.elements[i]] = p.elements[i];
}
}
#ifdefined(BLISS_VERIFY_AUTOMORPHISMS) /* Verify that it really is an automorphism */ if (!is_automorphism(first_path_automorphism))
fatal_error("First path automorphism validation check failed"); #endif
if (opt_use_long_prune) {
long_prune_add_automorphism(first_path_automorphism);
}
/* *Computebackjumpinglevel
*/ for (unsignedint i = 0; i < search_stack.size(); i++) {
TreeNode& n = search_stack[i]; if (n.fp_on) {
;
} else {
n.fp_extendable = TreeNode::YES;
}
}
/* Report automorphism by calling the user defined hook function */ if (report_hook)
(*report_hook)(
report_user_param, get_nof_vertices(), &(*first_path_automorphism));
void Digraph::Vertex::remove_duplicate_edges(std::vector<bool>& tmp) { #ifdefined(BLISS_CONSISTENCY_CHECKS) /* Pre-conditions */ for (unsignedint i = 0; i < tmp.size(); i++)
assert(tmp[i] == false); #endif for (std::vector<unsignedint>::iterator iter = edges_out.begin();
iter != edges_out.end();) { constunsignedint dest_vertex = *iter; if (tmp[dest_vertex] == true) { /* A duplicate edge found! */
iter = edges_out.erase(iter);
} else { /* Not seen earlier, mark as seen */
tmp[dest_vertex] = true;
iter++;
}
}
/* Clear tmp */ for (std::vector<unsignedint>::iterator iter = edges_out.begin();
iter != edges_out.end();
iter++) {
tmp[*iter] = false;
}
for (std::vector<unsignedint>::iterator iter = edges_in.begin();
iter != edges_in.end();) { constunsignedint dest_vertex = *iter; if (tmp[dest_vertex] == true) { /* A duplicate edge found! */
iter = edges_in.erase(iter);
} else { /* Not seen earlier, mark as seen */
tmp[dest_vertex] = true;
iter++;
}
}
/* Clear tmp */ for (std::vector<unsignedint>::iterator iter = edges_in.begin();
iter != edges_in.end();
iter++) {
tmp[*iter] = false;
} #ifdefined(BLISS_CONSISTENCY_CHECKS) /* Post-conditions */ for (unsignedint i = 0; i < tmp.size(); i++)
assert(tmp[i] == false); #endif
}
for (std::vector<Vertex>::iterator vi = vertices.begin();
vi != vertices.end();
vi++) { #ifdefined(BLISS_EXPENSIVE_CONSISTENCY_CHECKS) for (unsignedint i = 0; i < tmp.size(); i++)
assert(tmp[i] == false); #endif
(*vi).remove_duplicate_edges(tmp);
}
}
/* Hash the color of each vertex */ for (unsignedint i = 0; i < get_nof_vertices(); i++) {
h.update(vertices[i].color);
}
/* Hash the edges */ for (unsignedint i = 0; i < get_nof_vertices(); i++) {
Vertex& v = vertices[i]; for (std::vector<unsignedint>::const_iterator ei = v.edges_out.begin();
ei != v.edges_out.end();
ei++) {
h.update(i);
h.update(*ei);
}
}
/* Read comments and the problem definition line */ while (1) { int c = getc(fp); if (c == 'c') { /* A comment, ignore the rest of the line */ while ((c = getc(fp)) != '\n') { if (c == EOF) { if (errstr)
fprintf(
errstr, "error in line %u: not in DIMACS format\n", line_num); goto error_exit;
}
}
line_num++; continue;
} if (c == 'p') { /* The problem definition line */ if (fscanf(fp, " edge %u %u\n", &nof_vertices, &nof_edges) != 2) { if (errstr)
fprintf(
errstr, "error in line %u: not in DIMACS format\n", line_num); goto error_exit;
}
line_num++; break;
} if (errstr)
fprintf(errstr, "error in line %u: not in DIMACS format\n", line_num); goto error_exit;
}
if (nof_vertices <= 0) { if (errstr)
fprintf(errstr, "error: no vertices\n"); goto error_exit;
} if (verbose) {
fprintf(verbstr, "Instance has %d vertices and %d edges\n",
nof_vertices,
nof_edges);
fflush(verbstr);
}
g = new Digraph(nof_vertices);
// // Read vertex colors // if (verbose) {
fprintf(verbstr, "Reading vertex colors...\n");
fflush(verbstr);
} while (1) { int c = getc(fp); if (c != 'n') {
ungetc(c, fp); break;
}
ungetc(c, fp); unsignedint vertex; unsignedint color; if (fscanf(fp, "n %u %u\n", &vertex, &color) != 2) { if (errstr)
fprintf(errstr, "error in line %u: not in DIMACS format\n", line_num); goto error_exit;
} if (!((vertex >= 1) && (vertex <= nof_vertices))) { if (errstr)
fprintf(errstr, "error in line %u: vertex %u not in range [1,...%u]\n",
line_num,
vertex,
nof_vertices); goto error_exit;
}
line_num++;
g->change_color(vertex - 1, color);
} if (verbose) {
fprintf(verbstr, "Done\n");
fflush(verbstr);
}
// // Read edges // if (verbose) {
fprintf(verbstr, "Reading edges...\n");
fflush(verbstr);
} for (unsigned i = 0; i < nof_edges; i++) { unsignedint from, to; if (fscanf(fp, "e %u %u\n", &from, &to) != 2) { if (errstr)
fprintf(errstr, "error in line %u: not in DIMACS format\n", line_num); goto error_exit;
} if (not((1 <= from) and (from <= nof_vertices))) { if (errstr)
fprintf(errstr, "error in line %u: vertex %u not in range [1,...%u]\n",
line_num,
from,
nof_vertices); goto error_exit;
} if (not((1 <= to) and (to <= nof_vertices))) { if (errstr)
fprintf(errstr, "error in line %u: vertex %u not in range [1,...%u]\n",
line_num,
to,
nof_vertices); goto error_exit;
}
line_num++;
g->add_edge(from - 1, to - 1);
} if (verbose) {
fprintf(verbstr, "Done\n");
fflush(verbstr);
}
/* First count the total number of edges */ unsignedint nof_edges = 0; for (unsignedint i = 0; i < get_nof_vertices(); i++) {
nof_edges += vertices[i].edges_out.size();
}
/* Output the "header" line */
fprintf(fp, "p edge %u %u\n", get_nof_vertices(), nof_edges);
/* Print the color of each vertex */ for (unsignedint i = 0; i < get_nof_vertices(); i++) {
Vertex& v = vertices[i];
fprintf(fp, "n %u %u\n", i + 1, v.color); /* if(v.color!=0) { fprintf(fp,"n%u%u\n",i+1,v.color); }
*/
}
/* Print the edges */ for (unsignedint i = 0; i < get_nof_vertices(); i++) {
Vertex& v = vertices[i]; for (std::vector<unsignedint>::const_iterator ei = v.edges_out.begin();
ei != v.edges_out.end();
ei++) {
fprintf(fp, "e %u %u\n", i + 1, (*ei) + 1);
}
}
}
unsignedint Digraph::selfloop_invariant(const Digraph* const g, constunsignedint vnum) { /* Quite inefficient but luckily not in the critical path */ const Vertex& v = g->vertices[vnum]; for (std::vector<unsignedint>::const_iterator ei = v.edges_out.begin();
ei != v.edges_out.end();
ei++) { if (*ei == vnum) return1;
} return0;
}
/* Update certificate and hash if needed */ const Partition::Cell* c = neighbour_cell; while (1) { if (in_search) { /* Build certificate */
cert_add_redundant(CERT_SPLIT, c->first, c->length); /* No need to continue? */ if (refine_compare_certificate and (refine_equal_to_first == false) and (refine_cmp_to_best < 0)) goto worse_exit;
} if (compute_eqref_hash) {
eqref_hash.update(c->first);
eqref_hash.update(c->length);
} if (c == last_new_cell) break;
c = c->next;
}
}
if (cell->is_in_splitting_queue()) { returnfalse;
}
ep = p.elements + cell->first; for (unsignedint i = cell->length; i > 0; i--) { const Vertex& v = vertices[*ep++];
/* Update certificate and hash if needed */ const Partition::Cell* c = neighbour_cell; while (1) { if (in_search) { /* Build certificate */
cert_add_redundant(CERT_SPLIT, c->first, c->length); /* No need to continue? */ if (refine_compare_certificate and (refine_equal_to_first == false) and (refine_cmp_to_best < 0)) goto worse_exit;
} if (compute_eqref_hash) {
eqref_hash.update(c->first);
eqref_hash.update(c->length);
} if (c == last_new_cell) break;
c = c->next;
}
}
if (refine_compare_certificate and (refine_equal_to_first == false) and (refine_cmp_to_best < 0)) returntrue;
returnfalse;
worse_exit: /* Clear neighbour heap */
UintSeqHash rest; while (!neighbour_heap.is_empty()) { constunsignedint start = neighbour_heap.remove();
Partition::Cell* const neighbour_cell = p.get_cell(p.elements[start]); if (opt_use_failure_recording and was_equal_to_first) {
rest.update(neighbour_cell->first);
rest.update(neighbour_cell->length);
rest.update(neighbour_cell->max_ival);
rest.update(neighbour_cell->max_ival_count);
}
neighbour_cell->max_ival = 0;
neighbour_cell->max_ival_count = 0;
p.clear_ivs(neighbour_cell);
} if (opt_use_failure_recording and was_equal_to_first) { for (unsignedint i = p.splitting_queue.size(); i > 0; i--) {
Partition::Cell* const cell2 = p.splitting_queue.pop_front();
rest.update(cell2->first);
rest.update(cell2->length);
p.splitting_queue.push_back(cell2);
}
rest.update(failure_recording_fp_deviation);
failure_recording_fp_deviation = rest.get_value();
}
if (neighbour_cell->is_unit()) { if (in_search) { /* Remember neighbour in order to generate certificate */
neighbour_heap.insert(neighbour_cell->first);
} continue;
} if (neighbour_cell->max_ival_count == 0) {
neighbour_heap.insert(neighbour_cell->first);
}
neighbour_cell->max_ival_count++;
/* Add cells in splitting_queue */ if (neighbour_cell->is_in_splitting_queue()) { /* Both cells must be included in splitting_queue in order
to have refinement to equitable partition */
p.splitting_queue_add(new_cell);
} else {
Partition::Cell *min_cell, *max_cell; if (neighbour_cell->length <= new_cell->length) {
min_cell = neighbour_cell;
max_cell = new_cell;
} else {
min_cell = new_cell;
max_cell = neighbour_cell;
} /* Put the smaller cell in splitting_queue */
p.splitting_queue_add(min_cell); if (max_cell->is_unit()) { /* Put the "larger" cell also in splitting_queue */
p.splitting_queue_add(max_cell);
}
} /* Update pointer for certificate generation */
neighbour_cell = new_cell;
} else {
neighbour_cell->max_ival_count = 0;
}
/* *Buildcertificateifrequired
*/ if (in_search) { for (unsignedint i = neighbour_cell->first, j = neighbour_cell->length;
j > 0;
j--, i++) { /* Build certificate */
cert_add(CERT_EDGE, unit_cell->first, i); /* No need to continue? */ if (refine_compare_certificate and (refine_equal_to_first == false) and (refine_cmp_to_best < 0)) goto worse_exit;
}
} /* if(in_search) */
} /* while(!neighbour_heap.is_empty()) */
if (compute_eqref_hash) {
eqref_hash.update(neighbour_cell->first);
eqref_hash.update(neighbour_cell->length);
eqref_hash.update(0);
eqref_hash.update(new_cell->first);
eqref_hash.update(new_cell->length);
eqref_hash.update(1);
}
/* Add cells in splitting_queue */ if (neighbour_cell->is_in_splitting_queue()) { /* Both cells must be included in splitting_queue in order
to have refinement to equitable partition */
p.splitting_queue_add(new_cell);
} else {
Partition::Cell *min_cell, *max_cell; if (neighbour_cell->length <= new_cell->length) {
min_cell = neighbour_cell;
max_cell = new_cell;
} else {
min_cell = new_cell;
max_cell = neighbour_cell;
} /* Put the smaller cell in splitting_queue */
p.splitting_queue_add(min_cell); if (max_cell->is_unit()) { /* Put the "larger" cell also in splitting_queue */
p.splitting_queue_add(max_cell);
}
} /* Update pointer for certificate generation */
neighbour_cell = new_cell;
} else {
neighbour_cell->max_ival_count = 0;
}
/* *Buildcertificateifrequired
*/ if (in_search) { for (unsignedint i = neighbour_cell->first, j = neighbour_cell->length;
j > 0;
j--, i++) { /* Build certificate */
cert_add(CERT_EDGE, i, unit_cell->first); /* No need to continue? */ if (refine_compare_certificate and (refine_equal_to_first == false) and (refine_cmp_to_best < 0)) goto worse_exit;
}
} /* if(in_search) */
} /* while(!neighbour_heap.is_empty()) */
if (refine_compare_certificate and (refine_equal_to_first == false) and (refine_cmp_to_best < 0)) returntrue;
returnfalse;
worse_exit: /* Clear neighbour heap */
UintSeqHash rest; while (!neighbour_heap.is_empty()) { constunsignedint start = neighbour_heap.remove();
Partition::Cell* const neighbour_cell = p.get_cell(p.elements[start]); if (opt_use_failure_recording and was_equal_to_first) {
rest.update(neighbour_cell->first);
rest.update(neighbour_cell->length);
rest.update(neighbour_cell->max_ival_count);
}
neighbour_cell->max_ival_count = 0;
} if (opt_use_failure_recording and was_equal_to_first) {
rest.update(failure_recording_fp_deviation);
failure_recording_fp_deviation = rest.get_value();
} returntrue;
}
/* Count outgoing edges of the first vertex for cells */ for (std::vector<unsignedint>::const_iterator ei
= first_vertex.edges_out.begin();
ei != first_vertex.edges_out.end();
ei++) {
first_count[p.get_cell(*ei)->first]++;
}
/* Count and compare outgoing edges of the other vertices */ for (unsignedint i = cell->length; i > 1; i--) { const Vertex& vertex = vertices[*ep++]; for (std::vector<unsignedint>::const_iterator ei
= vertex.edges_out.begin();
ei != vertex.edges_out.end();
ei++) {
other_count[p.get_cell(*ei)->first]++;
} for (Partition::Cell* cell2 = p.first_cell; cell2;
cell2 = cell2->next) { if (first_count[cell2->first] != other_count[cell2->first]) { /* Not equitable */ returnfalse;
}
other_count[cell2->first] = 0;
}
} /* Reset first_count */ for (unsignedint i = 0; i < N; i++)
first_count[i] = 0;
}
/* *Checkequitablednessw.r.t.incomingedges
*/ for (Partition::Cell* cell = p.first_cell; cell; cell = cell->next) { if (cell->is_unit()) continue;
/* Count incoming edges of the first vertex for cells */ for (std::vector<unsignedint>::const_iterator ei
= first_vertex.edges_in.begin();
ei != first_vertex.edges_in.end();
ei++) {
first_count[p.get_cell(*ei)->first]++;
}
/* Count and compare incoming edges of the other vertices */ for (unsignedint i = cell->length; i > 1; i--) { const Vertex& vertex = vertices[*ep++]; for (std::vector<unsignedint>::const_iterator ei
= vertex.edges_in.begin();
ei != vertex.edges_in.end();
ei++) {
other_count[p.get_cell(*ei)->first]++;
} for (Partition::Cell* cell2 = p.first_cell; cell2;
cell2 = cell2->next) { if (first_count[cell2->first] != other_count[cell2->first]) { /* Not equitable */ returnfalse;
}
other_count[cell2->first] = 0;
}
} /* Reset first_count */ for (unsignedint i = 0; i < N; i++)
first_count[i] = 0;
} returntrue;
}
#ifdefined(BLISS_CONSISTENCY_CHECKS) if (!is_permutation(get_nof_vertices(), perm))
_INTERNAL_ERROR(); #endif
for (unsignedint i = 0; i < get_nof_vertices(); i++) {
Vertex& v1 = vertices[i];
Vertex& v2 = vertices[perm[i]];
edges1.clear(); for (std::vector<unsignedint>::iterator ei = v1.edges_in.begin();
ei != v1.edges_in.end();
ei++)
edges1.insert(perm[*ei]);
edges2.clear(); for (std::vector<unsignedint>::iterator ei = v2.edges_in.begin();
ei != v2.edges_in.end();
ei++)
edges2.insert(*ei); if (!(edges1 == edges2)) returnfalse;
edges1.clear(); for (std::vector<unsignedint>::iterator ei = v1.edges_out.begin();
ei != v1.edges_out.end();
ei++)
edges1.insert(perm[*ei]);
edges2.clear(); for (std::vector<unsignedint>::iterator ei = v2.edges_out.begin();
ei != v2.edges_out.end();
ei++)
edges2.insert(*ei); if (!(edges1 == edges2)) returnfalse;
}
returntrue;
}
bool Digraph::is_automorphism(const std::vector<unsignedint>& perm) const { if (!(perm.size() == get_nof_vertices() and is_permutation(perm))) returnfalse;
for (unsignedint i = 0; i < get_nof_vertices(); i++) { const Vertex& v1 = vertices[i]; const Vertex& v2 = vertices[perm[i]];
edges1.clear(); for (std::vector<unsignedint>::const_iterator ei = v1.edges_in.begin();
ei != v1.edges_in.end();
ei++)
edges1.insert(perm[*ei]);
edges2.clear(); for (std::vector<unsignedint>::const_iterator ei = v2.edges_in.begin();
ei != v2.edges_in.end();
ei++)
edges2.insert(*ei); if (!(edges1 == edges2)) returnfalse;
edges1.clear(); for (std::vector<unsignedint>::const_iterator ei = v1.edges_out.begin();
ei != v1.edges_out.end();
ei++)
edges1.insert(perm[*ei]);
edges2.clear(); for (std::vector<unsignedint>::const_iterator ei = v2.edges_out.begin();
ei != v2.edges_out.end();
ei++)
edges2.insert(*ei); if (!(edges1 == edges2)) returnfalse;
}
/* Skip unit neighbours */ if (neighbour_cell->is_unit()) continue; /* Already marked to be in the same component? */ if (neighbour_cell->max_ival == 1) continue; /* Is the neighbour at the same component recursion level? */ if (p.cr_get_level(neighbour_cell->first) != level) continue;
if (neighbour_cell->max_ival_count == 0)
neighbour_heap.insert(neighbour_cell->first);
neighbour_cell->max_ival_count++;
} while (!neighbour_heap.is_empty()) { constunsignedint start = neighbour_heap.remove();
Partition::Cell* const neighbour_cell = p.get_cell(p.elements[start]);
/* Skip unit neighbours */ if (neighbour_cell->is_unit()) continue; /* Already marked to be in the same component? */ if (neighbour_cell->max_ival == 1) continue; /* Is the neighbour at the same component recursion level? */ if (p.cr_get_level(neighbour_cell->first) != level) continue;
if (neighbour_cell->max_ival_count == 0)
neighbour_heap.insert(neighbour_cell->first);
neighbour_cell->max_ival_count++;
} while (!neighbour_heap.is_empty()) { constunsignedint start = neighbour_heap.remove();
Partition::Cell* const neighbour_cell = p.get_cell(p.elements[start]);
for (unsignedint i = 0; i < component.size(); i++) {
Partition::Cell* const cell = component[i];
cell->max_ival = 0;
cr_component.push_back(cell->first);
cr_component_elements += cell->length;
}
if (verbstr and verbose_level > 2) {
fprintf(verbstr, "NU-component with %lu cells and %u vertices\n",
(longunsigned) cr_component.size(),
cr_component_elements);
fflush(verbstr);
}
/* Skip unit neighbours */ if (neighbour_cell->is_unit()) continue; /* Is the neighbour at the same component recursion level? */ // if(p.cr_get_level(neighbour_cell->first) != level) // continue; if (neighbour_cell->max_ival_count == 0)
neighbours.push(neighbour_cell);
neighbour_cell->max_ival_count++;
} while (!neighbours.is_empty()) {
Partition::Cell* const neighbour_cell = neighbours.pop(); /* Skip saturated neighbour cells */ if (neighbour_cell->max_ival_count == neighbour_cell->length) {
neighbour_cell->max_ival_count = 0; continue;
}
nuconn++;
neighbour_cell->max_ival_count = 0; if (neighbour_cell->max_ival == 0) {
comp.push_back(neighbour_cell);
neighbour_cell->max_ival = 1;
}
}
/*| Phase 2: incoming edges */
ei = v.edges_in.begin(); for (unsignedint j = v.nof_edges_in(); j > 0; j--) { constunsignedint neighbour = *ei++;
Partition::Cell* const neighbour_cell = p.get_cell(neighbour); /*| Skip unit neighbours */ if (neighbour_cell->is_unit()) continue; /* Is the neighbour at the same component recursion level? */ // if(p.cr_get_level(neighbour_cell->first) != level) // continue; if (neighbour_cell->max_ival_count == 0)
neighbours.push(neighbour_cell);
neighbour_cell->max_ival_count++;
} while (!neighbours.is_empty()) {
Partition::Cell* const neighbour_cell = neighbours.pop(); /* Skip saturated neighbour cells */ if (neighbour_cell->max_ival_count == neighbour_cell->length) {
neighbour_cell->max_ival_count = 0; continue;
}
nuconn++;
neighbour_cell->max_ival_count = 0; if (neighbour_cell->max_ival == 0) {
comp.push_back(neighbour_cell);
neighbour_cell->max_ival = 1;
}
}
/*| Phase 3: splitting heuristics */ switch (sh) { case shs_f: if (cell->first <= sh_first) {
sh_return = cell;
sh_first = cell->first;
} break; case shs_fs: if (cell->length < sh_size or (cell->length == sh_size and cell->first <= sh_first)) {
sh_return = cell;
sh_first = cell->first;
sh_size = cell->length;
} break; case shs_fl: if (cell->length > sh_size or (cell->length == sh_size and cell->first <= sh_first)) {
sh_return = cell;
sh_first = cell->first;
sh_size = cell->length;
} break; case shs_fm: if (nuconn > sh_nuconn or (nuconn == sh_nuconn and cell->first <= sh_first)) {
sh_return = cell;
sh_first = cell->first;
sh_nuconn = nuconn;
} break; case shs_fsm: if (nuconn > sh_nuconn or (nuconn == sh_nuconn and (cell->length < sh_size or (cell->length == sh_size and cell->first <= sh_first)))) {
sh_return = cell;
sh_first = cell->first;
sh_size = cell->length;
sh_nuconn = nuconn;
} break; case shs_flm: if (nuconn > sh_nuconn or (nuconn == sh_nuconn and (cell->length > sh_size or (cell->length == sh_size and cell->first <= sh_first)))) {
sh_return = cell;
sh_first = cell->first;
sh_size = cell->length;
sh_nuconn = nuconn;
} break; default: // fatal_error("Internal error - unknown splitting heuristics"); returnfalse;
}
} if (sh_return == NULL) { returnfalse;
}
for (unsignedint i = 0; i < comp.size(); i++) {
Partition::Cell* const cell = comp[i];
cell->max_ival = 0;
component.push_back(cell->first);
component_elements += cell->length;
}
if (verbstr and verbose_level > 2) {
fprintf(verbstr, "NU-component with %lu cells and %u vertices\n",
(longunsigned) component.size(),
component_elements);
fflush(verbstr);
}
void Graph::Vertex::remove_duplicate_edges(std::vector<bool>& tmp) { #ifdefined(BLISS_CONSISTENCY_CHECKS) /* Pre-conditions */ for (unsignedint i = 0; i < tmp.size(); i++)
assert(tmp[i] == false); #endif for (std::vector<unsignedint>::iterator iter = edges.begin();
iter != edges.end();) { constunsignedint dest_vertex = *iter; if (tmp[dest_vertex] == true) { /* A duplicate edge found! */
iter = edges.erase(iter);
} else { /* Not seen earlier, mark as seen */
tmp[dest_vertex] = true;
iter++;
}
}
/* Clear tmp */ for (std::vector<unsignedint>::iterator iter = edges.begin();
iter != edges.end();
iter++) {
tmp[*iter] = false;
} #ifdefined(BLISS_CONSISTENCY_CHECKS) /* Post-conditions */ for (unsignedint i = 0; i < tmp.size(); i++)
assert(tmp[i] == false); #endif
}
/* Read comments and the problem definition line */ while (1) {
c = getc(fp); if (c == 'c') { /* A comment, ignore the rest of the line */ while ((c = getc(fp)) != '\n') { if (c == EOF) { if (errstr)
fprintf(
errstr, "error in line %u: not in DIMACS format\n", line_num); goto error_exit;
}
}
line_num++; continue;
} if (c == 'p') { /* The problem definition line */ if (fscanf(fp, " edge %u %u\n", &nof_vertices, &nof_edges) != 2) { if (errstr)
fprintf(
errstr, "error in line %u: not in DIMACS format\n", line_num); goto error_exit;
}
line_num++; break;
} if (errstr)
fprintf(errstr, "error in line %u: not in DIMACS format\n", line_num); goto error_exit;
}
if (nof_vertices <= 0) { if (errstr)
fprintf(errstr, "error: no vertices\n"); goto error_exit;
} if (verbose) {
fprintf(verbstr, "Instance has %d vertices and %d edges\n",
nof_vertices,
nof_edges);
fflush(verbstr);
}
g = new Graph(nof_vertices);
// // Read vertex colors // if (verbose) {
fprintf(verbstr, "Reading vertex colors...\n");
fflush(verbstr);
} while (1) {
c = getc(fp); if (c != 'n') {
ungetc(c, fp); break;
}
ungetc(c, fp); unsignedint vertex; unsignedint color; if (fscanf(fp, "n %u %u\n", &vertex, &color) != 2) { if (errstr)
fprintf(errstr, "error in line %u: not in DIMACS format\n", line_num); goto error_exit;
} if (!((vertex >= 1) && (vertex <= nof_vertices))) { if (errstr)
fprintf(errstr, "error in line %u: vertex %u not in range [1,...,%u]\n",
line_num,
vertex,
nof_vertices); goto error_exit;
}
line_num++;
g->change_color(vertex - 1, color);
} if (verbose) {
fprintf(verbstr, "Done\n");
fflush(verbstr);
}
// // Read edges // if (verbose) {
fprintf(verbstr, "Reading edges...\n");
fflush(verbstr);
} for (unsigned i = 0; i < nof_edges; i++) { unsignedint from, to; if (fscanf(fp, "e %u %u\n", &from, &to) != 2) { if (errstr)
fprintf(errstr, "error in line %u: not in DIMACS format\n", line_num); goto error_exit;
} if (!((from >= 1) && (from <= nof_vertices))) { if (errstr)
fprintf(errstr, "error in line %u: vertex %u not in range [1,...,%u]\n",
line_num,
from,
nof_vertices); goto error_exit;
} if (!((to >= 1) && (to <= nof_vertices))) { if (errstr)
fprintf(errstr, "error in line %u: vertex %u not in range [1,...,%u]\n",
line_num,
to,
nof_vertices); goto error_exit;
}
line_num++;
g->add_edge(from - 1, to - 1);
} if (verbose) {
fprintf(verbstr, "Done\n");
fflush(verbstr);
}
/* First count the total number of edges */ unsignedint nof_edges = 0; for (unsignedint i = 0; i < get_nof_vertices(); i++) {
Vertex& v = vertices[i]; for (std::vector<unsignedint>::const_iterator ei = v.edges.begin();
ei != v.edges.end();
ei++) { constunsignedint dest_i = *ei; if (dest_i < i) continue;
nof_edges++;
}
}
/* Output the "header" line */
fprintf(fp, "p edge %u %u\n", get_nof_vertices(), nof_edges);
/* Print the color of each vertex */ for (unsignedint i = 0; i < get_nof_vertices(); i++) {
Vertex& v = vertices[i];
fprintf(fp, "n %u %u\n", i + 1, v.color); /* if(v.color!=0) { fprintf(fp,"n%u%u\n",i+1,v.color); }
*/
}
/* Print the edges */ for (unsignedint i = 0; i < get_nof_vertices(); i++) {
Vertex& v = vertices[i]; for (std::vector<unsignedint>::const_iterator ei = v.edges.begin();
ei != v.edges.end();
ei++) { constunsignedint dest_i = *ei; if (dest_i < i) continue;
fprintf(fp, "e %u %u\n", i + 1, dest_i + 1);
}
}
}
void Graph::sort_edges() { for (unsignedint i = 0; i < get_nof_vertices(); i++)
vertices[i].sort_edges();
}
int Graph::cmp(Graph& other) { /* Compare the numbers of vertices */ if (get_nof_vertices() < other.get_nof_vertices()) return -1; if (get_nof_vertices() > other.get_nof_vertices()) return1; /* Compare vertex colors */ for (unsignedint i = 0; i < get_nof_vertices(); i++) { if (vertices[i].color < other.vertices[i].color) return -1; if (vertices[i].color > other.vertices[i].color) return1;
} /* Compare vertex degrees */
remove_duplicate_edges();
other.remove_duplicate_edges(); for (unsignedint i = 0; i < get_nof_vertices(); i++) { if (vertices[i].nof_edges() < other.vertices[i].nof_edges()) return -1; if (vertices[i].nof_edges() > other.vertices[i].nof_edges()) return1;
} /* Compare edges */ for (unsignedint i = 0; i < get_nof_vertices(); i++) {
Vertex& v1 = vertices[i];
Vertex& v2 = other.vertices[i];
v1.sort_edges();
v2.sort_edges();
std::vector<unsignedint>::const_iterator ei1 = v1.edges.begin();
std::vector<unsignedint>::const_iterator ei2 = v2.edges.begin(); while (ei1 != v1.edges.end()) { if (*ei1 < *ei2) return -1; if (*ei1 > *ei2) return1;
ei1++;
ei2++;
}
} return0;
}
/* Hash the color of each vertex */ for (unsignedint i = 0; i < get_nof_vertices(); i++) {
h.update(vertices[i].color);
}
/* Hash the edges */ for (unsignedint i = 0; i < get_nof_vertices(); i++) {
Vertex& v = vertices[i]; for (std::vector<unsignedint>::const_iterator ei = v.edges.begin();
ei != v.edges.end();
ei++) { constunsignedint dest_i = *ei; if (dest_i < i) continue;
h.update(i);
h.update(dest_i);
}
}
for (std::vector<Vertex>::iterator vi = vertices.begin();
vi != vertices.end();
vi++) { #ifdefined(BLISS_EXPENSIVE_CONSISTENCY_CHECKS) for (unsignedint i = 0; i < tmp.size(); i++)
assert(tmp[i] == false); #endif
(*vi).remove_duplicate_edges(tmp);
}
}
/* Update certificate and hash if needed */ const Partition::Cell* c = neighbour_cell; while (1) { if (in_search) { /* Build certificate */
cert_add_redundant(CERT_SPLIT, c->first, c->length); /* No need to continue? */ if (refine_compare_certificate and (refine_equal_to_first == false) and (refine_cmp_to_best < 0)) goto worse_exit;
} if (compute_eqref_hash) {
eqref_hash.update(c->first);
eqref_hash.update(c->length);
} if (c == last_new_cell) break;
c = c->next;
}
}
if (refine_compare_certificate and (refine_equal_to_first == false) and (refine_cmp_to_best < 0)) returntrue;
returnfalse;
worse_exit: /* Clear neighbour heap */
UintSeqHash rest; while (!neighbour_heap.is_empty()) { constunsignedint start = neighbour_heap.remove();
Partition::Cell* const neighbour_cell = p.get_cell(p.elements[start]); if (opt_use_failure_recording and was_equal_to_first) {
rest.update(neighbour_cell->first);
rest.update(neighbour_cell->length);
rest.update(neighbour_cell->max_ival);
rest.update(neighbour_cell->max_ival_count);
}
neighbour_cell->max_ival = 0;
neighbour_cell->max_ival_count = 0;
p.clear_ivs(neighbour_cell);
} if (opt_use_failure_recording and was_equal_to_first) { for (unsignedint i = p.splitting_queue.size(); i > 0; i--) {
Partition::Cell* const cell3 = p.splitting_queue.pop_front();
rest.update(cell3->first);
rest.update(cell3->length);
p.splitting_queue.push_back(cell3);
}
rest.update(failure_recording_fp_deviation);
failure_recording_fp_deviation = rest.get_value();
}
if (neighbour_cell->is_unit()) { if (in_search) { /* Remember neighbour in order to generate certificate */
neighbour_heap.insert(neighbour_cell->first);
} continue;
} if (neighbour_cell->max_ival_count == 0) {
neighbour_heap.insert(neighbour_cell->first);
}
neighbour_cell->max_ival_count++;
/* Add cells in splitting_queue */ if (neighbour_cell->is_in_splitting_queue()) { /* Both cells must be included in splitting_queue in order
to ensure refinement into equitable partition */
p.splitting_queue_add(new_cell);
} else {
Partition::Cell *min_cell, *max_cell; if (neighbour_cell->length <= new_cell->length) {
min_cell = neighbour_cell;
max_cell = new_cell;
} else {
min_cell = new_cell;
max_cell = neighbour_cell;
} /* Put the smaller cell in splitting_queue */
p.splitting_queue_add(min_cell); if (max_cell->is_unit()) { /* Put the "larger" cell also in splitting_queue */
p.splitting_queue_add(max_cell);
}
} /* Update pointer for certificate generation */
neighbour_cell = new_cell;
} else { /* neighbour_cell->length == 1 ||
neighbour_cell->max_ival_count == neighbour_cell->length */
neighbour_cell->max_ival_count = 0;
}
/* *Buildcertificateifrequired
*/ if (in_search) { for (unsignedint i = neighbour_cell->first, j = neighbour_cell->length;
j > 0;
j--, i++) { /* Build certificate */
cert_add(CERT_EDGE, unit_cell->first, i); /* No need to continue? */ if (refine_compare_certificate and (refine_equal_to_first == false) and (refine_cmp_to_best < 0)) goto worse_exit;
}
} /* if(in_search) */
} /* while(!neighbour_heap.is_empty()) */
if (refine_compare_certificate and (refine_equal_to_first == false) and (refine_cmp_to_best < 0)) returntrue;
returnfalse;
worse_exit: /* Clear neighbour heap */
UintSeqHash rest; while (!neighbour_heap.is_empty()) { constunsignedint start = neighbour_heap.remove();
Partition::Cell* const neighbour_cell = p.get_cell(p.elements[start]); if (opt_use_failure_recording and was_equal_to_first) {
rest.update(neighbour_cell->first);
rest.update(neighbour_cell->length);
rest.update(neighbour_cell->max_ival_count);
}
neighbour_cell->max_ival_count = 0;
} if (opt_use_failure_recording and was_equal_to_first) {
rest.update(failure_recording_fp_deviation);
failure_recording_fp_deviation = rest.get_value();
} returntrue;
}
/* Count how many edges lead from the first vertex to
* the neighbouring cells */ for (std::vector<unsignedint>::const_iterator ei
= first_vertex.edges.begin();
ei != first_vertex.edges.end();
ei++) {
first_count[p.get_cell(*ei)->first]++;
}
/* Count and compare to the edges of the other vertices */ for (unsignedint i = cell->length; i > 1; i--) { const Vertex& vertex = vertices[*ep++]; for (std::vector<unsignedint>::const_iterator ei
= vertex.edges.begin();
ei != vertex.edges.end();
ei++) {
other_count[p.get_cell(*ei)->first]++;
} for (Partition::Cell* cell2 = p.first_cell; cell2;
cell2 = cell2->next) { if (first_count[cell2->first] != other_count[cell2->first]) { /* Not equitable */ returnfalse;
}
other_count[cell2->first] = 0;
}
} /* Reset first_count */ for (unsignedint i = 0; i < N; i++)
first_count[i] = 0;
} returntrue;
}
#ifdefined(BLISS_CONSISTENCY_CHECKS) if (!is_permutation(get_nof_vertices(), perm))
_INTERNAL_ERROR(); #endif
for (unsignedint i = 0; i < get_nof_vertices(); i++) {
Vertex& v1 = vertices[i];
edges1.clear(); for (std::vector<unsignedint>::iterator ei = v1.edges.begin();
ei != v1.edges.end();
ei++)
edges1.insert(perm[*ei]);
Vertex& v2 = vertices[perm[i]];
edges2.clear(); for (std::vector<unsignedint>::iterator ei = v2.edges.begin();
ei != v2.edges.end();
ei++)
edges2.insert(*ei);
if (!(edges1 == edges2)) returnfalse;
}
returntrue;
}
bool Graph::is_automorphism(const std::vector<unsignedint>& perm) const { if (!(perm.size() == get_nof_vertices() and is_permutation(perm))) returnfalse;
for (unsignedint i = 0; i < get_nof_vertices(); i++) { const Vertex& v1 = vertices[i];
edges1.clear(); for (std::vector<unsignedint>::const_iterator ei = v1.edges.begin();
ei != v1.edges.end();
ei++)
edges1.insert(perm[*ei]);
const Vertex& v2 = vertices[perm[i]];
edges2.clear(); for (std::vector<unsignedint>::const_iterator ei = v2.edges.begin();
ei != v2.edges.end();
ei++)
edges2.insert(*ei);
/* Skip unit neighbours */ if (neighbour_cell->is_unit()) continue; /* Already marked to be in the same component? */ if (neighbour_cell->max_ival == 1) continue; /* Is the neighbour at the same component recursion level? */ if (p.cr_get_level(neighbour_cell->first) != level) continue;
if (neighbour_cell->max_ival_count == 0)
neighbour_heap.insert(neighbour_cell->first);
neighbour_cell->max_ival_count++;
} while (!neighbour_heap.is_empty()) { constunsignedint start = neighbour_heap.remove();
Partition::Cell* const neighbour_cell = p.get_cell(p.elements[start]);
for (unsignedint i = 0; i < component.size(); i++) {
Partition::Cell* const cell = component[i];
cell->max_ival = 0;
cr_component.push_back(cell->first);
cr_component_elements += cell->length;
}
if (verbstr and verbose_level > 2) {
fprintf(verbstr, "NU-component with %lu cells and %u vertices\n",
(longunsigned) cr_component.size(),
cr_component_elements);
fflush(verbstr);
}
switch (sh) { case shs_f: if (cell->first <= sh_first) {
sh_return = cell;
sh_first = cell->first;
} break; case shs_fs: if (cell->length < sh_size or (cell->length == sh_size and cell->first <= sh_first)) {
sh_return = cell;
sh_first = cell->first;
sh_size = cell->length;
} break; case shs_fl: if (cell->length > sh_size or (cell->length == sh_size and cell->first <= sh_first)) {
sh_return = cell;
sh_first = cell->first;
sh_size = cell->length;
} break; case shs_fm: if (nuconn > sh_nuconn or (nuconn == sh_nuconn and cell->first <= sh_first)) {
sh_return = cell;
sh_first = cell->first;
sh_nuconn = nuconn;
} break; case shs_fsm: if (nuconn > sh_nuconn or (nuconn == sh_nuconn and (cell->length < sh_size or (cell->length == sh_size and cell->first <= sh_first)))) {
sh_return = cell;
sh_first = cell->first;
sh_size = cell->length;
sh_nuconn = nuconn;
} break; case shs_flm: if (nuconn > sh_nuconn or (nuconn == sh_nuconn and (cell->length > sh_size or (cell->length == sh_size and cell->first <= sh_first)))) {
sh_return = cell;
sh_first = cell->first;
sh_size = cell->length;
sh_nuconn = nuconn;
} break; default:
fatal_error("Internal error - unknown splitting heuristics"); return0;
}
}
assert(sh_return);
for (unsignedint i = 0; i < comp.size(); i++) {
Partition::Cell* const cell = comp[i];
cell->max_ival = 0;
component.push_back(cell->first);
component_elements += cell->length;
}
if (verbstr and verbose_level > 2) {
fprintf(verbstr, "NU-component with %lu cells and %u vertices\n",
(longunsigned) component.size(),
component_elements);
fflush(verbstr);
}
returntrue;
}
} // namespace bliss_digraphs
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.119 Sekunden
(vorverarbeitet am 2026-09-10)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.