UNPKG

graph-builder

Version:

A graph builder library for modeling abstract graph structures.

137 lines 5.73 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const ConfigurableValueGraph_1 = require("./ConfigurableValueGraph"); const GraphConstants_1 = require("./GraphConstants"); const UndirectedGraphConnections_1 = require("./UndirectedGraphConnections"); const DirectedGraphConnections_1 = require("./DirectedGraphConnections"); /* * Copyright (C) 2016 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Modifications (C) 2019 Ben Sorohan */ /** * Configurable implementation of {@link MutableValueGraph} that supports both directed and * undirected graphs. Instances of this class should be constructed with {@link ValueGraphBuilder}. * * <p>Time complexities for mutation methods are all O(1) except for `removeNode(N node)`, * which is in O(d_node) where d_node is the degree of `node`. */ class ConfigurableMutableValueGraph extends ConfigurableValueGraph_1.ConfigurableValueGraph { /** Constructs a graph with the properties specified in `builder`. */ static from(builder) { return new ConfigurableMutableValueGraph(builder, builder.nodeOrderValue.createMap(builder.expectedNodeCountValue || GraphConstants_1.GraphConstants.DEFAULT_NODE_COUNT), 0); } addNode(node) { if (this.containsNode(node)) { return false; } this.addNodeInternal(node); return true; } /** * Adds `node` to the graph and returns the associated {@link GraphConnections}. * * throws IllegalStateException if `node` is already present */ addNodeInternal(node) { const connections = this.newConnections(); this.nodeConnections.set(node, connections); return connections; } putEdgeValue(nodeU, nodeV, value) { if (!this.allowsSelfLoops() && nodeU === nodeV) { throw new Error(GraphConstants_1.GraphConstants.SELF_LOOPS_NOT_ALLOWED); } let connectionsU = this.nodeConnections.get(nodeU); if (connectionsU === undefined) { connectionsU = this.addNodeInternal(nodeU); } const previousValue = connectionsU.addSuccessor(nodeV, value); let connectionsV = this.nodeConnections.get(nodeV); if (connectionsV === undefined) { connectionsV = this.addNodeInternal(nodeV); } connectionsV.addPredecessor(nodeU, value); if (previousValue === undefined) { ++this.edgeCountValue; } return previousValue; } putEdgeValueConnectingEndpoints(endpoints, value) { this.validateEndpoints(endpoints); return this.putEdgeValue(endpoints.nodeU, endpoints.nodeV, value); } removeNode(node) { const connections = this.nodeConnections.get(node); if (connections === undefined) { return false; } if (this.allowsSelfLoops()) { // Remove self-loop (if any) first, so we don't get CME while removing incident edges. if (connections.removeSuccessor(node) !== undefined) { connections.removePredecessor(node); --this.edgeCountValue; } } for (const successor of connections.successors()) { const successorConnections = this.nodeConnections.get(successor); if (successorConnections) { successorConnections.removePredecessor(node); --this.edgeCountValue; } } if (this.isDirected()) { // In undirected graphs, the successor and predecessor sets are equal. for (const predecessor of connections.predecessors()) { const predecessorConnections = this.nodeConnections.get(predecessor); if (predecessorConnections) { predecessorConnections.removeSuccessor(node); --this.edgeCountValue; } } } this.nodeConnections.delete(node); if (this.edgeCountValue < 0) { throw new Error('Edge count gone negative'); } return true; } removeEdge(nodeU, nodeV) { const connectionsU = this.nodeConnections.get(nodeU); const connectionsV = this.nodeConnections.get(nodeV); if (connectionsU === undefined || connectionsV === undefined) { return undefined; } const previousValue = connectionsU.removeSuccessor(nodeV); if (previousValue !== undefined) { connectionsV.removePredecessor(nodeU); --this.edgeCountValue; if (this.edgeCountValue < 0) { throw new Error('Edge count gone negative'); } } return previousValue; } removeEdgeConnectingEndpoints(endpoints) { this.validateEndpoints(endpoints); return this.removeEdge(endpoints.nodeU, endpoints.nodeV); } newConnections() { return this.isDirected() ? DirectedGraphConnections_1.DirectedGraphConnections.of() : UndirectedGraphConnections_1.UndirectedGraphConnections.of(); } } exports.ConfigurableMutableValueGraph = ConfigurableMutableValueGraph; //# sourceMappingURL=ConfigurableMutableValueGraph.js.map