Skip to content

Commit 3c0c990

Browse files
committed
Optimized matching algorithm
1 parent 89bb1c3 commit 3c0c990

6 files changed

Lines changed: 75 additions & 89 deletions

File tree

algorithms/matching/bfs_matching.cpp

Lines changed: 24 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ bool BFSMatching::ExitCondition::isSatisfied()
4848
// Algorithm -------------------------------------------------------------------
4949

5050
BFSMatching::BFSMatching() : _M(SET_FACT.createSet()), _dsbg()
51-
, _direction(Direction::kForward) {}
51+
, _direction(Direction::kForward), _X(SET_FACT.createSet())
52+
, _Y(SET_FACT.createSet()) {}
5253

5354
void BFSMatching::swapEdgesDirection(const Set& E)
5455
{
@@ -62,6 +63,14 @@ void BFSMatching::swapEdgesDirection(const Set& E)
6263
_dsbg = DirectedSBG{_dsbg.V(), _dsbg.Vmap(), mapB, mapD, _dsbg.Emap()};
6364
}
6465

66+
void BFSMatching::swapDirection(const Set& E)
67+
{
68+
swapEdgesDirection(E);
69+
Set temp_X = _X;
70+
_X = _Y;
71+
_Y = temp_X;
72+
}
73+
6574
PWMap BFSMatching::partitionSubsetEdges() const
6675
{
6776
PWMap result = PWMAP_FACT.createPWMap();
@@ -90,84 +99,51 @@ PWMap BFSMatching::partitionSubsetEdges() const
9099
return result;
91100
}
92101

93-
Set BFSMatching::edgesInPaths(const PWMap& smap, const Set& E) const
94-
{
95-
PWMap mapB = _dsbg.mapB().restrict(E);
96-
PWMap mapD = _dsbg.mapD().restrict(E);
97-
98-
// Vertices that are successors of other vertices in a path
99-
Set not_fixed = smap.domain().difference(smap.fixedPoints());
100-
Set succs = smap.restrict(not_fixed).image();
101-
// Edges whose endings are successors
102-
Set ending_edges = mapD.preImage(succs);
103-
// Map from a 'successor' edge to its start
104-
PWMap auxB = mapB.restrict(ending_edges);
105-
// Map from edge to the successor of its start
106-
PWMap map_succs = smap.composition(auxB);
107-
108-
return map_succs.equalImage(mapD);
109-
}
110-
111-
Set BFSMatching::directedStep(const Set& E, const Set& right_vertices)
102+
Set BFSMatching::directedStep(const Set& E)
112103
{
113104
PWMap mapB = _dsbg.mapB().restrict(E);
114105
PWMap mapD = _dsbg.mapD().restrict(E);
115106
PWMap Emap = partitionSubsetEdges().restrict(E);
116107

117108
// Calculate unmatched vertices in the side determined by the current
118109
// direction of edges
119-
Set forward_vertices = _dsbg.V().difference(right_vertices);
120110
Set matched_forward_vertices = mapB.image(_M);
121-
if (_direction == Direction::kBackward) {
122-
forward_vertices = right_vertices;
123-
}
124111
Set unmatched_forward_vertices
125-
= forward_vertices.difference(matched_forward_vertices);
112+
= _X.difference(matched_forward_vertices);
126113

127114
// Detect paths leading to unmatched_forward_vertices
128115
DirectedSBG restricted_dsbg{_dsbg.V(), _dsbg.Vmap(), mapB, mapD, Emap};
129116
BFSPaths paths;
130-
PWMap smap = paths.calculate(restricted_dsbg, unmatched_forward_vertices);
131117

132-
// Keep edges
133-
Set paths_edges = edgesInPaths(smap, E);
134-
PWMap rmap = smap.mapInf();
135-
Set reach_unmatched = rmap.preImage(unmatched_forward_vertices);
136-
paths_edges = paths_edges.intersection(mapD.preImage(reach_unmatched));
137-
138-
Util::DEBUG_LOG << "paths_edges in " << _direction << " direction: "
139-
<< paths_edges << "\n";
140-
141-
return paths_edges;
118+
return paths.calculate(restricted_dsbg, unmatched_forward_vertices);
142119
}
143120

