Skip to content

Commit eddc7c6

Browse files
committed
Fix O(n³) performance issue in sparse bipartite graph arc iteration
- Added position tracking maps (_arc_to_out_pos, _arc_to_in_pos) for O(1) arc lookups - Modified nextOut() and nextIn() to use position maps instead of linear search
1 parent a798893 commit eddc7c6

File tree

1 file changed

+46
-21
lines changed

1 file changed

+46
-21
lines changed

ot/lp/sparse_bipartitegraph.h

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,13 @@ namespace lemon {
4343

4444
mutable std::vector<std::vector<Arc>> _in_arcs; // _in_arcs[node] = incoming arc IDs
4545
mutable bool _in_arcs_built;
46+
47+
// Position tracking for O(1) iteration
48+
mutable std::vector<int64_t> _arc_to_out_pos; // _arc_to_out_pos[arc_id] = position in _arc_ids
49+
mutable std::vector<int64_t> _arc_to_in_pos; // _arc_to_in_pos[arc_id] = position in _in_arcs[target]
50+
mutable bool _position_maps_built;
4651

47-
SparseBipartiteDigraphBase() : _node_num(0), _arc_num(0), _n1(0), _n2(0), _in_arcs_built(false) {}
52+
SparseBipartiteDigraphBase() : _node_num(0), _arc_num(0), _n1(0), _n2(0), _in_arcs_built(false), _position_maps_built(false) {}
4853

4954
void construct(int n1, int n2) {
5055
_node_num = n1 + n2;
@@ -58,6 +63,9 @@ namespace lemon {
5863
_arc_ids.clear();
5964
_in_arcs.clear();
6065
_in_arcs_built = false;
66+
_arc_to_out_pos.clear();
67+
_arc_to_in_pos.clear();
68+
_position_maps_built = false;
6169
}
6270

6371
void build_in_arcs() const {
@@ -72,6 +80,31 @@ namespace lemon {
7280

7381
_in_arcs_built = true;
7482
}
83+
84+
void build_position_maps() const {
85+
if (_position_maps_built) return;
86+
87+
_arc_to_out_pos.resize(_arc_num);
88+
_arc_to_in_pos.resize(_arc_num);
89+
90+
// Build outgoing arc position map from CSR structure
91+
for (int64_t pos = 0; pos < _arc_num; ++pos) {
92+
Arc arc_id = _arc_ids[pos];
93+
_arc_to_out_pos[arc_id] = pos;
94+
}
95+
96+
// Build incoming arc position map
97+
build_in_arcs();
98+
for (Node node = 0; node < _node_num; ++node) {
99+
const std::vector<Arc>& in = _in_arcs[node];
100+
for (size_t pos = 0; pos < in.size(); ++pos) {
101+
Arc arc_id = in[pos];
102+
_arc_to_in_pos[arc_id] = pos;
103+
}
104+
}
105+
106+
_position_maps_built = true;
107+
}
75108

76109
public:
77110

@@ -212,18 +245,14 @@ namespace lemon {
212245

213246
void nextOut(Arc& arc) const {
214247
if (arc < 0) return;
215-
248+
249+
build_position_maps();
250+
251+
int64_t pos = _arc_to_out_pos[arc];
216252
Node src = _arc_sources[arc];
217-
int64_t start = _row_ptr[src];
218253
int64_t end = _row_ptr[src + 1];
219-
220-
for (int64_t i = start; i < end; ++i) {
221-
if (_arc_ids[i] == arc) {
222-
arc = (i + 1 < end) ? _arc_ids[i + 1] : Arc(-1);
223-
return;
224-
}
225-
}
226-
arc = -1;
254+
255+
arc = (pos + 1 < end) ? _arc_ids[pos + 1] : Arc(-1);
227256
}
228257

229258
void firstIn(Arc& arc, const Node& node) const {
@@ -240,18 +269,14 @@ namespace lemon {
240269

241270
void nextIn(Arc& arc) const {
242271
if (arc < 0) return;
243-
272+
273+
build_position_maps();
274+
275+
int64_t pos = _arc_to_in_pos[arc];
244276
Node tgt = _arc_targets[arc];
245277
const std::vector<Arc>& in = _in_arcs[tgt];
246-
247-
// Find current arc in the list and return next one
248-
for (size_t i = 0; i < in.size(); ++i) {
249-
if (in[i] == arc) {
250-
arc = (i + 1 < in.size()) ? in[i + 1] : Arc(-1);
251-
return;
252-
}
253-
}
254-
arc = -1;
278+
279+
arc = (pos + 1 < in.size()) ? in[pos + 1] : Arc(-1);
255280
}
256281
};
257282

0 commit comments

Comments
 (0)