private function run_discussion_order_once($cflt, $plist) { $m = new MinCostMaxFlow(); $m->add_progressf(array($this, "mcmf_progress")); $this->set_progress("Preparing assignment optimizer"); // paper nodes // set p->po edge cost so low that traversing that edge will // definitely lower total cost; all positive costs are <= // count($this->pcm), so this edge should have cost: $pocost = -(count($this->pcm) + 1); $this->mcmf_max_cost = $pocost * count($plist) * 0.75; $m->add_node(".s", "source"); $m->add_edge(".source", ".s", 1, 0); foreach ($plist as $i => $pids) { $m->add_node("p{$i}", "p"); $m->add_node("po{$i}", "po"); $m->add_edge(".s", "p{$i}", 1, 0); $m->add_edge("p{$i}", "po{$i}", 1, $pocost); $m->add_edge("po{$i}", ".sink", 1, 0); } // conflict edges $plist2 = $plist; // need copy for different iteration ptr foreach ($plist as $i => $pid1) { foreach ($plist2 as $j => $pid2) { if ($i != $j) { $pid1 = is_array($pid1) ? $pid1[count($pid1) - 1] : $pid1; $pid2 = is_array($pid2) ? $pid2[0] : $pid2; // cost of edge is number of different conflicts $cost = count($cflt[$pid1] + $cflt[$pid2]) - count(array_intersect($cflt[$pid1], $cflt[$pid2])); $m->add_edge("po{$i}", "p{$j}", 1, $cost); } } } // run MCMF $this->mcmf = $m; $m->shuffle(); $m->run(); // extract next roots $roots = array_keys($plist); $result = array(); while (count($roots)) { $source = ".source"; if (count($roots) !== count($plist)) { $source = "p" . $roots[mt_rand(0, count($roots) - 1)]; } $pgroup = $igroup = array(); foreach ($m->topological_sort($source, "p") as $v) { $pidx = (int) substr($v->name, 1); $igroup[] = $pidx; if (is_array($plist[$pidx])) { $pgroup = array_merge($pgroup, $plist[$pidx]); } else { $pgroup[] = $plist[$pidx]; } } $result[] = $pgroup; $roots = array_values(array_diff($roots, $igroup)); } // done $m->clear(); // break circular refs $this->mcmf = null; $this->profile["maxflow"] += $m->maxflow_end_at - $m->maxflow_start_at; if ($m->mincost_start_at) { $this->profile["mincost"] += $m->mincost_end_at - $m->mincost_start_at; } return $result; }
// the shuffle() uses this seed $m->shuffle(); $m->run(); $assignments[mcmf_assignment_text($m)] = true; } $assignments = array_keys($assignments); sort($assignments); xassert_eqq(count($assignments), 2); xassert_eqq($assignments[0], "u0 p0\nu1 p1\nu2 p2\n"); xassert_eqq($assignments[1], "u0 p1\nu1 p0\nu2 p2\n"); fwrite(STDERR, "- Phase 3 complete.\n"); // (4) all zero preferences => all possible results; this uses push-relabel $m = new MinCostMaxFlow(); foreach (array("u0", "u1", "u2") as $x) { $m->add_node($x, "u"); $m->add_edge(".source", $x, 1); } foreach (array("p0", "p1", "p2") as $x) { $m->add_node($x, "p"); $m->add_edge($x, ".sink", 1); } foreach (array("u0", "u1", "u2") as $x) { foreach (array("p0", "p1", "p2") as $y) { $m->add_edge($x, $y, 1); } } $assignments = array(); foreach (range(100, 921384, 1247) as $seed) { $m->reset(); srand($seed); // the shuffle() uses this seed