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

org.jgrapht.sux4j.AbstractSuccinctUndirectedGraph Maven / Gradle / Ivy

There is a newer version: 1.5.2
Show newest version
/*
 * (C) Copyright 2020-2021, by Sebastiano Vigna 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.sux4j;

import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.function.Function;

import org.jgrapht.Graph;
import org.jgrapht.GraphType;
import org.jgrapht.Graphs;
import org.jgrapht.graph.DefaultGraphType;

import it.unimi.dsi.bits.Fast;
import it.unimi.dsi.fastutil.ints.IntArrays;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.sux4j.util.EliasFanoIndexedMonotoneLongBigList;

/**
 * An abstract base class for all succinct undirected implementations.
 *
 * 

* Two subclasses, {@link CumulativeSuccessors} and {@link CumulativeDegrees}, generate the monotone * lists that will be encoded using the Elias–Fano representation. * *

* We use the representation described in {@link AbstractSuccinctDirectedGraph} applied to the * directed graph obtained by choosing the direction x → y for * an edge x — y if x ≤ y * (loops are represented twice). Each edge now appears exactly once in the list of outgoing edges, * and thus can be indexed as in the directed base. * *

* The set of vertices adjacent to a given vertex can then be retrieved by enumerating both outgoing * and incoming edges, being careful to avoid enumerating twice loops. * *

* However, in the case of a {@link SuccinctIntUndirectedGraph} after retrieving the source and * target of an incoming edge we need to index it. The slow indexing of the incoming edges is the * reason why a {@link SuccinctIntUndirectedGraph} enumerates edges very slowly, whereas a * {@link SuccinctUndirectedGraph} does not. * * @param the graph edge type */ public abstract class AbstractSuccinctUndirectedGraph extends AbstractSuccinctGraph { private static final long serialVersionUID = 0L; public AbstractSuccinctUndirectedGraph(final int n, final int m) { super(n, m); } /** * Turns all edges x — y, * x ≤ y, into a monotone sequence using the encoding * x2⌈log n + y, or all edges * x — y, x ≥ y, using * the encoding xn + y - e, where e is * the index of the edge in lexicographical order, depending on the value of the {@code sorted} * parameter. * * @param the graph edge type */ protected final static class CumulativeSuccessors implements LongIterator { private final Graph graph; private final long n; private final int sourceShift; private final Function> succ; private final boolean sorted; private int x = -1, d, i, e; private long next = -1; private int[] s = IntArrays.EMPTY_ARRAY; protected CumulativeSuccessors( final Graph graph, final boolean sorted, final Function> succ) { this.n = (int) graph.iterables().vertexCount(); this.sourceShift = Fast.ceilLog2(n); this.graph = graph; this.sorted = sorted; this.succ = succ; } @Override public boolean hasNext() { if (next != -1) return true; if (x == n) return false; while (i == d) { if (++x == n) return false; int d = 0; for (final E e : succ.apply(x)) { final int y = Graphs.getOppositeVertex(graph, e, x); if (sorted) { if (x <= y) { s = IntArrays.grow(s, d + 1); s[d++] = y; } } else { if (x >= y) { s = IntArrays.grow(s, d + 1); s[d++] = y; } } } Arrays.sort(s, 0, d); this.d = d; i = 0; } // The predecessor list will not be indexed, so we can gain a few bits of space by // subtracting the edge position in the list next = sorted ? s[i] + ((long) x << sourceShift) : s[i] + x * n - e++; i++; return true; } @Override public long nextLong() { if (!hasNext()) throw new NoSuchElementException(); final long result = next; next = -1; return result; } } /** * Iterates over the cumulative degrees (starts with a zero). Depending on the value of * {@code sorted}, only edges whose adjacent vertex is greater than or equal to the base vertex * (or vice versa) are included. * * @param the graph edge type */ protected final static class CumulativeDegrees implements LongIterator { private final int n; private int x = -1; private long cumul = 0; private final Function> succ; private final boolean sorted; private final Graph graph; protected CumulativeDegrees( final Graph graph, final boolean sorted, final Function> succ) { this.n = (int) graph.iterables().vertexCount(); this.graph = graph; this.succ = succ; this.sorted = sorted; } @Override public boolean hasNext() { return x < n; } @Override public long nextLong() { if (!hasNext()) throw new NoSuchElementException(); if (x == -1) return ++x; int d = 0; if (sorted) { for (final E e : succ.apply(x)) if (x <= Graphs.getOppositeVertex(graph, e, x)) d++; } else { for (final E e : succ.apply(x)) if (x >= Graphs.getOppositeVertex(graph, e, x)) d++; } x++; return cumul += d; } } @Override public int inDegreeOf(final Integer vertex) { return degreeOf(vertex); } @Override public int outDegreeOf(final Integer vertex) { return degreeOf(vertex); } protected boolean containsEdge( final EliasFanoIndexedMonotoneLongBigList successors, int x, int y) { if (x > y) { final int t = x; x = y; y = t; } return successors.indexOfUnsafe(((long) x << sourceShift) + y) != -1; } @Override public GraphType getType() { return new DefaultGraphType.Builder() .directed().weighted(false).modifiable(false).allowMultipleEdges(false) .allowSelfLoops(true).build(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy