askrene: add bigger test for MCF

Using zlib to read big test case file.

Changelog-None: askrene: add bigger test for MCF

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
This commit is contained in:
Lagrang3 2024-10-18 11:44:07 +01:00 committed by Rusty Russell
parent 2ea8e49683
commit e655fe7bbd
4 changed files with 141 additions and 1 deletions

4
external/Makefile vendored
View File

@ -53,6 +53,10 @@ else
LDLIBS += -lsodium
endif
ifeq ($(HAVE_ZLIB),1)
LDLIBS += -lz
endif
EXTERNAL_LDLIBS := -L${TARGET_DIR} $(patsubst lib%.a,-l%,$(notdir $(EXTERNAL_LIBS)))
submodcheck: $(FORCE)

View File

@ -10,7 +10,7 @@ $(PLUGIN_RENEPAY_TEST_OBJS): $(PLUGIN_ASKRENE_SRC)
PLUGIN_ASKRENE_TEST_COMMON_OBJS :=
plugins/askrene/test/run-bfs plugins/askrene/test/run-dijkstra plugins/askrene/test/run-flow plugins/askrene/test/run-mcf: \
plugins/askrene/test/run-bfs plugins/askrene/test/run-dijkstra plugins/askrene/test/run-flow plugins/askrene/test/run-mcf plugins/askrene/test/run-mcf-large: \
plugins/askrene/priorityqueue.o \
plugins/askrene/graph.o

Binary file not shown.

View File

@ -0,0 +1,136 @@
#include "config.h"
#include <assert.h>
#include <ccan/tal/tal.h>
#include <common/setup.h>
#include <inttypes.h>
#include <plugins/askrene/graph.h>
#include <stdio.h>
#include "../algorithm.c"
#ifdef HAVE_ZLIB
#include <zlib.h>
gzFile infile;
#define BUFFER_SIZE 10000
char buffer[BUFFER_SIZE];
static int myscanf(const char *fmt, ...)
{
gzgets(infile, buffer, BUFFER_SIZE);
va_list args;
va_start(args, fmt);
int ret = vsscanf(buffer, fmt, args);
va_end(args);
return ret;
}
#endif
#define CHECK(arg) if(!(arg)){fprintf(stderr, "failed CHECK at line %d: %s\n", __LINE__, #arg); abort();}
/* Read multiple testcases from a file.
* Each test case consist of:
* - one line with N and M, the number of nodes and arcs
* - for each arc a line with numbers head, tail, cap and cost, defining the
* arc's endpoints and values,
* - one line with numbers: amount and best_cost, indicating that we wish to
* send amount from node 0 to node 1 with minimum cost, the correct answer
* should contain a flow cost equal to best_cost.
*
* A feasible solution is guaranteed.
* The last test case has 0 nodes and should be ignored. */
static int next_bit(s64 x)
{
int b;
for (b = 0; (1LL << b) <= x; b++)
;
return b;
}
static bool solve_case(const tal_t *ctx)
{
static int c = 0;
c++;
tal_t *this_ctx = tal(ctx, tal_t);
int N_nodes, N_arcs;
scanf("%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)
goto fail;
const int MAX_NODES = N_nodes;
const int DUAL_BIT = next_bit(N_arcs-1);
const int MAX_ARCS = 1LL << (DUAL_BIT+1);
printf("max nodes %d max arcs %d bit %d\n", MAX_NODES, MAX_ARCS, DUAL_BIT);
struct graph *graph = graph_new(ctx, MAX_NODES, MAX_ARCS, DUAL_BIT);
assert(graph);
s64 *capacity = tal_arrz(ctx, s64, MAX_ARCS);
s64 *cost = tal_arrz(ctx, s64, MAX_ARCS);
for (u32 i = 0; i < N_arcs; i++) {
u32 from, to;
scanf("%" PRIu32 " %" PRIu32 " %" PRIi64 " %" PRIi64, &from,
&to, &capacity[i], &cost[i]);
struct arc arc = {.idx = i};
graph_add_arc(graph, arc, node_obj(from), node_obj(to));
struct arc dual = arc_dual(graph, arc);
cost[dual.idx] = -cost[i];
}
printf("Reading arcs finished\n");
struct node src = {.idx = 0};
struct node dst = {.idx = 1};
s64 amount, best_cost;
scanf("%" PRIi64 " %" PRIi64, &amount, &best_cost);
bool result = simple_mcf(ctx, graph, src, dst, capacity, amount, cost);
assert(result);
assert(node_balance(graph, src, capacity) == -amount);
assert(node_balance(graph, dst, capacity) == amount);
for (u32 i = 2; i < N_nodes; i++)
assert(node_balance(graph, node_obj(i), capacity) == 0);
const s64 total_cost = flow_cost(graph, capacity, cost);
assert(total_cost == best_cost);
tal_free(this_ctx);
return true;
fail:
tal_free(this_ctx);
return false;
}
int main(int argc, char *argv[])
{
#ifdef HAVE_ZLIB
common_setup(argv[0]);
infile = gzopen("plugins/askrene/test/data/linear_mcf.gz", "r");
CHECK(infile);
const tal_t *ctx = tal(NULL, tal_t);
CHECK(ctx);
/* One test case after another. The last test case has N number of nodes
* and arcs equal to 0 and must be ignored. */
while (solve_case(ctx))
;
ctx = tal_free(ctx);
gzclose(infile);
common_shutdown();
return 0;
#else
return 0;
#endif
}