|
1 | 1 | import test from 'ava' ;
|
| 2 | +import {enumerate} from '@aureooms/js-itertools'; |
2 | 3 |
|
3 | 4 | import blossom from '../../../src/exact/blossom' ;
|
4 | 5 |
|
5 |
| -function macro ( t , alg , callback ) { |
6 |
| - callback(alg, t); |
| 6 | +const macro = ( t , algorithm , edges , maxCardinality, expected ) => { |
| 7 | + const input = edges.map(edge => edge.slice()); // deepcopy |
| 8 | + const result = algorithm(edges, maxCardinality); |
| 9 | + t.deepEqual(expected, result); |
| 10 | + t.deepEqual(input, edges); |
7 | 11 | }
|
8 | 12 |
|
9 |
| -const tests = { |
| 13 | +macro.title = (title, algorithm, edges, maxCardinality, expected) => title || `${algorithm.name}(${JSON.stringify(edges)}, ${maxCardinality}) = ${JSON.stringify(expected)}`; |
10 | 14 |
|
11 |
| - test10_empty : (alg,t) => { |
12 |
| - // empty input graph |
13 |
| - t.deepEqual(alg([]), []); |
14 |
| - }, |
15 |
| - test11_singleedge : (alg,t) => { |
| 15 | +const tests = { |
| 16 | + // empty input graph |
| 17 | + test10_empty : { edges: [], expected: []}, |
| 18 | + test11_singleedge : |
16 | 19 | // single edge
|
17 |
| - t.deepEqual(alg([ [0,1,1] ]), [1, 0]); |
| 20 | + { edges: [ [0,1,1] ], expected: [1, 0] |
18 | 21 | },
|
19 | 22 |
|
20 |
| - test12 : (alg,t) => { |
21 |
| - t.deepEqual(alg([ [1,2,10], [2,3,11] ]), [ -1, -1, 3, 2 ]); |
| 23 | + test12 : |
| 24 | + { edges: [ [1,2,10], [2,3,11] ], expected: [ -1, -1, 3, 2 ] |
22 | 25 | },
|
23 | 26 |
|
24 |
| - test13 : (alg,t) => { |
25 |
| - t.deepEqual(alg([ [1,2,5], [2,3,11], [3,4,5] ]), [ -1, -1, 3, 2, -1 ]); |
| 27 | + test13 : |
| 28 | + { edges: [ [1,2,5], [2,3,11], [3,4,5] ], expected: [ -1, -1, 3, 2, -1 ] |
26 | 29 | },
|
27 | 30 |
|
28 |
| - test14_maxcard : (alg,t) => { |
29 |
| - // maximum cardinality |
30 |
| - t.deepEqual(alg([ [1,2,5], [2,3,11], [3,4,5] ], true), [ -1, 2, 1, 4, 3 ]); |
| 31 | + // maximum cardinality |
| 32 | + test14_maxcard : |
| 33 | + { edges: [ [1,2,5], [2,3,11], [3,4,5] ], maxCardinality: true, expected: [ -1, 2, 1, 4, 3 ] |
31 | 34 | },
|
32 | 35 |
|
33 |
| - test15_float : (alg,t) => { |
34 |
| - // floating point weigths |
35 |
| - t.deepEqual(alg([ [1,2,Math.PI], [2,3,Math.E], [1,3,3.0], [1,4,Math.sqrt(2.0)] ]), [ -1, 4, 3, 2, 1 ]); |
| 36 | + // floating point weigths |
| 37 | + test15_float : |
| 38 | + { edges: [ [1,2,Math.PI], [2,3,Math.E], [1,3,3.0], [1,4,Math.sqrt(2.0)] ], expected: [ -1, 4, 3, 2, 1 ] |
36 | 39 | },
|
37 | 40 |
|
38 |
| - test16_negative : (alg,t) => { |
39 |
| - // negative weights |
40 |
| - t.deepEqual(alg([ [1,2,2], [1,3,-2], [2,3,1], [2,4,-1], [3,4,-6] ], false), [ -1, 2, 1, -1, -1 ]); |
41 |
| - t.deepEqual(alg([ [1,2,2], [1,3,-2], [2,3,1], [2,4,-1], [3,4,-6] ], true), [ -1, 3, 4, 1, 2 ]); |
| 41 | + // negative weights |
| 42 | + test16_negative : |
| 43 | + { edges: [ [1,2,2], [1,3,-2], [2,3,1], [2,4,-1], [3,4,-6] ], maxCardinality: false, expected: [ -1, 2, 1, -1, -1 ] |
| 44 | + }, |
| 45 | + test16_negative_maxCardinality : |
| 46 | + { edges: [ [1,2,2], [1,3,-2], [2,3,1], [2,4,-1], [3,4,-6] ], maxCardinality: true, expected: [ -1, 3, 4, 1, 2 ] |
42 | 47 | },
|
43 | 48 |
|
44 |
| - test20_sblossom : (alg,t) => { |
45 |
| - // create S-blossom and use it for augmentation |
46 |
| - t.deepEqual(alg([ [1,2,8], [1,3,9], [2,3,10], [3,4,7] ]), [ -1, 2, 1, 4, 3 ]); |
47 |
| - t.deepEqual(alg([ [1,2,8], [1,3,9], [2,3,10], [3,4,7], [1,6,5], [4,5,6] ]), [ -1, 6, 3, 2, 5, 4, 1 ]); |
| 49 | + // create S-blossom and use it for augmentation |
| 50 | + test20_sblossom_1 : |
| 51 | + { edges: [ [1,2,8], [1,3,9], [2,3,10], [3,4,7] ], expected: [ -1, 2, 1, 4, 3 ] |
| 52 | + }, |
| 53 | + test20_sblossom_2 : |
| 54 | + { edges: [ [1,2,8], [1,3,9], [2,3,10], [3,4,7], [1,6,5], [4,5,6] ], expected: [ -1, 6, 3, 2, 5, 4, 1 ] |
48 | 55 | },
|
49 | 56 |
|
50 |
| - test21_tblossom : (alg,t) => { |
51 |
| - // create S-blossom, relabel as T-blossom, use for augmentation |
52 |
| - t.deepEqual(alg([ [1,2,9], [1,3,8], [2,3,10], [1,4,5], [4,5,4], [1,6,3] ]), [ -1, 6, 3, 2, 5, 4, 1 ]); |
53 |
| - t.deepEqual(alg([ [1,2,9], [1,3,8], [2,3,10], [1,4,5], [4,5,3], [1,6,4] ]), [ -1, 6, 3, 2, 5, 4, 1 ]); |
54 |
| - t.deepEqual(alg([ [1,2,9], [1,3,8], [2,3,10], [1,4,5], [4,5,3], [3,6,4] ]), [ -1, 2, 1, 6, 5, 4, 3 ]); |
| 57 | + // create S-blossom, relabel as T-blossom, use for augmentation |
| 58 | + test21_tblossom_1 : |
| 59 | + { edges: [ [1,2,9], [1,3,8], [2,3,10], [1,4,5], [4,5,4], [1,6,3] ], expected: [ -1, 6, 3, 2, 5, 4, 1 ] |
| 60 | + }, |
| 61 | + test21_tblossom_2 : |
| 62 | + { edges: [ [1,2,9], [1,3,8], [2,3,10], [1,4,5], [4,5,3], [1,6,4] ], expected: [ -1, 6, 3, 2, 5, 4, 1 ] |
| 63 | + }, |
| 64 | + test21_tblossom_3 : |
| 65 | + { edges: [ [1,2,9], [1,3,8], [2,3,10], [1,4,5], [4,5,3], [3,6,4] ], expected: [ -1, 2, 1, 6, 5, 4, 3 ] |
55 | 66 | },
|
56 | 67 |
|
57 |
| - test22_s_nest : (alg,t) => { |
58 |
| - // create nested S-blossom, use for augmentation |
59 |
| - t.deepEqual(alg([ [1,2,9], [1,3,9], [2,3,10], [2,4,8], [3,5,8], [4,5,10], [5,6,6] ]), [ -1, 3, 4, 1, 2, 6, 5 ]); |
| 68 | + // create nested S-blossom, use for augmentation |
| 69 | + test22_s_nest : |
| 70 | + { edges: [ [1,2,9], [1,3,9], [2,3,10], [2,4,8], [3,5,8], [4,5,10], [5,6,6] ], expected: [ -1, 3, 4, 1, 2, 6, 5 ] |
60 | 71 | },
|
61 | 72 |
|
62 |
| - test23_s_relabel_nest : (alg,t) => { |
63 |
| - // create S-blossom, relabel as S, include in nested S-blossom |
64 |
| - t.deepEqual(alg([ [1,2,10], [1,7,10], [2,3,12], [3,4,20], [3,5,20], [4,5,25], [5,6,10], [6,7,10], [7,8,8] ]), [ -1, 2, 1, 4, 3, 6, 5, 8, 7 ]); |
| 73 | + // create S-blossom, relabel as S, include in nested S-blossom |
| 74 | + test23_s_relabel_nest : |
| 75 | + { edges: [ [1,2,10], [1,7,10], [2,3,12], [3,4,20], [3,5,20], [4,5,25], [5,6,10], [6,7,10], [7,8,8] ], expected: [ -1, 2, 1, 4, 3, 6, 5, 8, 7 ] |
65 | 76 | },
|
66 | 77 |
|
67 |
| - test24_s_nest_expand : (alg,t) => { |
68 |
| - // create nested S-blossom, augment, expand recursively |
69 |
| - t.deepEqual(alg([ [1,2,8], [1,3,8], [2,3,10], [2,4,12], [3,5,12], [4,5,14], [4,6,12], [5,7,12], [6,7,14], [7,8,12] ]), [ -1, 2, 1, 5, 6, 3, 4, 8, 7 ]); |
| 78 | + // create nested S-blossom, augment, expand recursively |
| 79 | + test24_s_nest_expand : |
| 80 | + { edges: [ [1,2,8], [1,3,8], [2,3,10], [2,4,12], [3,5,12], [4,5,14], [4,6,12], [5,7,12], [6,7,14], [7,8,12] ], expected: [ -1, 2, 1, 5, 6, 3, 4, 8, 7 ] |
70 | 81 | },
|
71 | 82 |
|
72 |
| - test25_s_t_expand : (alg,t) => { |
73 |
| - // create S-blossom, relabel as T, expand |
74 |
| - t.deepEqual(alg([ [1,2,23], [1,5,22], [1,6,15], [2,3,25], [3,4,22], [4,5,25], [4,8,14], [5,7,13] ]), [ -1, 6, 3, 2, 8, 7, 1, 5, 4 ]); |
| 83 | + // create S-blossom, relabel as T, expand |
| 84 | + test25_s_t_expand : |
| 85 | + { edges: [ [1,2,23], [1,5,22], [1,6,15], [2,3,25], [3,4,22], [4,5,25], [4,8,14], [5,7,13] ], expected: [ -1, 6, 3, 2, 8, 7, 1, 5, 4 ] |
75 | 86 | },
|
76 | 87 |
|
77 |
| - test26_s_nest_t_expand : (alg,t) => { |
78 |
| - // create nested S-blossom, relabel as T, expand |
79 |
| - t.deepEqual(alg([ [1,2,19], [1,3,20], [1,8,8], [2,3,25], [2,4,18], [3,5,18], [4,5,13], [4,7,7], [5,6,7] ]), [ -1, 8, 3, 2, 7, 6, 5, 4, 1 ]); |
| 88 | + // create nested S-blossom, relabel as T, expand |
| 89 | + test26_s_nest_t_expand : |
| 90 | + { edges: [ [1,2,19], [1,3,20], [1,8,8], [2,3,25], [2,4,18], [3,5,18], [4,5,13], [4,7,7], [5,6,7] ], expected: [ -1, 8, 3, 2, 7, 6, 5, 4, 1 ] |
80 | 91 | },
|
81 | 92 |
|
82 |
| - test30_tnasty_expand : (alg,t) => { |
83 |
| - // create blossom, relabel as T in more than one way, expand, augment |
84 |
| - t.deepEqual(alg([ [1,2,45], [1,5,45], [2,3,50], [3,4,45], [4,5,50], [1,6,30], [3,9,35], [4,8,35], [5,7,26], [9,10,5] ]), [ -1, 6, 3, 2, 8, 7, 1, 5, 4, 10, 9 ]); |
| 93 | + // create blossom, relabel as T in more than one way, expand, augment |
| 94 | + test30_tnasty_expand : |
| 95 | + { edges: [ [1,2,45], [1,5,45], [2,3,50], [3,4,45], [4,5,50], [1,6,30], [3,9,35], [4,8,35], [5,7,26], [9,10,5] ], expected: [ -1, 6, 3, 2, 8, 7, 1, 5, 4, 10, 9 ] |
85 | 96 | },
|
86 | 97 |
|
87 |
| - test31_tnasty2_expand : (alg,t) => { |
88 |
| - // again but slightly different |
89 |
| - t.deepEqual(alg([ [1,2,45], [1,5,45], [2,3,50], [3,4,45], [4,5,50], [1,6,30], [3,9,35], [4,8,26], [5,7,40], [9,10,5] ]), [ -1, 6, 3, 2, 8, 7, 1, 5, 4, 10, 9 ]); |
| 98 | + // again but slightly different |
| 99 | + test31_tnasty2_expand : |
| 100 | + { edges: [ [1,2,45], [1,5,45], [2,3,50], [3,4,45], [4,5,50], [1,6,30], [3,9,35], [4,8,26], [5,7,40], [9,10,5] ], expected: [ -1, 6, 3, 2, 8, 7, 1, 5, 4, 10, 9 ] |
90 | 101 | },
|
91 | 102 |
|
92 |
| - test32_t_expand_leastslack : (alg,t) => { |
93 |
| - // create blossom, relabel as T, expand such that a new least-slack S-to-free edge is produced, augment |
94 |
| - t.deepEqual(alg([ [1,2,45], [1,5,45], [2,3,50], [3,4,45], [4,5,50], [1,6,30], [3,9,35], [4,8,28], [5,7,26], [9,10,5] ]), [ -1, 6, 3, 2, 8, 7, 1, 5, 4, 10, 9 ]); |
| 103 | + // create blossom, relabel as T, expand such that a new least-slack S-to-free edge is produced, augment |
| 104 | + test32_t_expand_leastslack : |
| 105 | + { edges: [ [1,2,45], [1,5,45], [2,3,50], [3,4,45], [4,5,50], [1,6,30], [3,9,35], [4,8,28], [5,7,26], [9,10,5] ], expected: [ -1, 6, 3, 2, 8, 7, 1, 5, 4, 10, 9 ] |
95 | 106 | },
|
96 | 107 |
|
97 |
| - test33_nest_tnasty_expand : (alg,t) => { |
98 |
| - // create nested blossom, relabel as T in more than one way, expand outer blossom such that inner blossom ends up on an augmenting path |
99 |
| - t.deepEqual(alg([ [1,2,45], [1,7,45], [2,3,50], [3,4,45], [4,5,95], [4,6,94], [5,6,94], [6,7,50], [1,8,30], [3,11,35], [5,9,36], [7,10,26], [11,12,5] ]), [ -1, 8, 3, 2, 6, 9, 4, 10, 1, 5, 7, 12, 11 ]); |
| 108 | + // create nested blossom, relabel as T in more than one way, expand outer blossom such that inner blossom ends up on an augmenting path |
| 109 | + test33_nest_tnasty_expand : |
| 110 | + { edges: [ [1,2,45], [1,7,45], [2,3,50], [3,4,45], [4,5,95], [4,6,94], [5,6,94], [6,7,50], [1,8,30], [3,11,35], [5,9,36], [7,10,26], [11,12,5] ], expected: [ -1, 8, 3, 2, 6, 9, 4, 10, 1, 5, 7, 12, 11 ] |
100 | 111 | },
|
101 | 112 |
|
102 |
| - test34_nest_relabel_expand : (alg,t) => { |
103 |
| - // create nested S-blossom, relabel as S, expand recursively |
104 |
| - t.deepEqual(alg([ [1,2,40], [1,3,40], [2,3,60], [2,4,55], [3,5,55], [4,5,50], [1,8,15], [5,7,30], [7,6,10], [8,10,10], [4,9,30] ]), [ -1, 2, 1, 5, 9, 3, 7, 6, 10, 4, 8 ]); |
| 113 | + // create nested S-blossom, relabel as S, expand recursively |
| 114 | + test34_nest_relabel_expand : |
| 115 | + { edges: [ [1,2,40], [1,3,40], [2,3,60], [2,4,55], [3,5,55], [4,5,50], [1,8,15], [5,7,30], [7,6,10], [8,10,10], [4,9,30] ], expected: [ -1, 2, 1, 5, 9, 3, 7, 6, 10, 4, 8 ] |
105 | 116 | }
|
106 | 117 | };
|
107 | 118 |
|
108 |
| -const alg = [ |
| 119 | +const algorithms = [ |
109 | 120 | blossom(true, true),
|
110 | 121 | blossom(false, false),
|
111 | 122 | blossom()
|
112 | 123 | ];
|
113 | 124 |
|
114 |
| -for(let i = 0; i < alg.length; ++i) |
115 |
| - for(const key in tests) |
116 |
| - test(`${key} ${i}`, macro, alg[i], tests[key]); |
| 125 | +for(const [i, algorithm] of enumerate(algorithms)) |
| 126 | + for(const [key, {edges, maxCardinality, expected}] of Object.entries(tests)) |
| 127 | + test(`${key} ${i}`, macro, algorithm, edges, maxCardinality, expected); |
0 commit comments