1 | const isequal = require('lodash.isequal')
|
2 | const isInteger = require('is-integer')
|
3 | const uniqueid = require('lodash.uniqueid')
|
4 | const uniqby = require('lodash.uniqby')
|
5 | const staticProps = require('static-props')
|
6 |
|
7 | const getDegree = require('./getDegree')
|
8 | const getIncidentEdgeIds = require('./getIncidentEdgeIds')
|
9 | const getRank = require('./getRank')
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 | class Graph {
|
30 | constructor () {
|
31 | const arg = arguments[0] || {}
|
32 | var obj = {}
|
33 |
|
34 | if (isInteger(arg.uniform)) {
|
35 | if (arg.uniform < 2) {
|
36 | throw new TypeError('Argument uniform cannot be less than 2')
|
37 | } else {
|
38 | obj.uniform = arg.uniform
|
39 | }
|
40 | }
|
41 |
|
42 | if (arg.multigraph === true) obj.multigraph = true
|
43 |
|
44 | if (arg.pseudograph === true) {
|
45 | obj.multigraph = true
|
46 | obj.pseudograph = true
|
47 | }
|
48 |
|
49 | obj.edges = arg.edges || {}
|
50 | obj.nodes = arg.nodes || {}
|
51 |
|
52 | const enumerable = true
|
53 | staticProps(this)(obj, enumerable)
|
54 | }
|
55 |
|
56 | |
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 | addEdge (nodeIds) {
|
64 | if (nodeIds.length < 2) {
|
65 | throw new Error('An edge must point at two or more nodes')
|
66 | }
|
67 |
|
68 | const uniform = this.uniform
|
69 |
|
70 | if (uniform) {
|
71 | const cardinality = nodeIds.length
|
72 |
|
73 | if (uniform !== cardinality) {
|
74 | throw new Error(`Cannot add an edge with cardinality ${cardinality} to a ${uniform}-uniform graph`)
|
75 | }
|
76 | }
|
77 |
|
78 | if (!this.pseudograph) {
|
79 | if (uniqby(nodeIds).length < nodeIds.length) {
|
80 | throw new Error('This is not a pseudograph, it is not allowed to create loops')
|
81 | }
|
82 | }
|
83 |
|
84 | if (!this.multigraph) {
|
85 | for (let edgeId in this.edges) {
|
86 | let edge = this.edges[edgeId]
|
87 |
|
88 | if (isequal(nodeIds, edge)) {
|
89 | throw new Error('This is not a multigraph, you cannot add duplicated edges')
|
90 | }
|
91 | }
|
92 | }
|
93 |
|
94 | const nodeIdsNotFound = nodeIds.filter((id) => {
|
95 | return !this.nodes.hasOwnProperty(id)
|
96 | })
|
97 |
|
98 | if (nodeIdsNotFound.length > 0) {
|
99 | throw new Error('Edge points to some nodeId not found in this graph; ' + nodeIdsNotFound.join(','))
|
100 | }
|
101 |
|
102 | const id = uniqueid()
|
103 |
|
104 | this.edges[id] = nodeIds
|
105 |
|
106 | return id
|
107 | }
|
108 |
|
109 | |
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 | addNode (data) {
|
117 | const id = uniqueid()
|
118 |
|
119 | this.nodes[id] = data
|
120 |
|
121 | return id
|
122 | }
|
123 |
|
124 | |
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 | degreeOf (nodeId) {
|
132 | return getDegree(this.edges, nodeId)
|
133 | }
|
134 |
|
135 | |
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 | delEdge (id) {
|
143 | delete this.edges[id]
|
144 | }
|
145 |
|
146 | |
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 | delNode (id) {
|
154 | delete this.nodes[id]
|
155 |
|
156 | const incidentEdgeIds = getIncidentEdgeIds(this.edges, id)
|
157 |
|
158 |
|
159 |
|
160 |
|
161 | for (var edgeId in incidentEdgeIds) {
|
162 | this.delEdge(edgeId)
|
163 | }
|
164 | }
|
165 |
|
166 | |
167 |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 | getRank () {
|
173 | if (this.uniform) return this.uniform
|
174 |
|
175 | return getRank(this.edges)
|
176 | }
|
177 | }
|
178 |
|
179 | module.exports = Graph
|