<tb@panthema.net>
<http://www.gnu.org/licenses/>
#ifndef BISPANNING_ALG_PLAY_DECOMPOSE_HEADER
#define BISPANNING_ALG_PLAY_DECOMPOSE_HEADER
#include "alg_game.h"
struct AlgPlayDecompose
{
static const bool debug = true;
using id_type = BaseGraph::id_type;
using vertex = BaseGraph::vertex_iterator;
using edge = BaseGraph::edge_iterator;
using vertex_edge = BaseGraph::vertex_edge_iterator;
using const_vertex = BaseGraph::const_vertex_iterator;
using const_edge = BaseGraph::const_edge_iterator;
using const_vertex_edge = BaseGraph::const_vertex_edge_iterator;
using tvertex = TauGraph::vertex_iterator;
using tedge = TauGraph::edge_iterator;
using tvertex_edge = TauGraph::vertex_edge_iterator;
using Exchange = TauEdge;
using ExchangeList = std::vector<Exchange>;
using ExchangeListList = std::vector<ExchangeList>;
void checked_unique_exchange(BaseGraph& g, edge& eM, edge& eB)
{
assert(g.contains(eM) && g.contains(eB));
DBGG("swap: " << eM << " - " << eB);
if (eM->dashed) {
DBGG("ALREADY SWAPPED! " << eM);
}
if (eB->dashed) {
DBGG("ALREADY SWAPPED! " << eB);
}
std::vector<edge> xchg = g.calc_exchange_edges(eM);
DBGG("exchanges: " << xchg);
if (xchg.size() != 1) {
DBGG("NON-UNIQUE EXCHANGE!");
abort();
}
else if (xchg[0] != eB) {
DBGG("NON-MATCHING UNIQUE EXCHANGE!");
abort();
}
std::swap(eM->color, eB->color);
eM->dashed = eB->dashed = true;
}
template <bool CheckLeafUE = false>
void do_checked_unique_exchange(BaseGraph& g, const Exchange& xchg)
{
static const bool debug = false;
edge eM = g.edge(xchg.UEin), eB = g.edge(xchg.UEout);
DBGG("swap: " << eM << " - " << eB);
if (eM->dashed) {
DBGG1("ALREADY SWAPPED! " << eM);
abort();
}
if (eB->dashed) {
DBGG1("ALREADY SWAPPED! " << eB);
abort();
}
if (eM->color + 1 != xchg.colors) {
DBGG1("WRONG SWAP COLOR! " << xchg.colors + 1 << " != " << eM->color);
abort();
}
if (CheckLeafUE)
{
unsigned int in_head = 0, in_tail = 0;
for (vertex_edge ve : eM.head().edge_list()) {
if (ve->color == eM->color)
++in_head;
}
for (vertex_edge ve : eM.tail().edge_list()) {
if (ve->color == eM->color)
++in_tail;
}
std::cerr << "head/tail: " << in_head << " - " << in_tail << "\n";
if (in_head != 1 && in_tail != 1) {
DBGG1("NON-LEAF UNIQUE EXCHANGE! " << xchg);
abort();
}
}
std::vector<edge> swaps = g.calc_exchange_edges(eM);
DBGG("swappable edge exchanges: " << swaps);
if (swaps.size() != 1) {
DBGG1("NON-UNIQUE EXCHANGE! " << xchg);
abort();
}
else if (swaps[0] != eB) {
DBGG1("NON-MATCHING UNIQUE EXCHANGE! " << xchg);
abort();
}
std::swap(eM->color, eB->color);
eM->dashed = eB->dashed = true;
}
template <bool CheckLeafUE = false>
void do_checked_leaf_sequence(const BaseGraph& _g,
const ExchangeList& xchglist)
{
static const bool debug = true;
BaseGraph g = _g;
Tree src_tree = extract_tree(g, RED);
Tree tgt_tree = tree_complement(src_tree, g);
DBG(g.graphviz());
for (const Exchange& xchg : xchglist)
{
do_checked_unique_exchange<CheckLeafUE>(g, xchg);
DBG(g.graphviz());
}
if (extract_tree(g, RED) != tgt_tree) {
DBGG1("NON-INVERTING EXCHANGE SEQUENCE!");
abort();
}
}
bool is_atomic_or_get_partition(const BaseGraph& g)
{
static const bool debug = false;
std::vector<id_type> vmap(g.total_vertex());
id_type i = 0;
for (const_vertex v : g.vertex_list())
vmap[v.vertex_id()] = i++;
std::vector<std::vector<size_t> > comp_partition;
DBG(g.graphviz());
enumerate_set_partitions(
g.num_vertex(),
[&](const std::vector<size_t>& setp)
{
size_t np = *std::max_element(setp.begin(), setp.end()) + 1;
if (np == 1 || np == g.num_vertex()) return true;
unsigned int cross = 0;
for (const_edge e : g.edge_list())
{
id_type v = e.tail_id(), w = e.head_id();
if (setp[vmap[v]] != setp[vmap[w]])
++cross;
}
DBGG(setp << " - " << np << " - cross " << cross);
if (cross == 2 * (np - 1)) {
DBGG(setp << " - " << np << " - cross " << cross);
comp_partition.push_back(setp);
{
BaseGraph g0 = g;
g0.m_title = "super-graph " + to_str(setp);
std::vector<id_type> v0(np, BaseGraph::ID_INVALID);
for (vertex v : g0.vertex_list())
{
id_type vi = v.vertex_id();
id_type vc = setp[vmap[vi]];
if (v0[vc] == BaseGraph::ID_INVALID) {
v0[vc] = vi;
}
else {
g0.contract(v0[vc], vi);
}
}
DBG(g0.graphviz());
if (!g0.is_connected())
abort();
}
for (size_t c = 0; c < np; ++c)
{
BaseGraph g0 = g;
g0.m_title = "sub-graph " + to_str(setp) + " c=" + to_str(c);
for (vertex v : g0.vertex_list())
{
id_type vi = v.vertex_id();
id_type vc = setp[vmap[vi]];
if (vc != c)
g0.delete_vertex(v);
}
DBG(g0.graphviz());
if (!g0.is_connected())
abort();
}
}
return true;
});
return comp_partition.size() == 0;
}
ExchangeListList get_exchangelist_list_direct(const BaseGraph& g)
{
static const bool debug = false;
TauGraph tau = AlgGame<BaseGraph>(g).tau_;
DBG(graphviz(tau, TauGraphDecorator()));
Tree src_tree = extract_tree(g, RED);
Tree tgt_tree = tree_complement(src_tree, g);
tvertex src = tau.find_vertex(src_tree);
tvertex tgt = tau.find_vertex(tgt_tree);
std::vector<std::vector<tedge> > allpaths
= tau.find_all_shortest_paths(src, tgt);
std::sort(allpaths.begin(), allpaths.end());
ExchangeListList listlist;
for (const std::vector<tedge>& uepath : allpaths)
{
std::vector<std::string> uedesc;
for (const tedge& ue : uepath)
{
std::ostringstream oss;
oss << ue->UEin << "->" << ue->UEout;
uedesc.push_back(oss.str());
}
std::cerr << vector_join(uedesc, " ") << "\n";
ExchangeList xchglist;
for (const tedge& ue : uepath)
xchglist.push_back(*ue);
if (debug)
do_checked_leaf_sequence<true>(g, xchglist);
listlist.push_back(xchglist);
}
return listlist;
}
void decompose_deg3(const BaseGraph& g, const_vertex deg3v)
{
DBGGE("decomposing atomic at deg(v)=3 : " << deg3v);
DBGGE(g.graphstring());
assert(deg3v.degree() == 3);
const_edge e0 = deg3v.edge(0);
const_edge e1 = deg3v.edge(1);
const_edge e2 = deg3v.edge(2);
int single_color = (e0->color + e1->color + e2->color) % 2;
int double_color = (single_color == BLUE ? RED : BLUE);
DBGGE("single_color = " << single_color << " - double_color = " << double_color);
if (e1->color == single_color) std::swap(e1, e0);
if (e2->color == single_color) std::swap(e2, e0);
assert(e1->color == e2->color);
id_type v1i = e1.other_id(deg3v);
id_type v2i = e2.other_id(deg3v);
std::vector<const_edge> cycle_path
= g.find_color_path(deg3v, e0.other(deg3v), double_color);
ASSERT(cycle_path[0] == e1 || cycle_path[0] == e2);
const_edge& e_cycle = cycle_path[0];
const_edge& e_noncycle = (cycle_path[0] == e1 ? e2 : e1);
BaseGraph gr = g;
gr.delete_vertex(deg3v.vertex_id());
edge e_split = gr.add_edge(v1i, v2i, EdgeT(double_color));
gr.m_title = "reduced at deg3v = " + to_str(deg3v.vertex_id());
DBG(gr.graphviz());
std::cerr << "original graph" << std::endl;
get_exchangelist_list_direct(g);
std::cerr << "reduced graph" << std::endl;
get_exchangelist_list_direct(gr);
exit(0);
(void)e_cycle;
(void)e_noncycle;
(void)e_split;
}
void algorithm_decompose(const BaseGraph& g)
{
bool is_atomic = is_atomic_or_get_partition(g);
if (is_atomic)
{
DBG0(g.graphviz());
assert(g.get_min_degree() == 3);
for (const_vertex deg3v : g.vertex_list())
{
if (deg3v.degree() != 3) continue;
DBG(g.graphviz());
decompose_deg3(g, deg3v);
}
}
else
{ }
}
explicit AlgPlayDecompose(const BaseGraph& _g)
{
DBG0(_g.graphviz());
TauGraph tau = AlgGame<BaseGraph>(_g).tau_;
DBG0(graphviz(tau, TauGraphDecorator()));
for (TauGraph::const_vertex_iterator vi : tau.vertex_list())
{
BaseGraph g = _g;
vi->tree.colorize_graph(g);
DBG1(g.graphviz());
algorithm_decompose(g);
}
}
};
#endif