Skip to content

Commit

Permalink
askrene: fix bug, not all arcs exists
Browse files Browse the repository at this point in the history
We use an arc "array" in the graph structure, but not all arc indexes
correspond to real topological arcs. We must be careful when iterating
through all arcs, and check if they are enabled before making operations
on them.

Changelog-None: askrene: fix bug, not all arcs exists

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
  • Loading branch information
Lagrang3 committed Oct 18, 2024
1 parent 9d28df7 commit 8512473
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 4 deletions.
15 changes: 14 additions & 1 deletion plugins/askrene/algorithm.c
Original file line number Diff line number Diff line change
Expand Up @@ -554,8 +554,9 @@ static bool mcf_refinement(const tal_t *ctx,
* constraints. */
for (u32 arc_id = 0; arc_id < max_num_arcs; arc_id++) {
struct arc arc = {.idx = arc_id};
if(!arc_enabled(graph, arc))
continue;
const s64 r = capacity[arc.idx];

if (reduced_cost(graph, arc, cost, potential) < 0 && r > 0) {
/* This arc's reduced cost is negative and non
* saturated. */
Expand Down Expand Up @@ -615,7 +616,19 @@ static bool mcf_refinement(const tal_t *ctx,
for (u32 i = 0; i < max_num_nodes; i++) {
assert(excess[i] == 0);
}
for (u32 i = 0; i < max_num_arcs; i++) {
struct arc arc = {.idx = i};
if(!arc_enabled(graph, arc))
continue;
const s64 cap = capacity[arc.idx];
const s64 rc = reduced_cost(graph, arc, cost, potential);

assert(cap >= 0);
/* asserts logic implication: (rc<0 -> cap==0)*/
assert(!(rc < 0) || cap == 0);
}
#endif
solved = true;

finish:
tal_free(this_ctx);
Expand Down
6 changes: 6 additions & 0 deletions plugins/askrene/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ static inline struct node arc_head(const struct graph *graph,
return graph->arc_tail[dual.idx];
}

/* We use an arc array but not all arcs in that array do exist in the graph. */
static inline bool arc_enabled(const struct graph *graph, const struct arc arc)
{
return graph->arc_tail[arc.idx].idx < graph->max_num_nodes;
}

/* Used to loop over the arcs that exit a node.
*
* for example:
Expand Down
10 changes: 7 additions & 3 deletions plugins/askrene/test/run-mcf-large.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
* A feasible solution is guaranteed.
* The last test case has 0 nodes and should be ignored. */

/* check-source does not like me to use scanf, how am I going to read the test
* data otherwise? */
#define myscanf scanf

static int next_bit(s64 x)
{
int b;
Expand All @@ -37,7 +41,7 @@ static bool solve_case(const tal_t *ctx)
tal_t *this_ctx = tal(ctx, tal_t);

int N_nodes, N_arcs;
scanf("%d %d\n", &N_nodes, &N_arcs);
myscanf("%d %d\n", &N_nodes, &N_arcs);
printf("Testcase %d\n", c);
printf("nodes %d arcs %d\n", N_nodes, N_arcs);
if (N_nodes == 0 && N_arcs == 0)
Expand All @@ -56,7 +60,7 @@ static bool solve_case(const tal_t *ctx)

for (u32 i = 0; i < N_arcs; i++) {
u32 from, to;
scanf("%" PRIu32 " %" PRIu32 " %" PRIi64 " %" PRIi64, &from,
myscanf("%" PRIu32 " %" PRIu32 " %" PRIi64 " %" PRIi64, &from,
&to, &capacity[i], &cost[i]);

struct arc arc = {.idx = i};
Expand All @@ -70,7 +74,7 @@ static bool solve_case(const tal_t *ctx)
struct node dst = {.idx = 1};

s64 amount, best_cost;
scanf("%" PRIi64 " %" PRIi64, &amount, &best_cost);
myscanf("%" PRIi64 " %" PRIi64, &amount, &best_cost);

bool result = simple_mcf(ctx, graph, src, dst, capacity, amount, cost);
assert(result);
Expand Down

0 comments on commit 8512473

Please sign in to comment.