144-
BFSMatching::ExitCondition BFSMatching::step(const Set& right_vertices)
121+
BFSMatching::ExitCondition BFSMatching::step()
145122
{
146123
Set E = _dsbg.E();
147124

148125
// Forward direction
149-
Set paths_edgesD = directedStep(E, right_vertices);
126+
Set P = directedStep(E);
150127

151128
// Backward direction
152-
swapEdgesDirection(E);
129+
swapDirection(E);
153130
_direction = Direction::kBackward;
154-
Set paths_edgesB = directedStep(paths_edgesD, right_vertices);
131+
Set augmenting_edges = directedStep(P);
155132

156-
// Calculate augmenting paths and swap edges in these paths
157-
Set augmenting_edges = paths_edgesB.intersection(paths_edgesD);
133+
// Swap direction for edges in augmenting paths
158134
Util::DEBUG_LOG << "augmenting paths: " << augmenting_edges << "\n";
159-
swapEdgesDirection(augmenting_edges);
135+
swapDirection(augmenting_edges);
160136

161137
// Swap directions in all graph
162138
swapEdgesDirection(E);
163139
_direction = Direction::kForward;
164140

165141
// Calculate new matched edges
166-
_M = _dsbg.mapD().preImage(right_vertices);
142+
_M = _dsbg.mapD().preImage(_Y);
167143

168144
// Calculate exit conditions
169145
Set matchedU = _dsbg.mapD().image(_M);
170-
bool full_match = right_vertices.difference(matchedU).isEmpty();
146+
bool full_match = _Y.difference(matchedU).isEmpty();
171147
bool found_paths = !augmenting_edges.isEmpty();
172148

173149
return ExitCondition{full_match, found_paths};
@@ -204,11 +180,12 @@ MatchData BFSMatching::calculate(const BipartiteSBG& bsbg)
204180
Util::Internal::TimeProfiler profiler{"Total matching exec time: "};
205181

206182
init(bsbg);
207-
Set right_vertices = bsbg.Y();
183+
_X = bsbg.X();
184+
_Y = bsbg.Y();
208185

209186
ExitCondition exit_cond{false, false};
210187
do {
211-
exit_cond = step(right_vertices);
188+
exit_cond = step();
212189
} while (!exit_cond.isSatisfied());
213190

214191
_M.compact();

algorithms/matching/bfs_matching.hpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class BFSMatching {
9494
* saturated and b) New paths weren't found. This is calculated here instead
9595
* of the main loop to avoid recalculation of certain values.
9696
*/
97-
ExitCondition step(const Set& right_vertices);
97+
ExitCondition step();
9898

9999
/**
100100
* @brief Computes alternating paths in a certain direction.
@@ -103,29 +103,27 @@ class BFSMatching {
103103
* @return Edges belonging to alternating paths that reach unmatched vertices
104104
* in the aforementioned direction.
105105
*/
106-
Set directedStep(const Set& E, const Set& right_vertices);
106+
Set directedStep(const Set& E);
107107

108108
/**
109109
* @brief Modifies the `dsbg_` member, swapping mapB and mapD for elements of
110110
* the domain that belong to `E`.
111111
*/
112112
void swapEdgesDirection(const Set& E);
113113

114+
void swapDirection(const Set& E);
115+
114116
/**
115117
* @brief Separates in different subset-edges matched and unmatched edges
116118
* belonging to the same subset-edge in `dsbg_`.
117119
*/
118120
PWMap partitionSubsetEdges() const;
119121

120-
/**
121-
* @brief Returns edges in `E` that belong to the paths described by the
122-
* successor map `smap`.
123-
*/
124-
Set edgesInPaths(const PWMap& smap, const Set& E) const;
125-
126122
DirectedSBG _dsbg; ///< Directed graph according to matching
127123
Set _M; ///< Matched edges
128124
Direction _direction;
125+
Set _X;
126+
Set _Y;
129127
};
130128

131129
} // namespace detail

