Commit 318edb24 authored by David Gibson's avatar David Gibson

aga,agar: Negative weight cycle testcase

Adds a new test graph which includes a negative weight cycle.  This means
that shortest paths are not well defined, and both Dijkstra's algorithm and
the Bellman-Ford algorithm (which can handle some negative edge weights)
will fail.
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
parent eedf1079
...@@ -63,8 +63,9 @@ int main(void) ...@@ -63,8 +63,9 @@ int main(void)
struct traversal1_graph t1g; struct traversal1_graph t1g;
struct shortcut1_graph s1g; struct shortcut1_graph s1g;
struct shortcut2_graph s2g; struct shortcut2_graph s2g;
struct negacycle_graph ng;
plan_tests(2 + 7 + 35 + 30 + 30 + 42 + 9 + 30 + 9 + 9); plan_tests(2 + 7 + 35 + 30 + 30 + 42 + 9 + 30 + 9 + 9 + 9);
trivial_graph_init(&tg); trivial_graph_init(&tg);
test_adjacency("trivial", &tg.sg, trivial_adjacency); test_adjacency("trivial", &tg.sg, trivial_adjacency);
...@@ -99,5 +100,8 @@ int main(void) ...@@ -99,5 +100,8 @@ int main(void)
shortcut2_graph_init(&s2g); shortcut2_graph_init(&s2g);
test_adjacency("shortcut2 graph", &s2g.sg, shortcut2_adjacency); test_adjacency("shortcut2 graph", &s2g.sg, shortcut2_adjacency);
negacycle_graph_init(&ng);
test_adjacency("negacycle graph", &ng.sg, negacycle_adjacency);
return exit_status(); return exit_status();
} }
...@@ -246,12 +246,24 @@ static void test_shortcut2(void) ...@@ -246,12 +246,24 @@ static void test_shortcut2(void)
aga_finish(&s2g.sg.g); aga_finish(&s2g.sg.g);
} }
static void test_negacycle(void)
{
struct negacycle_graph ng;
negacycle_graph_init(&ng);
ok1(aga_bellman_ford_start(&ng.sg.g, &ng.sg.nodes[1]) == 0);
aga_bellman_ford_complete(&ng.sg.g);
ok1(aga_error(&ng.sg.g) == AGA_ERR_NEGATIVE_COST);
aga_finish(&ng.sg.g);
}
int main(void) int main(void)
{ {
plan_tests(5 + 15 plan_tests(5 + 15
+ FULL_LEN * (1 + FULL_LEN * 4) + FULL_LEN * (1 + FULL_LEN * 4)
+ CHAIN_LEN * (1 + CHAIN_LEN * 2) + CHAIN_LEN * (1 + CHAIN_LEN * 2)
+ 10 + 32 + 7 + 7); + 10 + 32 + 7 + 7 + 2);
test_trivial(); test_trivial();
test_parallel(); test_parallel();
...@@ -261,6 +273,7 @@ int main(void) ...@@ -261,6 +273,7 @@ int main(void)
test_traversal1(); test_traversal1();
test_shortcut1(); test_shortcut1();
test_shortcut2(); test_shortcut2();
test_negacycle();
return exit_status(); return exit_status();
} }
...@@ -42,9 +42,10 @@ int main(void) ...@@ -42,9 +42,10 @@ int main(void)
struct grid_graph gg1, gg2; struct grid_graph gg1, gg2;
struct error_graph eg; struct error_graph eg;
struct traversal1_graph t1g; struct traversal1_graph t1g;
struct negacycle_graph ng;
struct aga_node *node; struct aga_node *node;
plan_tests(2 * 13 + 10 + 10); plan_tests(2 * 13 + 10 + 10 + 6);
trivial_graph_init(&tg); trivial_graph_init(&tg);
test_bfs(&tg.sg, 1, 1); test_bfs(&tg.sg, 1, 1);
...@@ -100,5 +101,10 @@ int main(void) ...@@ -100,5 +101,10 @@ int main(void)
test_bfs_partial(&t1g.sg, 1, 1, 2, 3); test_bfs_partial(&t1g.sg, 1, 1, 2, 3);
aga_finish(&t1g.sg.g); aga_finish(&t1g.sg.g);
negacycle_graph_init(&ng);
test_bfs(&ng.sg, 1, 1, 2, 3);
test_bfs(&ng.sg, 2, 2, 3, 1);
test_bfs(&ng.sg, 3, 3, 1, 2);
return exit_status(); return exit_status();
} }
...@@ -42,9 +42,10 @@ int main(void) ...@@ -42,9 +42,10 @@ int main(void)
struct grid_graph gg1, gg2; struct grid_graph gg1, gg2;
struct error_graph eg; struct error_graph eg;
struct traversal1_graph t1g; struct traversal1_graph t1g;
struct negacycle_graph ng;
struct aga_node *node; struct aga_node *node;
plan_tests(2 * 13 + 10 + 10); plan_tests(2 * 13 + 10 + 10 + 6);
trivial_graph_init(&tg); trivial_graph_init(&tg);
test_dfs(&tg.sg, 1, 1); test_dfs(&tg.sg, 1, 1);
...@@ -100,5 +101,10 @@ int main(void) ...@@ -100,5 +101,10 @@ int main(void)
test_dfs_partial(&t1g.sg, 1, 1, 2, 3); test_dfs_partial(&t1g.sg, 1, 1, 2, 3);
aga_finish(&t1g.sg.g); aga_finish(&t1g.sg.g);
negacycle_graph_init(&ng);
test_dfs(&ng.sg, 1, 1, 2, 3);
test_dfs(&ng.sg, 2, 2, 3, 1);
test_dfs(&ng.sg, 3, 3, 1, 2);
return exit_status(); return exit_status();
} }
...@@ -246,12 +246,24 @@ static void test_shortcut2(void) ...@@ -246,12 +246,24 @@ static void test_shortcut2(void)
aga_finish(&s2g.sg.g); aga_finish(&s2g.sg.g);
} }
static void test_negacycle(void)
{
struct negacycle_graph ng;
negacycle_graph_init(&ng);
ok1(aga_dijkstra_start(&ng.sg.g, &ng.sg.nodes[1]) == 0);
aga_dijkstra_complete(&ng.sg.g);
ok1(aga_error(&ng.sg.g) == AGA_ERR_NEGATIVE_COST);
aga_finish(&ng.sg.g);
}
int main(void) int main(void)
{ {
plan_tests(7 + 20 plan_tests(7 + 20
+ FULL_LEN * (1 + FULL_LEN*4) + FULL_LEN * (1 + FULL_LEN*4)
+ CHAIN_LEN * (1 + CHAIN_LEN*2) + CHAIN_LEN * (1 + CHAIN_LEN*2)
+ 12 + 32 + 7 + 2); + 12 + 32 + 7 + 2 + 2);
test_trivial(); test_trivial();
test_parallel(); test_parallel();
...@@ -261,6 +273,7 @@ int main(void) ...@@ -261,6 +273,7 @@ int main(void)
test_traversal1(); test_traversal1();
test_shortcut1(); test_shortcut1();
test_shortcut2(); test_shortcut2();
test_negacycle();
return exit_status(); return exit_status();
} }
#include "config.h"
#include <assert.h>
#include <ccan/container_of/container_of.h>
#include <ccan/ptrint/ptrint.h>
#include <ccan/aga/aga.h>
#include "simple-graph.h"
static ptrint_t *negacycle_first_edge(const struct aga_graph *g,
const struct aga_node *n)
{
return int2ptr(1);
}
static ptrint_t *negacycle_next_edge(const struct aga_graph *g,
const struct aga_node *n,
ptrint_t *e)
{
assert(ptr2int(e) == 1);
return NULL;
}
static int negacycle_edge_info(const struct aga_graph *g,
const struct aga_node *n,
ptrint_t *e, struct aga_edge_info *ei)
{
struct negacycle_graph *ng = container_of(g, struct negacycle_graph,
sg.g);
int ni = n - ng->sg.nodes;
assert(ptr2int(e) == 1);
ei->to = &ng->sg.nodes[(ni % 3) + 1];
if (ni == 3)
ei->icost = -3;
return 0;
}
void negacycle_graph_init(struct negacycle_graph *ng)
{
simple_graph_init(&ng->sg, negacycle_first_edge,
negacycle_next_edge,
negacycle_edge_info);
}
...@@ -256,4 +256,23 @@ static const struct adjacency_list shortcut2_adjacency[] = { ...@@ -256,4 +256,23 @@ static const struct adjacency_list shortcut2_adjacency[] = {
{}, {},
}; };
/* Negacycle graph
*
* A <---- (-3) ----- C
* \ ^
* (1)-> B -- (1)-/
*
* Graph with a negative length cycle, and so lacking well-defined shortest paths.
*/
struct negacycle_graph {
struct simple_graph sg;
};
void negacycle_graph_init(struct negacycle_graph *ng);
static const struct adjacency_list negacycle_adjacency[] = {
{1, {2}},
{2, {3}},
{3, {1}},
{},
};
#endif /* _TEST_GRAPHS_H */ #endif /* _TEST_GRAPHS_H */
...@@ -229,12 +229,22 @@ static void test_shortcut2(void) ...@@ -229,12 +229,22 @@ static void test_shortcut2(void)
tal_free(sr); tal_free(sr);
} }
static void test_negacycle(void)
{
struct agar_state *sr;
ok1(sr = agar_bellman_ford_new(NULL, &negacycle_graphr.gr, int2ptr(1)));
agar_bellman_ford_complete(sr);
ok1(agar_error(sr) == AGA_ERR_NEGATIVE_COST);
tal_free(sr);
}
int main(void) int main(void)
{ {
plan_tests(3 + 15 plan_tests(3 + 15
+ FULL_LEN * (FULL_LEN*4 - 1) + FULL_LEN * (FULL_LEN*4 - 1)
+ CHAIN_LEN * (1 + CHAIN_LEN*2) + CHAIN_LEN * (1 + CHAIN_LEN*2)
+ 10 + 32 + 7 + 7); + 10 + 32 + 7 + 7 + 2);
test_trivial(); test_trivial();
test_parallel(); test_parallel();
...@@ -244,6 +254,7 @@ int main(void) ...@@ -244,6 +254,7 @@ int main(void)
test_traversal1(); test_traversal1();
test_shortcut1(); test_shortcut1();
test_shortcut2(); test_shortcut2();
test_negacycle();
return exit_status(); return exit_status();
} }
...@@ -45,7 +45,7 @@ int main(void) ...@@ -45,7 +45,7 @@ int main(void)
struct agar_state *sr; struct agar_state *sr;
const void *nr; const void *nr;
plan_tests(2 * 13 + 12 + 10); plan_tests(2 * 13 + 12 + 10 + 6);
test_bfs(&trivial_graphr.gr, 1, 1); test_bfs(&trivial_graphr.gr, 1, 1);
...@@ -97,5 +97,9 @@ int main(void) ...@@ -97,5 +97,9 @@ int main(void)
test_bfs_partial(sr, 1, 1, 2, 3); test_bfs_partial(sr, 1, 1, 2, 3);
tal_free(sr); tal_free(sr);
test_bfs(&negacycle_graphr.gr, 1, 1, 2, 3);
test_bfs(&negacycle_graphr.gr, 2, 2, 3, 1);
test_bfs(&negacycle_graphr.gr, 3, 3, 1, 2);
return exit_status(); return exit_status();
} }
...@@ -45,7 +45,7 @@ int main(void) ...@@ -45,7 +45,7 @@ int main(void)
struct agar_state *sr; struct agar_state *sr;
const void *nr; const void *nr;
plan_tests(2 * 13 + 12 + 10); plan_tests(2 * 13 + 12 + 10 + 6);
test_dfs(&trivial_graphr.gr, 1, 1); test_dfs(&trivial_graphr.gr, 1, 1);
...@@ -97,5 +97,9 @@ int main(void) ...@@ -97,5 +97,9 @@ int main(void)
test_dfs_partial(sr, 1, 1, 2, 3); test_dfs_partial(sr, 1, 1, 2, 3);
tal_free(sr); tal_free(sr);
test_dfs(&negacycle_graphr.gr, 1, 1, 2, 3);
test_dfs(&negacycle_graphr.gr, 2, 2, 3, 1);
test_dfs(&negacycle_graphr.gr, 3, 3, 1, 2);
return exit_status(); return exit_status();
} }
...@@ -236,12 +236,22 @@ static void test_shortcut2(void) ...@@ -236,12 +236,22 @@ static void test_shortcut2(void)
tal_free(sr); tal_free(sr);
} }
static void test_negacycle(void)
{
struct agar_state *sr;
ok1(sr = agar_dijkstra_new(NULL, &negacycle_graphr.gr, int2ptr(1)));
agar_dijkstra_complete(sr);
ok1(agar_error(sr) == AGA_ERR_NEGATIVE_COST);
tal_free(sr);
}
int main(void) int main(void)
{ {
plan_tests(6 + 23 plan_tests(6 + 23
+ FULL_LEN * (FULL_LEN*4 - 1) + FULL_LEN * (FULL_LEN*4 - 1)
+ CHAIN_LEN * (1 + CHAIN_LEN*2) + CHAIN_LEN * (1 + CHAIN_LEN*2)
+ 12 + 32 + 7 + 2); + 12 + 32 + 7 + 2 + 2);
test_trivial(); test_trivial();
test_parallel(); test_parallel();
...@@ -251,6 +261,7 @@ int main(void) ...@@ -251,6 +261,7 @@ int main(void)
test_traversal1(); test_traversal1();
test_shortcut1(); test_shortcut1();
test_shortcut2(); test_shortcut2();
test_negacycle();
return exit_status(); return exit_status();
} }
#include "config.h"
#include <assert.h>
#include <ccan/container_of/container_of.h>
#include <ccan/ptrint/ptrint.h>
#include <ccan/agar/agar.h>
#include "simple-graphr.h"
static const void *negacycle_first_edge_r(const struct agar_graph *gr,
const void *nr)
{
return int2ptr(1);
}
static const void *negacycle_next_edge_r(const struct agar_graph *gr,
const void *nr, const void *e)
{
assert(ptr2int(e) == 1);
return NULL;
}
static int negacycle_edge_info_r(const struct agar_graph *gr,
const void *nr, const void *e,
struct agar_edge_info *eir)
{
int ni = ptr2int(nr);
assert(ptr2int(e) == 1);
eir->to = int2ptr((ni % 3) + 1);
if (ni == 3)
eir->icost = -3;
return 0;
}
struct negacycle_graphr negacycle_graphr = {
AGAR_INIT_GRAPH(negacycle_first_edge_r,
negacycle_next_edge_r,
negacycle_edge_info_r),
};
...@@ -240,4 +240,23 @@ static const struct adjacency_listr shortcut2_adjacencyr[] = { ...@@ -240,4 +240,23 @@ static const struct adjacency_listr shortcut2_adjacencyr[] = {
{}, {},
}; };
/* Negacycle graph
*
* A <---- (-3) ----- C
* \ ^
* (1)-> B -- (1)-/
*
* Graph with a negative length cycle, and so lacking well-defined shortest paths.
*/
struct negacycle_graphr {
struct agar_graph gr;
};
extern struct negacycle_graphr negacycle_graphr;
static const struct adjacency_listr negacycle_adjacencyr[] = {
{1, {2}},
{2, {3}},
{3, {1}},
{},
};
#endif /* _SIMPLE_GRAPHR_H */ #endif /* _SIMPLE_GRAPHR_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment