Package emapse.graph

Source Code of emapse.graph.BipartiteGraph

package emapse.graph;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import javolution.util.FastSet;

public class BipartiteGraph<T> extends SimpleGraph<T, BipartiteNode<T>> {

    // First independent set in the bipartite graph
    private Set<BipartiteNode<T>> U;
    // Second independent set the bipartite graph
    private Set<BipartiteNode<T>> V;

    public BipartiteGraph() {
        U = FastSet.newInstance();
        V = FastSet.newInstance();
    }

    @Override
    protected BipartiteNode<T> createNode(T element) {
        return new BipartiteNode<T>(element);
    }

    /**
     * Sets the first independent Set of the Bipartite graph. This method has to
     * be called.
     */
    public void setFirstIndependentSet(Collection<T> collection) {
        Set<BipartiteNode<T>> Un = FastSet.newInstance();
        for (T element : collection) {
            if (nodes.get(element) != null)
                Un.add(nodes.get(element));
        }
        U = Un;
    }

    /**
     * Sets the second independent Set of the Bipartite graph. This method has
     * to be called.
     */
    public void setSecondIndependentSet(Collection<T> collection) {
        Set<BipartiteNode<T>> Vn = FastSet.newInstance();
        for (T element : collection) {
            if (nodes.get(element) != null)
                Vn.add(nodes.get(element));
        }
        V = Vn;
    }

    protected Set<BipartiteNode<T>> calculateMinimumCover() {
        // Consider a bipartite graph where the vertices are partitioned into
        // left (L) and right (R) sets.
        // Suppose there is a maximum matching which partitions the edges into
        // those used in the matching (Em) and those not (E0).
        // Let B consist of all unmatched vertices from L(B1), as well as all
        // vertices reachable from those by going left-to-right along edges from
        // E0 (B2) and right-to-left along edges from Em (B3). This essentially
        // means that for each unmatched Edge in L, we add into B all vertices
        // that occur in a path alternating between edges from E0 and Em.

        // Then (L minus B) union (R intersect B) is a minimum Edge cover.

        Set<Edge<BipartiteNode<T>>> maximumMatching = calculateMaxmimumMatching();
        Set<Edge<BipartiteNode<T>>> unmatchedEdges = edges;
        unmatchedEdges.removeAll(maximumMatching);
        // Koing's theorem: if U,BipartiteNode<T> are the left and right
        // independent sets of
        // the bipartite graph, and T the unmatched vertices of U + the vertices
        // that belong to an alternative path of the unmatched and matched
        // vertices, then the minimum Edge Set is
        // (U\T)Union (BipartiteNode<T> Intersection T)

        Set<BipartiteNode<T>> matchedVertices = FastSet.newInstance();
        for (Edge<BipartiteNode<T>> Edge : maximumMatching) {
            matchedVertices.add(Edge.getSource());
            matchedVertices.add(Edge.getTarget());
        }
        // calculates unmatched vertices from L
        Collection<BipartiteNode<T>> unmatchedVertices = nodes.values();
        unmatchedVertices.removeAll(matchedVertices);
        unmatchedVertices.retainAll(U);
        Set<BipartiteNode<T>> B1 = FastSet.newInstance();
        B1.addAll(unmatchedVertices);
        Set<BipartiteNode<T>> B2 = FastSet.newInstance();
        B2.addAll(B1);
        while (true) {
            Set<BipartiteNode<T>> B3 = FastSet.newInstance();
            for (Edge<BipartiteNode<T>> edge : unmatchedEdges) {
                if (B2.contains(edge.getSource()))
                    B3.add(edge.getTarget());
            }
            B3.removeAll(B1);
            if (B3.isEmpty())
                break;
            B1.addAll(B3);

            Set<BipartiteNode<T>> B4 = FastSet.newInstance();
            for (Edge<BipartiteNode<T>> edge : maximumMatching) {
                if (B3.contains(edge.getTarget()))
                    B4.add(edge.getSource());
            }
            B4.removeAll(B1);
            if (B4.isEmpty())
                break;
            B1.addAll(B4);

            B2 = B4;
        }

        Set<BipartiteNode<T>> leftClone = new FastSet(U);
        Set<BipartiteNode<T>> rightClone = new FastSet(V);

        leftClone.removeAll(B1);
        rightClone.retainAll(B1);
        leftClone.addAll(rightClone);
        return leftClone;
    }

    public Set<Edge<BipartiteNode<T>>> calculateMaxmimumMatching() {
        for (BipartiteNode<T> node : U) {
            node.matching = null;
        }
        for (BipartiteNode<T> node : V) {
            node.matching = null;
        }

        while (true) {
            // Find all potential beginnings of shortest augmenting paths
            Set<BipartiteNode<T>> B = FastSet.newInstance();
            for (BipartiteNode<T> u : U) {
                if (u.matching == null)
                    B.add(u);
            }

            // Find all endings of shortest augmenting paths
            Set<BipartiteNode<T>> F = findAugmentingPathEndings(B);
            Set<Edge<BipartiteNode<T>>> M = FastSet.newInstance();
            if (F.isEmpty()) {
                M = FastSet.newInstance();
                for (BipartiteNode<T> u : U) {
                    if (u.matching != null)
                        M.add(new Edge<BipartiteNode<T>>(u, u.matching));
                }
                return M;
            }
            augmentPaths(F);
        }
    }