algorithms/matching/bfs_paths.cpp

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,60 +34,71 @@ namespace detail {
3434

3535
BFSPaths::BFSPaths() {}
3636

37-
PWMap BFSPaths::calculate(const DirectedSBG& dsbg, const Set& endings)
37+
Set BFSPaths::calculate(const DirectedSBG& dsbg, const Set& endings)
3838
{
3939
Set V = dsbg.V();
4040
PWMap mapB = dsbg.mapB();
41+
PWMap auxB = mapB;
4142
PWMap mapD = dsbg.mapD();
43+
PWMap auxD = mapD;
4244
PWMap Emap = dsbg.Emap();
4345

4446
// Successor map to unmatched vertices
45-
PWMap result = PWMAP_FACT.createPWMap(endings);
47+
PWMap smap = PWMAP_FACT.createPWMap(endings);
4648

4749
// A record of allowed edges to keep out cycle edges
48-
Set allowed_edges = dsbg.E();
50+
Set E = dsbg.E();
4951
// Ingoing edges to vertices that reach endings
5052
Set ingoing = mapD.preImage(endings);
5153
// A record of visited set-edges
52-
Set visitedE = SET_FACT.createSet();
54+
Set visitedSE = SET_FACT.createSet();
5355
do {
5456
// Calculate successor for ith vertices
55-
PWMap ingoingB = mapB.restrict(ingoing);
56-
PWMap ingoingD = mapD.restrict(ingoing);
57+
PWMap ingoingB = auxB.restrict(ingoing);
58+
PWMap ingoingD = auxD.restrict(ingoing);
5759
PWMap ith_smap = ingoingB.minAdj(ingoingD);
5860

5961
Util::DEBUG_LOG << "ith_smap: " << ith_smap << "\n";
6062

6163
// Edges that lead to a successor
62-
Set Eith = mapD.equalImage(ith_smap.composition(mapB));
64+
Set Ei = auxD.equalImage(ith_smap.composition(auxB));
6365
// Visited set-edges
64-
Set Erec = visitedE.intersection(Emap.image(Eith));
65-
// Handle recursion
66-
if (!Erec.isEmpty()) {
67-
Set Eplus = Emap.preImage(Erec);
68-
PWMap rec_smap = mapB.restrict(Eplus).minAdj(mapD.restrict(Eplus));
69-
Util::DEBUG_LOG << "rec_smap: " << rec_smap << "\n";
70-
ith_smap = ith_smap.combine(rec_smap);
66+
Set repeatedSE = visitedSE.intersection(Emap.image(Ei));
67+
if (!repeatedSE.isEmpty()) {
68+
// Propose candidate successors for repetitive paths
69+
Set Eplus = Emap.preImage(repeatedSE);
70+
PWMap smap_plus = auxB.restrict(Eplus).minAdj(auxD.restrict(Eplus));
71+
Util::DEBUG_LOG << "smap_plus: " << smap_plus << "\n";
72+
ith_smap = ith_smap.combine(smap_plus);
73+
visitedSE = visitedSE.difference(repeatedSE);
74+
} else {
75+
visitedSE = visitedSE.disjointCup(Emap.image(Ei));
7176
}
72-
result = ith_smap.combine(result);
77+
smap = ith_smap.combine(smap);
7378

7479
// Take out other outgoing edges to avoid cycles
75-
allowed_edges = allowed_edges.difference(mapB.preImage(result.domain()));
76-
mapD = mapD.restrict(allowed_edges);
77-
mapB = mapB.restrict(allowed_edges);
80+
E = E.difference(auxB.preImage(smap.domain()));
81+
auxD = auxD.restrict(E);
82+
auxB = auxB.restrict(E);
7883

7984
// Edges that reach vertices with a successor
80-
ingoing = mapD.preImage(result.domain()).intersection(allowed_edges);
85+
ingoing = auxD.preImage(smap.domain()).intersection(E);
8186

82-
visitedE = visitedE.cup(Emap.image(Eith));
83-
84-
Util::DEBUG_LOG << "Eith: " << Eith << "\n";
85-
Util::DEBUG_LOG << "Erec: " << Erec << "\n";
86-
Util::DEBUG_LOG << "visitedE: " << visitedE << "\n";
87-
Util::DEBUG_LOG << "result: " << result << "\n\n";
87+
Util::DEBUG_LOG << "Ei: " << Ei << "\n";
88+
Util::DEBUG_LOG << "repeatedSE: " << repeatedSE << "\n";
89+
Util::DEBUG_LOG << "visitedSE: " << visitedSE << "\n";
90+
Util::DEBUG_LOG << "smap: " << smap << "\n\n";
8891
} while (!ingoing.isEmpty());
8992

90-
return result;
93+
// Keep edges that reach vertices in U
94+
Set P = smap.composition(mapB).equalImage(mapD);
95+
PWMap rmap = smap.mapInf();
96+
Set reach_unmatched = rmap.preImage(endings);
97+
P = P.intersection(mapD.preImage(reach_unmatched));
98+
99+
Util::DEBUG_LOG << "BFS Paths P: " << P << "\n\n";
100+
101+
return P;
91102
}
92103

93104
} // namespace detail

algorithms/matching/bfs_paths.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class BFSPaths : public PathsContext<BFSPaths> {
5555
* than once, replicating the same path for every element of the same
5656
* Set-Vertex.
5757
*/
58-
PWMap calculate(const DirectedSBG& dsbg, const Set& endings);
58+
Set calculate(const DirectedSBG& dsbg, const Set& endings);
5959
};
6060

6161
} // namespace detail

