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

org.jgrapht.generate.netgen.MaximumFlowProblem Maven / Gradle / Ivy

/*
 * (C) Copyright 2020-2021, by Timofey Chudakov and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * See the CONTRIBUTORS.md file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0, or the
 * GNU Lesser General Public License v2.1 or later
 * which is available at
 * http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
 */
package org.jgrapht.generate.netgen;

import org.jgrapht.Graph;

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

/**
 * This class represents a maximum flow problem. Use this class for both directed and undirected
 * maximum flow problems.
 * 

* The single-source, single-sink maximum flow problem is defined as follows: \[ \begin{align} * \mbox{maximize}~& \sum_{e \in \delta^+(s)}f_e - \sum_{e \in \delta^-(s)}f_e &\\ * \mbox{s.t. }&\sum_{e\in \delta^-(v)} f_e = \sum_{e\in \delta^+(v)} f_e & \forall v\in * V\setminus \{s, t\} \\ &0 \leq f_e \leq c_e & \forall e\in E \end{align} \] Here * $\delta^+(v)$ and $\delta^-(v)$ denote the outgoing and incoming edges of vertex $v$ * respectively. The value $f_e$ denotes the flow on edge $e$, which is bounded by $c_e$ - the * capacity of the edge $e$. The vertex $s$ is a network source, the vertex $t$ - network sink. The * edge capacities can be retrieved using {@link MaximumFlowProblem#getCapacities()}. The problem * formulation above defines a canonical maximum flow problem, i.e. with only one source and one * sink. *

* A maximum flow problem can be defined on a network with multiple sources and sinks. This problem * can be reduced to the above problem definition as follows: *

    *
  • Two special vertices are added to the graph: a super source and a super sink;
  • *
  • Edges with infinite capacity are added from the super source to every source and from every * sink to the super sink
  • *
* To use this reduction, see {@link MaximumFlowProblem#toSingleSourceSingleSinkProblem()}. * * @param the graph vertex type * @param the graph edge type * @author Timofey Chudakov * @see org.jgrapht.alg.interfaces.MaximumFlowAlgorithm */ public interface MaximumFlowProblem { double CAPACITY_INF = Integer.MAX_VALUE; /** * Returns the network the problem is defined on. * * @return the network the problem is defined on. */ Graph getGraph(); /** * Returns the source set of this problem. * * @return the source set of this problem. */ Set getSources(); /** * Returns the sink set of this problem. * * @return the sink set of this problem. */ Set getSinks(); /** * Returns one source of this problem (a problem is guaranteed to have at least one source). Use * this method if the problem is in canonical form (only one source and one sink). * * @return one source of this problem. */ default V getSource() { return getSources().iterator().next(); } /** * Returns one sink of this problem (a problem is guaranteed to have at least one sink). Use * this method if the problem is in canonical form (only one source and one sink). * * @return one sink of this problem. */ default V getSink() { return getSinks().iterator().next(); } /** * Returns the capacity function of this problem. This function is defined for all edges of the * underlying network. * * @return the capacity function of this problem. */ Function getCapacities(); /** * Converts this problem to the canonical form. Resulting problem is equivalent to the previous * one. * * @return a problem in the canonical form. */ MaximumFlowProblem toSingleSourceSingleSinkProblem(); /** * Checks if this problem is in the canonical form. * * @return {@code true} if this problem is in the canonical form, {@code false} otherwise. */ default boolean isSingleSourceSingleSinkProblem() { return getSources().size() == 1 && getSinks().size() == 1; } /** * Dumps the network edge capacities to the underlying graph. */ default void dumpCapacities() { Graph graph = getGraph(); Function capacities = getCapacities(); for (E edge : graph.edgeSet()) { graph.setEdgeWeight(edge, capacities.apply(edge)); } } /** * Default implementation of a Maximum Flow Problem. * * @param the graph vertex type * @param the graph edge type */ class MaximumFlowProblemImpl implements MaximumFlowProblem { private final Graph graph; private final Set sources; private final Set sinks; private final Function capacities; /** * Constructs a new maximum flow problem. * * @param graph flow network * @param sources set of network sources * @param sinks set of network sinks * @param capacities network capacity function */ public MaximumFlowProblemImpl( Graph graph, Set sources, Set sinks, Function capacities) { this.graph = graph; this.sources = sources; this.sinks = sinks; this.capacities = capacities; } /** * {@inheritDoc} */ @Override public Graph getGraph() { return graph; } /** * {@inheritDoc} */ @Override public Set getSources() { return sources; } /** * {@inheritDoc} */ @Override public Set getSinks() { return sinks; } /** * {@inheritDoc} */ @Override public Function getCapacities() { return capacities; } /** * {@inheritDoc} */ @Override public MaximumFlowProblem toSingleSourceSingleSinkProblem() { Set newEdges = new HashSet<>(); Set sourceSet = convert(sources, newEdges, true); Set sinkSet = convert(sinks, newEdges, false); Function updatedCapacities = e -> { if (newEdges.contains(e)) { return CAPACITY_INF; } else { return capacities.apply(e); } }; return new MaximumFlowProblemImpl<>(graph, sourceSet, sinkSet, updatedCapacities); } /** * Adds a new super vertex and connects it to all vertices in {@code vertices}. Depending on * the value of {@code sources}, the edges are directed from super vertex or to super * vertex. New edges are added to {@code newEdges}. * * @param vertices set of vertices to connect super vertex to * @param newEdges container to add new edges to * @param sources {@code true} if super vertex is super source, {@code false} if it's super * sink * @return 1 element set containing the super vertex */ private Set convert(Set vertices, Set newEdges, boolean sources) { if (vertices.size() == 1) { return vertices; } V superVertex = graph.addVertex(); Set newSourceSet = Collections.singleton(superVertex); for (V vertex : vertices) { E edge; if (sources) { edge = graph.addEdge(superVertex, vertex); } else { edge = graph.addEdge(vertex, superVertex); } newEdges.add(edge); } return newSourceSet; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy