All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gr.james.simplegraph.MutableBipartiteGraph Maven / Gradle / Ivy

Go to download

Simple Graph is a graph interface for Java 6 that is designed to expose a very simple API to support working with graphs

The newest version!
package gr.james.simplegraph;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * The {@link BipartiteGraph} implementation using adjacency lists.
 */
public class MutableBipartiteGraph implements BipartiteGraph {
    private static final long serialVersionUID = 1L;

    private final MutableGraph g;
    private final Set a;
    private final Set b;

    /**
     * Constructs a new empty {@link MutableBipartiteGraph}.
     * 

* Complexity: O(1) */ public MutableBipartiteGraph() { this.g = new MutableGraph(); this.a = new HashSet(); this.b = new HashSet(); } /** * Constructs a new {@link MutableBipartiteGraph} as a copy of the given graph {@code g}. *

* Complexity: O(V+E) * * @param g the graph to copy * @throws NullPointerException if {@code g} is {@code null} */ public MutableBipartiteGraph(BipartiteGraph g) { this.g = new MutableGraph(g); this.a = new HashSet(g.setA()); this.b = new HashSet(g.setB()); assert g.equals(this); } /** * {@inheritDoc} * * @return {@inheritDoc} */ @Override public int size() { assert this.a.size() + this.b.size() == g.size(); return this.g.size(); } /** * {@inheritDoc} *

Implementation note

* The {@link Set} returned is directly backed by the graph and changes will reflect on that {@link Set}. A side * effect of this property is that the iterator, like any other, will throw * {@link java.util.ConcurrentModificationException} if elements are modified during iteration. * * @return {@inheritDoc} * @see #setB() */ @Override public Set setA() { return Collections.unmodifiableSet(a); } /** * {@inheritDoc} *

Implementation note

* The {@link Set} returned is directly backed by the graph and changes will reflect on that {@link Set}. A side * effect of this property is that the iterator, like any other, will throw * {@link java.util.ConcurrentModificationException} if elements are modified during iteration. * * @return {@inheritDoc} * @see #setA() */ @Override public Set setB() { return Collections.unmodifiableSet(a); } /** * {@inheritDoc} *

Implementation note

* The {@link Set} returned is directly backed by the graph and changes will reflect on that {@link Set}. A side * effect of this property is that the iterator, like any other, will throw * {@link java.util.ConcurrentModificationException} if elements are modified during iteration. * * @param v {@inheritDoc} * @return {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ @Override public Set adjacent(int v) { return this.g.adjacent(v); } /** * {@inheritDoc} *

Implementation note

* The {@link Iterable} returned is directly backed by the graph and changes will reflect on that {@link Iterable}. * A side effect of this property is that the iterator, like any other, will throw * {@link java.util.ConcurrentModificationException} if elements are modified during iteration. * * @return {@inheritDoc} */ @Override public final Iterable edges() { return this.g.edges(); } /** * Adds a vertex to set {@code A}. *

* This method adds a new unconnected vertex in the graph with ID equal to {@code size} and then increases the value * of {@code size} by one. The new vertex is also pushed to set {@code A}. *

* Complexity: O(1) */ public void addVertexInA() { final int newID = g.size(); g.addVertex(); this.a.add(newID); } /** * Adds a vertex to set {@code B}. *

* This method adds a new unconnected vertex in the graph with ID equal to {@code size} and then increases the value * of {@code size} by one. The new vertex is also pushed to set {@code B}. *

* Complexity: O(1) */ public void addVertexInB() { final int newID = g.size(); g.addVertex(); this.b.add(newID); } /** * Removes a vertex along with all of its edges from the graph. *

* This method works in a way that preserves the insertion order of vertices. More specifically, initially all edges * referring to {@code v} are removed, resulting in {@code v} being unconnected. Afterwards, while {@code v} is * removed, all vertices with ID {@code > v} slide one position to the left to occupy the empty slot. Finally, the * {@code size} of the graph is reduced by one. A side effect of this process is that the vertices with ID higher * than {@code v} are mutated to an ID that is lower by one unit. *

* Complexity: O(V+E) * * @param v the vertex to remove from the graph * @throws IndexOutOfBoundsException if {@code v} is outside of {@code [O,V)} */ public void removeVertex(int v) { this.g.removeVertex(v); for (int i = v + 1; i < size(); i++) { assert a.contains(i) ^ a.contains(i); if (a.contains(i)) { a.remove(i); a.add(i - 1); } else if (b.contains(i)) { b.remove(i); b.add(i - 1); } } } /** * Adds an edge on this graph. *

* Complexity: O(1) * * @param v one end of the edge * @param w the other end of the edge * @return {@code true} if there was previously no edge connecting {@code v} with {@code w}, otherwise {@code false} * @throws IndexOutOfBoundsException if {@code v} or {@code w} are outside of {@code [O,V)} * @throws UnsupportedOperationException if {@code v} and {@code w} are both in set {@code A} or both in set {@code B} */ public boolean putEdge(int v, int w) { if (a.contains(v) && a.contains(w)) { throw new UnsupportedOperationException(); } if (b.contains(v) && b.contains(w)) { throw new UnsupportedOperationException(); } return this.g.putEdge(v, w); } /** * Remove an edge from this graph. *

* Complexity: O(1) * * @param v one end of the edge * @param w the other end of the edge * @return {@code true} if there was previously an edge connecting {@code v} with {@code w}, otherwise {@code false} * @throws IndexOutOfBoundsException if {@code v} or {@code w} are outside of {@code [O,V)} */ public boolean removeEdge(int v, int w) { return this.g.removeEdge(v, w); } /** * Construct and return a new unmodifiable {@link BipartiteGraph} as a copy of this graph. *

* The object produced by this method is completely independent of this graph. *

* This method is equivalent to *


     * return new MutableBipartiteGraph(this).asUnmodifiable();
     * 
*

* Complexity: O(V+E) * * @return a copy of this graph as a new unmodifiable {@link BipartiteGraph} */ public final BipartiteGraph toImmutable() { return new MutableBipartiteGraph(this).asUnmodifiable(); } /** * Returns an unmodifiable decorator around this graph. *

* Invoking any mutation methods on the resulting graph will result in {@link UnsupportedOperationException}. *

* Complexity: O(1) * * @return an unmodifiable decorator around this graph */ public final BipartiteGraph asUnmodifiable() { return new MutableBipartiteGraph() { @Override public int size() { return MutableBipartiteGraph.this.size(); } @Override public Set adjacent(int v) { return MutableBipartiteGraph.this.adjacent(v); } @Override public Set setA() { return MutableBipartiteGraph.this.setA(); } @Override public Set setB() { return MutableBipartiteGraph.this.setB(); } @Override public void addVertexInA() { throw new UnsupportedOperationException(); } @Override public void addVertexInB() { throw new UnsupportedOperationException(); } @Override public void removeVertex(int v) { throw new UnsupportedOperationException(); } @Override public boolean putEdge(int v, int w) { throw new UnsupportedOperationException(); } @Override public boolean removeEdge(int v, int w) { throw new UnsupportedOperationException(); } }; } /** * {@inheritDoc} *

Implementation note

* Because there are semantic differences among different types of graphs, some mutation methods in the resulting * graph may be ambiguous when forwarded to this graph. Instead of trying to circumvent these types of restrictions * with unusual or opinionated ways, these methods will immediately throw {@link UnsupportedOperationException}. * * @return {@inheritDoc} */ @Override public final MutableDirectedGraph asDirected() { return new MutableDirectedGraph() { @Override public int size() { return MutableBipartiteGraph.this.size(); } @Override public Set adjacentOut(int v) { return MutableBipartiteGraph.this.adjacent(v); } @Override public Set adjacentIn(int v) { return MutableBipartiteGraph.this.adjacent(v); } @Override public void addVertex() { throw new UnsupportedOperationException(); } @Override public void removeVertex(int v) { MutableBipartiteGraph.this.removeVertex(v); } @Override public boolean putEdge(int source, int target) { throw new UnsupportedOperationException(); } @Override public boolean removeEdge(int source, int target) { throw new UnsupportedOperationException(); } }; } /** * {@inheritDoc} *

Implementation note

* Because there are semantic differences among different types of graphs, some mutation methods in the resulting * graph may be ambiguous when forwarded to this graph. Instead of trying to circumvent these types of restrictions * with unusual or opinionated ways, these methods will immediately throw {@link UnsupportedOperationException}. * * @return {@inheritDoc} */ @Override public final MutableWeightedGraph asWeighted() { return new MutableWeightedGraph() { @Override public int size() { return MutableBipartiteGraph.this.size(); } @Override public Set getEdges(int v) { return MutableBipartiteGraph.this.adjacent(v); } @Override public double getEdgeWeight(int v, int w) { Graphs.requireEdgeExists(MutableBipartiteGraph.this, v, w); return 1.0; } @Override public void addVertex() { throw new UnsupportedOperationException(); } @Override public void removeVertex(int v) { MutableBipartiteGraph.this.removeVertex(v); } @Override public Double putEdge(int v, int w, double weight) { throw new UnsupportedOperationException(); } @Override public Double removeEdge(int v, int w) { return MutableBipartiteGraph.this.removeEdge(v, w) ? 1.0 : null; } }; } /** * {@inheritDoc} *

Implementation note

* Because there are semantic differences among different types of graphs, some mutation methods in the resulting * graph may be ambiguous when forwarded to this graph. Instead of trying to circumvent these types of restrictions * with unusual or opinionated ways, these methods will immediately throw {@link UnsupportedOperationException}. * * @return {@inheritDoc} */ @Override public final MutableWeightedDirectedGraph asWeightedDirected() { return new MutableWeightedDirectedGraph() { @Override public int size() { return MutableBipartiteGraph.this.size(); } @Override public Set getOutEdges(int v) { return MutableBipartiteGraph.this.adjacent(v); } @Override public Set getInEdges(int v) { return MutableBipartiteGraph.this.adjacent(v); } @Override public double getEdgeWeight(int source, int target) { Graphs.requireEdgeExists(MutableBipartiteGraph.this, source, target); return 1.0; } @Override public void addVertex() { throw new UnsupportedOperationException(); } @Override public void removeVertex(int v) { MutableBipartiteGraph.this.removeVertex(v); } @Override public Double putEdge(int source, int target, double weight) { throw new UnsupportedOperationException(); } @Override public Double removeEdge(int source, int target) { throw new UnsupportedOperationException(); } }; } /** * {@inheritDoc} * * @return {@inheritDoc} */ @Override public final String toString() { final StringBuilder sb = new StringBuilder(); sb.append(String.format("%s(%d,%d+%d) {%n", "BipartiteGraph", this.size(), this.setA().size(), this.setB().size())); for (Edge e : edges()) { if (setA().contains(e.v())) { sb.append(String.format(" %s%n", e)); } else { sb.append(String.format(" %s%n", e.swap())); } } sb.append("}"); return sb.toString(); } /** * {@inheritDoc} * * @param obj {@inheritDoc} * @return {@inheritDoc} */ @Override public final boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || !(obj instanceof Graph)) { return false; } final Graph that = (Graph) obj; return Graphs.equals(this, that); } /** * {@inheritDoc} * * @return {@inheritDoc} */ @Override public final int hashCode() { return this.g.hashCode(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy