001/*
002 * Copyright (C) 2016 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.graph;
018
019import static com.google.common.base.Preconditions.checkNotNull;
020import static com.google.common.graph.Graphs.checkNonNegative;
021
022import com.google.common.annotations.Beta;
023import com.google.common.base.Optional;
024
025/**
026 * A builder for constructing instances of {@link MutableNetwork} or {@link ImmutableNetwork} with
027 * user-defined properties.
028 *
029 * <p>A network built by this class will have the following properties by default:
030 *
031 * <ul>
032 *   <li>does not allow parallel edges
033 *   <li>does not allow self-loops
034 *   <li>orders {@link Network#nodes()} and {@link Network#edges()} in the order in which the
035 *       elements were added
036 * </ul>
037 *
038 * <p>Examples of use:
039 *
040 * <pre>{@code
041 * // Building a mutable network
042 * MutableNetwork<String, Integer> network =
043 *     NetworkBuilder.directed().allowsParallelEdges(true).build();
044 * flightNetwork.addEdge("LAX", "ATL", 3025);
045 * flightNetwork.addEdge("LAX", "ATL", 1598);
046 * flightNetwork.addEdge("ATL", "LAX", 2450);
047 *
048 * // Building a immutable network
049 * ImmutableNetwork<String, Integer> immutableNetwork =
050 *     NetworkBuilder.directed()
051 *         .allowsParallelEdges(true)
052 *         .<String, Integer>immutable()
053 *         .addEdge("LAX", "ATL", 3025)
054 *         .addEdge("LAX", "ATL", 1598)
055 *         .addEdge("ATL", "LAX", 2450)
056 *         .build();
057 * }</pre>
058 *
059 * @author James Sexton
060 * @author Joshua O'Madadhain
061 * @param <N> The most general node type this builder will support. This is normally {@code Object}
062 *     unless it is constrained by using a method like {@link #nodeOrder}, or the builder is
063 *     constructed based on an existing {@code Network} using {@link #from(Network)}.
064 * @param <E> The most general edge type this builder will support. This is normally {@code Object}
065 *     unless it is constrained by using a method like {@link #edgeOrder}, or the builder is
066 *     constructed based on an existing {@code Network} using {@link #from(Network)}.
067 * @since 20.0
068 */
069@Beta
070@ElementTypesAreNonnullByDefault
071public final class NetworkBuilder<N, E> extends AbstractGraphBuilder<N> {
072  boolean allowsParallelEdges = false;
073  ElementOrder<? super E> edgeOrder = ElementOrder.insertion();
074  Optional<Integer> expectedEdgeCount = Optional.absent();
075
076  /** Creates a new instance with the specified edge directionality. */
077  private NetworkBuilder(boolean directed) {
078    super(directed);
079  }
080
081  /** Returns a {@link NetworkBuilder} for building directed networks. */
082  public static NetworkBuilder<Object, Object> directed() {
083    return new NetworkBuilder<>(true);
084  }
085
086  /** Returns a {@link NetworkBuilder} for building undirected networks. */
087  public static NetworkBuilder<Object, Object> undirected() {
088    return new NetworkBuilder<>(false);
089  }
090
091  /**
092   * Returns a {@link NetworkBuilder} initialized with all properties queryable from {@code
093   * network}.
094   *
095   * <p>The "queryable" properties are those that are exposed through the {@link Network} interface,
096   * such as {@link Network#isDirected()}. Other properties, such as {@link
097   * #expectedNodeCount(int)}, are not set in the new builder.
098   */
099  public static <N, E> NetworkBuilder<N, E> from(Network<N, E> network) {
100    return new NetworkBuilder<N, E>(network.isDirected())
101        .allowsParallelEdges(network.allowsParallelEdges())
102        .allowsSelfLoops(network.allowsSelfLoops())
103        .nodeOrder(network.nodeOrder())
104        .edgeOrder(network.edgeOrder());
105  }
106
107  /**
108   * Returns an {@link ImmutableNetwork.Builder} with the properties of this {@link NetworkBuilder}.
109   *
110   * <p>The returned builder can be used for populating an {@link ImmutableNetwork}.
111   *
112   * @since 28.0
113   */
114  public <N1 extends N, E1 extends E> ImmutableNetwork.Builder<N1, E1> immutable() {
115    NetworkBuilder<N1, E1> castBuilder = cast();
116    return new ImmutableNetwork.Builder<>(castBuilder);
117  }
118
119  /**
120   * Specifies whether the network will allow parallel edges. Attempting to add a parallel edge to a
121   * network that does not allow them will throw an {@link UnsupportedOperationException}.
122   *
123   * <p>The default value is {@code false}.
124   */
125  public NetworkBuilder<N, E> allowsParallelEdges(boolean allowsParallelEdges) {
126    this.allowsParallelEdges = allowsParallelEdges;
127    return this;
128  }
129
130  /**
131   * Specifies whether the network will allow self-loops (edges that connect a node to itself).
132   * Attempting to add a self-loop to a network that does not allow them will throw an {@link
133   * UnsupportedOperationException}.
134   *
135   * <p>The default value is {@code false}.
136   */
137  public NetworkBuilder<N, E> allowsSelfLoops(boolean allowsSelfLoops) {
138    this.allowsSelfLoops = allowsSelfLoops;
139    return this;
140  }
141
142  /**
143   * Specifies the expected number of nodes in the network.
144   *
145   * @throws IllegalArgumentException if {@code expectedNodeCount} is negative
146   */
147  public NetworkBuilder<N, E> expectedNodeCount(int expectedNodeCount) {
148    this.expectedNodeCount = Optional.of(checkNonNegative(expectedNodeCount));
149    return this;
150  }
151
152  /**
153   * Specifies the expected number of edges in the network.
154   *
155   * @throws IllegalArgumentException if {@code expectedEdgeCount} is negative
156   */
157  public NetworkBuilder<N, E> expectedEdgeCount(int expectedEdgeCount) {
158    this.expectedEdgeCount = Optional.of(checkNonNegative(expectedEdgeCount));
159    return this;
160  }
161
162  /**
163   * Specifies the order of iteration for the elements of {@link Network#nodes()}.
164   *
165   * <p>The default value is {@link ElementOrder#insertion() insertion order}.
166   */
167  public <N1 extends N> NetworkBuilder<N1, E> nodeOrder(ElementOrder<N1> nodeOrder) {
168    NetworkBuilder<N1, E> newBuilder = cast();
169    newBuilder.nodeOrder = checkNotNull(nodeOrder);
170    return newBuilder;
171  }
172
173  /**
174   * Specifies the order of iteration for the elements of {@link Network#edges()}.
175   *
176   * <p>The default value is {@link ElementOrder#insertion() insertion order}.
177   */
178  public <E1 extends E> NetworkBuilder<N, E1> edgeOrder(ElementOrder<E1> edgeOrder) {
179    NetworkBuilder<N, E1> newBuilder = cast();
180    newBuilder.edgeOrder = checkNotNull(edgeOrder);
181    return newBuilder;
182  }
183
184  /** Returns an empty {@link MutableNetwork} with the properties of this {@link NetworkBuilder}. */
185  public <N1 extends N, E1 extends E> MutableNetwork<N1, E1> build() {
186    return new StandardMutableNetwork<>(this);
187  }
188
189  @SuppressWarnings("unchecked")
190  private <N1 extends N, E1 extends E> NetworkBuilder<N1, E1> cast() {
191    return (NetworkBuilder<N1, E1>) this;
192  }
193}