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

com.salesforce.jgrapht.alg.flow.PadbergRaoOddMinimumCutset Maven / Gradle / Ivy

Go to download

This project contains the apt processor that implements all the checks enumerated in @Verify. It is a self contained, and shaded jar.

There is a newer version: 2.0.7
Show newest version
/*
 * (C) Copyright 2016-2017, by Joris Kinable and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * This program and the accompanying materials are dual-licensed under
 * either
 *
 * (a) the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation, or (at your option) any
 * later version.
 *
 * or (per the licensee's choosing)
 *
 * (b) the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation.
 */
package com.salesforce.jgrapht.alg.flow;

import java.util.*;
import java.util.function.*;
import java.util.stream.*;

import com.salesforce.jgrapht.*;
import com.salesforce.jgrapht.alg.*;
import com.salesforce.jgrapht.alg.interfaces.*;
import com.salesforce.jgrapht.graph.*;

/**
 * Implementation of the algorithm by Padberg and Rao to compute Odd Minimum Cut-Sets. Let G=(V,E)
 * be an undirected, simple weighted graph, where all edge weights are positive. Let T ⊂ V with
 * |T| even, be a set of vertices that are labelled odd. A cut-set (U:V-U) is called odd if
 * |T ∩ U| is an odd number. Let c(U:V-U) be the weight of the cut, that is, the sum of weights
 * of the edges which have exactly one endpoint in U and one endpoint in V-U. The problem of finding
 * an odd minimum cut-set in G is stated as follows: Find W ⊆ V such that
 * c(W:V-W)=min{c(U:V-U)|U⊆ V, |T ∩ U| is odd}.
 *
 * 

* The algorithm has been published in: Padberg, M. Rao, M. Odd Minimum Cut-Sets and b-Matchings. * Mathematics of Operations Research, 7(1), p67-80, 1982. A more concise description is published * in: Letchford, A. Reinelt, G. Theis, D. Odd minimum cut-sets and b-matchings revisited. SIAM * Journal of Discrete Mathematics, 22(4), p1480-1487, 2008. * *

* The runtime complexity of this algorithm is dominated by the runtime complexity of the algorithm * used to compute A Gomory-Hu tree on graph G. Consequently, the runtime complexity of this class * is O(V^4). * *

* This class does not support changes to the underlying graph. The behavior of this class is * undefined when the graph is modified after instantiating this class. * * @param the graph vertex type * @param the graph edge type * * @author Joris Kinable */ public class PadbergRaoOddMinimumCutset { /* Input graph */ private final Graph network; /* Set of vertices which are labeled 'odd' (set T in the paper) */ private Set oddVertices; /* Algorithm used to calculate the Gomory-Hu Cut-tree */ private final GusfieldGomoryHuCutTree gusfieldGomoryHuCutTreeAlgorithm; /* The Gomory-Hu tree */ private SimpleWeightedGraph gomoryHuTree; /* Weight of the minimum odd cut-set */ private double minimumCutWeight = Double.MAX_VALUE; /* Source partition constituting the minimum odd cut-set */ private Set sourcePartitionMinimumCut; /** * Creates a new instance of the PadbergRaoOddMinimumCutset algorithm. * * @param network input graph */ public PadbergRaoOddMinimumCutset(Graph network) { this(network, MaximumFlowAlgorithmBase.DEFAULT_EPSILON); } /** * Creates a new instance of the PadbergRaoOddMinimumCutset algorithm. * * @param network input graph * @param epsilon tolerance */ public PadbergRaoOddMinimumCutset(Graph network, double epsilon) { this(network, new PushRelabelMFImpl<>(network, epsilon)); } /** * Creates a new instance of the PadbergRaoOddMinimumCutset algorithm. * * @param network input graph * @param minimumSTCutAlgorithm algorithm used to calculate the Gomory-Hu tree */ public PadbergRaoOddMinimumCutset( Graph network, MinimumSTCutAlgorithm minimumSTCutAlgorithm) { if (!(network instanceof UndirectedGraph)) throw new IllegalArgumentException("Graph must be undirected"); this.network = network; gusfieldGomoryHuCutTreeAlgorithm = new GusfieldGomoryHuCutTree<>(network, minimumSTCutAlgorithm); } /** * Calculates the minimum odd cut. The implementation follows Algorithm 1 in the paper Odd * minimum cut sets and b-matchings revisited by Adam Letchford, Gerhard Reinelt and Dirk Theis. * The original algorithm runs on a compressed Gomory-Hu tree: a cut-tree with the odd vertices * as terminal vertices. This tree has |T|-1 edges as opposed to |V|-1 for a Gomory-Hu tree * defined on the input graph G. This compression step can however be skipped. If you want to * run the original algorithm in the paper, set the parameter useTreeCompression to * true. Alternatively, experiment which setting of this parameter produces the fastest results. * Both settings are guaranteed to find the optimal cut. Experiments on random graphs showed * that setting useTreeCompression to false was on average a bit faster. * * @param oddVertices Set of vertices which are labeled 'odd'. Note that the number of vertices * in this set must be even! * @param useTreeCompression parameter indicating whether tree compression should be used * (recommended: false). * @return weight of the minimum odd cut. */ public double calculateMinCut(Set oddVertices, boolean useTreeCompression) { minimumCutWeight = Double.MAX_VALUE; this.oddVertices = oddVertices; if (oddVertices.size() % 2 == 1) throw new IllegalArgumentException("There needs to be an even number of odd vertices"); assert network.vertexSet().containsAll(oddVertices); // All odd vertices must be contained // in the graph // all edge weights mucht be non-negative assert network.edgeSet().stream().filter(e -> network.getEdgeWeight(e) < 0).count() == 0; gomoryHuTree = gusfieldGomoryHuCutTreeAlgorithm.getGomoryHuTree(); if (useTreeCompression) return calculateMinCutWithTreeCompression(); else return calculateMinCutWithoutTreeCompression(); } /** * Modified implementation of the algorithm proposed in Odd Minimum Cut-sets and b-matchings by * Padberg and Rao. The optimal cut is directly computed on the Gomory-Hu tree computed for * graph G. This approach iterates efficiently over all possible cuts of the graph (there are * |V| such cuts). * * @return weight of the minimum odd cut. */ private double calculateMinCutWithoutTreeCompression() { Set edges = new LinkedHashSet<>(gomoryHuTree.edgeSet()); for (DefaultWeightedEdge edge : edges) { V source = gomoryHuTree.getEdgeSource(edge); V target = gomoryHuTree.getEdgeTarget(edge); double edgeWeight = gomoryHuTree.getEdgeWeight(edge); if (edgeWeight >= minimumCutWeight) continue; gomoryHuTree.removeEdge(edge); // Temporarily remove edge Set sourcePartition = new ConnectivityInspector<>(gomoryHuTree).connectedSetOf(source); if (PadbergRaoOddMinimumCutset.isOddVertexSet(sourcePartition, oddVertices)) { // If the // source // partition // forms // an odd // cutset, // check // whether // the // cut // isn't // better // than // the // one we // already // found. minimumCutWeight = edgeWeight; sourcePartitionMinimumCut = sourcePartition; } gomoryHuTree.addEdge(source, target, edge); // Place edge back } return minimumCutWeight; } /** * Implementation of the algorithm proposed in Odd Minimum Cut-sets and b-matchings by Padberg * and Rao. The algorithm evaluates at most |T| cuts in the Gomory-Hu tree. * * @return weight of the minimum odd cut. */ private double calculateMinCutWithTreeCompression() { Queue> queue = new LinkedList<>(); queue.add(oddVertices); // Keep splitting the clusters until each resulting cluster containes exactly one vertex. while (!queue.isEmpty()) { Set nextCluster = queue.poll(); this.splitCluster(nextCluster, queue); } return minimumCutWeight; } /** * Takes a set of odd vertices with cardinality 2 or more, and splits them into 2 new non-empty * sets. * * @param cluster group of odd vertices * @param queue clusters with cardinality 2 or more */ private void splitCluster(Set cluster, Queue> queue) { assert cluster.size() >= 2; // Choose 2 random odd nodes Iterator iterator = cluster.iterator(); V oddNode1 = iterator.next(); V oddNode2 = iterator.next(); // Calculate the minimum cut separating these two nodes. double cutWeight = gusfieldGomoryHuCutTreeAlgorithm.calculateMinCut(oddNode1, oddNode2); Set sourcePartition = null; if (cutWeight < minimumCutWeight) { sourcePartition = gusfieldGomoryHuCutTreeAlgorithm.getSourcePartition(); if (PadbergRaoOddMinimumCutset.isOddVertexSet(sourcePartition, oddVertices)) { this.minimumCutWeight = cutWeight; this.sourcePartitionMinimumCut = sourcePartition; } } if (cluster.size() == 2) return; if (sourcePartition == null) sourcePartition = gusfieldGomoryHuCutTreeAlgorithm.getSourcePartition(); Set split1 = this.intersection(cluster, sourcePartition); Set split2 = new HashSet<>(cluster); split2.removeAll(split1); if (split1.size() > 1) queue.add(split1); if (split2.size() > 1) queue.add(split2); } /** * Efficient way to compute the intersection between two sets * * @param set1 set 1 * @param set2 set 2 * @return intersection of set 1 and 2 */ private Set intersection(Set set1, Set set2) { Set a; Set b; if (set1.size() <= set2.size()) { a = set1; b = set2; } else { a = set2; b = set1; } return a.stream().filter(v -> b.contains(v)).collect(Collectors.toSet()); } /** * Convenience method which test whether the given set contains an odd number of odd-labeled * nodes. * * @param vertex type * @param vertices input set * @param oddVertices subset of vertices which are labeled odd * @return true if the given set contains an odd number of odd-labeled nodes. */ public static boolean isOddVertexSet(Set vertices, Set oddVertices) { if (vertices.size() < oddVertices.size()) return vertices.stream().filter(oddVertices::contains).count() % 2 == 1; else return oddVertices.stream().filter(vertices::contains).count() % 2 == 1; } /** * Returns partition W of the cut obtained after the last invocation of * {@link #calculateMinCut(Set, boolean)} * * @return partition W */ public Set getSourcePartition() { return sourcePartitionMinimumCut; } /** * Returns partition V-W of the cut obtained after the last invocation of * {@link #calculateMinCut(Set, boolean)} * * @return partition V-W */ public Set getSinkPartition() { Set sinkPartition = new LinkedHashSet<>(network.vertexSet()); sinkPartition.removeAll(sourcePartitionMinimumCut); return sinkPartition; } /** * Returns the set of edges which run from the source partition to the sink partition, in the * s-t cut obtained after the last invocation of {@link #calculateMinCut(Set, boolean)} * * @return set of edges which have one endpoint in the source partition and one endpoint in the * sink partition. */ public Set getCutEdges() { Predicate predicate = e -> sourcePartitionMinimumCut.contains(network.getEdgeSource(e)) ^ sourcePartitionMinimumCut.contains(network.getEdgeTarget(e)); return network.edgeSet().stream().filter(predicate).collect( Collectors.toCollection(LinkedHashSet::new)); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy