Skip to content

Commit

Permalink
Modernised utils to classes (#716)
Browse files Browse the repository at this point in the history
* Modernised utils to classes

* Export directed edges
  • Loading branch information
Hugo-ter-Doest authored Dec 5, 2023
1 parent f5b56da commit a728884
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 195 deletions.
49 changes: 49 additions & 0 deletions lib/natural/util/directed_edge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
Copyright (c) 2014, Lee Wenzhu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

const util = require('util')

class DirectedEdge {
constructor (start, end, weight) {
this.start = start
this.end = end
this.weight = weight
}

weight () {
return this.weight
}

from () {
return this.start
}

to () {
return this.end
}

toString () {
return util.format('%s -> %s, %s', this.start, this.end, this.weight)
}
}

module.exports = DirectedEdge
128 changes: 54 additions & 74 deletions lib/natural/util/edge_weighted_digraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,92 +22,72 @@ THE SOFTWARE.

'use strict'

const util = require('util')
const Bag = require('./bag')
const DirectedEdge = require('./directed_edge')

const DirectedEdge = function (start, end, weight) {
this.start = start
this.end = end
this.weight = weight
}

DirectedEdge.prototype.weight = function () {
return this.weight
}

DirectedEdge.prototype.from = function () {
return this.start
}

DirectedEdge.prototype.to = function () {
return this.end
}

DirectedEdge.prototype.toString = function () {
return util.format('%s -> %s, %s', this.start, this.end, this.weight)
}
class EdgeWeightedDigraph {
constructor () {
this.edgesNum = 0
this.adj = [] // adjacency list
}

const EdgeWeightedDigraph = function () {
this.edgesNum = 0
this.adj = [] // adjacency list
}
/**
* the number of vertexs saved.
*/
v () {
return this.adj.length
}

/**
* the number of vertexs saved.
*/
EdgeWeightedDigraph.prototype.v = function () {
return this.adj.length
}
/**
* the number of edges saved.
*/
e () {
return this.edgesNum
}

/**
* the number of edges saved.
*/
EdgeWeightedDigraph.prototype.e = function () {
return this.edgesNum
}
add (start, end, weight) {
const e = new DirectedEdge(start, end, weight)
this.addEdge(e)
}

EdgeWeightedDigraph.prototype.add = function (start, end, weight) {
const e = new DirectedEdge(start, end, weight)
this.addEdge(e)
}
addEdge (e) {
if (!this.adj[e.from()]) {
this.adj[e.from()] = new Bag()
}
this.adj[e.from()].add(e)
this.edgesNum++
}

EdgeWeightedDigraph.prototype.addEdge = function (e) {
if (!this.adj[e.from()]) {
this.adj[e.from()] = new Bag()
/**
* use callback on all edges from v.
*/
getAdj (v) {
if (!this.adj[v]) return []
return this.adj[v].unpack()
}
this.adj[e.from()].add(e)
this.edgesNum++
}

/**
* use callback on all edges from v.
*/
EdgeWeightedDigraph.prototype.getAdj = function (v) {
if (!this.adj[v]) return []
return this.adj[v].unpack()
}
/**
* use callback on all edges.
*/
edges () {
const adj = this.adj
const list = new Bag()
for (const i in adj) {
adj[i].unpack().forEach(function (item) {
list.add(item)
})
}
return list.unpack()
}

/**
* use callback on all edges.
*/
EdgeWeightedDigraph.prototype.edges = function () {
const adj = this.adj
const list = new Bag()
for (const i in adj) {
adj[i].unpack().forEach(function (item) {
list.add(item)
toString () {
const result = []
const list = this.edges()
list.forEach(function (edge) {
result.push(edge.toString())
})
return result.join('\n')
}
return list.unpack()
}

EdgeWeightedDigraph.prototype.toString = function () {
const result = []
const list = this.edges()
list.forEach(function (edge) {
result.push(edge.toString())
})
return result.join('\n')
}

module.exports = EdgeWeightedDigraph
1 change: 1 addition & 0 deletions lib/natural/util/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ THE SOFTWARE.
exports.stopwords = require('./stopwords').words
exports.ShortestPathTree = require('./shortest_path_tree')
exports.LongestPathTree = require('./longest_path_tree')
exports.DirectedEdge = require('./directed_edge')
exports.EdgeWeightedDigraph = require('./edge_weighted_digraph')
106 changes: 54 additions & 52 deletions lib/natural/util/longest_path_tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,66 +34,68 @@ const Topological = require('./topological')
* constant time and the pathTo() method takes time proportional to the
* number of edges in the longest path returned.
*/
const LongestPathTree = function (digraph, start) {
const _this = this
this.edgeTo = []
this.distTo = []
this.distTo[start] = 0.0
this.start = start
this.top = new Topological(digraph)
this.top.order().forEach(function (vertex) {
_this.relaxVertex(digraph, vertex, _this)
})
}
class LongestPathTree {
constructor (digraph, start) {
const _this = this
this.edgeTo = []
this.distTo = []
this.distTo[start] = 0.0
this.start = start
this.top = new Topological(digraph)
this.top.order().forEach(function (vertex) {
_this.relaxVertex(digraph, vertex, _this)
})
}

LongestPathTree.prototype.relaxEdge = function (e) {
const distTo = this.distTo
const edgeTo = this.edgeTo
const v = e.from(); const w = e.to()
if (distTo[w] < distTo[v] + e.weight) {
distTo[w] = distTo[v] + e.weight
edgeTo[w] = e
relaxEdge (e) {
const distTo = this.distTo
const edgeTo = this.edgeTo
const v = e.from(); const w = e.to()
if (distTo[w] < distTo[v] + e.weight) {
distTo[w] = distTo[v] + e.weight
edgeTo[w] = e
}
}
}

/**
* relax a vertex v in the specified digraph g
* @param {EdgeWeightedDigraph} the apecified digraph
* @param {Vertex} v vertex to be relaxed
*/
LongestPathTree.prototype.relaxVertex = function (digraph, vertex, tree) {
const distTo = tree.distTo
const edgeTo = tree.edgeTo
/**
* relax a vertex v in the specified digraph g
* @param {EdgeWeightedDigraph} the apecified digraph
* @param {Vertex} v vertex to be relaxed
*/
relaxVertex (digraph, vertex, tree) {
const distTo = tree.distTo
const edgeTo = tree.edgeTo

digraph.getAdj(vertex).forEach(function (edge) {
const w = edge.to()
distTo[w] = distTo[w] || 0.0
distTo[vertex] = distTo[vertex] || 0.0
if (distTo[w] < distTo[vertex] + edge.weight) {
// in case of the result of 0.28+0.34 is 0.62000001
distTo[w] = parseFloat((distTo[vertex] + edge.weight).toFixed(2))
edgeTo[w] = edge
}
})
}
digraph.getAdj(vertex).forEach(function (edge) {
const w = edge.to()
distTo[w] = distTo[w] || 0.0
distTo[vertex] = distTo[vertex] || 0.0
if (distTo[w] < distTo[vertex] + edge.weight) {
// in case of the result of 0.28+0.34 is 0.62000001
distTo[w] = parseFloat((distTo[vertex] + edge.weight).toFixed(2))
edgeTo[w] = edge
}
})
}

LongestPathTree.prototype.getDistTo = function (v) {
return this.distTo[v]
}
getDistTo (v) {
return this.distTo[v]
}

LongestPathTree.prototype.hasPathTo = function (v) {
return !!this.distTo[v]
}
hasPathTo (v) {
return !!this.distTo[v]
}

LongestPathTree.prototype.pathTo = function (v) {
if (!this.hasPathTo(v)) return []
const path = []
const edgeTo = this.edgeTo
for (let e = edgeTo[v]; e; e = edgeTo[e.from()]) {
path.push(e.to())
pathTo (v) {
if (!this.hasPathTo(v)) return []
const path = []
const edgeTo = this.edgeTo
for (let e = edgeTo[v]; e; e = edgeTo[e.from()]) {
path.push(e.to())
}
path.push(this.start)
return path.reverse()
}
path.push(this.start)
return path.reverse()
}

module.exports = LongestPathTree
Loading

0 comments on commit a728884

Please sign in to comment.