Skip to content

gradientCentralDifference sets wrong boundaries for random accesses #42

@hanslovsky

Description

@hanslovsky

I encountered ArrayIndexOufOfBoundsException in calls to PartialDerivative.gradientCentralDifference. I was able to make minimum working example that reproduced that behavior:

import net.imglib2.algorithm.gradient.PartialDerivative;
import net.imglib2.cache.img.CellLoader;
import net.imglib2.cache.img.DiskCachedCellImg;
import net.imglib2.cache.img.DiskCachedCellImgFactory;
import net.imglib2.cache.img.DiskCachedCellImgOptions;
import net.imglib2.type.numeric.real.FloatType;
import net.imglib2.view.Views;

public class PartialDerivativeBug
{

	public static void main( final String[] args )
	{

		final long[] dim = new long[] { 200, 300, 400 };

		final DiskCachedCellImgOptions opts = DiskCachedCellImgOptions.options().cellDimensions( 64, 64, 64 ).dirtyAccesses( false ).maxCacheSize( 100 );

		final DiskCachedCellImgFactory< FloatType > factory = new DiskCachedCellImgFactory<>( opts );

		final CellLoader< FloatType > loader1 = img -> {

		};

		final DiskCachedCellImg< FloatType, ? > img1 = factory.create( dim, new FloatType(), loader1 );

		final CellLoader< FloatType > loader2 = img -> {
			PartialDerivative.gradientCentralDifference( Views.extendBorder( img1 ), img, 2 );
		};

		final DiskCachedCellImg< FloatType, ? > gradient = factory.create( dim, new FloatType(), loader2 );

		for ( final FloatType g : gradient )
			g.get();


	}

}

This code throws the following Exception:

Exception in thread "main" java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: -4096
	at net.imglib2.cache.util.CacheAsUncheckedCacheAdapter.get(CacheAsUncheckedCacheAdapter.java:32)
	at net.imglib2.img.cell.LazyCellImg$LazyCells.get(LazyCellImg.java:78)
	at net.imglib2.img.list.AbstractLongListImg$LongListCursor.get(AbstractLongListImg.java:98)
	at net.imglib2.img.cell.CellCursor.getCell(CellCursor.java:94)
	at net.imglib2.img.cell.CellCursor.moveToNextCell(CellCursor.java:182)
	at net.imglib2.img.cell.CellCursor.reset(CellCursor.java:152)
	at net.imglib2.img.cell.CellCursor.<init>(CellCursor.java:88)
	at net.imglib2.img.cell.AbstractCellImg.cursor(AbstractCellImg.java:92)
	at net.imglib2.img.cell.AbstractCellImg.cursor(AbstractCellImg.java:51)
	at net.imglib2.img.AbstractImg.iterator(AbstractImg.java:75)
	at de.hanslovsky.zspacing.spark.experiments.visualization.PartialDerivativeBug.main(PartialDerivativeBug.java:35)
Caused by: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: -4096
	at net.imglib2.cache.ref.SoftRefLoaderRemoverCache.get(SoftRefLoaderRemoverCache.java:168)
	at net.imglib2.cache.util.LoaderRemoverCacheAsLoaderCacheAdapter.get(LoaderRemoverCacheAsLoaderCacheAdapter.java:37)
	at net.imglib2.cache.util.LoaderCacheAsCacheAdapter.get(LoaderCacheAsCacheAdapter.java:30)
	at net.imglib2.cache.util.CacheAsUncheckedCacheAdapter.get(CacheAsUncheckedCacheAdapter.java:28)
	... 10 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: -4096
	at net.imglib2.img.basictypeaccess.array.AbstractFloatArray.getValue(AbstractFloatArray.java:61)
	at net.imglib2.type.numeric.real.FloatType.get(FloatType.java:115)
	at net.imglib2.type.numeric.real.FloatType.sub(FloatType.java:198)
	at net.imglib2.type.numeric.real.FloatType.sub(FloatType.java:50)
	at net.imglib2.algorithm.gradient.PartialDerivative.gradientCentralDifference(PartialDerivative.java:198)
	at de.hanslovsky.zspacing.spark.experiments.visualization.PartialDerivativeBug.lambda$1(PartialDerivativeBug.java:30)
	at net.imglib2.cache.img.LoadedCellCacheLoader.get(LoadedCellCacheLoader.java:82)
	at net.imglib2.cache.img.LoadedCellCacheLoader.get(LoadedCellCacheLoader.java:44)
	at net.imglib2.cache.img.DiskCellCache.get(DiskCellCache.java:104)
	at net.imglib2.cache.img.DiskCellCache.get(DiskCellCache.java:43)
	at net.imglib2.cache.IoSync.get(IoSync.java:174)
	at net.imglib2.cache.ref.SoftRefLoaderRemoverCache.get(SoftRefLoaderRemoverCache.java:158)
	... 13 more

gradientCentralDifference tries to get the most efficient RandomAccesses by specifying the required intervals for the forward and backward terms of the finite difference sum:
https://github.com/imglib/imglib2-algorithm/blob/master/src/main/java/net/imglib2/algorithm/gradient/PartialDerivative.java#L183-L184
As far as I can tell, the specifications for the required intervals are wrong, though: back and front should be translated by -1 and 1, respectively. Currently, it is the other way round. As some implementations of RandomAccessible delegate randomAccess( Interval ) to randomAccess(), this issue does not happen a lot, in practice.

I will make a fix for this.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions