net.imglib2.histogram.HistogramNd Maven / Gradle / Ivy
Show all versions of imglib2 Show documentation
/*
* #%L
* ImgLib2: a general-purpose, multidimensional image processing library.
* %%
* Copyright (C) 2009 - 2018 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld,
* John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke,
* Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner,
* Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert,
* Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin,
* Jean-Yves Tinevez and Michael Zinsmaier.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package net.imglib2.histogram;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import net.imglib2.Cursor;
import net.imglib2.Interval;
import net.imglib2.Positionable;
import net.imglib2.RandomAccess;
import net.imglib2.RealPositionable;
import net.imglib2.img.Img;
import net.imglib2.img.ImgFactory;
import net.imglib2.type.numeric.integer.LongType;
// TODO - calculate lazily but should be able to count upper/lower/middle in
// one pass rather than the multiple passes that are now in place.
/**
* A HistogramNd is an n-dimensional histogram that tracks up to four kinds of
* values: 1) values in the center of the distribution 2) values to the left of
* the center of the distribution (lower tail) 3) values to the right of the
* center of the distribution (upper tail) 4) values outside the other areas
*
* Note: the last three classifications may not be present depending upon the
* makeup of the input data.
*
* @author Barry DeZonia
*/
public class HistogramNd< T > implements Img< LongType >
{
// -- instance variables --
private List< BinMapper1d< T >> mappers;
private DiscreteFrequencyDistribution distrib;
private long[] pos;
private long ignoredCount;
@SuppressWarnings( "synthetic-access" )
private final Incrementer incrementer = new Incrementer();
@SuppressWarnings( "synthetic-access" )
private final Decrementer decrementer = new Decrementer();
// -- constructors --
/**
* Construct a histogram from a list of bin mapping algorithms. Use
* countData() to populate it.
*
* @param mappers
* The algorithms used to map values to bins
*/
public HistogramNd( final List< BinMapper1d< T >> mappers )
{
this.mappers = mappers;
final long[] dims = new long[ mappers.size() ];
for ( int i = 0; i < mappers.size(); i++ )
{
dims[ i ] = mappers.get( i ).getBinCount();
}
distrib = new DiscreteFrequencyDistribution( dims );
pos = new long[ mappers.size() ];
ignoredCount = 0;
}
/**
* Construct a histogram whose bin mappings match another histogram. After
* this construction the histogram bins are unpopulated.
*
* @param other
* The histogram to copy.
*/
public HistogramNd( final HistogramNd< T > other )
{
final List< BinMapper1d< T >> mappersCopy = new ArrayList< BinMapper1d< T >>();
for ( final BinMapper1d< T > m : mappers )
{
mappersCopy.add( m.copy() );
}
mappers = mappersCopy;
distrib = other.distrib.copy();
pos = other.pos.clone();
ignoredCount = 0;
}
/**
* Construct a histogram from an iterable set of data and a list of bin
* mapping algorithms. Must be given one iterable data source that returns
* multiple data values at each point.
*
* @param data
* The iterable set of values to calculate upon
* @param mappers
* The algorithms used to map values to bins
*/
public HistogramNd( final Iterable< List< T >> data, final List< BinMapper1d< T >> mappers )
{
this( mappers );
init( data );
}
/**
* Construct a histogram from an iterable set of data and a list of bin
* mapping algorithms. Must be given multiple iterable data sources that
* each return a single data value at each point.
*
* @param data
* The iterable set of values to calculate upon
* @param mappers
* The algorithms used to map values to bins
*/
public HistogramNd( final List< Iterable< T >> data, final List< BinMapper1d< T >> mappers )
{
this( mappers );
init( data );
}
// -- public api --
/**
* Returns true if the histogram has tail bins which count extreme values
* for the given dimension.
*/
public boolean hasTails( final int dim )
{
return mappers.get( dim ).hasTails();
}
/**
* Returns true if the histogram has tail bins which count extreme values
* for one or more dimensions
*/
public boolean hasTails()
{
for ( int i = 0; i < mappers.size(); i++ )
{
if ( hasTails( i ) )
return true;
}
return false;
}
/**
* Returns the frequency count of values in the lower tail bin (if any) for
* the given dimension.
*/
public long lowerTailCount( final int dim )
{
if ( !hasTails( dim ) )
return 0;
long sum = 0;
final Cursor< ? > cursor = distrib.localizingCursor();
final long[] binPos = new long[ distrib.numDimensions() ];
while ( cursor.hasNext() )
{
cursor.next();
cursor.localize( binPos );
if ( binPos[ dim ] == 0 )
sum += distrib.frequency( binPos );
}
return sum;
}
/**
* Returns the frequency count of values in all lower tail bins (if any).
*/
public long lowerTailCount()
{
if ( !hasTails() )
return 0;
long sum = 0;
final Cursor< ? > cursor = distrib.localizingCursor();
final long[] binPos = new long[ distrib.numDimensions() ];
while ( cursor.hasNext() )
{
cursor.next();
cursor.localize( binPos );
for ( int i = 0; i < mappers.size(); i++ )
{
if ( binPos[ i ] == 0 )
{
sum += distrib.frequency( binPos );
break;
}
}
}
return sum;
}
/**
* Returns the frequency count of values in the upper tail bin (if any) for
* the given dimension.
*/
public long upperTailCount( final int dim )
{
if ( !hasTails( dim ) )
return 0;
final long dimSize = mappers.get( dim ).getBinCount();
long sum = 0;
final Cursor< ? > cursor = distrib.localizingCursor();
final long[] binPos = new long[ distrib.numDimensions() ];
while ( cursor.hasNext() )
{
cursor.next();
cursor.localize( binPos );
if ( binPos[ dim ] == dimSize - 1 )
sum += distrib.frequency( binPos );
}
return sum;
}
/**
* Returns the frequency count of values in all upper tail bins (if any).
*/
public long upperTailCount()
{
if ( !hasTails() )
return 0;
long sum = 0;
final Cursor< ? > cursor = distrib.localizingCursor();
final long[] binPos = new long[ distrib.numDimensions() ];
while ( cursor.hasNext() )
{
cursor.next();
cursor.localize( binPos );
for ( int i = 0; i < mappers.size(); i++ )
{
if ( binPos[ i ] == mappers.get( i ).getBinCount() - 1 )
{
sum += distrib.frequency( binPos );
break;
}
}
}
return sum;
}
/**
* Returns the frequency count of all values in the middle of the
* distribution for a given dimension.
*/
public long valueCount( final int dim )
{
final boolean hasTails = hasTails( dim );
final long dimSize = mappers.get( dim ).getBinCount();
long sum = 0;
final Cursor< ? > cursor = distrib.localizingCursor();
final long[] binPos = new long[ distrib.numDimensions() ];
while ( cursor.hasNext() )
{
cursor.next();
cursor.localize( binPos );
boolean inTail = false;
if ( hasTails && ( binPos[ dim ] == 0 ) || ( binPos[ dim ] == dimSize - 1 ) )
{
inTail = true;
}
if ( !inTail )
sum += distrib.frequency( binPos );
}
return sum;
}
/**
* Returns the frequency count of all values in the middle of the
* distribution.
*/
public long valueCount()
{
// NB : would like to do this:
// return distributionCount() - lowerTailCount() - upperTailCount();
// But this double counts some tail bins.
if ( !hasTails() )
return distributionCount();
long sum = 0;
final Cursor< ? > cursor = distrib.localizingCursor();
final long[] binPos = new long[ distrib.numDimensions() ];
while ( cursor.hasNext() )
{
cursor.next();
cursor.localize( binPos );
boolean inTail = false;
for ( int i = 0; i < binPos.length; i++ )
{
if ( ( binPos[ i ] == 0 ) || ( binPos[ i ] == mappers.get( i ).getBinCount() - 1 ) )
{
inTail = true;
break;
}
}
if ( !inTail )
sum += distrib.frequency( binPos );
}
return sum;
}
/**
* Returns the frequency count of all values in the specified dimension of
* the distribution: lower tail + middle + upper tail. Does not include
* ignored values.
*/
public long distributionCount( final int dim, final long dimVal )
{
long sum = 0;
final Cursor< ? > cursor = distrib.localizingCursor();
final long[] binPos = new long[ distrib.numDimensions() ];
while ( cursor.hasNext() )
{
cursor.next();
cursor.localize( binPos );
if ( binPos[ dim ] != dimVal )
continue;
sum += distrib.frequency( binPos );
}
return sum;
}
/**
* Returns the frequency count of all values in the distribution: lower tail
* + middle + upper tail. Does not include ignored values.
*/
public long distributionCount()
{
return distrib.totalValues();
}
/**
* Returns the frequency count of values that were ignored because they
* could not be mapped to any bin.
*/
public long ignoredCount()
{
return ignoredCount;
}
/**
* Returns the total count of all values observed; both within and without
* the entire distribution. Thus it includes ignored values. One should
* decide carefully between using distributionCount() and totalCount().
*/
public long totalCount()
{
return distributionCount() + ignoredCount();
}
/**
* Returns the frequency count of values within a bin using a set of
* representative values. Note that multiple values can be mapped to one bin
* so this is NOT the frequency count of this exact set of values in the
* distribution.
*
* @param values
* A set of representative values of interest
*/
public long frequency( final List< T > values )
{
map( values, pos );
return frequency( pos );
}
/**
* Returns the frequency count of the values within a bin.
*/
public long frequency( final long[] binPos )
{
return distrib.frequency( binPos );
}
/**
* Returns the relative frequency of values within a bin using a set of
* representative values. Note that multiple values can be mapped to one bin
* so this is NOT the relative frequency of this exact set of values in the
* distribution.
*
* This calculation is of the number of values in the bin divided by either
* the number of values in the distribution or the number of values in the
* center of the distribution (tails ignored).
*
* One can devise other ways to count relative frequencies that consider
* ignored values also. If needed one can use the various count methods and
* frequency methods to calculate any relative frequency desired.
*
* @param values
* A representative set of values of interest
* @param includeTails
* Flag for determining whether to include tails in calculation.
*/
public double relativeFrequency( final List< T > values, final boolean includeTails )
{
map( values, pos );
return relativeFrequency( pos, includeTails );
}
/**
* Returns the relative frequency of values within a bin.
*
* This calculation is of the number of values in the bin divided by either
* the number of values in the distribution or the number of values in the
* center of the distribution (tails ignored).
*
* One can devise other ways to count relative frequencies that consider
* ignored values also. If needed one can use the various count methods and
* frequency methods to calculate any relative frequency desired.
*
* @param binPos
* The position of the bin of interest
* @param includeTails
* Flag for determining whether to include tails in calculation.
*/
public double relativeFrequency( final long[] binPos, final boolean includeTails )
{
final double numer = frequency( binPos );
final long denom = includeTails ? totalCount() : valueCount();
return numer / denom;
}
/**
* Returns the number of bins contained in the histogram.
*/
public long getBinCount()
{
if ( mappers.size() == 0 )
return 0;
long count = 1;
for ( int i = 0; i < mappers.size(); i++ )
{
count *= mappers.get( i ).getBinCount();
}
return count;
}
/**
* Fills a bin position by mapping from a set of representative values.
*/
public void map( final List< T > values, final long[] binPos )
{
for ( int i = 0; i < mappers.size(); i++ )
{
binPos[ i ] = mappers.get( i ).map( values.get( i ) );
}
}
/**
* Gets the values associated with the center of a bin.
*
* @param binPos
* The bin index of interest
* @param values
* The outputs to fill with the center values
*/
public void getCenterValues( final long[] binPos, final List< T > values )
{
for ( int i = 0; i < mappers.size(); i++ )
{
final T value = values.get( i );
mappers.get( i ).getCenterValue( binPos[ i ], value );
}
}
/**
* Gets the values associated with the left edge of a bin.
*
* @param binPos
* The bin index of interest
* @param values
* The outputs to fill with the left edge values
*/
public void getLowerBounds( final long[] binPos, final List< T > values )
{
for ( int i = 0; i < mappers.size(); i++ )
{
final T value = values.get( i );
mappers.get( i ).getLowerBound( binPos[ i ], value );
}
}
/**
* Gets the values associated with the right edge of a bin.
*
* @param binPos
* The bin index of interest
* @param values
* The outputs to fill with the right edge values
*/
public void getUpperBounds( final long[] binPos, final List< T > values )
{
for ( int i = 0; i < mappers.size(); i++ )
{
final T value = values.get( i );
mappers.get( i ).getUpperBound( binPos[ i ], value );
}
}
/**
* Returns true if the given bin interval is closed on the right
*
* @param binPos
* The bin number of the interval of interest
*/
public boolean includesUpperBounds( final long[] binPos )
{
for ( int i = 0; i < mappers.size(); i++ )
{
if ( !mappers.get( i ).includesUpperBound( binPos[ i ] ) )
return false;
}
return true;
}
/**
* Returns true if the given bin interval is closed on the left
*
* @param binPos
* The bin number of the interval of interest
*/
public boolean includesLowerBounds( final long[] binPos )
{
for ( int i = 0; i < mappers.size(); i++ )
{
if ( !mappers.get( i ).includesLowerBound( binPos[ i ] ) )
return false;
}
return true;
}
/**
* Returns true if the given bin interval is closed on the right for the
* given dimension.
*
* @param dim
* The dimension of interest
* @param binPos
* The bin number of the interval of interest
*/
public boolean includesUpperBound( final int dim, final long binPos )
{
return mappers.get( dim ).includesUpperBound( binPos );
}
/**
* Returns true if the given bin interval is closed on the left for the
* given dimension.
*
* @param dim
* The dimension of interest
* @param binPos
* The bin number of the interval of interest
*/
public boolean includesLowerBound( final int dim, final long binPos )
{
return mappers.get( dim ).includesLowerBound( binPos );
}
/**
* Returns true if a given set of values are mapped to the lower tail of the
* distribution.
*
* @param values
* The set of values to determine the location of
*/
public boolean isInLowerTail( final List< T > values )
{
for ( int i = 0; i < mappers.size(); i++ )
{
if ( isInLowerTail( i, values.get( i ) ) ) { return true; }
}
return false;
}
/**
* Returns true if a given value for a given dimension is mapped to the
* lower tail of the distribution.
*
* @param dim
* The dimension number of the axis of interest
* @param value
* The value to determine the location of
*/
public boolean isInLowerTail( final int dim, final T value )
{
if ( hasTails( dim ) )
{
final long binPos = mappers.get( dim ).map( value );
if ( binPos == 0 ) { return true; }
}
return false;
}
/**
* Returns true if a given set of values are mapped to the upper tail of the
* distribution.
*
* @param values
* The set of values to determine the location of
*/
public boolean isInUpperTail( final List< T > values )
{
for ( int i = 0; i < mappers.size(); i++ )
{
if ( isInUpperTail( i, values.get( i ) ) ) { return true; }
}
return false;
}
/**
* Returns true if a given value for a given dimension is mapped to the
* upper tail of the distribution.
*
* @param dim
* The dimension number of the axis of interest
* @param value
* The value to determine the location of
*/
public boolean isInUpperTail( final int dim, final T value )
{
if ( hasTails( dim ) )
{
final long binPos = mappers.get( dim ).map( value );
if ( binPos == mappers.get( dim ).getBinCount() - 1 ) { return true; }
}
return false;
}
/**
* Returns true if a given set of values are mapped to the middle of the
* distribution.
*
* @param values
* The set of values to determine the location of
*/
public boolean isInMiddle( final List< T > values )
{
for ( int i = 0; i < mappers.size(); i++ )
{
if ( !isInMiddle( i, values.get( i ) ) ) { return false; }
}
return true;
}
/**
* Returns true if a given value for a given dimension is mapped to the
* middle of the distribution.
*
* @param dim
* The dimension number of the axis of interest
* @param value
* The value to determine the location of
*/
public boolean isInMiddle( final int dim, final T value )
{
if ( hasTails( dim ) )
{
final long binPos = mappers.get( dim ).map( value );
if ( ( binPos == 0 ) || ( binPos == mappers.get( dim ).getBinCount() - 1 ) ) { return false; }
}
return true;
}
/**
* Returns true if a given set of values are outside the distribution.
*
* @param values
* The set of values to determine the location of
*/
public boolean isOutside( final List< T > values )
{
for ( int i = 0; i < mappers.size(); i++ )
{
if ( isOutside( i, values.get( i ) ) ) { return true; }
}
return false;
}
/**
* Returns true if a given value for a given dimension is outside the
* distribution.
*
* @param value
* The value to determine the location of
*/
public boolean isOutside( final int dim, final T value )
{
final long binPos = mappers.get( dim ).map( value );
if ( ( binPos == Long.MIN_VALUE ) || ( binPos == Long.MAX_VALUE ) ) { return true; }
return false;
}
/**
* Get the discrete frequency distribution associated with this histogram.
*/
public DiscreteFrequencyDistribution dfd()
{
return distrib;
}
/**
* Counts the data contained in the given data source using the underlying
* bin distribution.
*
* @param data
* The total data to count
*/
public void countData( final Iterable< List< T >> data )
{
init( data );
}
/**
* Counts the data contained in the given data source using the underlying
* bin distribution.
*
* @param data
* The total data to count
*/
public void countData( final List< Iterable< T >> data )
{
init( data );
}
/**
* Counts additional data contained in a given iterable collection. One can
* use this to update an existing histogram with a subset of values.
*
* @param data
* The new data to count
*/
public void addData( final Iterable< List< T >> data )
{
add( data );
}
/**
* Counts additional data contained in a given iterable collection. One can
* use this to update an existing histogram with a subset of values.
*
* @param data
* The new data to count
*/
public void addData( final List< Iterable< T >> data )
{
add( data );
}
/**
* Uncounts some original data contained in a given iterable collection. One
* can use this to update an existing histogram with a subset of values.
*
* @param data
* The old data to uncount
*/
public void subtractData( final Iterable< List< T >> data )
{
subtract( data );
}
/**
* Uncounts some original data contained in a given iterable collection. One
* can use this to update an existing histogram with a subset of values.
*
* @param data
* The old data to uncount
*/
public void subtractData( final List< Iterable< T >> data )
{
subtract( data );
}
/**
* Directly increment a bin by position.
*
* @param binPos
* The 1-d index of the bin
*/
public void increment( final long[] binPos )
{
distrib.increment( binPos );
}
/**
* Directly decrement a bin by position.
*
* @param binPos
* The 1-d index of the bin
*/
public void decrement( final long[] binPos )
{
distrib.decrement( binPos );
}
/**
* Directly increment a bin by value.
*
* @param values
* The values to map to a bin position
*/
public void increment( final List< T > values )
{
count( values, incrementer );
}
/**
* Directly decrement a bin by value,
*
* @param values
* The values to map to a bin position
*/
public void decrement( final List< T > values )
{
count( values, decrementer );
}
/**
* Resets all data counts to 0.
*/
public void resetCounters()
{
reset();
}
// -- delegated Img methods --
/**
* Return the number of dimensions of the frequency distribution of this
* histogram.
*/
@Override
public int numDimensions()
{
return distrib.numDimensions();
}
/**
* Return the size of the given dimension of the frequency distribution of
* this histogram.
*/
@Override
public long dimension( final int d )
{
return distrib.dimension( d );
}
/**
* Fill the provided long[] with the sizes of all dimensions of the
* frequency distribution of this histogram.
*/
@Override
public void dimensions( final long[] dims )
{
distrib.dimensions( dims );
}
@Override
public RandomAccess< LongType > randomAccess()
{
return distrib.randomAccess();
}
@Override
public RandomAccess< LongType > randomAccess( final Interval interval )
{
return distrib.randomAccess( interval );
}
@Override
public long min( final int d )
{
return distrib.min( d );
}
@Override
public void min( final long[] min )
{
distrib.min( min );
}
@Override
public void min( final Positionable min )
{
distrib.min( min );
}
@Override
public long max( final int d )
{
return distrib.max( d );
}
@Override
public void max( final long[] max )
{
distrib.max( max );
}
@Override
public void max( final Positionable max )
{
distrib.max( max );
}
@Override
public double realMin( final int d )
{
return distrib.realMin( d );
}
@Override
public void realMin( final double[] min )
{
distrib.realMin( min );
}
@Override
public void realMin( final RealPositionable min )
{
distrib.realMin( min );
}
@Override
public double realMax( final int d )
{
return distrib.realMax( d );
}
@Override
public void realMax( final double[] max )
{
distrib.realMax( max );
}
@Override
public void realMax( final RealPositionable max )
{
distrib.realMax( max );
}
@Override
public Cursor< LongType > cursor()
{
return distrib.cursor();
}
@Override
public Cursor< LongType > localizingCursor()
{
return distrib.localizingCursor();
}
@Override
public long size()
{
return distrib.size();
}
@Override
public LongType firstElement()
{
return distrib.firstElement();
}
@Override
public Object iterationOrder()
{
return distrib.iterationOrder();
}
@Override
public Iterator< LongType > iterator()
{
return distrib.iterator();
}
@Override
public ImgFactory< LongType > factory()
{
return distrib.factory();
}
@Override
public HistogramNd< T > copy()
{
return new HistogramNd< T >( this );
}
// -- helpers --
private void reset()
{
distrib.resetCounters();
ignoredCount = 0;
}
private void init( final Iterable< List< T >> data )
{
reset();
add( data );
}
private void init( final List< Iterable< T >> data )
{
reset();
add( data );
}
private void add( final Iterable< List< T >> data )
{
modifyCounts( data, incrementer );
}
private void add( final List< Iterable< T >> data )
{
modifyCounts( data, incrementer );
}
private void subtract( final Iterable< List< T >> data )
{
modifyCounts( data, decrementer );
}
private void subtract( final List< Iterable< T >> data )
{
modifyCounts( data, decrementer );
}
private void modifyCounts( final Iterable< List< T >> data, final Counter counter )
{
final Iterator< List< T >> iter = data.iterator();
while ( iter.hasNext() )
{
count( iter.next(), counter );
}
}
private void modifyCounts( final List< Iterable< T >> data, final Counter counter )
{
final List< T > vals = new ArrayList< T >( mappers.size() );
final List< Iterator< T >> iters = new ArrayList< Iterator< T >>();
for ( int i = 0; i < data.size(); i++ )
{
iters.add( data.get( i ).iterator() );
vals.add( null );
}
boolean hasNext = true;
do
{
for ( int i = 0; i < iters.size(); i++ )
{
if ( !iters.get( i ).hasNext() )
hasNext = false;
}
if ( hasNext )
{
for ( int i = 0; i < iters.size(); i++ )
{
vals.set( i, iters.get( i ).next() );
}
count( vals, counter );
}
}
while ( hasNext );
}
private void count( final List< T > values, final Counter counter )
{
map( values, pos );
boolean ignored = false;
for ( int i = 0; i < pos.length; i++ )
{
if ( pos[ i ] == Long.MIN_VALUE || pos[ i ] == Long.MAX_VALUE )
{
ignored = true;
break;
}
}
counter.count( pos, ignored );
}
private interface Counter
{
void count( long[] pos, boolean ignored );
}
private class Decrementer implements Counter
{
@SuppressWarnings( "synthetic-access" )
@Override
public void count( final long[] position, final boolean ignored )
{
if ( ignored )
ignoredCount--;
else
distrib.decrement( position );
}
}
private class Incrementer implements Counter
{
@SuppressWarnings( "synthetic-access" )
@Override
public void count( final long[] position, final boolean ignored )
{
if ( ignored )
ignoredCount++;
else
distrib.increment( position );
}
}
}