src.it.unimi.dsi.webgraph.labelling.ArcLabelledImmutableGraph Maven / Gradle / Ivy
package it.unimi.dsi.webgraph.labelling;
/*
* Copyright (C) 2007-2011 Paolo Boldi and Sebastiano Vigna
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*
*/
import it.unimi.dsi.logging.ProgressLogger;
import it.unimi.dsi.webgraph.BVGraph;
import it.unimi.dsi.webgraph.ImmutableGraph;
import it.unimi.dsi.webgraph.labelling.ArcLabelledNodeIterator.LabelledArcIterator;
import java.io.IOException;
import java.io.InputStream;
/** An abstract implementation of a graph labelled on its arcs.
*
* The main purpose of this class is that of override covariantly the return
* type of {@link #nodeIterator()} and {@link #nodeIterator(int)} so that
* it is an {@link ArcLabelledNodeIterator}, and the return type of
* all static load methods and of {@link #copy()} so that it is an {@link ArcLabelledImmutableGraph} (the
* methods themselves just delegate to the corresponding method in {@link ImmutableGraph}).
*
*
The only additional instance methods are {@link #labelArray(int)} and {@link #prototype()}.
*
*
Saving labels
*
* A subclass of this class may implement
*
* store(ArcLabelledImmutableGraph, CharSequence, CharSequence, ProgressLogger)
;
* store(ArcLabelledImmutableGraph, CharSequence, CharSequence)
.
*
*
* These methods must save the labels of the given arc-labelled graph using the first given character
* sequence as a basename, and a suitable property file using the second given basename. Note that the graph
* will not be saved—use the store()
* method of an {@link ImmutableGraph} implementation for that purpose.
*
*
For istance, assuming g
is an arc-labelled graph the idiomatic way
* of storing it on disk using {@link BVGraph} for the underlying graph and
* {@link BitStreamArcLabelledImmutableGraph} for the labels is
*
* BVGraph.store( g, "foo" );
* BitStreamArcLabelledImmutableGraph.store( g, "bar", "foo" );
*
*
* Underlying graphs
*
* Often, implementations of this class will just wrap an underlying graph (i.e.,
* an instance of {@link ImmutableGraph}). In that case, we suggest that if the implementation
* uses property files the basename of the underlying graph is specified using the property
* key {@link #UNDERLYINGGRAPH_PROPERTY_KEY}. If the basename must be generated starting
* from the arc-labelled graph basename, we suggest to just add at the end the string
* {@link #UNDERLYINGGRAPH_SUFFIX}.
*/
public abstract class ArcLabelledImmutableGraph extends ImmutableGraph {
/** The standard property key for the underlying graph. All implementations decorating
* with labels an underlying graph are strongly encouraged to use this property
* name to specify the basename of the underlying graph. */
public static final String UNDERLYINGGRAPH_PROPERTY_KEY = "underlyinggraph";
/** The standard suffix added to basenames in order to give a basename
* to the underlying graph, when needed. */
public static final String UNDERLYINGGRAPH_SUFFIX = "-underlying";
public abstract ArcLabelledImmutableGraph copy();
public ArcLabelledNodeIterator nodeIterator() {
return nodeIterator( 0 );
}
/** Returns a node iterator for scanning the graph sequentially, starting from the given node.
*
*
This implementation strengthens that provided in {@link ImmutableGraph}, but
* calls the labelled random-access method {@link #successors(int)}.
*
* @param from the node from which the iterator will iterate.
* @return an {@link ArcLabelledNodeIterator} for accessing nodes, successors and their labels sequentially.
*
* @see ImmutableGraph#nodeIterator()
*/
public ArcLabelledNodeIterator nodeIterator( final int from ) {
return new ArcLabelledNodeIterator() {
int curr = from - 1;
final int n = numNodes();
public int nextInt() {
if ( ! hasNext() ) throw new java.util.NoSuchElementException();
return ++curr;
}
public boolean hasNext() {
return ( curr < n - 1 );
}
public LabelledArcIterator successors() {
if ( curr == from - 1 ) throw new IllegalStateException();
return ArcLabelledImmutableGraph.this.successors( curr );
}
public int outdegree() {
if ( curr == from - 1 ) throw new IllegalStateException();
return ArcLabelledImmutableGraph.this.outdegree( curr );
}
};
}
public abstract ArcLabelledNodeIterator.LabelledArcIterator successors( int x );
/** Returns a prototype of the labels used by this graph. The prototype can be
* used to produce new copies, but must not be modified by the caller.
*
* @return a prototype for the labels of this graph.
*/
public abstract Label prototype();
/** Returns a reference to an array containing the labels of the arcs going out of a given node
* in the same order as the order in which the corresponding successors are returned by {@link #successors(int)}.
*
*
The returned array may contain more entries than the outdegree of x
.
* However, only those with indices from 0 (inclusive) to the outdegree of x
(exclusive)
* contain valid data.
*
*
This implementation just unwrap the iterator returned by {@link #successors(int)} and
* writes in a newly allocated array copies of the labels returned by {@link LabelledArcIterator#label()}.
*
* @return an array whose first elements are the labels of the arcs going
* out of x
; the array must not be modified by the caller.
*/
public Label[] labelArray( int x ) {
return ArcLabelledNodeIterator.unwrap( successors( x ), outdegree( x ) );
}
public static ArcLabelledImmutableGraph loadSequential( CharSequence basename ) throws IOException {
return (ArcLabelledImmutableGraph)ImmutableGraph.loadSequential( basename );
}
public static ArcLabelledImmutableGraph loadSequential( CharSequence basename, ProgressLogger pl ) throws IOException {
return (ArcLabelledImmutableGraph)ImmutableGraph.loadSequential( basename, pl );
}
public static ArcLabelledImmutableGraph loadOffline( CharSequence basename ) throws IOException {
return (ArcLabelledImmutableGraph)ImmutableGraph.loadOffline( basename );
}
public static ArcLabelledImmutableGraph loadOffline( CharSequence basename, ProgressLogger pl ) throws IOException {
return (ArcLabelledImmutableGraph)ImmutableGraph.loadOffline( basename, pl );
}
public static ArcLabelledImmutableGraph load( CharSequence basename ) throws IOException {
return (ArcLabelledImmutableGraph)ImmutableGraph.load( basename );
}
public static ArcLabelledImmutableGraph load( CharSequence basename, ProgressLogger pl ) throws IOException {
return (ArcLabelledImmutableGraph)ImmutableGraph.load( basename, pl );
}
public static ArcLabelledImmutableGraph loadOnce( InputStream is ) throws IOException {
return (ArcLabelledImmutableGraph)ImmutableGraph.loadOnce( is );
}
@Override
public String toString() {
final StringBuilder s = new StringBuilder();
long numArcs = -1;
try {
numArcs = numArcs();
}
catch( UnsupportedOperationException ignore ) {}
s.append( "Nodes: " + numNodes() + "\nArcs: " + ( numArcs == -1 ? "unknown" : Long.toString( numArcs ) ) + "\n" );
final ArcLabelledNodeIterator nodeIterator = nodeIterator();
ArcLabelledNodeIterator.LabelledArcIterator successors;
int curr;
for ( int i = numNodes(); i-- != 0; ) {
curr = nodeIterator.nextInt();
s.append( "Successors of " + curr + " (degree " + nodeIterator.outdegree() + "):" );
successors = nodeIterator.successors();
int d = nodeIterator.outdegree();
while ( d-- != 0 ) s.append( " " + successors.nextInt() + " [" + successors.label() + "]" );
s.append( '\n' );
}
return s.toString();
}
@Override
public boolean equals( Object x ) {
if ( ! ( x instanceof ArcLabelledImmutableGraph ) ) return false;
ArcLabelledImmutableGraph g = (ArcLabelledImmutableGraph)x;
if ( g.numNodes() != numNodes() ) return false;
ArcLabelledNodeIterator nodeIterator = nodeIterator();
ArcLabelledNodeIterator gNodeIterator = g.nodeIterator();
while ( nodeIterator.hasNext() ) {
nodeIterator.nextInt(); gNodeIterator.nextInt();
if ( nodeIterator.outdegree() != gNodeIterator.outdegree() ) return false;
LabelledArcIterator arcIterator = nodeIterator.successors();
LabelledArcIterator gArcIterator = gNodeIterator.successors();
int d = nodeIterator.outdegree();
while ( d-- != 0 ) {
if ( arcIterator.nextInt() != gArcIterator.nextInt()
|| ! arcIterator.label().equals( gArcIterator.label() ) ) return false;
}
}
return true;
}
}