Skip to content

Commit 143a527

Browse files
♻️ refactor: Extract blossom code and clean up a bit.
1 parent 86503b7 commit 143a527

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+62
-2857
lines changed

.esdoc.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"autoPrivate": true
3636
},
3737
"brand": {
38-
"title": "@aureooms/js-gn"
38+
"title": "@aureooms/js-maximum-matching"
3939
},
4040
"test": {
4141
"type": "ava",

README.md

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[@aureooms/js-gn](https://aureooms.github.io/js-gn)
1+
[@aureooms/js-maximum-matching](https://aureooms.github.io/js-maximum-matching)
22
==
33

44
Graphs and networks code bricks for JavaScript.
@@ -7,17 +7,17 @@ Parents are
77
and
88
[@aureooms/js-data-structures](https://github.com/aureooms/js-data-structures).
99

10-
[![License](https://img.shields.io/github/license/aureooms/js-gn.svg)](https://raw.githubusercontent.com/aureooms/js-gn/master/LICENSE)
11-
[![Version](https://img.shields.io/npm/v/@aureooms/js-gn.svg)](https://www.npmjs.org/package/@aureooms/js-gn)
12-
[![Build](https://img.shields.io/travis/aureooms/js-gn/master.svg)](https://travis-ci.org/aureooms/js-gn/branches)
13-
[![Dependencies](https://img.shields.io/david/aureooms/js-gn.svg)](https://david-dm.org/aureooms/js-gn)
14-
[![Dev dependencies](https://img.shields.io/david/dev/aureooms/js-gn.svg)](https://david-dm.org/aureooms/js-gn?type=dev)
15-
[![GitHub issues](https://img.shields.io/github/issues/aureooms/js-gn.svg)](https://github.com/aureooms/js-gn/issues)
16-
[![Downloads](https://img.shields.io/npm/dm/@aureooms/js-gn.svg)](https://www.npmjs.org/package/@aureooms/js-gn)
10+
[![License](https://img.shields.io/github/license/aureooms/js-maximum-matching.svg)](https://raw.githubusercontent.com/aureooms/js-maximum-matching/master/LICENSE)
11+
[![Version](https://img.shields.io/npm/v/@aureooms/js-maximum-matching.svg)](https://www.npmjs.org/package/@aureooms/js-maximum-matching)
12+
[![Build](https://img.shields.io/travis/aureooms/js-maximum-matching/master.svg)](https://travis-ci.org/aureooms/js-maximum-matching/branches)
13+
[![Dependencies](https://img.shields.io/david/aureooms/js-maximum-matching.svg)](https://david-dm.org/aureooms/js-maximum-matching)
14+
[![Dev dependencies](https://img.shields.io/david/dev/aureooms/js-maximum-matching.svg)](https://david-dm.org/aureooms/js-maximum-matching?type=dev)
15+
[![GitHub issues](https://img.shields.io/github/issues/aureooms/js-maximum-matching.svg)](https://github.com/aureooms/js-maximum-matching/issues)
16+
[![Downloads](https://img.shields.io/npm/dm/@aureooms/js-maximum-matching.svg)](https://www.npmjs.org/package/@aureooms/js-maximum-matching)
1717

18-
[![Code issues](https://img.shields.io/codeclimate/issues/aureooms/js-gn.svg)](https://codeclimate.com/github/aureooms/js-gn/issues)
19-
[![Code maintainability](https://img.shields.io/codeclimate/maintainability/aureooms/js-gn.svg)](https://codeclimate.com/github/aureooms/js-gn/trends/churn)
20-
[![Code coverage (cov)](https://img.shields.io/codecov/c/gh/aureooms/js-gn/master.svg)](https://codecov.io/gh/aureooms/js-gn)
21-
[![Code technical debt](https://img.shields.io/codeclimate/tech-debt/aureooms/js-gn.svg)](https://codeclimate.com/github/aureooms/js-gn/trends/technical_debt)
22-
[![Documentation](https://aureooms.github.io/js-gn/badge.svg)](https://aureooms.github.io/js-gn/source.html)
23-
[![Package size](https://img.shields.io/bundlephobia/minzip/@aureooms/js-gn)](https://bundlephobia.com/result?p=@aureooms/js-gn)
18+
[![Code issues](https://img.shields.io/codeclimate/issues/aureooms/js-maximum-matching.svg)](https://codeclimate.com/github/aureooms/js-maximum-matching/issues)
19+
[![Code maintainability](https://img.shields.io/codeclimate/maintainability/aureooms/js-maximum-matching.svg)](https://codeclimate.com/github/aureooms/js-maximum-matching/trends/churn)
20+
[![Code coverage (cov)](https://img.shields.io/codecov/c/gh/aureooms/js-maximum-matching/master.svg)](https://codecov.io/gh/aureooms/js-maximum-matching)
21+
[![Code technical debt](https://img.shields.io/codeclimate/tech-debt/aureooms/js-maximum-matching.svg)](https://codeclimate.com/github/aureooms/js-maximum-matching/trends/technical_debt)
22+
[![Documentation](https://aureooms.github.io/js-maximum-matching/badge.svg)](https://aureooms.github.io/js-maximum-matching/source.html)
23+
[![Package size](https://img.shields.io/bundlephobia/minzip/@aureooms/js-maximum-matching)](https://bundlephobia.com/result?p=@aureooms/js-maximum-matching)

doc/manual/example.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Examples
22

3-
> More examples in [the test files](https://github.com/aureooms/js-gn/tree/master/test/src).
3+
> More examples in [the test files](https://github.com/aureooms/js-maximum-matching/tree/master/test/src).

doc/manual/installation.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ or [jspm](https://jspm.org/docs).
88

99
### yarn
1010
```terminal
11-
yarn add @aureooms/js-gn
11+
yarn add @aureooms/js-maximum-matching
1212
```
1313

1414
### npm
1515
```terminal
16-
npm install @aureooms/js-gn --save
16+
npm install @aureooms/js-maximum-matching --save
1717
```
1818

1919
### jspm
2020
```terminal
21-
jspm install npm:@aureooms/js-gn
21+
jspm install npm:@aureooms/js-maximum-matching
2222
```

doc/manual/usage.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import 'regenerator-runtime/runtime' ;
1212

1313
Then, import the library where needed
1414
```js
15-
const gn = require( '@aureooms/js-gn' ) ;
15+
const mm = require( '@aureooms/js-maximum-matching' ) ;
1616
// or
17-
import * as gn from '@aureooms/js-gn' ;
17+
import * as mm from '@aureooms/js-maximum-matching' ;
1818
```

doc/scripts/header.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ domReady(function(){
1313

1414
var projectname = document.createElement('a');
1515
projectname.classList.add('project-name');
16-
projectname.text = 'aureooms/js-gn';
16+
projectname.text = 'aureooms/js-maximum-matching';
1717
projectname.href = './index.html' ;
1818

1919
var header = document.getElementsByTagName('header')[0] ;
2020
header.insertBefore(projectname,header.firstChild);
2121

2222
var testlink = document.querySelector('header > a[data-ice="testLink"]') ;
23-
testlink.href = 'https://coveralls.io/github/aureooms/js-gn' ;
23+
testlink.href = 'https://coveralls.io/github/aureooms/js-maximum-matching' ;
2424
testlink.target = '_BLANK' ;
2525

2626
var searchBox = document.querySelector('.search-box');

package.json

+9-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "@aureooms/js-gn",
3-
"description": "graphs and networks code bricks for JavaScript",
2+
"name": "@aureooms/js-maximum-matching",
3+
"description": "Maximum matching algorithms for JavaScript",
44
"version": "1.0.5",
55
"author": "aureooms",
66
"ava": {
@@ -73,7 +73,7 @@
7373
}
7474
},
7575
"bugs": {
76-
"url": "https://github.com/aureooms/js-gn/issues"
76+
"url": "https://github.com/aureooms/js-maximum-matching/issues"
7777
},
7878
"dependencies": {},
7979
"devDependencies": {
@@ -101,23 +101,19 @@
101101
"files": [
102102
"lib"
103103
],
104-
"homepage": "https://aureooms.github.io/js-gn",
104+
"homepage": "https://aureooms.github.io/js-maximum-matching",
105105
"keywords": [
106-
"adt",
106+
"graph",
107107
"algorithm",
108-
"complexity",
109-
"gn",
110-
"graphs",
111-
"javascript",
112-
"js",
113-
"networks",
114-
"template"
108+
"maximum",
109+
"matching",
110+
"javascript"
115111
],
116112
"license": "AGPL-3.0",
117113
"main": "lib/index.js",
118114
"repository": {
119115
"type": "git",
120-
"url": "https://github.com/aureooms/js-gn.git"
116+
"url": "https://github.com/aureooms/js-maximum-matching.git"
121117
},
122118
"scripts": {
123119
"build": "babel --delete-dir-on-start --env-name production src -d lib",

src/undirected/offline/algo/eulerian/wblossom_n3.js renamed to src/exact/blossom.js

+23-28
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import assert from 'assert';
2+
13
// Adapted from http://jorisvr.nl/maximummatching.html
24
// All credit for the implementation goes to Joris van Rantwijk [http://jorisvr.nl].
35

@@ -17,10 +19,7 @@
1719
// to validate this new code.
1820

1921

20-
export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
21-
22-
// If assigned, DEBUG(str) is called with lots of debug messages.
23-
var DEBUG = debug ? function(s){ console.log('DEBUG:', s); } : null;
22+
export default function blossom (CHECK_OPTIMUM, CHECK_DELTA) {
2423

2524
// Check delta2/delta3 computation after every substage;
2625
// only works on integer weights, slows down the algorithm to O(n^4).
@@ -32,10 +31,6 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
3231

3332
// Compatibility
3433

35-
var assert = function (condition) {
36-
if (!condition) throw new Error('Assertion failed');
37-
};
38-
3934
var min = function (a, i, j) {
4035

4136
var o = a[i];
@@ -284,7 +279,7 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
284279
// and record the fact that w was reached through the edge with
285280
// remote endpoint p.
286281
var assignLabel = function (w, t, p) {
287-
if (DEBUG) DEBUG('assignLabel(' + w + ',' + t + ',' + p + ')');
282+
console.debug('DEBUG: assignLabel(' + w + ',' + t + ',' + p + ')');
288283
var b = inblossom[w], e;
289284
assert(label[w] === 0 && label[b] === 0);
290285
label[w] = label[b] = t;
@@ -293,7 +288,7 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
293288
if (t === 1){
294289
// b became an S-vertex/blossom; add it(s vertices) to the queue.
295290
blossomLeaves(b, function(e){ queue.push(e); });
296-
if (DEBUG) DEBUG('PUSH ' + queue);
291+
console.debug('DEBUG: PUSH ' + queue);
297292
}
298293
else if (t === 2){
299294
// b became a T-vertex/blossom; assign label S to its mate.
@@ -309,7 +304,7 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
309304
// Trace back from vertices v and w to discover either a new blossom
310305
// or an augmenting path. Return the base vertex of the new blossom or -1.
311306
var scanBlossom = function (v, w) {
312-
if (DEBUG) DEBUG('scanBlossom(' + v + ',' + w + ')');
307+
console.debug('DEBUG: scanBlossom(' + v + ',' + w + ')');
313308
// Trace back from v and w, placing breadcrumbs as we go.
314309
var b, tmp, i;
315310
var path = [];
@@ -370,7 +365,7 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
370365
var bw = inblossom[w];
371366
// Create blossom.
372367
var b = unusedblossoms.pop();
373-
if (DEBUG) DEBUG('addBlossom(' + base + ',' + k + ') (v=' + v + ' w=' + w + ') -> ' + b);
368+
console.debug('DEBUG: addBlossom(' + base + ',' + k + ') (v=' + v + ' w=' + w + ') -> ' + b);
374369
blossombase[b] = base;
375370
blossomparent[b] = -1;
376371
blossomparent[bb] = b;
@@ -503,12 +498,12 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
503498
}
504499
else bestedge[b] = -1;
505500

506-
if (DEBUG) DEBUG('blossomchilds[' + b + ']=' + blossomchilds[b]);
501+
console.debug('DEBUG: blossomchilds[' + b + ']=' + blossomchilds[b]);
507502
};
508503

509504
// Expand the given top-level blossom.
510505
var expandBlossom = function(b, endstage) {
511-
if (DEBUG) DEBUG('expandBlossom(' + b + ',' + endstage + ') ' + blossomchilds[b]);
506+
console.debug('DEBUG: expandBlossom(' + b + ',' + endstage + ') ' + blossomchilds[b]);
512507
// Convert sub-blossoms into top-level blossoms.
513508
var i, j, len, s, p, entrychild, jstep, endptrick, bv, stop, base;
514509

@@ -622,7 +617,7 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
622617
// Swap matched/unmatched edges over an alternating path through blossom b
623618
// between vertex v and the base vertex. Keep blossom bookkeeping consistent.
624619
var augmentBlossom = function(b, v){
625-
if (DEBUG) DEBUG('augmentBlossom(' + b + ',' + v + ')');
620+
console.debug('DEBUG: augmentBlossom(' + b + ',' + v + ')');
626621
// Bubble up through the blossom tree from vertex v to an immediate
627622
// sub-blossom of b.
628623
var i, j, t, jstep, endptrick, stop, len, p;
@@ -663,7 +658,7 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
663658
// Match the edge connecting those sub-blossoms.
664659
mate[endpoint[p]] = p ^ 1;
665660
mate[endpoint[p ^ 1]] = p;
666-
if (DEBUG) DEBUG('PAIR ' + endpoint[p] + ' ' + endpoint[p^1] + ' (k=' + Math.floor(p/2) + ')');
661+
console.debug('DEBUG: PAIR ' + endpoint[p] + ' ' + endpoint[p^1] + ' (k=' + Math.floor(p/2) + ')');
667662
}
668663
// Rotate the list of sub-blossoms to put the new base at the front.
669664
rotate(blossomchilds[b], i);
@@ -683,8 +678,8 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
683678
var w = edges[k][1];
684679
var wt = edges[k][2];
685680

686-
if (DEBUG) DEBUG('augmentMatching(' + k + ') (v=' + v + ' w=' + w + ')');
687-
if (DEBUG) DEBUG('PAIR ' + v + ' ' + w + ' (k=' + k + ')');
681+
console.debug('DEBUG: augmentMatching(' + k + ') (v=' + v + ' w=' + w + ')');
682+
console.debug('DEBUG: PAIR ' + v + ' ' + w + ' (k=' + k + ')');
688683

689684
[[v, 2 * k + 1], [w, 2 * k]].forEach(function(e){
690685
var s = e[0];
@@ -722,7 +717,7 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
722717
// Keep the opposite endpoint;
723718
// it will be assigned to mate[s] in the next step.
724719
p = labelend[bt] ^ 1;
725-
if (DEBUG) DEBUG('PAIR ' + s + ' ' + t + ' (k=' + Math.floor(p/2) + ')');
720+
console.debug('DEBUG: PAIR ' + s + ' ' + t + ' (k=' + Math.floor(p/2) + ')');
726721
}
727722
});
728723
};
@@ -801,9 +796,9 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
801796
}
802797
}
803798
}
804-
if (DEBUG && (bestedge[v] !== -1 || bk !== -1) &&
799+
if ((bestedge[v] !== -1 || bk !== -1) &&
805800
(bestedge[v] === -1 || bd !== slack(bestedge[v]))) {
806-
DEBUG(
801+
console.debug(
807802
'v=' + v +
808803
' bk=' + bk +
809804
' bd=' + bd +
@@ -856,8 +851,8 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
856851
}
857852
}
858853
}
859-
if (DEBUG && bd !== tbd)
860-
DEBUG('bk=' + bk + ' tbk=' + tbk + ' bd=' + bd + ' tbd=' + tbd);
854+
if (bd !== tbd)
855+
console.debug('bk=' + bk + ' tbk=' + tbk + ' bd=' + bd + ' tbd=' + tbd);
861856
assert(bd === tbd);
862857
};
863858

@@ -869,7 +864,7 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
869864
// Each iteration of this loop is a "stage".
870865
// A stage finds an augmenting path and uses that to improve
871866
// the matching.
872-
if (DEBUG) DEBUG('STAGE ' + t);
867+
console.debug('DEBUG: STAGE ' + t);
873868

874869
// Remove labels from top-level blossoms/vertices.
875870
i = 2 * nvertex;
@@ -888,7 +883,7 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
888883

889884
// Make queue empty.
890885
queue = [];
891-
886+
892887
// Label single blossoms/vertices with S and put them in the queue.
893888
for (v = 0; v < nvertex; ++v) {
894889
if (mate[v] === -1 && label[inblossom[v]] === 0)
@@ -905,15 +900,15 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
905900
// the stage ends. If there is no augmenting path, the
906901
// primal-dual method is used to pump some slack out of
907902
// the dual variables.
908-
if (DEBUG) DEBUG('SUBSTAGE');
903+
console.debug('DEBUG: SUBSTAGE');
909904

910905
// Continue labeling until all vertices which are reachable
911906
// through an alternating path have got a label.
912907
while (queue.length && !augmented) {
913908

914909
// Take an S vertex from the queue.
915910
v = queue.pop();
916-
if (DEBUG) DEBUG('POP v=' + v);
911+
console.debug('DEBUG: POP v=' + v);
917912
assert(label[inblossom[v]] === 1);
918913

919914
// Scan its neighbours:
@@ -1077,7 +1072,7 @@ export function wblossom_n3_t (debug, CHECK_OPTIMUM, CHECK_DELTA) {
10771072
}
10781073

10791074
// Take action at the point where minimum delta occurred.
1080-
if (DEBUG) DEBUG('delta' + deltatype + '=' + delta);
1075+
console.debug('DEBUG: delta' + deltatype + '=' + delta);
10811076
if (deltatype === 1) {
10821077
// No further improvement possible; optimum reached.
10831078
break;

src/index.js

-1
This file was deleted.

src/undirected/index.js

-2
This file was deleted.

src/undirected/offline/algo/eulerian/dup.js

-32
This file was deleted.

0 commit comments

Comments
 (0)