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

org.jgrapht.traverse.MaximumCardinalityIterator Maven / Gradle / Ivy

The newest version!
/*
 * (C) Copyright 2018-2023, by Timofey Chudakov 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.traverse;

import org.jgrapht.*;
import org.jgrapht.util.*;

import java.util.*;

/**
 * A maximum cardinality search iterator for an undirected graph.
 * 

* For every vertex in graph its cardinality is defined as the number of its neighbours, which have * been already visited by this iterator. Iterator chooses vertex with the maximum cardinality, * breaking ties arbitrarily. For more information of maximum cardinality search see: Berry, A., * Blair, J., Heggernes, P. et al. Algorithmica (2004) 39: 287. * https://doi.org/10.1007/s00453-004-1084-3 * Maximum Cardinality Search for Computing * Minimal Triangulations. *

* For this iterator to work correctly the graph must not be modified during iteration. Currently * there are no means to ensure that, nor to fail-fast. The results of such modifications are * undefined. *

* Note: only vertex events are fired by this iterator. * * @param the graph vertex type. * @param the graph edge type. * @author Timofey Chudakov */ public class MaximumCardinalityIterator extends AbstractGraphIterator { /** * The maximum index of non-empty set in {@code buckets}. */ private int maxCardinality; /** * Number of unvisited vertices. */ private int remainingVertices; /** * Contains current vertex. */ private V current; /** * Disjoint sets of vertices of the graph, indexed by the cardinalities of already visited * neighbours. */ private ArrayList> buckets; /** * Maps every vertex to its cardinality. */ private Map cardinalityMap; /** * Creates a maximum cardinality iterator for the {@code graph}. * * @param graph the graph to be iterated. */ public MaximumCardinalityIterator(Graph graph) { super(graph); remainingVertices = graph.vertexSet().size(); if (remainingVertices > 0) { GraphTests.requireUndirected(graph); buckets = new ArrayList<>(Collections.nCopies(graph.vertexSet().size(), null)); buckets.set(0, new LinkedHashSet<>(graph.vertexSet())); cardinalityMap = CollectionUtil.newHashMapWithExpectedSize(graph.vertexSet().size()); for (V v : graph.vertexSet()) { cardinalityMap.put(v, 0); } maxCardinality = 0; } } /** * Checks whether there exists unvisited vertex. * * @return true if there exists unvisited vertex. */ @Override public boolean hasNext() { if (current != null) { return true; } current = advance(); if (current != null && nListeners != 0) { fireVertexTraversed(createVertexTraversalEvent(current)); } return current != null; } /** * Returns the next vertex in the ordering. * * @return the next vertex in the ordering. */ @Override public V next() { if (!hasNext()) { throw new NoSuchElementException(); } V result = current; current = null; if (nListeners != 0) { fireVertexFinished(createVertexTraversalEvent(result)); } return result; } /** * {@inheritDoc} *

* Always returns true since this iterator doesn't care about connected components. */ @Override public boolean isCrossComponentTraversal() { return true; } /** * {@inheritDoc} *

* Trying to disable the cross components nature of this iterator will result into throwing a * {@link IllegalArgumentException}. */ @Override public void setCrossComponentTraversal(boolean crossComponentTraversal) { if (!crossComponentTraversal) { throw new IllegalArgumentException("Iterator is always cross-component"); } } /** * Retrieves a vertex from the {@code buckets} with the maximum cardinality and returns it. * * @return vertex retrieved from {@code buckets}. */ private V advance() { if (remainingVertices > 0) { Set bucket = buckets.get(maxCardinality); V vertex = bucket.iterator().next(); removeFromBucket(vertex); if (bucket.isEmpty()) { buckets.set(maxCardinality, null); do { --maxCardinality; } while (maxCardinality >= 0 && buckets.get(maxCardinality) == null); } updateNeighbours(vertex); --remainingVertices; return vertex; } else { return null; } } /** * Removes {@code vertex} from the bucket it was contained in. * * @param vertex the vertex, which has to be removed from the bucket it was contained in. * @return the cardinality of the removed vertex or -1, if the vertex wasn't contained in any * bucket. */ private int removeFromBucket(V vertex) { if (cardinalityMap.containsKey(vertex)) { int cardinality = cardinalityMap.get(vertex); buckets.get(cardinality).remove(vertex); cardinalityMap.remove(vertex); if (buckets.get(cardinality).isEmpty()) { buckets.set(cardinality, null); } return cardinality; } return -1; } /** * Adds the {@code vertex} to the bucket with the given {@code cardinality}. * * @param vertex the vertex, which has to be added to the the bucket. * @param cardinality the cardinality of the destination bucket. */ private void addToBucket(V vertex, int cardinality) { cardinalityMap.put(vertex, cardinality); if (buckets.get(cardinality) == null) { buckets.set(cardinality, new LinkedHashSet<>()); } buckets.get(cardinality).add(vertex); } /** * Increments the cardinalities of the neighbours of the {@code vertex} by 1. If the maximum * cardinality increases, increments {@code maxCardinality} by 1. * * @param vertex the vertex whose neighbours are to be updated. */ private void updateNeighbours(V vertex) { Set processed = new HashSet<>(); for (E edge : graph.edgesOf(vertex)) { V opposite = Graphs.getOppositeVertex(graph, edge, vertex); if (cardinalityMap.containsKey(opposite) && !processed.contains(opposite)) { processed.add(opposite); addToBucket(opposite, removeFromBucket(opposite) + 1); } } if (maxCardinality < graph.vertexSet().size() && maxCardinality >= 0 && buckets.get(maxCardinality + 1) != null) { ++maxCardinality; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy