graph-builder
Version:
A graph builder library for modeling abstract graph structures.
137 lines • 5.73 kB
JavaScript
"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