algorithms/scc/decreasing_edges_mrv.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ PWMap LtEdgesMRV::repetitivePaths(const PWMap& rmap
7171
Vi = _smap.image(Vi);
7272
V = V.disjointCup(Vi);
7373
}
74-
PWMap rec_smap = _smap.restrict(V);
75-
Set E_repetition = rec_smap.composition(mapB).equalImage(mapD);
74+
PWMap smap_rep = _smap.restrict(V);
75+
Set E_repetition = smap_rep.composition(mapB).equalImage(mapD);
7676

7777
Set E_plus = Emap.preImage(Emap.image(E_repetition));
7878
// In the presence of a cycle, if the minimum vertex belongs to the

eval/visitors/set_impl_visitor.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ int SetImplExprVisitor::operator()(AST::BinOp v) const
5757
int SetImplExprVisitor::operator()(AST::Call v) const
5858
{
5959
int impl = 2;
60-
for (const AST::Expr &e : v.args()) {
60+
for (const AST::Expr& e : v.args()) {
6161
impl = std::min(impl, boost::apply_visitor(*this, e));
6262
}
6363

@@ -78,7 +78,7 @@ int SetImplExprVisitor::operator()(AST::MultiDimInter v) const
7878
return 1;
7979
}
8080

81-
for (const AST::Expr &e : v.intervals()) {
81+
for (const AST::Expr& e : v.intervals()) {
8282
impl = std::min(impl, boost::apply_visitor(*this, e));
8383
}
8484

@@ -88,7 +88,7 @@ int SetImplExprVisitor::operator()(AST::MultiDimInter v) const
8888
int SetImplExprVisitor::operator()(AST::Set v) const
8989
{
9090
int impl = 2;
91-
for (const AST::Expr &e : v.pieces()) {
91+
for (const AST::Expr& e : v.pieces()) {
9292
impl = std::min(impl, boost::apply_visitor(*this, e));
9393
}
9494

@@ -106,7 +106,7 @@ int SetImplExprVisitor::operator()(AST::LinearExp v) const
106106
int SetImplExprVisitor::operator()(AST::MDLExp v) const
107107
{
108108
int impl = 2;
109-
for (const AST::Expr &e : v.exps()) {
109+
for (const AST::Expr& e : v.exps()) {
110110
impl = std::min(impl, boost::apply_visitor(*this, e));
111111
}
112112

@@ -124,7 +124,7 @@ int SetImplExprVisitor::operator()(AST::LinearMap v) const
124124
int SetImplExprVisitor::operator()(AST::PWLMap v) const
125125
{
126126
int impl = 2;
127-
for (const AST::Expr &e : v.maps()) {
127+
for (const AST::Expr& e : v.maps()) {
128128
impl = std::min(impl, boost::apply_visitor(*this, e));
129129
}
130130

0 commit comments

Comments
 (0)