package gdsc.smlm.filters;
import gdsc.smlm.TestSettings;
import java.util.ArrayList;
import org.junit.Assert;
import org.junit.Test;
public class AreaAverageFilterTest
{
private gdsc.core.utils.Random rand;
private boolean debug = false;
private int ITER = 100;
private int InternalITER = 300;
// TODO - The test data should be representative of the final use case
int[] primes = new int[] { 113, 97, 53, 29 };
//int[] primes = new int[] { 1024 };
float[] boxSizes = new float[] { 15.5f, 9.5f, 5.5f, 3.5f, 2.5f, 1.5f, 0.5f };
private float[] createData(int width, int height)
{
float[] data = new float[width * height];
for (int i = data.length; i-- > 0;)
data[i] = rand.next();
return data;
}
private double speedUpFactor(long slowTotal, long fastTotal)
{
return (1.0 * slowTotal) / fastTotal;
}
@Test
public void areaAverageUsingSumsNxNInternalIsFasterThanAreaAverageNxNInternal()
{
org.junit.Assume.assumeTrue(TestSettings.RUN_SPEED_TESTS);
rand = new gdsc.core.utils.Random(-300519);
AreaAverageFilter filter = new AreaAverageFilter();
ArrayList<float[]> dataSet = createSpeedData(InternalITER);
ArrayList<Long> fastTimes = new ArrayList<Long>();
// Initialise
for (float boxSize : boxSizes)
{
filter.areaAverageUsingAveragesInternal(dataSet.get(0).clone(), primes[0], primes[0], boxSize);
filter.areaAverageUsingSumsInternal(dataSet.get(0).clone(), primes[0], primes[0], boxSize);
}
for (float boxSize : boxSizes)
for (int width : primes)
for (int height : primes)
{
ArrayList<float[]> dataSet2 = new ArrayList<float[]>(dataSet.size());
for (float[] data : dataSet)
dataSet2.add(data.clone());
long time = System.nanoTime();
for (float[] data : dataSet2)
filter.areaAverageUsingSumsInternal(data, width, height, boxSize);
time = System.nanoTime() - time;
fastTimes.add(time);
}
long slowTotal = 0, fastTotal = 0;
int index = 0;
for (float boxSize : boxSizes)
{
long boxSlowTotal = 0, boxFastTotal = 0;
for (int width : primes)
for (int height : primes)
{
ArrayList<float[]> dataSet2 = new ArrayList<float[]>(dataSet.size());
for (float[] data : dataSet)
dataSet2.add(data.clone());
long time = System.nanoTime();
for (float[] data : dataSet2)
filter.areaAverageUsingAveragesInternal(data, width, height, boxSize);
time = System.nanoTime() - time;
long fastTime = fastTimes.get(index++);
slowTotal += time;
fastTotal += fastTime;
boxSlowTotal += time;
boxFastTotal += fastTime;
if (debug)
System.out
.printf("float areaAverageInternal [%dx%d] @ %.1f : %d => areaAverageUsingSumsInternal %d = %.2fx\n",
width, height, boxSize, time, fastTime, speedUpFactor(time, fastTime));
//if (TestSettings.ASSERT_SPEED_TESTS) Assert.assertTrue(String.format("Not faster: [%dx%d] @ %d : %d > %d", width, height, boxSize,
// blockTime, time), blockTime < time);
}
//if (debug)
System.out.printf("float areaAverageInternal %.1f : %d => areaAverageUsingSumsInternal %d = %.2fx\n",
boxSize, boxSlowTotal, boxFastTotal, speedUpFactor(boxSlowTotal, boxFastTotal));
if (TestSettings.ASSERT_SPEED_TESTS)
Assert.assertTrue(String.format("Not faster: Block %d : %d > %d", boxSize, boxFastTotal, boxSlowTotal),
boxFastTotal < boxSlowTotal);
}
System.out.printf("float areaAverageInternal %d => areaAverageUsingSumsInternal %d = %.2fx\n", slowTotal,
fastTotal, speedUpFactor(slowTotal, fastTotal));
if (TestSettings.ASSERT_SPEED_TESTS)
Assert.assertTrue(String.format("Not faster: %d > %d", fastTotal, slowTotal), fastTotal < slowTotal);
}
@Test
public void stripedBlockAverageIsFasterThanAreaAverage()
{
org.junit.Assume.assumeTrue(TestSettings.RUN_SPEED_TESTS);
rand = new gdsc.core.utils.Random(-300519);
AreaAverageFilter filter = new AreaAverageFilter();
AverageFilter filter2 = new AverageFilter();
ArrayList<float[]> dataSet = createSpeedData(ITER);
ArrayList<Long> fastTimes = new ArrayList<Long>();
// Initialise
for (float boxSize : boxSizes)
{
filter.areaAverageUsingAverages(dataSet.get(0).clone(), primes[0], primes[0], boxSize);
filter2.stripedBlockAverage(dataSet.get(0).clone(), primes[0], primes[0], boxSize);
}
for (float boxSize : boxSizes)
for (int width : primes)
for (int height : primes)
{
ArrayList<float[]> dataSet2 = new ArrayList<float[]>(dataSet.size());
for (float[] data : dataSet)
dataSet2.add(data.clone());
long time = System.nanoTime();
for (float[] data : dataSet2)
filter2.stripedBlockAverage(data, width, height, boxSize);
time = System.nanoTime() - time;
fastTimes.add(time);
}
long slowTotal = 0, fastTotal = 0;
int index = 0;
for (float boxSize : boxSizes)
{
long boxSlowTotal = 0, boxFastTotal = 0;
for (int width : primes)
for (int height : primes)
{
ArrayList<float[]> dataSet2 = new ArrayList<float[]>(dataSet.size());
for (float[] data : dataSet)
dataSet2.add(data.clone());
long time = System.nanoTime();
for (float[] data : dataSet2)
filter.areaAverageUsingAverages(data, width, height, boxSize);
time = System.nanoTime() - time;
long fastTime = fastTimes.get(index++);
slowTotal += time;
fastTotal += fastTime;
boxSlowTotal += time;
boxFastTotal += fastTime;
if (debug)
System.out
.printf("float areaAverageUsingAverages [%dx%d] @ %.1f : %d => stripedBlockAverage %d = %.2fx\n",
width, height, boxSize, time, fastTime, speedUpFactor(time, fastTime));
//if (TestSettings.ASSERT_SPEED_TESTS) Assert.assertTrue(String.format("Not faster: [%dx%d] @ %d : %d > %d", width, height, boxSize,
// blockTime, time), blockTime < time);
}
//if (debug)
System.out.printf("float areaAverageUsingAverages %.1f : %d => stripedBlockAverage %d = %.2fx\n",
boxSize, boxSlowTotal, boxFastTotal, speedUpFactor(boxSlowTotal, boxFastTotal));
if (TestSettings.ASSERT_SPEED_TESTS)
Assert.assertTrue(String.format("Not faster: Block %d : %d > %d", boxSize, boxFastTotal, boxSlowTotal),
boxFastTotal < boxSlowTotal);
}
System.out.printf("float areaAverageUsingAverages %d => stripedBlockAverage %d = %.2fx\n", slowTotal,
fastTotal, speedUpFactor(slowTotal, fastTotal));
if (TestSettings.ASSERT_SPEED_TESTS)
Assert.assertTrue(String.format("Not faster: %d > %d", fastTotal, slowTotal), fastTotal < slowTotal);
}
@Test
public void stripedBlockAverageInternalIsFasterThanAreaAverageInternal()
{
org.junit.Assume.assumeTrue(TestSettings.RUN_SPEED_TESTS);
rand = new gdsc.core.utils.Random(-300519);
AreaAverageFilter filter = new AreaAverageFilter();
AverageFilter filter2 = new AverageFilter();
ArrayList<float[]> dataSet = createSpeedData(InternalITER);
ArrayList<Long> fastTimes = new ArrayList<Long>();
// Initialise
for (float boxSize : boxSizes)
{
filter.areaAverageUsingAveragesInternal(dataSet.get(0).clone(), primes[0], primes[0], boxSize);
filter2.stripedBlockAverageInternal(dataSet.get(0).clone(), primes[0], primes[0], boxSize);
}
for (float boxSize : boxSizes)
for (int width : primes)
for (int height : primes)
{
ArrayList<float[]> dataSet2 = new ArrayList<float[]>(dataSet.size());
for (float[] data : dataSet)
dataSet2.add(data.clone());
long time = System.nanoTime();
for (float[] data : dataSet2)
filter2.stripedBlockAverageInternal(data, width, height, boxSize);
time = System.nanoTime() - time;
fastTimes.add(time);
}
long slowTotal = 0, fastTotal = 0;
int index = 0;
for (float boxSize : boxSizes)
{
long boxSlowTotal = 0, boxFastTotal = 0;
for (int width : primes)
for (int height : primes)
{
ArrayList<float[]> dataSet2 = new ArrayList<float[]>(dataSet.size());
for (float[] data : dataSet)
dataSet2.add(data.clone());
long time = System.nanoTime();
for (float[] data : dataSet2)
filter.areaAverageUsingAveragesInternal(data, width, height, boxSize);
time = System.nanoTime() - time;
long fastTime = fastTimes.get(index++);
slowTotal += time;
fastTotal += fastTime;
boxSlowTotal += time;
boxFastTotal += fastTime;
if (debug)
System.out
.printf("float areaAverageUsingAveragesInternal [%dx%d] @ %.1f : %d => stripedBlockAverageInternal %d = %.2fx\n",
width, height, boxSize, time, fastTime, speedUpFactor(time, fastTime));
//if (TestSettings.ASSERT_SPEED_TESTS) Assert.assertTrue(String.format("Not faster: [%dx%d] @ %d : %d > %d", width, height, boxSize,
// blockTime, time), blockTime < time);
}
//if (debug)
System.out.printf("float areaAverageUsingAveragesInternal %.1f : %d => stripedBlockAverageInternal %d = %.2fx\n",
boxSize, boxSlowTotal, boxFastTotal, speedUpFactor(boxSlowTotal, boxFastTotal));
if (TestSettings.ASSERT_SPEED_TESTS)
Assert.assertTrue(String.format("Not faster: Block %d : %d > %d", boxSize, boxFastTotal, boxSlowTotal),
boxFastTotal < boxSlowTotal);
}
System.out.printf("float areaAverageUsingAveragesInternal %d => stripedBlockAverageInternal %d = %.2fx\n", slowTotal,
fastTotal, speedUpFactor(slowTotal, fastTotal));
if (TestSettings.ASSERT_SPEED_TESTS)
Assert.assertTrue(String.format("Not faster: %d > %d", fastTotal, slowTotal), fastTotal < slowTotal);
}
private ArrayList<float[]> createSpeedData(int iter)
{
ArrayList<float[]> dataSet = new ArrayList<float[]>(iter);
for (int i = iter; i-- > 0;)
{
dataSet.add(createData(primes[0], primes[0]));
}
return dataSet;
}
@Test
public void areaAverageCorrectlyInterpolatesBetweenBlocks()
{
rand = new gdsc.core.utils.Random(-30051976);
int max = 50;
float[] data = createData(max, max);
AreaAverageFilter filter = new AreaAverageFilter();
int n = 30;
float[][] results = new float[n + 1][];
double[] w = new double[n + 1];
int count = 0;
for (int i = 0; i <= n; i++)
{
w[count] = i / 10.0;
results[count] = data.clone();
filter.areaAverageUsingAverages(results[count], max, max, w[count]);
count++;
}
checkInterpolation(max, n, w, results, count);
}
public void checkInterpolation(int max, int n, double[] w, float[][] results, int count)
{
// Pick some points and see if they are monototically interpolated between integer blocks
int[] p = new int[] { 10, 20, 30, 40 };
for (int x : p)
{
for (int y : p)
{
int index = y * max + x;
double[] yy = new double[count];
int c = 0;
for (float[] data1 : results)
{
yy[c++] = data1[index];
}
//// Debugging
//String title = "AreaAverage";
//ij.gui.Plot plot = new ij.gui.Plot(title, "width", "Mean", w, yy);
//gdsc.core.ij.Utils.display(title, plot);
for (int i = 0; i < n; i += 10)
{
boolean up = yy[i + 10] > yy[i];
for (int j = i + 1; j < i + 10; j++)
{
if (up)
{
Assert.assertTrue(yy[j] >= yy[j - 1]);
Assert.assertTrue(yy[j] <= yy[j + 1]);
}
else
{
Assert.assertTrue(yy[j] <= yy[j - 1]);
Assert.assertTrue(yy[j] >= yy[j + 1]);
}
}
}
}
}
}
@Test
public void areaAverageInternalCorrectlyInterpolatesBetweenBlocks()
{
rand = new gdsc.core.utils.Random(-30051976);
int max = 50;
float[] data = createData(max, max);
AreaAverageFilter filter = new AreaAverageFilter();
int n = 30;
float[][] results = new float[n + 1][];
double[] w = new double[n + 1];
int count = 0;
for (int i = 0; i <= n; i++)
{
w[count] = i / 10.0;
results[count] = data.clone();
filter.areaAverageUsingAveragesInternal(results[count], max, max, w[count]);
count++;
}
checkInterpolation(max, n, w, results, count);
}
@Test
public void areaAverageUsingSumsCorrectlyInterpolatesBetweenBlocks()
{
rand = new gdsc.core.utils.Random(-30051976);
int max = 50;
float[] data = createData(max, max);
AreaAverageFilter filter = new AreaAverageFilter();
filter.setSimpleInterpolation(false);
int n = 30;
float[][] results = new float[n + 1][];
double[] w = new double[n + 1];
int count = 0;
for (int i = 0; i <= n; i++)
{
w[count] = i / 10.0;
results[count] = data.clone();
filter.areaAverageUsingSums(results[count], max, max, w[count]);
count++;
}
checkInterpolation(max, n, w, results, count);
}
@Test
public void areaAverageUsingSumsInternalCorrectlyInterpolatesBetweenBlocks()
{
rand = new gdsc.core.utils.Random(-30051976);
int max = 50;
float[] data = createData(max, max);
AreaAverageFilter filter = new AreaAverageFilter();
filter.setSimpleInterpolation(false);
int n = 30;
float[][] results = new float[n + 1][];
double[] w = new double[n + 1];
int count = 0;
for (int i = 0; i <= n; i++)
{
w[count] = i / 10.0;
results[count] = data.clone();
filter.areaAverageUsingSumsInternal(results[count], max, max, w[count]);
count++;
}
checkInterpolation(max, n, w, results, count);
}
}