From 5fe9189af349a7643ef3103981f1e04aa6eafa60 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Sat, 28 Oct 2023 15:51:53 +0200 Subject: [PATCH] New matching --- eval/defs.cpp | 2 +- eval/defs.hpp | 2 +- eval/visitors/eval_expr.cpp | 28 +++ sbg/map.cpp | 13 +- sbg/map.hpp | 2 + sbg/ord_pw_mdinter.cpp | 10 + sbg/ord_pw_mdinter.hpp | 2 + sbg/pw_map.cpp | 73 +++++- sbg/pw_map.hpp | 9 +- sbg/sbg_algorithms.cpp | 474 +++++++++++++++++++++++++++++++++--- sbg/sbg_algorithms.hpp | 77 +++++- sbg/unord_pw_mdinter.cpp | 10 + sbg/unord_pw_mdinter.hpp | 2 +- test/sbg4.test | 31 +++ test/sbg5.test | 31 +++ test/sbg6.test | 88 +++++++ 16 files changed, 796 insertions(+), 58 deletions(-) create mode 100644 test/sbg4.test create mode 100644 test/sbg5.test create mode 100644 test/sbg6.test diff --git a/eval/defs.cpp b/eval/defs.cpp index 3df978d..529ce9e 100755 --- a/eval/defs.cpp +++ b/eval/defs.cpp @@ -59,7 +59,7 @@ MaybeVValue VarEnv::operator[](VKey k) const FuncEnv::FuncEnv() {} FuncEnvType FuncEnv::mapping_ = {{"isEmpty", 0}, {"isMember", 1}, {"minElem", 2}, {"maxElem", 3}, {"lt", 4}, {"compose", 5}, {"inv", 6}, {"image", 7}, {"preImage", 8}, {"dom", 9}, {"combine", 10}, {"minMap", 11}, - {"reduce", 12}, {"minAdj", 13}, {"CC", 14}, {"minReach", 15}}; + {"reduce", 12}, {"minAdj", 13}, {"CC", 14}, {"minReach", 15}, {"matching", 16}}; MaybeFValue FuncEnv::operator[](FKey k) const { diff --git a/eval/defs.hpp b/eval/defs.hpp index 1d697eb..0b02a93 100755 --- a/eval/defs.hpp +++ b/eval/defs.hpp @@ -142,7 +142,7 @@ struct FuncEnv{ }; typedef enum { empty, member, min, max, lt, comp, inv, im, preim, dom, comb, min_map, red, min_adj - , connected, min_reach } Func; + , connected, min_reach, matching } Func; // Classes for pretty printing ------------------------------------------------ diff --git a/eval/visitors/eval_expr.cpp b/eval/visitors/eval_expr.cpp index e233e28..f6ccd9a 100755 --- a/eval/visitors/eval_expr.cpp +++ b/eval/visitors/eval_expr.cpp @@ -267,6 +267,7 @@ auto connected_visitor_ = Util::Overload { } }; +/* auto min_reach_visitor_ = Util::Overload { [](LIB::BaseDSBG a) { LIB::BaseMR mr(a); @@ -281,7 +282,22 @@ auto min_reach_visitor_ = Util::Overload { return ExprBaseType(); } }; +*/ +auto matching_visitor_ = Util::Overload { + [](LIB::BaseSBG a) { + LIB::BaseMatch match(a); + return ExprBaseType(match.calculate().matched_edges()); + }, + [](LIB::CanonSBG a) { + LIB::CanonMatch match(a); + return ExprBaseType(match.calculate().matched_edges()); + }, + [](auto a) { + Util::ERROR("Wrong arguments for minReach"); + return ExprBaseType(); + } +}; // ----------------------------------------------------------------------------- // Expression evaluator -------------------------------------------------------- @@ -564,6 +580,7 @@ ExprBaseType EvalExpression::operator()(AST::Call v) const } break; +/* case Eval::Func::min_reach: if (eval_args.size() == 1) { arity_ok = true; @@ -573,6 +590,17 @@ ExprBaseType EvalExpression::operator()(AST::Call v) const return result; } break; +*/ + + case Eval::Func::matching: + if (eval_args.size() == 1) { + arity_ok = true; + + SBGBaseType g = Apply(EvalGraph{}, eval_args[0]); + ExprBaseType result = std::visit(matching_visitor_, g); + return result; + } + break; default: Util::ERROR("EvalExpression: function %s not implemented", vname.c_str()); diff --git a/sbg/map.cpp b/sbg/map.cpp index 5423f03..3f4dc50 100755 --- a/sbg/map.cpp +++ b/sbg/map.cpp @@ -199,17 +199,20 @@ SBGMap composition(SBGMap sbgmap1, SBGMap sbgmap2) // Extra functions ------------------------------------------------------------- template -SBGMap minInv(SBGMap sbgmap) +SBGMap minInv(Set d, SBGMap sbgmap) { - Set dom = sbgmap.dom(); + Set dom = sbgmap.dom(), res_dom = image(restrict(d, sbgmap)); Exp e = sbgmap.exp(); if (cardinal(dom) == 1 || isConstant(e)) - return SBGMap(image(sbgmap), Exp(minElem(dom))); + return SBGMap(res_dom, Exp(minElem(sbgmap.dom()))); - return SBGMap(image(sbgmap), inverse(e)); + return SBGMap(res_dom, inverse(e)); } +template +SBGMap minInv(SBGMap sbgmap) { return minInv(sbgmap.dom(), sbgmap); } + template std::size_t hash_value(const SBGMap &sbgmap) { @@ -230,6 +233,7 @@ template UnordSet image(UnordSet subdom, BaseMap sbgmap); template UnordSet preImage(BaseMap sbgmap); template UnordSet preImage(UnordSet subdom, BaseMap sbgmap); template BaseMap composition(BaseMap sbgmap1, BaseMap sbgmap2); +template BaseMap minInv(UnordSet im, BaseMap sbgmap); template BaseMap minInv(BaseMap sbgmap); template std::size_t hash_value(const BaseMap &sbgmap); @@ -241,6 +245,7 @@ template OrdSet image(OrdSet subdom, CanonMap sbgmap); template OrdSet preImage(CanonMap sbgmap); template OrdSet preImage(OrdSet subdom, CanonMap sbgmap); template CanonMap composition(CanonMap sbgmap1, CanonMap sbgmap2); +template CanonMap minInv(OrdSet im, CanonMap sbgmap); template CanonMap minInv(CanonMap sbgmap); template std::size_t hash_value(const CanonMap &sbgmap); diff --git a/sbg/map.hpp b/sbg/map.hpp index 28b66a2..3fbc7e6 100755 --- a/sbg/map.hpp +++ b/sbg/map.hpp @@ -89,6 +89,8 @@ SBGMap composition(SBGMap sbgmap1, SBGMap sbgmap2); * @brief Extra operations. */ +template +SBGMap minInv(Set im, SBGMap sbgmap); template SBGMap minInv(SBGMap sbgmap); diff --git a/sbg/ord_pw_mdinter.cpp b/sbg/ord_pw_mdinter.cpp index e2ca4d4..d2b6491 100755 --- a/sbg/ord_pw_mdinter.cpp +++ b/sbg/ord_pw_mdinter.cpp @@ -353,6 +353,16 @@ OrdPWMDInter concatenation(OrdPWMDInter pwi1, OrdPWMDInter pwi2) return res; } +OrdPWMDInter filterSet(bool (*f)(SetPiece), OrdPWMDInter pwi) +{ + OrdPWMDInter res; + + BOOST_FOREACH (SetPiece mdi, pwi) + if (f(mdi)) res.emplace_hint(res.end(), mdi); + + return res; +} + MDInterOrdSet boundedTraverse(OrdPWMDInter pwi1, OrdPWMDInter pwi2, SetPiece (*func)(SetPiece, SetPiece)) { MDInterOrdSet result; diff --git a/sbg/ord_pw_mdinter.hpp b/sbg/ord_pw_mdinter.hpp index 0b5d28d..eb05c9c 100755 --- a/sbg/ord_pw_mdinter.hpp +++ b/sbg/ord_pw_mdinter.hpp @@ -145,6 +145,8 @@ MDInterOrdSet canonize(MDInterOrdSet ii); */ OrdPWMDInter concatenation(OrdPWMDInter pwi1, OrdPWMDInter pwi2); +OrdPWMDInter filterSet(bool (*f)(SetPiece), OrdPWMDInter pwi); + /** @function boundedTraverse * * @brief Traverse pwis in order until one reaches its end, obtaining an ordered diff --git a/sbg/pw_map.cpp b/sbg/pw_map.cpp index 3fff3b4..70f99f2 100755 --- a/sbg/pw_map.cpp +++ b/sbg/pw_map.cpp @@ -71,7 +71,10 @@ PWMap::PWMap(Set s) : maps_() { } } template -PWMap::PWMap(SBGMap sm) : maps_() { maps_ref().emplace(sm); } +PWMap::PWMap(SBGMap sm) : maps_() { + if (!isEmpty(sm.dom())) + maps_ref().emplace(sm); +} template PWMap::PWMap(MapSet maps) : maps_(maps) {} @@ -542,9 +545,9 @@ PWMap minMap(Set dom, Exp e1, Exp e2, Exp e3, Exp e4) BOOST_FOREACH (SetPiece dom_piece, dom) { PWMap ith = minMap(dom_piece, e1, e2, e3, e4); BOOST_FOREACH (SBGMap sbgmap, ith) { - if (sbgmap.exp() == e2) d2 = concatenation(d2, sbgmap.dom()); + if (sbgmap.exp() == e2) d2 = cup(d2, sbgmap.dom()); // HERE - else d3 = concatenation(d3, sbgmap.dom()); + else d3 = cup(d3, sbgmap.dom()); // HERE } } @@ -719,20 +722,22 @@ PWMap minAdjMap(PWMap pw1, PWMap pw2) } template -PWMap minInv(PWMap pw) +PWMap minInv(Set d, PWMap pw) { PWMap res; if (!isEmpty(pw)) { SBGMap first = *(pw.maps_ref().begin()); - res.emplace(minInv(first)); - BOOST_FOREACH (SBGMap sbgmap, pw.maps()) { - SBGMap ith = minInv(sbgmap); + res.emplace(minInv(d, first)); + BOOST_FOREACH (SBGMap sbgmap, pw) { + SBGMap ith = minInv(d, sbgmap); Set cap_dom = intersection(ith.dom(), dom(res)); if (!isEmpty(cap_dom)) { PWMap min = minMap(res, PWMap(ith)); res = combine(min, res); + Set diff = difference(ith.dom(), dom(res)); + res.emplace(SBGMap(diff, ith.exp())); } else res.emplace(ith); @@ -743,7 +748,10 @@ PWMap minInv(PWMap pw) } template -PWMap filterMap(PWMap pw, bool (*f)(SBGMap)) +PWMap minInv(PWMap pw) { return minInv(dom(pw), pw); } + +template +PWMap filterMap(bool (*f)(SBGMap), PWMap pw) { PWMap res; @@ -763,7 +771,7 @@ Set equalImage(PWMap pw1, PWMap pw2) Set cap_dom = intersection(sbgmap1.dom(), sbgmap2.dom()); if (!isEmpty(cap_dom)) { SBGMap map1(cap_dom, sbgmap1.exp()), map2(cap_dom, sbgmap2.exp()); - if (map1 == map2) res = concatenation(res, cap_dom); + if (map1 == map2) res = cup(res, cap_dom); } } } @@ -771,6 +779,39 @@ Set equalImage(PWMap pw1, PWMap pw2) return res; } +template +PWMap offsetDom(PWMap off, PWMap pw) +{ + PWMap res; + + BOOST_FOREACH (SBGMap sbgmap, pw) { + Set ith_dom = image(sbgmap.dom(), off); + res.emplace_hint(res.end(), SBGMap(ith_dom, sbgmap.exp())); + } + + return res; +} + +template +PWMap offsetImage(Util::MD_NAT off, PWMap pw) +{ + PWMap res; + + BOOST_FOREACH (SBGMap sbgmap, pw) { + Exp e = sbgmap.exp(), res_e; + parallel_foreach2 (off, e.exps_ref()) { + Util::NAT o = boost::get<0>(items); + LExp lexp = boost::get<1>(items); + LExp res_lexp(lexp.slope(), lexp.offset() + (Util::RATIONAL) o); + res_e.emplaceBack(res_lexp); + } + + res.emplace_hint(res.end(), SBGMap(sbgmap.dom(), res_e)); + } + + return res; +} + template PWMap normalize(PWMap pw) { @@ -781,9 +822,9 @@ PWMap normalize(PWMap pw) if (isEmpty(intersection(sbgmap1.dom(), visited))) { Set ith(sbgmap1.dom()); BOOST_FOREACH (SBGMap sbgmap2, pw) - if (sbgmap1.exp() == sbgmap2.exp()) concatenation(ith, sbgmap2.dom()); + if (sbgmap1.exp() == sbgmap2.exp()) cup(ith, sbgmap2.dom()); //HERE - visited = concatenation(visited, ith); + visited = cup(visited, ith); //HERE res.emplace(SBGMap(ith, sbgmap1.exp())); } } @@ -820,9 +861,12 @@ template BasePWMap reduce(BaseMap sbgmap); template BasePWMap reduce(BasePWMap pw); template BasePWMap minAdjMap(BasePWMap pw1, BasePWMap pw2, BasePWMap pw3); template BasePWMap minAdjMap(BasePWMap pw1, BasePWMap pw2); +template BasePWMap minInv(UnordSet im, BasePWMap pw); template BasePWMap minInv(BasePWMap pw); -template BasePWMap filterMap(BasePWMap pw, bool (*f)(BaseMap)); +template BasePWMap filterMap(bool (*f)(BaseMap), BasePWMap pw); template UnordSet equalImage(BasePWMap pw1, BasePWMap pw2); +template BasePWMap offsetDom(BasePWMap off, BasePWMap pw); +template BasePWMap offsetImage(Util::MD_NAT off, BasePWMap pw); template BasePWMap normalize(BasePWMap pw); template std::ostream &operator<<(std::ostream &out, const MapSet &ms); @@ -852,9 +896,12 @@ template CanonPWMap reduce(CanonMap sbgmap); template CanonPWMap reduce(CanonPWMap pw); template CanonPWMap minAdjMap(CanonPWMap pw1, CanonPWMap pw2, CanonPWMap pw3); template CanonPWMap minAdjMap(CanonPWMap pw1, CanonPWMap pw2); +template CanonPWMap minInv(OrdSet im, CanonPWMap pw); template CanonPWMap minInv(CanonPWMap pw); -template CanonPWMap filterMap(CanonPWMap pw, bool (*f)(CanonMap)); +template CanonPWMap filterMap(bool (*f)(CanonMap), CanonPWMap pw); template OrdSet equalImage(CanonPWMap pw1, CanonPWMap pw2); +template CanonPWMap offsetDom(CanonPWMap off, CanonPWMap pw); +template CanonPWMap offsetImage(Util::MD_NAT off, CanonPWMap pw); template CanonPWMap normalize(CanonPWMap pw); } // namespace LIB diff --git a/sbg/pw_map.hpp b/sbg/pw_map.hpp index ea50ddb..099b5af 100755 --- a/sbg/pw_map.hpp +++ b/sbg/pw_map.hpp @@ -170,16 +170,23 @@ PWMap minAdjMap(PWMap pw1, PWMap pw2, PWMap pw3); template PWMap minAdjMap(PWMap pw1, PWMap pw2); +template +PWMap minInv(Set im, PWMap pw); template PWMap minInv(PWMap pw); template -PWMap filterMap(PWMap pw, bool (*f)(SBGMap)); +PWMap filterMap(bool (*f)(SBGMap), PWMap pw); // Returns elements in both doms, that have the same image in both maps template Set equalImage(PWMap pw1, PWMap pw2); +template +PWMap offsetDom(PWMap off, PWMap pw); +template +PWMap offsetImage(Util::MD_NAT off, PWMap pw); + template PWMap normalize(PWMap pw); diff --git a/sbg/sbg_algorithms.cpp b/sbg/sbg_algorithms.cpp index 9be30c1..0eaa940 100755 --- a/sbg/sbg_algorithms.cpp +++ b/sbg/sbg_algorithms.cpp @@ -23,7 +23,9 @@ namespace SBG { namespace LIB { +// ----------------------------------------------------------------------------- // Connected components -------------------------------------------------------- +// ----------------------------------------------------------------------------- template PWMap connectedComponents(SBGraph g) @@ -61,7 +63,9 @@ PWMap connectedComponents(SBGraph g) return PWMap(); } +// ----------------------------------------------------------------------------- // Minimum reachable ----------------------------------------------------------- +// ----------------------------------------------------------------------------- template PathInfo::PathInfo() : succs_(), reps_() {} @@ -71,6 +75,9 @@ PathInfo::PathInfo(PWMap succs, PWMap reps) : succs_(succs), reps member_imp_temp(template, PathInfo, PWMap, succs); member_imp_temp(template, PathInfo, PWMap, reps); +template +bool eqId(SBGMap sbgmap) { return image(sbgmap) == sbgmap.dom(); } + template bool notEqId(SBGMap sbgmap) { return !(image(sbgmap) == sbgmap.dom()); } @@ -85,8 +92,6 @@ PWMap updateMap(Set V, PWMap smap, PWMap new_smap, PWMap rma PWMap res; PWMap vto_rep = composition(rmap, smap), new_vto_rep = composition(rmap, new_smap); - //PWMap delta = vto_rep - new_vto_rep; - //Set not_updated = preImage(zero, delta); Set not_updated = equalImage(vto_rep, new_vto_rep); res = restrict(not_updated, smap); @@ -96,54 +101,80 @@ PWMap updateMap(Set V, PWMap smap, PWMap new_smap, PWMap rma } template -PWMap minReach1(Set V, PWMap mapB, PWMap mapD, PWMap smap, PWMap rmap) +PWMap minReach1(Set V, Set E, PWMap mapB, PWMap mapD, PWMap smap, PWMap rmap) { SetPiece mi_zero(V[0].size(), Interval(0)); Set zero(mi_zero); - PWMap adj_smap = minAdjMap(mapB, mapD, rmap); // Get minimum adjacent vertex with minimum representative - PWMap new_smap = minMap(rmap, adj_smap, smap, rmap); // Get minimum between current rep and adjacent reps + PWMap auto_succs = filterMap(eqId, smap); + Set auto_reps = equalImage(auto_succs, rmap); + Set usable_verts = cup(auto_reps, dom(filterMap(notEqId, smap))); + + PWMap auxB = restrict(E, mapB), auxD = restrict(E, mapD); + PWMap adj_smap = minAdjMap(auxB, auxD, rmap); // Get minimum adjacent vertex with minimum representative + PWMap new_smap = minMap(rmap, adj_smap, restrict(usable_verts, smap), rmap); // Get minimum between current rep and adjacent reps new_smap = updateMap(V, smap, new_smap, rmap); // Update rep iff new is less than current - new_smap = combine(new_smap, smap); // Keep current rep if a new one wasn't found + new_smap = combine(new_smap, adj_smap); + new_smap = combine(new_smap, smap); return new_smap; } // Handle ONE recursion template -PWMap recursion(unsigned int n, Set ER, DSBGraph dsbg, PWMap smap, PWMap semap, PWMap rmap) +PathInfo MinReach::recursion(unsigned int n, Set ER, Set rv, PWMap smap, PWMap rmap) { - PWMap mapB = dsbg.mapB(), mapD = dsbg.mapD(), Emap = dsbg.Emap(); + PWMap mapB = dsbg().mapB(), mapD = dsbg().mapD(), Emap = dsbg().Emap(), Vmap = dsbg().Vmap(); + PWMap ERB = restrict(ER, mapB), ERD = restrict(ER, mapD); + + Set start = image(ERB), end = image(ERD), aux_start = start; + start = difference(start, end), end = difference(end, aux_start); - Set set_edges = image(ER, Emap); // Sub-set-edges in recursive paths - Set ER_plus = preImage(set_edges, Emap); // Edges in the same sub-set-edges as E_recursive + Set ER_plus = preImage(image(ER, Emap), Emap); + Set VR_plus = cup(image(ER_plus, mapB), image(ER_plus, mapD)); + + + PWMap new_smap; + Set repeated = intersection(start, end); + Set available_vertices = dsbg().V(); + while (isEmpty(repeated)) { + Set side = intersection(VR_plus, preImage(image(start, Vmap), Vmap)); + Set ER_side = preImage(start, mapB); + Set ER_plus_side = preImage(image(ER_side, Emap), Emap); + + PWMap sideB = restrict(ER_plus_side, mapB), sideD = restrict(ER_plus_side, mapD); + PWMap ith = restrict(available_vertices, composition(sideD, minInv(sideB))); + new_smap = combine(ith, new_smap); - PWMap tildeB = restrict(ER_plus, mapB), tildeD = restrict(ER_plus, mapD); // Restrict edges to recursion - PWMap smap_plus = composition(tildeD, minInv(tildeB)); // In a recursion the succ is the only adjacent vertex - PWMap new_smap = combine(smap_plus, smap); + start = image(start, smap); + repeated = intersection(start, end); + available_vertices = difference(available_vertices, side); + } - PWMap rmap_plus = composition(rmap, mapInf(smap_plus, n)); // Solve recursion + new_smap = combine(restrict(rv, smap), new_smap); + new_smap = combine(new_smap, smap); + PWMap rmap_plus = composition(rmap, mapInf(new_smap, n)); // Solve recursion PWMap new_rmap = minMap(rmap, rmap_plus); new_rmap = combine(new_rmap, rmap); - return new_rmap; + return PathInfo(new_smap, new_rmap); } template -MinReach::MinReach() : sbg_() {} +MinReach::MinReach() : dsbg_() {} template -MinReach::MinReach(DSBGraph sbg) : sbg_(sbg) {} +MinReach::MinReach(DSBGraph sbg) : dsbg_(sbg) {} -member_imp_temp(template, MinReach, DSBGraph, sbg); +member_imp_temp(template, MinReach, DSBGraph, dsbg); template -PathInfo MinReach::calculate() +PathInfo MinReach::calculate(Set unmatched_V) { - DSBGraph dsbg = sbg(); + DSBGraph dg = dsbg(); - if (!isEmpty(dsbg.V())) { - Set V = dsbg.V(), E = dsbg.E(); - PWMap mapB = dsbg.mapB(), mapD = dsbg.mapD(), Emap = dsbg.Emap(); + if (!isEmpty(dg.V())) { + Set V = dg.V(), E = dg.E(); + PWMap mapB = dg.mapB(), mapD = dg.mapD(), Emap = dg.Emap(); SetPiece mi_zero(V[0].size(), Interval(0)); Set zero(mi_zero); @@ -155,12 +186,19 @@ PathInfo MinReach::calculate() Set Vc; // Vertices that changed sucessor Set Ec; // Edges that changed successor + Set unmatched_D = intersection(unmatched_V, image(mapD)); + Set reach_vertices = unmatched_D; + Set reach_edges; + // If a path changes, we have to check if this allows new vertices to // reach a new rep. The condition of the loop corresponds to the fact // that paths are uniquely defined by the sequence of vertices they traverse. do { + reach_edges = preImage(reach_vertices, mapD); + reach_vertices = cup(reach_vertices, image(reach_edges, mapB)); + old_smap = new_smap; - new_smap = minReach1(V, mapB, mapD, new_smap, new_rmap); // Find adjacent vertex that reaches a minor vertex than current one + new_smap = minReach1(V, reach_edges, mapB, mapD, new_smap, new_rmap); // Find adjacent vertex that reaches a minor vertex than current one Vc = difference(V, equalImage(old_smap, new_smap)); if (!isEmpty(Vc)) { @@ -170,26 +208,40 @@ PathInfo MinReach::calculate() if (!isEmpty(E_succ)) { // A new path was chosen old_semap = new_semap; PWMap mapB_succ = restrict(E_succ, mapB), mapD_succ = restrict(E_succ, mapD); - new_semap = composition(minInv(mapB_succ), mapD_succ); + new_semap = composition(minInv(E_succ, mapB_succ), mapD_succ); new_semap = combine(new_semap, old_semap); Set not_changed = equalImage(new_semap, old_semap); Ec = difference(E, not_changed); Set ER; // Recursive edges that changed its successor + Set visited_edges = cup(dom(new_semap), image(new_semap)); + Set old_subset_edges, visited_subset_edges = image(visited_edges, Emap); + Set repeated_subset_edges; PWMap semap_nth = composition(new_semap, new_semap); unsigned int j = 0; - for (; j < nmbrSV(dsbg); j++) { // The max depth of recursion is the number of SVs - ER = equalImage(Emap, composition(Emap, filterMap(semap_nth, notEqId))); + do { // The max depth of recursion is the number of SVs + ER = equalImage(Emap, composition(Emap, filterMap(notEqId, semap_nth))); semap_nth = composition(semap_nth, new_semap); - if (!isEmpty(ER)) break; + visited_edges = image(visited_edges, new_semap); + old_subset_edges = visited_subset_edges; + visited_subset_edges = image(visited_edges, Emap); + repeated_subset_edges = intersection(old_subset_edges, visited_subset_edges); + j++; + } while(isEmpty(ER) && isEmpty(repeated_subset_edges)); + ER = intersection(ER, Ec); + + semap_nth = new_semap; + for (unsigned int k = 0; k < j; k++) { + ER = cup(ER, image(ER, semap_nth)); + semap_nth = composition(semap_nth, new_semap); } - ER = intersection(ER, Ec); if (!isEmpty(ER)) { // There are recursions, lets handle one of them - ER = Set(ER[0]); - new_rmap = recursion(j, ER, dsbg, new_smap, new_semap, new_rmap); + PathInfo res = recursion(j, ER, reach_vertices, new_smap, new_rmap); + new_smap = res.succs(); + new_rmap = res.reps(); } } } @@ -198,9 +250,363 @@ PathInfo MinReach::calculate() return PathInfo(new_smap, new_rmap); } + return PathInfo(); } +// ----------------------------------------------------------------------------- +// Matching -------------------------------------------------------------------- +// ----------------------------------------------------------------------------- + +// Short path ------------------------------------------------------------------ + +bool moreThanOne(SetPiece mdi) { return cardinal(mdi) > 1; } + +template +Set SBGMatching::getManyToOne() +{ + Set res; + + BOOST_FOREACH (SBGMap sbgmapB, mapB_ref()) { + BOOST_FOREACH (SBGMap sbgmapD, mapD_ref()) { + Exp expB = sbgmapB.exp(), expD = sbgmapD.exp(); + if (isConstant(expD)) { + Set dom = intersection(sbgmapB.dom(), sbgmapD.dom()); + if (!isEmpty(dom)) { + dom = intersection(dom, paths_edges()); + if (!isEmpty(dom)) { + Set multi_sized = filterSet(moreThanOne, dom); + res = cup(res, multi_sized); + } + } + } + } + } + + return res; +} + +template +void SBGMatching::shortPathDirection(Set endings, Direction dir) +{ + PWMap auxB = restrict(paths_edges(), mapB()), auxD = restrict(paths_edges(), mapD()); + + set_smap(PWMap(V())); + set_rmap(PWMap(V())); + + Set reach_end = endings; // Vertices that reach endings + Set P; // Vertices adjacent to reach_end + unsigned int k = 0; // Current length of path + + do { + Set pe = paths_edges(); + + if (dir == forward) { + auxB = restrict(pe, auxB); + auxD = restrict(pe, auxD); + } + + P = image(preImage(reach_end, auxD), auxB); // Start of edges entering reach_end + P = difference(P, reach_end); // Take out vertices that are self-reps + Set reach_edges = intersection(preImage(P, auxB), preImage(reach_end, auxD)); // Edges that reach reach_end + PWMap starts = minInv(reach_edges, auxB); // Map from starts to the edges that take them to reach_end + PWMap smap_reach = composition(auxD, starts); + set_smap(combine(smap_reach, smap())); + PWMap rmap_reach = composition(rmap(), smap_reach); + set_rmap(combine(rmap_reach, rmap())); + + if (dir == forward) { + reach_end = cup(reach_end, P); + Set used_subset_edges = image(P, composition(Emap(), starts)); + set_paths_edges(difference(pe, preImage(used_subset_edges, Emap()))); + } + k++; + } while (!isEmpty(reach_end) && k < nmbrSV(sbg())); + + return; +} + +template +void SBGMatching::shortPathStep() +{ + // *** Forward direction + shortPathDirection(unmatched_F(), forward); + Set pe = getAllowedEdges(); + set_paths_edges(pe); + + // *** Backward direction + PWMap auxB = mapB(); + set_mapB(mapD()); + set_mapD(auxB); + + shortPathDirection(unmatched_U(), backward); + pe = intersection(pe, getAllowedEdges()); + set_paths_edges(pe); + + // *** Initial direction + set_mapD(mapB()); + set_mapB(auxB); + + // *** Update structures to reflect new matched edges + updatePaths(); + + return; +} + +template +void SBGMatching::shortPath() +{ + set_paths_edges(difference(E(), getManyToOne())); + + // Finish if all unknowns are matched, or there aren't any available edges left + do { + shortPathStep(); + } while(!fullyMatchedU() && !isEmpty(paths_edges())); + + // In this case we only offset vertices here because shortPath isn't looking + // for any minimum reachable vertex + updateOffset(); + + return; +} + +// Minimum reachable ----------------------------------------------------------- + +template +PWMap SBGMatching::directedOffset(PWMap dir_map) +{ + Set unmatched_side = image(paths_edges(), dir_map); + unmatched_side = intersection(unmatched_side, unmatched_V()); + PWMap res = restrict(unmatched_side, omap()); + res = offsetImage(max_V(), res); + + return combine(res, omap()); +} + +template +DSBGraph SBGMatching::offsetGraph(PWMap dir_omap) +{ + Set _V = image(dir_omap); + PWMap _Vmap = offsetDom(dir_omap, Vmap()); + + PWMap _mapB = composition(dir_omap, mapB()), _mapD = composition(dir_omap, mapD()); + _mapB = restrict(paths_edges(), _mapB); + _mapD = restrict(paths_edges(), _mapD); + + return DSBGraph(_V, _Vmap, _mapB, _mapD, restrict(paths_edges(), Emap())); +} + +template +void SBGMatching::directedMinReach(PWMap dir_map) +{ + PWMap dir_omap = directedOffset(dir_map); + DSBGraph dsbg = offsetGraph(dir_omap); + MinReach min_reach(dsbg); + PathInfo res = min_reach.calculate(unmatched_V()); + + PWMap aux_omap = combine(dir_omap, omap()), to_normal = minInv(aux_omap); + PWMap aux_succs = composition(res.succs(), aux_omap); + set_smap(composition(to_normal, aux_succs)); + PWMap aux_reps = composition(res.reps(), aux_omap); + set_rmap(composition(to_normal, aux_reps)); +} + +template +void SBGMatching::minReachableStep() +{ + // *** Forward direction + directedMinReach(mapU()); + Set pe = getAllowedEdges(); + Set reach_unmatched = preImage(unmatched_V(), rmap()); + reach_unmatched = preImage(reach_unmatched, mapB()); + set_paths_edges(intersection(pe, reach_unmatched)); + + // *** Backward direction + PWMap auxB = mapB(); + set_mapB(mapD()); + set_mapD(auxB); + + directedMinReach(mapF()); + pe = intersection(paths_edges(), getAllowedEdges()); + + // *** Leave edges that connect unmatched left vertices with unmatched right vertices + reach_unmatched = preImage(unmatched_V(), rmap()); + set_rmap(restrict(reach_unmatched, rmap())); + set_smap(restrict(reach_unmatched, smap())); + + pe = intersection(pe, preImage(reach_unmatched, mapB())); + pe = intersection(pe, preImage(reach_unmatched, mapD())); + set_paths_edges(pe); + + // *** Initial direction + set_mapD(mapB()); + set_mapB(auxB); + + // *** Update structures to reflect new matched edges + updatePaths(); + + // *** Offset matched vertices + updateOffset(); + + return; +} + +template +void SBGMatching::minReachable() +{ + do { + set_paths_edges(E()); + minReachableStep(); + } while (!fullyMatchedU() && !isEmpty(paths_edges())); + + return; +} + +// Matching -------------------------------------------------------------------- + +template +MatchInfo::MatchInfo() : matched_edges_(), fully_matchedU_() {} +template +MatchInfo::MatchInfo(Set matched_edges, bool fully_matchedU) : matched_edges_(matched_edges), fully_matchedU_(fully_matchedU) {} + +member_imp_temp(template, MatchInfo, Set, matched_edges); +member_imp_temp(template, MatchInfo, bool, fully_matchedU); + +template +std::ostream &operator<<(std::ostream &out, const MatchInfo &m_info) +{ + out << m_info.matched_edges(); + if (m_info.fully_matchedU()) out << " [FULLY MATCHED]"; + + else out << " [UNMATCHED]"; + + return out; +} + +template +SBGMatching::SBGMatching() : sbg_(), V_(), Vmap_(), E_(), Emap_(), smap_(), rmap_(), omap_(), + max_V_(), F_(), U_(), mapF_(), mapU_(), mapB_(), mapD_(), paths_edges_(), matched_E_(), + unmatched_E_(), matched_V_(), unmatched_V_(), unmatched_F_(), matched_U_(), unmatched_U_() {} +template +SBGMatching::SBGMatching(SBGraph sbg) : sbg_(sbg), V_(sbg.V()), Vmap_(sbg.Vmap()), + Emap_(sbg.Emap()) { + set_E(dom(Emap())); + + PWMap id_vertex(V()); + set_smap(id_vertex); + set_rmap(id_vertex); + + set_omap(id_vertex); + set_max_V(maxElem(V())); + + set_F(image(sbg.map1())); + set_U(image(sbg.map2())); + set_mapF(sbg.map1()); + set_mapU(sbg.map2()); + + set_mapB(sbg.map2()); + set_mapD(sbg.map1()); + + set_paths_edges(E()); + set_matched_E(Set()); + set_unmatched_E(E()); + + set_matched_V(Set()); + set_unmatched_V(V()); + set_unmatched_F(F()); + set_matched_U(Set()); + set_unmatched_U(U()); +} + +member_imp_temp(template, SBGMatching, SBGraph, sbg); +member_imp_temp(template, SBGMatching, Set, V); +member_imp_temp(template, SBGMatching, PWMap, Vmap); +member_imp_temp(template, SBGMatching, Set, E); +member_imp_temp(template, SBGMatching, PWMap, Emap); + +member_imp_temp(template, SBGMatching, PWMap, smap); +member_imp_temp(template, SBGMatching, PWMap, rmap); + +member_imp_temp(template, SBGMatching, PWMap, omap); +member_imp_temp(template, SBGMatching, Util::MD_NAT, max_V); + +member_imp_temp(template, SBGMatching, Set, F); +member_imp_temp(template, SBGMatching, Set, U); +member_imp_temp(template, SBGMatching, PWMap, mapF); +member_imp_temp(template, SBGMatching, PWMap, mapU); + +member_imp_temp(template, SBGMatching, PWMap, mapB); +member_imp_temp(template, SBGMatching, PWMap, mapD); + +member_imp_temp(template, SBGMatching, Set, paths_edges); +member_imp_temp(template, SBGMatching, Set, matched_E); +member_imp_temp(template, SBGMatching, Set, unmatched_E); + +member_imp_temp(template, SBGMatching, Set, matched_V); +member_imp_temp(template, SBGMatching, Set, unmatched_V); +member_imp_temp(template, SBGMatching, Set, unmatched_F); +member_imp_temp(template, SBGMatching, Set, matched_U); +member_imp_temp(template, SBGMatching, Set, unmatched_U); + +template +Set SBGMatching::getAllowedEdges() +{ + Set succs = image(filterMap(notEqId, smap())); // Vertices that are successor of other vertices in a path + Set ending_edges = preImage(succs, mapD()); // Edges whose endings are successors + PWMap auxB = restrict(ending_edges, mapB()); // Map from a 'successor' edge to its start + PWMap map_succs = composition(smap(), auxB); // Map from edge to the successor of its start + + return equalImage(map_succs, mapD()); // Edges that connect vertices with their successors +} + +template +bool SBGMatching::fullyMatchedU() { return isEmpty(difference(U(), matched_U())); } + +template +void SBGMatching::updatePaths() +{ + // *** Revert match and unmatched edges in augmenting paths + PWMap paths_mapB = restrict(paths_edges(), mapB()), paths_mapD = restrict(paths_edges(), mapD()); + set_mapB(combine(paths_mapD, mapB())); + set_mapD(combine(paths_mapB, mapD())); + + // *** Update matched edges + set_matched_E(preImage(U(), mapD())); + set_unmatched_E(preImage(F(), mapD())); + + // *** Update matched vertices + Set matchedB = image(matched_E(), mapB()), matchedD = image(matched_E(), mapD()); + set_matched_V(cup(matchedB, matchedD)); + set_matched_U(intersection(U(), matched_V())); + + set_unmatched_V(difference(V(), matched_V())); + set_unmatched_F(intersection(unmatched_V(), F())); + set_unmatched_U(intersection(unmatched_V(), U())); + + return; +} + +template +void SBGMatching::updateOffset() +{ + PWMap aux = restrict(matched_V(), omap()); + aux = offsetImage(max_V(), aux); + aux = offsetImage(max_V(), aux); + set_omap(combine(aux, omap())); + + return; +} + +template +MatchInfo SBGMatching::calculate() +{ + shortPath(); + + if (!fullyMatchedU()) minReachable(); + + return MatchInfo(matched_E(), fullyMatchedU()); +} + // Template instantiations ----------------------------------------------------- template BasePWMap connectedComponents(BaseSBG g); @@ -212,6 +618,12 @@ template struct PathInfo; template struct MinReach; template struct MinReach; +template struct MatchInfo; +template struct MatchInfo; + +template struct SBGMatching; +template struct SBGMatching; + } // namespace LIB } // namespace SBG diff --git a/sbg/sbg_algorithms.hpp b/sbg/sbg_algorithms.hpp index 5d8096c..dfd7c1b 100755 --- a/sbg/sbg_algorithms.hpp +++ b/sbg/sbg_algorithms.hpp @@ -47,19 +47,18 @@ struct PathInfo { }; template -PWMap minReach1(Set V, PWMap mapB, PWMap mapD, PWMap smap, PWMap rmap); +PWMap minReach1(Set V, Set E, PWMap mapB, PWMap mapD, PWMap smap, PWMap rmap); -template -PWMap recursion(unsigned int n, Set ER, DSBGraph dsbg, PWMap smap, PWMap semap, PWMap rmap); template struct MinReach { - member_class(DSBGraph, sbg); + member_class(DSBGraph, dsbg); MinReach(); - MinReach(DSBGraph sbg); + MinReach(DSBGraph dsbg); - PathInfo calculate(); + PathInfo recursion(unsigned int n, Set ER, Set not_rv, PWMap smap, PWMap rmap); + PathInfo calculate(Set unmatched_V); }; typedef MinReach BaseMR; @@ -67,14 +66,80 @@ typedef MinReach CanonMR; // Matching -------------------------------------------------------------------- +enum Direction { forward, backward }; + +template +struct MatchInfo { + member_class(Set, matched_edges); + member_class(bool, fully_matchedU); + + MatchInfo(); + MatchInfo(Set matched_edges, bool fully_matchedU); +}; +template +std::ostream &operator<<(std::ostream &out, const MatchInfo &m_info); + template struct SBGMatching { + //*** SBG info, constant member_class(SBGraph, sbg); + member_class(Set, V); + member_class(PWMap, Vmap); + + member_class(Set, E); + member_class(PWMap, Emap); + //----------------------------- + + member_class(PWMap, smap); // Successors map + member_class(PWMap, rmap); // Representatives map + + member_class(PWMap, omap); // Offset map + member_class(Util::MD_NAT, max_V); // Current maximum value + + member_class(Set, F); // Left vertices, constant + member_class(Set, U); // Right vertices, constant + member_class(PWMap, mapF); // Left map, constant + member_class(PWMap, mapU); // Forward map, constant + + member_class(PWMap, mapB); // Backward map, mutable + member_class(PWMap, mapD); // Forward map, mutable + + member_class(Set, paths_edges); // Available edges in each step to find paths, mutable + member_class(Set, matched_E); // Matched edges, mutable + member_class(Set, unmatched_E); // Unmatched edges, mutable + + member_class(Set, matched_V); // All matched vertices, mutable + member_class(Set, unmatched_V); // All matched vertices, mutable + member_class(Set, unmatched_F); // Left unmatched vertices, mutable + member_class(Set, matched_U); // Right matched vertices, mutable + member_class(Set, unmatched_U); // Right unmatched vertices, mutable + SBGMatching(); SBGMatching(SBGraph sbg); + + Set getManyToOne(); // Find N:1 connections + void shortPathDirection(Set endings, Direction dir); + void shortPathStep(); + void shortPath(); + + PWMap directedOffset(PWMap dir_map); + DSBGraph offsetGraph(PWMap dir_omap); + void directedMinReach(PWMap dir_map); + void minReachableStep(); + void minReachable(); + + Set getAllowedEdges(); // Calculate edges used by paths + bool fullyMatchedU(); + void offsetVertices(); + void updatePaths(); + void updateOffset(); + MatchInfo calculate(); }; +typedef SBGMatching BaseMatch; +typedef SBGMatching CanonMatch; + } // namespace LIB } // namespace SBG diff --git a/sbg/unord_pw_mdinter.cpp b/sbg/unord_pw_mdinter.cpp index f3559a3..0af4731 100755 --- a/sbg/unord_pw_mdinter.cpp +++ b/sbg/unord_pw_mdinter.cpp @@ -295,6 +295,16 @@ UnordPWMDInter concatenation(UnordPWMDInter pwi1, UnordPWMDInter pwi2) return res; } +UnordPWMDInter filterSet(bool (*f)(SetPiece), UnordPWMDInter pwi) +{ + UnordPWMDInter res; + + BOOST_FOREACH (SetPiece mdi, pwi) + if (f(mdi)) res.emplace_hint(res.end(), mdi); + + return res; +} + std::size_t hash_value(const UnordPWMDInter &pwi) { UnordPWMDInter aux_pwi = pwi; diff --git a/sbg/unord_pw_mdinter.hpp b/sbg/unord_pw_mdinter.hpp index b329c02..947cdb0 100755 --- a/sbg/unord_pw_mdinter.hpp +++ b/sbg/unord_pw_mdinter.hpp @@ -106,7 +106,7 @@ UnordPWMDInter difference(UnordPWMDInter pwi1, UnordPWMDInter pwi2); * disjoint. */ UnordPWMDInter concatenation(UnordPWMDInter pwi1, UnordPWMDInter pwi2); -SetPiece oneElem(UnordPWMDInter pwi); +UnordPWMDInter filterSet(bool (*f)(SetPiece), UnordPWMDInter pwi); std::size_t hash_value(const UnordPWMDInter &pwi); diff --git a/test/sbg4.test b/test/sbg4.test new file mode 100644 index 0000000..68739e9 --- /dev/null +++ b/test/sbg4.test @@ -0,0 +1,31 @@ +// Matching test, with recursions that starts in the middle + +N = 10000 +N2 = 5000 + +V1 = 1 +V2 = N-1+V1 +V3 = N+V2 + +E1 = 1 +E2 = N-1+E1 +E3 = N-1+E2 + +off1d = N+N2 +off3b = N-1 +off2d = N-1 +off3d = 1 + + V %= {[1:1:V1], [V1+1:1:V2], [V2+1:1:V3]}; + Vmap %= <<{[1:1:V1]} -> 0*x+1, {[V1+1:1:V2]} -> 0*x+2, {[V2+1:1:V3]} -> 0*x+3>>; + map1 %= <<{[1:1:E1]} -> 0*x+1, {[E1+1:1:E2]} -> 1*x+0, {[E2+1:1:E3]} -> 1*x-off3b>>; + map2 %= <<{[1:1:E1]} -> 0*x+off1d, {[E1+1:1:E2]} -> 1*x+off2d, {[E2+1:1:E3]} -> 1*x+off3d>>; + Emap %= <<{[1:1:E1]} -> 0*x+1, {[E1+1:1:E2]} -> 0*x+2, {[E2+1:1:E3]} -> 0*x+3>>; + +matching( + V %= {[1:1:V1], [V1+1:1:V2], [V2+1:1:V3]}; + Vmap %= <<{[1:1:V1]} -> 0*x+1, {[V1+1:1:V2]} -> 0*x+2, {[V2+1:1:V3]} -> 0*x+3>>; + map1 %= <<{[1:1:E1]} -> 0*x+1, {[E1+1:1:E2]} -> 1*x+0, {[E2+1:1:E3]} -> 1*x-off3b>>; + map2 %= <<{[1:1:E1]} -> 0*x+off1d, {[E1+1:1:E2]} -> 1*x+off2d, {[E2+1:1:E3]} -> 1*x+off3d>>; + Emap %= <<{[1:1:E1]} -> 0*x+1, {[E1+1:1:E2]} -> 0*x+2, {[E2+1:1:E3]} -> 0*x+3>>; +) diff --git a/test/sbg5.test b/test/sbg5.test new file mode 100644 index 0000000..cb5e9e7 --- /dev/null +++ b/test/sbg5.test @@ -0,0 +1,31 @@ +// Matching test, with a simple recursion + +N = 10000 +N2 = 5000 + +V1 = 1 +V2 = N-1+V1 +V3 = N+V2 + +E1 = 1 +E2 = N-1+E1 +E3 = N-1+E2 + +off1d = N+1 +off3b = N-1 +off2d = N-1 +off3d = 1 + + V %= {[1:1:V1], [V1+1:1:V2], [V2+1:1:V3]}; + Vmap %= <<{[1:1:V1]} -> 0*x+1, {[V1+1:1:V2]} -> 0*x+2, {[V2+1:1:V3]} -> 0*x+3>>; + map1 %= <<{[1:1:E1]} -> 0*x+1, {[E1+1:1:E2]} -> 1*x+0, {[E2+1:1:E3]} -> 1*x-off3b>>; + map2 %= <<{[1:1:E1]} -> 0*x+off1d, {[E1+1:1:E2]} -> 1*x+off2d, {[E2+1:1:E3]} -> 1*x+off3d>>; + Emap %= <<{[1:1:E1]} -> 0*x+1, {[E1+1:1:E2]} -> 0*x+2, {[E2+1:1:E3]} -> 0*x+3>>; + +matching( + V %= {[1:1:V1], [V1+1:1:V2], [V2+1:1:V3]}; + Vmap %= <<{[1:1:V1]} -> 0*x+1, {[V1+1:1:V2]} -> 0*x+2, {[V2+1:1:V3]} -> 0*x+3>>; + map1 %= <<{[1:1:E1]} -> 0*x+1, {[E1+1:1:E2]} -> 1*x+0, {[E2+1:1:E3]} -> 1*x-off3b>>; + map2 %= <<{[1:1:E1]} -> 0*x+off1d, {[E1+1:1:E2]} -> 1*x+off2d, {[E2+1:1:E3]} -> 1*x+off3d>>; + Emap %= <<{[1:1:E1]} -> 0*x+1, {[E1+1:1:E2]} -> 0*x+2, {[E2+1:1:E3]} -> 0*x+3>>; +) diff --git a/test/sbg6.test b/test/sbg6.test new file mode 100644 index 0000000..e7d8c2d --- /dev/null +++ b/test/sbg6.test @@ -0,0 +1,88 @@ +// Matching test, RC circuit with variables iR, vA, vB, der(vC) + +N = 10000 + +F1 = 1 +F2 = N+F1 +F3 = N+F2 +F4 = N-1+F3 +F5 = N-1+F4 +F6 = 1+F5 +U1 = N+F6 +U2 = N+U1 +U3 = N+U2 +U4 = N+U3 + +E1 = 1 +E2 = N+E1 +E3 = N+E2 +E4 = N+E3 +E5 = N+E4 +E6 = N-1+E5 +E7 = N-1+E6 +E8a = N-1+E7 +E8b = N-1+E8a +E9 = N-1+E8b +E10 = 1+E9 +E11 = 1+E10 + +off1b = 4*N +off2b = 4*N-1 +off3d = N +off3b = off2b +off4d = N +off4b = 2*N-1 +off5d = 2*N +off5b = 3*N-1 +off6d = 2*N +off6b = N +off7d = 3*N-1 +off7b = N+1 +off8ad = 3*N-1 +off8ab = 2*N-1 +off8bd = 4*N-2 +off8bb = 3*N-3 +off9d = 5*N-3 +off9b = N-3 +off10d = 5*N-3 +off10b = 4*N-3 +off11d = 5*N-2 +off11b = N-2 + +V %= {[1:1:F1], [F1+1:1:F2], [F2+1:1:F3], [F3+1:1:F4], [F4+1:1:F5], [F5+1:1:F6], [F6+1:1:U1] + , [U1+1:1:U2], [U2+1:1:U3], [U3+1:1:U4]}; +Vmap %= <<{[1:1:F1]} -> 0*x+1, {[F1+1:1:F2]} -> 0*x+2, {[F2+1:1:F3]} -> 0*x+3, {[F3+1:1:F4]} -> 0*x+4 + , {[F4+1:1:F5]} -> 0*x+5, {[F5+1:1:F6]} -> 0*x+6, {[F6+1:1:U1]} -> 0*x+7 + , {[U1+1:1:U2]} -> 0*x+8, {[U2+1:1:U3]} -> 0*x+9, {[U3+1:1:U4]} -> 0*x+10>>; +map1 %= <<{[1:1:E1]} -> 1*x+0, {[E1+1:1:E2]} -> 1*x+0, {[E2+1:1:E3]} -> 1*x-off3d + , {[E3+1:1:E4]} -> 1*x-off4d, {[E4+1:1:E5]} -> 1*x-off5d, {[E5+1:1:E6]} -> 1*x-off6d + , {[E6+1:1:E7]} -> 1*x-off7d, {[E7+1:1:E8a]} -> 1*x-off8ad, {[E8a+1:1:E8b]} -> 1*x-off8bd + , {[E8b+1:1:E9]} -> 1*x-off9d, {[E9+1:1:E10]} -> 1*x-off10d, {[E10+1:1:E11]} -> 1*x-off11d>>; +map2 %= <<{[1:1:E1]} -> 1*x+off1b, {[E1+1:1:E2]} -> 1*x+off2b, {[E2+1:1:E3]} -> 1*x+off3b + , {[E3+1:1:E4]} -> 1*x+off4b, {[E4+1:1:E5]} -> 1*x+off5b, {[E5+1:1:E6]} -> 1*x+off6b + , {[E6+1:1:E7]} -> 1*x+off7b, {[E7+1:1:E8a]} -> 1*x-off8ab, {[E8a+1:1:E8b]} -> 1*x-off8bb + , {[E8b+1:1:E9]} -> 1*x-off9b, {[E9+1:1:E10]} -> 1*x-off10b, {[E10+1:1:E11]} -> 1*x-off11b>>; +Emap %= <<{[1:1:E1]} -> 0*x+1, {[E1+1:1:E2]} -> 0*x+2, {[E2+1:1:E3]} -> 0*x+3 + , {[E3+1:1:E4]} -> 0*x+4, {[E4+1:1:E5]} -> 0*x+5, {[E5+1:1:E6]} -> 0*x+6 + , {[E6+1:1:E7]} -> 0*x+7, {[E7+1:1:E8a], [E8a+1:1:E8b]} -> 0*x+8, {[E8b+1:1:E9]} -> 0*x+9 + , {[E9+1:1:E10]} -> 0*x+10, {[E10+1:1:E11]} -> 0*x+11>>; + +matching( + V %= {[1:1:F1], [F1+1:1:F2], [F2+1:1:F3], [F3+1:1:F4], [F4+1:1:F5], [F5+1:1:F6], [F6+1:1:U1] + , [U1+1:1:U2], [U2+1:1:U3], [U3+1:1:U4]}; + Vmap %= <<{[1:1:F1]} -> 0*x+1, {[F1+1:1:F2]} -> 0*x+2, {[F2+1:1:F3]} -> 0*x+3, {[F3+1:1:F4]} -> 0*x+4 + , {[F4+1:1:F5]} -> 0*x+5, {[F5+1:1:F6]} -> 0*x+6, {[F6+1:1:U1]} -> 0*x+7 + , {[U1+1:1:U2]} -> 0*x+8, {[U2+1:1:U3]} -> 0*x+9, {[U3+1:1:U4]} -> 0*x+10>>; + map1 %= <<{[1:1:E1]} -> 1*x+0, {[E1+1:1:E2]} -> 1*x+0, {[E2+1:1:E3]} -> 1*x-off3d + , {[E3+1:1:E4]} -> 1*x-off4d, {[E4+1:1:E5]} -> 1*x-off5d, {[E5+1:1:E6]} -> 1*x-off6d + , {[E6+1:1:E7]} -> 1*x-off7d, {[E7+1:1:E8a]} -> 1*x-off8ad, {[E8a+1:1:E8b]} -> 1*x-off8bd + , {[E8b+1:1:E9]} -> 1*x-off9d, {[E9+1:1:E10]} -> 1*x-off10d, {[E10+1:1:E11]} -> 1*x-off11d>>; + map2 %= <<{[1:1:E1]} -> 1*x+off1b, {[E1+1:1:E2]} -> 1*x+off2b, {[E2+1:1:E3]} -> 1*x+off3b + , {[E3+1:1:E4]} -> 1*x+off4b, {[E4+1:1:E5]} -> 1*x+off5b, {[E5+1:1:E6]} -> 1*x+off6b + , {[E6+1:1:E7]} -> 1*x+off7b, {[E7+1:1:E8a]} -> 1*x-off8ab, {[E8a+1:1:E8b]} -> 1*x-off8bb + , {[E8b+1:1:E9]} -> 1*x-off9b, {[E9+1:1:E10]} -> 1*x-off10b, {[E10+1:1:E11]} -> 1*x-off11b>>; + Emap %= <<{[1:1:E1]} -> 0*x+1, {[E1+1:1:E2]} -> 0*x+2, {[E2+1:1:E3]} -> 0*x+3 + , {[E3+1:1:E4]} -> 0*x+4, {[E4+1:1:E5]} -> 0*x+5, {[E5+1:1:E6]} -> 0*x+6 + , {[E6+1:1:E7]} -> 0*x+7, {[E7+1:1:E8a], [E8a+1:1:E8b]} -> 0*x+8, {[E8b+1:1:E9]} -> 0*x+9 + , {[E9+1:1:E10]} -> 0*x+10, {[E10+1:1:E11]} -> 0*x+11>>; +)