From 128ff6b3a11e94109d064749cfa467c9e56282ad Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Wed, 28 Apr 2021 10:29:01 +0100 Subject: [PATCH] feat: ts for algs --- lib/alg/{components.js => components.ts} | 9 ++++----- lib/alg/{dfs.js => dfs.ts} | 11 +++-------- lib/alg/dijkstra-all.js | 14 -------------- lib/alg/dijkstra-all.ts | 13 +++++++++++++ lib/alg/{dijkstra.js => dijkstra.ts} | 7 +++---- lib/alg/{find-cycles.js => find-cycles.ts} | 9 ++++----- lib/alg/{floyd-warshall.js => floyd-warshall.ts} | 7 +++---- lib/alg/index.js | 13 ------------- lib/alg/index.ts | 11 +++++++++++ lib/alg/is-acyclic.js | 15 --------------- lib/alg/is-acyclic.ts | 14 ++++++++++++++ lib/alg/postorder.js | 7 ------- lib/alg/postorder.ts | 6 ++++++ lib/alg/preorder.js | 7 ------- lib/alg/preorder.ts | 6 ++++++ lib/alg/{prim.js => prim.ts} | 10 ++++------ lib/alg/{tarjan.js => tarjan.ts} | 15 +++++++-------- lib/alg/{topsort.js => topsort.ts} | 13 +++++-------- lib/index.ts | 4 ++-- test/alg/is-acyclic.test.ts | 2 +- test/alg/postorder.test.ts | 8 ++++---- test/alg/preorder.test.ts | 8 ++++---- test/alg/topsort.test.ts | 6 +++--- 23 files changed, 97 insertions(+), 118 deletions(-) rename lib/alg/{components.js => components.ts} (72%) rename lib/alg/{dfs.js => dfs.ts} (87%) delete mode 100644 lib/alg/dijkstra-all.js create mode 100644 lib/alg/dijkstra-all.ts rename lib/alg/{dijkstra.js => dijkstra.ts} (91%) rename lib/alg/{find-cycles.js => find-cycles.ts} (53%) rename lib/alg/{floyd-warshall.js => floyd-warshall.ts} (90%) delete mode 100644 lib/alg/index.js create mode 100644 lib/alg/index.ts delete mode 100644 lib/alg/is-acyclic.js create mode 100644 lib/alg/is-acyclic.ts delete mode 100644 lib/alg/postorder.js create mode 100644 lib/alg/postorder.ts delete mode 100644 lib/alg/preorder.js create mode 100644 lib/alg/preorder.ts rename lib/alg/{prim.js => prim.ts} (84%) rename lib/alg/{tarjan.js => tarjan.ts} (80%) rename lib/alg/{topsort.js => topsort.ts} (63%) diff --git a/lib/alg/components.js b/lib/alg/components.ts similarity index 72% rename from lib/alg/components.js rename to lib/alg/components.ts index 9e1429d2..1d596ddf 100644 --- a/lib/alg/components.js +++ b/lib/alg/components.ts @@ -1,10 +1,9 @@ -const _ = require('../lodash'); +import type { Graph } from '..'; +import * as _ from '../lodash'; -module.exports = components; - -function components(g) { +export function components(g: Graph) { const visited = {}; - const cmpts = []; + const cmpts: any[][] = []; let cmpt; function dfs(v) { diff --git a/lib/alg/dfs.js b/lib/alg/dfs.ts similarity index 87% rename from lib/alg/dfs.js rename to lib/alg/dfs.ts index 807152b6..72edce90 100644 --- a/lib/alg/dfs.js +++ b/lib/alg/dfs.ts @@ -1,6 +1,5 @@ -const _ = require('../lodash'); - -module.exports = dfs; +import type { Graph } from '..'; +import * as _ from '../lodash'; /* * A helper that preforms a pre- or post-order traversal on the input graph @@ -10,11 +9,7 @@ module.exports = dfs; * * Order must be one of "pre" or "post". */ -function dfs(g, vs, order) { - if (!_.isArray(vs)) { - vs = [vs]; - } - +export function dfs(g: Graph, vs: string[], order: 'pre' | 'post'): string[] { const navigation = (g.isDirected() ? g.successors : g.neighbors).bind(g); const acc = []; diff --git a/lib/alg/dijkstra-all.js b/lib/alg/dijkstra-all.js deleted file mode 100644 index 3f352a4e..00000000 --- a/lib/alg/dijkstra-all.js +++ /dev/null @@ -1,14 +0,0 @@ -const dijkstra = require('./dijkstra'); -const _ = require('../lodash'); - -module.exports = dijkstraAll; - -function dijkstraAll(g, weightFunc, edgeFunc) { - return _.transform( - g.nodes(), - function (acc, v) { - acc[v] = dijkstra(g, v, weightFunc, edgeFunc); - }, - {}, - ); -} diff --git a/lib/alg/dijkstra-all.ts b/lib/alg/dijkstra-all.ts new file mode 100644 index 00000000..4cdbcaff --- /dev/null +++ b/lib/alg/dijkstra-all.ts @@ -0,0 +1,13 @@ +import { Graph } from '..'; +import * as _ from '../lodash'; +import { dijkstra } from './dijkstra'; + +export function dijkstraAll(g: Graph, weightFunc?, edgeFunc?) { + return _.transform( + g.nodes(), + function (acc, v) { + acc[v] = dijkstra(g, v, weightFunc, edgeFunc); + }, + {}, + ); +} diff --git a/lib/alg/dijkstra.js b/lib/alg/dijkstra.ts similarity index 91% rename from lib/alg/dijkstra.js rename to lib/alg/dijkstra.ts index a97f61ce..0496e5fc 100644 --- a/lib/alg/dijkstra.js +++ b/lib/alg/dijkstra.ts @@ -1,11 +1,10 @@ -const _ = require('../lodash'); +import type { Graph } from '..'; +import * as _ from '../lodash'; const PriorityQueue = require('../data/priority-queue'); -module.exports = dijkstra; - const DEFAULT_WEIGHT_FUNC = _.constant(1); -function dijkstra(g, source, weightFn, edgeFn) { +export function dijkstra(g: Graph, source, weightFn?, edgeFn?) { return runDijkstra( g, String(source), diff --git a/lib/alg/find-cycles.js b/lib/alg/find-cycles.ts similarity index 53% rename from lib/alg/find-cycles.js rename to lib/alg/find-cycles.ts index 6e5b910a..491e9ee3 100644 --- a/lib/alg/find-cycles.js +++ b/lib/alg/find-cycles.ts @@ -1,9 +1,8 @@ -const _ = require('../lodash'); -const tarjan = require('./tarjan'); +import { Graph } from '..'; +import * as _ from '../lodash'; +import { tarjan } from './tarjan'; -module.exports = findCycles; - -function findCycles(g) { +export function findCycles(g: Graph) { return _.filter(tarjan(g), function (cmpt) { return ( cmpt.length > 1 || (cmpt.length === 1 && g.hasEdge(cmpt[0], cmpt[0])) diff --git a/lib/alg/floyd-warshall.js b/lib/alg/floyd-warshall.ts similarity index 90% rename from lib/alg/floyd-warshall.js rename to lib/alg/floyd-warshall.ts index 540308a8..b4c5a09d 100644 --- a/lib/alg/floyd-warshall.js +++ b/lib/alg/floyd-warshall.ts @@ -1,10 +1,9 @@ -const _ = require('../lodash'); - -module.exports = floydWarshall; +import { Graph } from '..'; +import * as _ from '../lodash'; const DEFAULT_WEIGHT_FUNC = _.constant(1); -function floydWarshall(g, weightFn, edgeFn) { +export function floydWarshall(g: Graph, weightFn?, edgeFn?) { return runFloydWarshall( g, weightFn || DEFAULT_WEIGHT_FUNC, diff --git a/lib/alg/index.js b/lib/alg/index.js deleted file mode 100644 index 36a6dc8a..00000000 --- a/lib/alg/index.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - components: require('./components'), - dijkstra: require('./dijkstra'), - dijkstraAll: require('./dijkstra-all'), - findCycles: require('./find-cycles'), - floydWarshall: require('./floyd-warshall'), - isAcyclic: require('./is-acyclic'), - postorder: require('./postorder'), - preorder: require('./preorder'), - prim: require('./prim'), - tarjan: require('./tarjan'), - topsort: require('./topsort'), -}; diff --git a/lib/alg/index.ts b/lib/alg/index.ts new file mode 100644 index 00000000..7604f5ba --- /dev/null +++ b/lib/alg/index.ts @@ -0,0 +1,11 @@ +export { components } from './components'; +export { dijkstra } from './dijkstra'; +export { dijkstraAll } from './dijkstra-all'; +export { findCycles } from './find-cycles'; +export { floydWarshall } from './floyd-warshall'; +export { isAcyclic } from './is-acyclic'; +export { postorder } from './postorder'; +export { preorder } from './preorder'; +export { prim } from './prim'; +export { tarjan } from './tarjan'; +export { topsort, CycleException } from './topsort'; diff --git a/lib/alg/is-acyclic.js b/lib/alg/is-acyclic.js deleted file mode 100644 index a29cc691..00000000 --- a/lib/alg/is-acyclic.js +++ /dev/null @@ -1,15 +0,0 @@ -const topsort = require('./topsort'); - -module.exports = isAcyclic; - -function isAcyclic(g) { - try { - topsort(g); - } catch (e) { - if (e instanceof topsort.CycleException) { - return false; - } - throw e; - } - return true; -} diff --git a/lib/alg/is-acyclic.ts b/lib/alg/is-acyclic.ts new file mode 100644 index 00000000..d95b7930 --- /dev/null +++ b/lib/alg/is-acyclic.ts @@ -0,0 +1,14 @@ +import type { Graph } from '..'; +import { CycleException, topsort } from './topsort'; + +export function isAcyclic(g: Graph) { + try { + topsort(g); + } catch (e) { + if (e instanceof CycleException) { + return false; + } + throw e; + } + return true; +} diff --git a/lib/alg/postorder.js b/lib/alg/postorder.js deleted file mode 100644 index 52a97fd7..00000000 --- a/lib/alg/postorder.js +++ /dev/null @@ -1,7 +0,0 @@ -const dfs = require('./dfs'); - -module.exports = postorder; - -function postorder(g, vs) { - return dfs(g, vs, 'post'); -} diff --git a/lib/alg/postorder.ts b/lib/alg/postorder.ts new file mode 100644 index 00000000..a207bb92 --- /dev/null +++ b/lib/alg/postorder.ts @@ -0,0 +1,6 @@ +import type { Graph } from '..'; +import { dfs } from './dfs'; + +export function postorder(g: Graph, vs: string[]): string[] { + return dfs(g, vs, 'post'); +} diff --git a/lib/alg/preorder.js b/lib/alg/preorder.js deleted file mode 100644 index 5ead480a..00000000 --- a/lib/alg/preorder.js +++ /dev/null @@ -1,7 +0,0 @@ -const dfs = require('./dfs'); - -module.exports = preorder; - -function preorder(g, vs) { - return dfs(g, vs, 'pre'); -} diff --git a/lib/alg/preorder.ts b/lib/alg/preorder.ts new file mode 100644 index 00000000..461d7e34 --- /dev/null +++ b/lib/alg/preorder.ts @@ -0,0 +1,6 @@ +import { Graph } from '..'; +import { dfs } from './dfs'; + +export function preorder(g: Graph, vs: string[]) { + return dfs(g, vs, 'pre'); +} diff --git a/lib/alg/prim.js b/lib/alg/prim.ts similarity index 84% rename from lib/alg/prim.js rename to lib/alg/prim.ts index a4aa038c..795902bb 100644 --- a/lib/alg/prim.js +++ b/lib/alg/prim.ts @@ -1,10 +1,8 @@ -const _ = require('../lodash'); -const Graph = require('../graph'); -const PriorityQueue = require('../data/priority-queue'); +import * as _ from '../lodash'; +import Graph from '../graph'; +import PriorityQueue from '../data/priority-queue'; -module.exports = prim; - -function prim(g, weightFunc) { +export function prim(g: Graph, weightFunc) { const result = new Graph(); const parents = {}; const pq = new PriorityQueue(); diff --git a/lib/alg/tarjan.js b/lib/alg/tarjan.ts similarity index 80% rename from lib/alg/tarjan.js rename to lib/alg/tarjan.ts index 2ff2865e..7b4d1bc0 100644 --- a/lib/alg/tarjan.js +++ b/lib/alg/tarjan.ts @@ -1,12 +1,11 @@ -const _ = require('../lodash'); +import type { Graph } from '..'; +import * as _ from '../lodash'; -module.exports = tarjan; - -function tarjan(g) { +export function tarjan(g: Graph) { let index = 0; - const stack = []; + const stack: any[] = []; const visited = {}; // node id -> { onStack, lowlink, index } - const results = []; + const results: any[] = []; function dfs(v) { const entry = (visited[v] = { @@ -26,8 +25,8 @@ function tarjan(g) { }); if (entry.lowlink === entry.index) { - const cmpt = []; - var w; + const cmpt: any[] = []; + let w; do { w = stack.pop(); visited[w].onStack = false; diff --git a/lib/alg/topsort.js b/lib/alg/topsort.ts similarity index 63% rename from lib/alg/topsort.js rename to lib/alg/topsort.ts index 5b51a4f8..47763e75 100644 --- a/lib/alg/topsort.js +++ b/lib/alg/topsort.ts @@ -1,12 +1,10 @@ -const _ = require('../lodash'); +import * as _ from '../lodash'; +import type { Graph } from '..'; -module.exports = topsort; -topsort.CycleException = CycleException; - -function topsort(g) { +export function topsort(g: Graph): string[] { const visited = {}; const stack = {}; - const results = []; + const results: any[] = []; function visit(node) { if (_.has(stack, node)) { @@ -31,5 +29,4 @@ function topsort(g) { return results; } -function CycleException() {} -CycleException.prototype = new Error(); // must be an instance of Error to pass testing +export class CycleException extends Error {} diff --git a/lib/index.ts b/lib/index.ts index b725d3c1..8786747f 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,5 +1,5 @@ export * as json from './json'; -import alg from './alg'; +export * as alg from './alg'; import Graph from './graph'; -export { Graph, alg }; +export { Graph }; diff --git a/test/alg/is-acyclic.test.ts b/test/alg/is-acyclic.test.ts index 7407d5ab..fad657e5 100644 --- a/test/alg/is-acyclic.test.ts +++ b/test/alg/is-acyclic.test.ts @@ -23,7 +23,7 @@ describe('alg.isAcyclic', function () { it('rethrows non-CycleException errors', function () { expect(function () { - isAcyclic(undefined); + isAcyclic(undefined as any); }).toThrow(); }); }); diff --git a/test/alg/postorder.test.ts b/test/alg/postorder.test.ts index 419532a8..63300090 100644 --- a/test/alg/postorder.test.ts +++ b/test/alg/postorder.test.ts @@ -7,7 +7,7 @@ describe('alg.postorder', function () { it('returns the root for a singleton graph', function () { const g = new Graph(); g.setNode('a'); - expect(postorder(g, 'a')).toEqual(['a']); + expect(postorder(g, ['a'])).toEqual(['a']); }); it('visits each node in the graph once', function () { @@ -15,7 +15,7 @@ describe('alg.postorder', function () { g.setPath(['a', 'b', 'd', 'e']); g.setPath(['a', 'c', 'd', 'e']); - const nodes = postorder(g, 'a'); + const nodes = postorder(g, ['a']); expect(_.sortBy(nodes)).toEqual(['a', 'b', 'c', 'd', 'e']); }); @@ -25,7 +25,7 @@ describe('alg.postorder', function () { g.setPath(['a', 'c', 'd']); g.setEdge('c', 'e'); - const nodes = postorder(g, 'a'); + const nodes = postorder(g, ['a']); expect(_.sortBy(nodes)).toEqual(['a', 'b', 'c', 'd', 'e']); expect(nodes.indexOf('b')).toBeLessThan(nodes.indexOf('a')); expect(nodes.indexOf('c')).toBeLessThan(nodes.indexOf('a')); @@ -63,7 +63,7 @@ describe('alg.postorder', function () { const g = new Graph(); g.setNode('a'); expect(function () { - postorder(g, 'b'); + postorder(g, ['b']); }).toThrow(); }); }); diff --git a/test/alg/preorder.test.ts b/test/alg/preorder.test.ts index 382562a2..befc791d 100644 --- a/test/alg/preorder.test.ts +++ b/test/alg/preorder.test.ts @@ -7,7 +7,7 @@ describe('alg.preorder', function () { it('returns the root for a singleton graph', function () { const g = new Graph(); g.setNode('a'); - expect(preorder(g, 'a')).toEqual(['a']); + expect(preorder(g, ['a'])).toEqual(['a']); }); it('visits each node in the graph once', function () { @@ -15,7 +15,7 @@ describe('alg.preorder', function () { g.setPath(['a', 'b', 'd', 'e']); g.setPath(['a', 'c', 'd', 'e']); - const nodes = preorder(g, 'a'); + const nodes = preorder(g, ['a']); expect(_.sortBy(nodes)).toEqual(['a', 'b', 'c', 'd', 'e']); }); @@ -25,7 +25,7 @@ describe('alg.preorder', function () { g.setPath(['a', 'c', 'd']); g.setEdge('c', 'e'); - const nodes = preorder(g, 'a'); + const nodes = preorder(g, ['a']); expect(_.sortBy(nodes)).toEqual(['a', 'b', 'c', 'd', 'e']); expect(nodes.indexOf('b')).toBeGreaterThan(nodes.indexOf('a')); expect(nodes.indexOf('c')).toBeGreaterThan(nodes.indexOf('a')); @@ -50,7 +50,7 @@ describe('alg.preorder', function () { const g = new Graph(); g.setNode('a'); expect(function () { - preorder(g, 'b'); + preorder(g, ['b']); }).toThrow(); }); }); diff --git a/test/alg/topsort.test.ts b/test/alg/topsort.test.ts index 82fd120a..58de31f7 100644 --- a/test/alg/topsort.test.ts +++ b/test/alg/topsort.test.ts @@ -31,7 +31,7 @@ describe('alg.topsort', function () { g.setPath(['b', 'c', 'a', 'b']); expect(function () { topsort(g); - }).toThrow(topsort.CycleException); + }).toThrow(alg.CycleException); }); it('throws CycleException if there is a cycle #2', function () { @@ -40,7 +40,7 @@ describe('alg.topsort', function () { g.setEdge('b', 'd'); expect(function () { topsort(g); - }).toThrow(topsort.CycleException); + }).toThrow(alg.CycleException); }); it('throws CycleException if there is a cycle #3', function () { @@ -49,6 +49,6 @@ describe('alg.topsort', function () { g.setNode('d'); expect(function () { topsort(g); - }).toThrow(topsort.CycleException); + }).toThrow(alg.CycleException); }); });