    private Set<BipartiteNode<T>> findAugmentingPathEndings(
            Set<BipartiteNode<T>> B) {
        // Perform BFS starting with vertices of B.
        // Return: a list of free vertices which potentially
        // end the shortest Edge-disjoint augmenting paths.
        // Side effect: For any Edge v.layer has the index of
        // the BFS layer to reach this Edge (or -1)
        // B: potential beginning of augmenting paths

        Set<BipartiteNode<T>> Q = new FastSet(B);
        // F: The set of free endings (the other side of augmenting paths)
        Set<BipartiteNode<T>> F = FastSet.newInstance();
        for (BipartiteNode<T> node : U) {
            node.layer = -1;
        }
        for (BipartiteNode<T> node : V) {
            node.layer = -1;
        }

        // The potential beginnings of augmenting paths are at layer 0.
        for (BipartiteNode<T> node : B) {
            node.layer = 0;
        }

        while (!Q.isEmpty()) {
            Set<BipartiteNode<T>> G = FastSet.newInstance();

            for (BipartiteNode<T> q : Q) {
                for (Edge<BipartiteNode<T>> v : edges) {
                    if (v.getSource() == q || v.getTarget() == q) {
                        BipartiteNode<T> p;
                        if (v.getSource() == q)
                            p = v.getTarget();
                        else
                            // (v.getTarget() == q)
                            p = v.getSource();
                        if (p.layer == -1) {
                            p.layer = q.layer + 1;
                            if (p.matching == null)
                                // Collect the free Edge, continue BFS
                                F.add(p);
                            else
                                G.add(p);
                        }
                    }
                }
            }
            if (!F.isEmpty())
                // Free vertices found, stop at this layer.
                return F;

            Q.clear();
            for (BipartiteNode<T> q : G) {
                // By construction, q matched.
                BipartiteNode<T> p = q.matching;
                p.layer = q.layer + 1;
                Q.add(p);
            }
        }

        return FastSet.newInstance();
    }

    private void augmentPaths(Set<BipartiteNode<T>> F) {
        for (BipartiteNode<T> node : U) {
            node.visited = false;
        }
        for (BipartiteNode<T> node : V) {
            node.visited = false;
        }

        for (BipartiteNode<T> q : F) {
            List<Edge<BipartiteNode<T>>> P = getAugmentingPath(q);
            // Make sure q ends a Edge-disjoint augmenting path
            if (!P.isEmpty()) {
                // Perform M := M + P
                boolean odd = true;
                for (Edge<BipartiteNode<T>> v : P) {
                    BipartiteNode<T> t = v.getSource();
                    BipartiteNode<T> qprime = v.getTarget();

                    if (odd) {
                        // Make (t,q) match (first, third, ... edges)
                        // System.out.println("layer"+qprime.layer+t.layer);
                        t.matching = qprime;
                        qprime.matching = t;
                        odd = false;
                    } else {
                        // System.out.println("layer"+qprime.layer+t.layer);
                        // t.matching has already been updated by the odd
                        // condition

                        // This section is not needed entirely. Only the part
                        // inside the else is needed
                        if (U.contains(qprime))
                            qprime.matching = null;
                        else
                            // This is not strictly required
                            t.matching = null;
                        odd = true;
                    }
                }
            }
        }
    }

    // f is always in the girls group
    private List<Edge<BipartiteNode<T>>> getAugmentingPath(BipartiteNode<T> f) {
        if (f.visited || f.layer == 0)
            return new ArrayList<Edge<BipartiteNode<T>>>();

        f.visited = true;
        // Consider only edges going one layer backwards.
        for (Edge<BipartiteNode<T>> v : edges) {
            if (v.getSource() == f || v.getTarget() == f) {
                BipartiteNode<T> q;
                BipartiteNode<T> p;
                if (v.getTarget() == f) {
                    p = v.getTarget();
                    q = v.getSource();
                } else {
                    // (v.getSource() == f)
                    p = v.getSource();
                    q = v.getTarget();
                }

                if (p.layer == q.layer + 1) {
                    if (q.layer == 0 && q.visited == false) {
                        // q is at an even layer
                        q.visited = true;
                        List<Edge<BipartiteNode<T>>> result = new ArrayList<Edge<BipartiteNode<T>>>();
                        result.add(v);
                        return result;
                    }
                    // Note that q.matching must be defined, and point to
                    // the previous layer. This is due to BFS traversal order.
                    List<Edge<BipartiteNode<T>>> P = getAugmentingPath(q.matching);
                    if (!P.isEmpty()) {
                        // Append (q, p) to the path found so far.
                        P.add(new Edge<BipartiteNode<T>>(q, q.matching));
                        P.add(v);
                        return P;
                    }
                }
            }
        }
        return new ArrayList<Edge<BipartiteNode<T>>>();
    }
}
TOP

Related Classes of emapse.graph.BipartiteGraph

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.