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

com.salesforce.jgrapht.alg.vertexcover.ClarksonTwoApproxVCImpl Maven / Gradle / Ivy

/*
 * (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.vertexcover;

import java.util.*;

import com.salesforce.jgrapht.*;
import com.salesforce.jgrapht.alg.interfaces.*;
import com.salesforce.jgrapht.alg.vertexcover.util.*;

/**
 * Implementation of the 2-opt algorithm for a minimum weighted vertex cover by Clarkson, Kenneth L.
 * "A modification of the greedy algorithm for vertex cover." Information Processing Letters 16.1
 * (1983): 23-25. The solution is guaranteed to be within 2 times the optimum solution. Runtime:
 * O(|E|*log|V|)
 *
 * Note: this class supports pseudo-graphs
 *
 * @param  the graph vertex type
 * @param  the graph edge type
 *
 * @author Joris Kinable
 *
 */
public class ClarksonTwoApproxVCImpl
    implements MinimumWeightedVertexCoverAlgorithm
{

    private static int vertexCounter = 0;

    @Override
    public VertexCover getVertexCover(
        UndirectedGraph graph, Map vertexWeightMap)
    {
        // Result
        Set cover = new LinkedHashSet<>();
        double weight = 0;

        // Create working graph: for every vertex, create a RatioVertex which maintains its own list
        // of neighbors
        Map> vertexEncapsulationMap = new HashMap<>();
        graph.vertexSet().stream().filter(v -> graph.degreeOf(v) > 0).forEach(
            v -> vertexEncapsulationMap
                .put(v, new RatioVertex(vertexCounter++, v, vertexWeightMap.get(v))));

        for (E e : graph.edgeSet()) {
            V u = graph.getEdgeSource(e);
            RatioVertex ux = vertexEncapsulationMap.get(u);
            V v = graph.getEdgeTarget(e);
            RatioVertex vx = vertexEncapsulationMap.get(v);
            ux.addNeighbor(vx);
            vx.addNeighbor(ux);

            assert (ux.neighbors.get(vx).equals(
                vx.neighbors.get(
                    ux))) : " in an undirected graph, if vx is a neighbor of ux, then ux must be a neighbor of vx";
        }

        TreeSet> workingGraph = new TreeSet<>();
        workingGraph.addAll(vertexEncapsulationMap.values());
        assert (workingGraph.size() == vertexEncapsulationMap
            .size()) : "vertices in vertexEncapsulationMap: " + graph.vertexSet().size()
                + "vertices in working graph: " + workingGraph.size();

        while (!workingGraph.isEmpty()) { // Continue until all edges are covered

            // Find a vertex vx for which W(vx)/degree(vx) is minimal
            RatioVertex vx = workingGraph.pollFirst();
            assert (workingGraph.parallelStream().allMatch(
                ux -> vx.getRatio() <= ux
                    .getRatio())) : "vx does not have the smallest ratio among all elements. VX: "
                        + vx + " WorkingGraph: " + workingGraph;

            // Iterate over all the neighbors ux of vx and update ux.W
            double ratio = vx.getRatio();
            for (RatioVertex nx : vx.neighbors.keySet()) {

                if (nx == vx) // Ignore self loops
                    continue;

                workingGraph.remove(nx);
                nx.weight -= ratio * vx.neighbors.get(nx);

                // Delete vx from nx' neighbor list. Delete nx from the graph and place it back,
                // thereby updating the ordering of the graph
                nx.removeNeighbor(vx);

                if (nx.getDegree() > 0)
                    workingGraph.add(nx);

            }

            // Update cover
            cover.add(vx.v);
            weight += vertexWeightMap.get(vx.v);
            assert (!workingGraph.parallelStream().anyMatch(
                ux -> ux.ID == vx.ID)) : "vx should no longer exist in the working graph";
        }

        return new VertexCoverImpl<>(cover, weight);

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy