org.structnetalign.merge.BronKerboschCliqueFinder.java Source code

Java tutorial

Introduction

Here is the source code for org.structnetalign.merge.BronKerboschCliqueFinder.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
 * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 * @author dmyersturnbull
 */
package org.structnetalign.merge;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.NavigableSet;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.collections.CollectionUtils;

import edu.uci.ics.jung.graph.UndirectedGraph;

/**
 * An implementation of naive BronKerbosch.
 * @author dmyersturnbull
 *
 * @param <V> The types of the vertices of the graph
 * @param <E> The types of the edges of the graph
 * @see CliqueFinder
 */
public class BronKerboschCliqueFinder<V, E> implements CliqueFinder<V, E> {

    @Override
    public NavigableSet<Set<V>> transform(UndirectedGraph<V, E> graph) {
        InternalBronKerboschCliqueFinder<V, E> finder = new InternalBronKerboschCliqueFinder<V, E>(graph);
        Collection<Set<V>> unsortedCliques = finder.getAllMaximalCliques();
        Comparator<Set<V>> comparator = new Comparator<Set<V>>() {
            @Override
            public int compare(Set<V> clique1, Set<V> clique2) {
                if (CollectionUtils.isEqualCollection(clique1, clique2))
                    return 0;
                if (clique1.size() < clique2.size()) {
                    return 1;
                } else if (clique1.size() > clique2.size()) {
                    return -1;
                } else {
                    return -1;
                }
            }
        };
        NavigableSet<Set<V>> yes = new TreeSet<>(comparator);
        for (Set<V> s : unsortedCliques) {
            yes.add(s);
        }
        return yes;
    }

    @Override
    public NavigableSet<Set<V>> getMaximumCliques(UndirectedGraph<V, E> graph) {
        NavigableSet<Set<V>> top = new TreeSet<>();
        int max = 0;
        NavigableSet<Set<V>> cliques = transform(graph);
        for (Set<V> clique : cliques) {
            if (clique.size() >= max) {
                max = clique.size();
                top.add(clique);
            }
        }
        return top;
    }

    @Override
    public NavigableSet<Set<V>> getMaximalCliques(UndirectedGraph<V, E> graph) {
        return transform(graph);
    }

    /**
     * 
     * This code was written by <a href="https://plus.google.com/116035002500528609208/">Reuben Doetsch</a>,
     * who adapted it from <a href="http://jgrapht.org/">JGraphT</a>. Since JGraphT is under the LGPL, it is unclear which
     * license is under effect here. At the least, the code is OSG-certified Free and is not my work.
     * 
     * Adopted from JGraphT for use with Jung. The Bron-Kerbosch algorithm is an algorithm for finding maximal cliques in an
     * undirected graph This algorithmn is taken from Coenraad Bron- Joep Kerbosch in 1973. This works on undirected graph
     * See {@linktourl See http://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm}
     * 
     * @author Reuben Doetsch
     * 
     * @param <V>
     *            vertex class of graph
     * @param <E>
     *            edge class of graph
     */
    private static class InternalBronKerboschCliqueFinder<V, E> {

        private Collection<Set<V>> cliques;

        private final UndirectedGraph<V, E> graph;

        /**
         * Creates a new clique finder. Make sure this is a simple graph.
         * 
         * @param graph
         *            the graph in which cliques are to be found; graph must be simple
         */
        public InternalBronKerboschCliqueFinder(UndirectedGraph<V, E> graph) {

            this.graph = graph;
        }

        /**
         * Finds all maximal cliques of the graph. A clique is maximal if it is impossible to enlarge it by adding another
         * vertex from the graph. Note that a maximal clique is not necessarily the biggest clique in the graph.
         * 
         * @return Collection of cliques (each of which is represented as a Set of vertices)
         */
        public Collection<Set<V>> getAllMaximalCliques() {
            // TODO: assert that graph is simple

            cliques = new ArrayList<Set<V>>();
            List<V> potential_clique = new ArrayList<V>();
            List<V> candidates = new ArrayList<V>();
            List<V> already_found = new ArrayList<V>();
            candidates.addAll(graph.getVertices());
            findCliques(potential_clique, candidates, already_found);
            return cliques;
        }

        /**
         * Finds the biggest maximal cliques of the graph.
         * 
         * @return Collection of cliques (each of which is represented as a Set of vertices)
         */
        public Collection<Set<V>> getBiggestMaximalCliques() {
            // first, find all cliques
            getAllMaximalCliques();

            int maximum = 0;
            Collection<Set<V>> biggest_cliques = new ArrayList<Set<V>>();
            for (Set<V> clique : cliques) {
                if (maximum < clique.size()) {
                    maximum = clique.size();
                }
            }
            for (Set<V> clique : cliques) {
                if (maximum == clique.size()) {
                    biggest_cliques.add(clique);
                }
            }
            return biggest_cliques;
        }

        private boolean end(List<V> candidates, List<V> already_found) {
            // if a node in already_found is connected to all nodes in candidates
            boolean end = false;
            int edgecounter;
            for (V found : already_found) {
                edgecounter = 0;
                for (V candidate : candidates) {
                    if (graph.isNeighbor(found, candidate)) {
                        edgecounter++;
                    } // of if
                } // of for
                if (edgecounter == candidates.size()) {
                    end = true;
                }
            } // of for
            return end;
        }

        private void findCliques(List<V> potential_clique, List<V> candidates, List<V> already_found) {
            List<V> candidates_array = new ArrayList<V>(candidates);
            if (!end(candidates, already_found)) {
                // for each candidate_node in candidates do
                for (V candidate : candidates_array) {
                    List<V> new_candidates = new ArrayList<V>();
                    List<V> new_already_found = new ArrayList<V>();

                    // move candidate node to potential_clique
                    potential_clique.add(candidate);
                    candidates.remove(candidate);

                    // create new_candidates by removing nodes in candidates not
                    // connected to candidate node
                    for (V new_candidate : candidates) {
                        if (graph.isNeighbor(candidate, new_candidate)) {
                            new_candidates.add(new_candidate);
                        } // of if
                    } // of for

                    // create new_already_found by removing nodes in already_found
                    // not connected to candidate node
                    for (V new_found : already_found) {
                        if (graph.isNeighbor(candidate, new_found)) {
                            new_already_found.add(new_found);
                        } // of if
                    } // of for

                    // if new_candidates and new_already_found are empty
                    if (new_candidates.isEmpty() && new_already_found.isEmpty()) {
                        // potential_clique is maximal_clique
                        cliques.add(new HashSet<V>(potential_clique));
                    } // of if
                    else {
                        // recursive call
                        findCliques(potential_clique, new_candidates, new_already_found);
                    } // of else

                    // move candidate_node from potential_clique to already_found;
                    already_found.add(candidate);
                    potential_clique.remove(candidate);
                } // of for
            } // of if
        }
    }

}