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; }
} 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 $m->shuffle(); $m->run(); $assignments[mcmf_assignment_text($m)] = true; } $assignments = array_keys($assignments); sort($assignments); xassert_eqq(count($assignments), 6); xassert_eqq($assignments[0], "u0 p0\nu1 p1\nu2 p2\n"); xassert_eqq($assignments[1], "u0 p0\nu1 p2\nu2 p1\n"); xassert_eqq($assignments[2], "u0 p1\nu1 p0\nu2 p2\n"); xassert_eqq($assignments[3], "u0 p1\nu1 p2\nu2 p0\n"); xassert_eqq($assignments[4], "u0 p2\nu1 p0\nu2 p1\n"); xassert_eqq($assignments[5], "u0 p2\nu1 p1\nu2 p0\n"); fwrite(STDERR, "- Phase 4 complete.\n"); $m = new MinCostMaxFlow(); $m->parse_dimacs("n 1 s\nn 2 t\nc ninfo 3 u0 u\nc ninfo 4 u1 u\nc ninfo 5 u2 u\nc ninfo 6 p0 p\nc ninfo 7 p1 p\nc ninfo 8 p2 p\na 1 3 1\na 1 4 1\na 1 5 1\na 3 6 0 1 0\na 3 7 0 1 -1\na 4 6 0 1 0\na 4 7 0 1 0\na 4 8 0 1 0\na 5 6 0 1 0\na 5 8 0 1 1\na 6 2 1\na 7 2 1\na 8 2 1"); $m->run(); xassert_eqq(mcmf_assignment_text($m), "u0 p1\nu1 p2\nu2 p0\n"); xassert_eqq(preg_replace('/^c[^\\n]*\\n/m', "", $m->mincost_dimacs_output()), "s -1\nf 1 3 1\nf 1 4 1\nf 1 5 1\nf 3 7 1\nf 4 8 1\nf 5 6 1\nf 6 2 1\nf 7 2 1\nf 8 2 1\n"); xassert_exit();