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

org.jgrapht.alg.clique.PivotBronKerboschCliqueFinder Maven / Gradle / Ivy

/*
 * (C) Copyright 2017-2021, by Dimitrios Michail 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.alg.clique;

import org.jgrapht.*;

import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;

/**
 * Bron-Kerbosch maximal clique enumeration algorithm with pivot.
 * 
 * 

* The pivoting follows the rule from the paper *

    *
  • E. Tomita, A. Tanaka, and H. Takahashi. The worst-case time complexity for generating all * maximal cliques and computational experiments. Theor. Comput. Sci. 363(1):28–42, 2006.
  • *
* *

* where the authors show that using that rule guarantees that the Bron-Kerbosch algorithm has * worst-case running time $O(3^{n/3})$ where $n$ is the number of vertices of the graph, excluding * time to write the output, which is worst-case optimal. * *

* The algorithm first computes all maximal cliques and then returns the result to the user. A * timeout can be set using the constructor parameters. * * @param the graph vertex type * @param the graph edge type * * @see BronKerboschCliqueFinder * @see DegeneracyBronKerboschCliqueFinder * * @author Dimitrios Michail */ public class PivotBronKerboschCliqueFinder extends BaseBronKerboschCliqueFinder { /** * Constructs a new clique finder. * * @param graph the input graph; must be simple */ public PivotBronKerboschCliqueFinder(Graph graph) { this(graph, 0L, TimeUnit.SECONDS); } /** * Constructs a new clique finder. * * @param graph the input graph; must be simple * @param timeout the maximum time to wait, if zero no timeout * @param unit the time unit of the timeout argument */ public PivotBronKerboschCliqueFinder(Graph graph, long timeout, TimeUnit unit) { super(graph, timeout, unit); } /** * Lazily execute the enumeration algorithm. */ @Override protected void lazyRun() { if (allMaximalCliques == null) { if (!GraphTests.isSimple(graph)) { throw new IllegalArgumentException("Graph must be simple"); } allMaximalCliques = new ArrayList<>(); long nanosTimeLimit; try { nanosTimeLimit = Math.addExact(System.nanoTime(), nanos); } catch (ArithmeticException ignore) { nanosTimeLimit = Long.MAX_VALUE; } findCliques( new HashSet<>(graph.vertexSet()), new HashSet<>(), new HashSet<>(), nanosTimeLimit); } } /** * Choose a pivot. * * @param p vertices to consider adding to the clique * @param x vertices which must be excluded from the clique * @return a pivot */ private V choosePivot(Set p, Set x) { int max = -1; V pivot = null; Iterator it = Stream.concat(p.stream(), x.stream()).iterator(); while (it.hasNext()) { V u = it.next(); int count = 0; for (E e : graph.edgesOf(u)) { if (p.contains(Graphs.getOppositeVertex(graph, e, u))) { count++; } } if (count > max) { max = count; pivot = u; } } return pivot; } /** * Recursive implementation of the Bron-Kerbosch with pivot. * * @param p vertices to consider adding to the clique * @param r a possibly non-maximal clique * @param x vertices which must be excluded from the clique * @param nanosTimeLimit time limit */ protected void findCliques(Set p, Set r, Set x, final long nanosTimeLimit) { /* * Check if maximal clique */ if (p.isEmpty() && x.isEmpty()) { Set maximalClique = new HashSet<>(r); allMaximalCliques.add(maximalClique); maxSize = Math.max(maxSize, maximalClique.size()); return; } /* * Check if timeout */ if (nanosTimeLimit - System.nanoTime() < 0) { timeLimitReached = true; return; } /* * Choose pivot */ V u = choosePivot(p, x); /* * Find candidates for addition */ Set uNeighbors = new HashSet<>(); for (E e : graph.edgesOf(u)) { uNeighbors.add(Graphs.getOppositeVertex(graph, e, u)); } Set candidates = new HashSet<>(); for (V v : p) { if (!uNeighbors.contains(v)) { candidates.add(v); } } /* * Main loop */ for (V v : candidates) { Set vNeighbors = new HashSet<>(); for (E e : graph.edgesOf(v)) { vNeighbors.add(Graphs.getOppositeVertex(graph, e, v)); } Set newP = p.stream().filter(vNeighbors::contains).collect(Collectors.toSet()); Set newX = x.stream().filter(vNeighbors::contains).collect(Collectors.toSet()); Set newR = new HashSet<>(r); newR.add(v); findCliques(newP, newR, newX, nanosTimeLimit); p.remove(v); x.add(v); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy