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

example.OutOfBoundsData Maven / Gradle / Ivy

/*
 * Zorbage: an algebraic data hierarchy for use in numeric processing.
 *
 * Copyright (c) 2016-2021 Barry DeZonia All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 * Redistributions of source code must retain the above copyright notice, this list
 * of conditions and the following disclaimer.
 * 
 * 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.
 * 
 * Neither the name of the  nor the names of its contributors may
 * be used to endorse or promote products derived from this software without specific
 * prior written permission.
 * 
 * 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  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.
 */
package example;

import nom.bdezonia.zorbage.algebra.G;
import nom.bdezonia.zorbage.algorithm.ConvolveND;
import nom.bdezonia.zorbage.algorithm.FFT;
import nom.bdezonia.zorbage.algorithm.Fill;
import nom.bdezonia.zorbage.data.DimensionedDataSource;
import nom.bdezonia.zorbage.data.DimensionedStorage;
import nom.bdezonia.zorbage.data.ProcedurePaddedDimensionedDataSource;
import nom.bdezonia.zorbage.datasource.FixedSizeDataSource;
import nom.bdezonia.zorbage.datasource.IndexedDataSource;
import nom.bdezonia.zorbage.datasource.ProcedurePaddedDataSource;
import nom.bdezonia.zorbage.oob.nd.ConstantNdOOB;
import nom.bdezonia.zorbage.oob.nd.CyclicNdOOB;
import nom.bdezonia.zorbage.oob.nd.EdgeNdOOB;
import nom.bdezonia.zorbage.oob.nd.MirrorNdOOB;
import nom.bdezonia.zorbage.oob.nd.NanNdOOB;
import nom.bdezonia.zorbage.oob.nd.ZeroNdOOB;
import nom.bdezonia.zorbage.oob.oned.ConstantOOB;
import nom.bdezonia.zorbage.oob.oned.CyclicOOB;
import nom.bdezonia.zorbage.oob.oned.EdgeOOB;
import nom.bdezonia.zorbage.oob.oned.MirrorOOB;
import nom.bdezonia.zorbage.oob.oned.NanOOB;
import nom.bdezonia.zorbage.oob.oned.ZeroOOB;
import nom.bdezonia.zorbage.type.complex.float32.ComplexFloat32Member;
import nom.bdezonia.zorbage.type.real.float32.Float32Algebra;
import nom.bdezonia.zorbage.type.real.float32.Float32Member;

/**
 * @author Barry DeZonia
 */
class OutOfBoundsData {

	/*
	 * Sometimes you use an algorithm that can query data point values which are out of
	 * the bounds of the dataset of interest. Zorbage provides a mechanism for padding
	 * datasets so that (probably neutral) values can pass through an algorithm without
	 * corrupting the output values.
	 */
	
	/*
	 * This can be apparent in 1-d datasets if you consider the case of finding the FFT
	 * of a dataset. The current FFT algorithm requires an input dataset whose length
	 * is a power of 2. In order to pass any size list of data to the FFT algorithm
	 * Zorbage allows you to pad a dataset with appropriate values. Then you wrap the
	 * dataset so that any observer thinks its list's length is a power of two. Maybe
	 * an example will be helpful here.
	 */
	
	void example1() {
		
		// Make an unusual size list
		
		IndexedDataSource data =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.CFLT.construct(), 413);

		// 413
		long weirdSize = data.size();
		
		// 512
		long perfectSize = FFT.enclosingPowerOf2(weirdSize);
		
		// Fill our input list with random data
		
		Fill.compute(G.CFLT, G.CFLT.random(), data);
		
		// Now make sure querying it outside its bounds will return the value zero. The
		// ZeroOOB procedure does the heavy lifting. The ProcedurePaddedDataSource returns
		// values from its underlying data source when the coordinates queried are within
		// its bounds and returns the result from a procedure call when they are out.
		
		IndexedDataSource paddedData =
				new ProcedurePaddedDataSource<>(
						G.CFLT,
						data,
						new ZeroOOB<>(G.CFLT, data.size()));
		
		// The FFT wants a power of two size. make the list have a perfect size.
		
		IndexedDataSource perfectSizedData =
				new FixedSizeDataSource<>(perfectSize, paddedData);
		
		// Allocate the destination data list
		
		IndexedDataSource fftData =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.CFLT.construct(), perfectSize);
		
		// The fft algorithm will hit every location (0 to 511). The out of bounds procedure
		// will return 0 when the original data is queried beyond location 412. The extra
		// zero values will have no effect on the final results
		
		FFT.compute(G.CFLT, G.FLT, perfectSizedData, fftData);
	}
	
	// There are other predefined 1-d out of bounds behaviors. Here is a quick tour of them.
	
	@SuppressWarnings("unused")
	void example2() {
		
		IndexedDataSource data =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.FLT.construct(), 100);

		// pad with a constant like 0.4
		
		IndexedDataSource constantPad =
				new ProcedurePaddedDataSource<>(
						G.FLT,
						data,
						new ConstantOOB<>(G.FLT, data.size(), G.FLT.construct("0.4")));

		// pad in a cyclic fashion
		//   imagine list = [0, 1, 2, 3]
		//   then with cyclic oob
		//     list[3] == 3
		//     list[4] == 0
		//     list[5] == 1
		//     list[6] == 2
		//     list[7] == 3
		//     list[8] == 0
		//     list[9] == 1
		
		IndexedDataSource cyclicPad =
				new ProcedurePaddedDataSource<>(
						G.FLT,
						data,
						new CyclicOOB<>(data));
		
		// pad from the edges
		//   imagine list = [1, 2, 3, 4]
		//   then with edge oob
		//     etc.
		//     list[-2] == 1
		//     list[-1] == 1
		//     list[0] == 1
		//     list[1] == 2
		//     list[2] == 3
		//     list[3] == 4
		//     list[4] == 4
		//     list[5] == 4
		//     etc.
		
		IndexedDataSource edgePad =
				new ProcedurePaddedDataSource<>(
						G.FLT,
						data,
						new EdgeOOB<>(data));
		
		// pad in a mirrored fashion
		//   imagine list = [1, 2, 3, 4]
		//   then with mirrored oob
		//     etc.
		//     list[-6] == 3
		//     list[-5] == 4
		//     list[-4] == 4
		//     list[-3] == 3
		//     list[-2] == 2
		//     list[-1] == 1
		//     list[0] == 1
		//     list[1] == 2
		//     list[2] == 3
		//     list[3] == 4
		//     list[4] == 4
		//     list[5] == 3
		//     list[4] == 2
		//     list[5] == 1
		//     list[4] == 1
		//     list[5] == 2
		//     etc.
		
		IndexedDataSource mirrorPad =
				new ProcedurePaddedDataSource<>(
						G.FLT,
						data,
						new MirrorOOB<>(data));
		

		// pad with NaN
		
		IndexedDataSource nanPad =
				new ProcedurePaddedDataSource<>(
						G.FLT,
						data,
						new NanOOB<>(G.FLT, data.size()));
		
		// pad with 0.0
		
		IndexedDataSource zeroPad =
				new ProcedurePaddedDataSource<>(
						G.FLT,
						data,
						new ZeroOOB<>(G.FLT, data.size()));

	}
	
	/*
	 * Zorbage has similar capabilities in the n-d domain rather than 1-d domain. One 
	 * example where these become useful is when doing convolutions on n-d datasets.
	 */
	
	void example3() {
	
		// original dims of input data
		
		long[] dims = new long[] {640,480};
		
		// make input
		
		DimensionedDataSource input =
				DimensionedStorage.allocate(G.FLT.construct(), dims);
		
		// assume here we've filled it with some values
		
		// now pad it so id we request an out of bounds pixel we get a 0
		
		ProcedurePaddedDimensionedDataSource paddedInput = 
				new ProcedurePaddedDimensionedDataSource<>(
						G.FLT,
						input,
						new ZeroNdOOB<>(G.FLT, input));
		
		// make an output dataset that has the same dims as the original dataset
		
		DimensionedDataSource output =
				DimensionedStorage.allocate(G.FLT.construct(), dims);
		
		// make a 3x3 convolution filter
		
		DimensionedDataSource filter =
				DimensionedStorage.allocate(G.FLT.construct(), new long[] {3,3});
		
		// assume we've set the nine filter values to something sensible
		
		// run a convolution. the convolve algorithm will slide the window around on the
		// padded image and will poke outside the bounds of the original image. the padded
		// image just returns zero for these places. and this has no effect on the computed
		// output values.
		
		ConvolveND.compute(G.FLT, filter, paddedInput, output);
	}
	
	// There are other predefined n-d out of bounds behaviors. Here is a quick tour of them.
	// Note that their behavior matches their 1-d counterparts documented above. The
	// following code just shows you how to construct them.
	
	@SuppressWarnings("unused")
	void example4() {
		
		// make input
		
		DimensionedDataSource input =
				DimensionedStorage.allocate(G.FLT.construct(), new long[] {1024, 1024});
		
		// make constant padded input
		
		DimensionedDataSource constantPad =
				new ProcedurePaddedDimensionedDataSource<>(
						G.FLT,
						input,
						new ConstantNdOOB<>(G.FLT, input, G.FLT.construct("1.3")));
		
		// make cyclic padded input
		
		DimensionedDataSource cyclicPad =
				new ProcedurePaddedDimensionedDataSource<>(
						G.FLT,
						input,
						new CyclicNdOOB<>(input));
		
		// make edge padded input
		
		DimensionedDataSource edgePad =
				new ProcedurePaddedDimensionedDataSource<>(
						G.FLT,
						input,
						new EdgeNdOOB<>(input));
		
		// make mirror padded input
		
		DimensionedDataSource mirrorPad =
				new ProcedurePaddedDimensionedDataSource<>(
						G.FLT,
						input,
						new MirrorNdOOB<>(input));
		
		// make NaN padded input
		
		DimensionedDataSource nanPad =
				new ProcedurePaddedDimensionedDataSource<>(
						G.FLT,
						input,
						new NanNdOOB<>(G.FLT, input));
		
		// make zero padded input
		
		DimensionedDataSource zeroPad =
				new ProcedurePaddedDimensionedDataSource<>(
						G.FLT,
						input,
						new ZeroNdOOB<>(G.FLT, input));
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy