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

example.Transforms 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.Fill;
import nom.bdezonia.zorbage.algorithm.FixedTransform2a;
import nom.bdezonia.zorbage.algorithm.FixedTransform2b;
import nom.bdezonia.zorbage.algorithm.Map;
import nom.bdezonia.zorbage.algorithm.ParallelTransform4;
import nom.bdezonia.zorbage.algorithm.Reduce;
import nom.bdezonia.zorbage.algorithm.Transform2;
import nom.bdezonia.zorbage.algorithm.Transform3;
import nom.bdezonia.zorbage.datasource.IndexedDataSource;
import nom.bdezonia.zorbage.procedure.Procedure2;
import nom.bdezonia.zorbage.procedure.Procedure3;
import nom.bdezonia.zorbage.procedure.Procedure4;
import nom.bdezonia.zorbage.storage.array.ArrayStorage;
import nom.bdezonia.zorbage.storage.sparse.SparseStorage;
import nom.bdezonia.zorbage.type.complex.float16.ComplexFloat16Member;
import nom.bdezonia.zorbage.type.integer.int16.SignedInt16Member;
import nom.bdezonia.zorbage.type.integer.int6.SignedInt6Member;
import nom.bdezonia.zorbage.type.real.float16.Float16Member;
import nom.bdezonia.zorbage.type.real.float32.Float32Member;
import nom.bdezonia.zorbage.type.real.float64.Float64Member;

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

	// Zorbage has a handful of transformation classes that sets destination data to
	// arbitrary combinations of input data.
	
	// One thing to be on the lookout for: many transforms can take multiple lists
	// of different data types and combine them into results. The combination is
	// done by a Procedure defined by you and the sky is the limit here. Below are
	// a couple such examples. Another nice part of this different data types design
	// is that user defined types beyond what Zorbage provides can use this api.
	
	// Basic transforms: Transform1, Trandform2, Transform3, Transform4
	//
	//   y = f(a,b,...)
	//
	//   Example with lists of the same type
	
	void example1() {
		
		// make a list of 1000 half precision numbers
		
		IndexedDataSource a =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.HLF.construct(), 1000);
		
		// set them to random values
		
		Fill.compute(G.HLF, G.HLF.random(), a);
		
		// make another list of the same size
		
		IndexedDataSource b =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.HLF.construct(), a.size());
		
		// set all of them to the mathematical constant E
		
		Fill.compute(G.HLF, G.HLF.E(), b);
		
		// allocate space for the results
		
		IndexedDataSource results =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.HLF.construct(), a.size());
		
		// set the results to the elementwise multiplication of a and b
		
		Transform3.compute(G.HLF, G.HLF.multiply(), a, b, results);
	}
	
	// Basic transforms: Transform1, Trandform2, Transform3, Transform4
	//
	//   Example with lists of different types
	
	void example2() {

		// create a list of complex numbers
		
		IndexedDataSource a =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.CHLF.construct(), 1000);

		// fill it with random values
		
		Fill.compute(G.CHLF, G.CHLF.random(), a);
		
		// create a similarly sized list of real values
		
		IndexedDataSource results =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.HLF.construct(), a.size());
		
		// copy the real values of the inputs to the results
		
		Procedure2 grabReals =
				new Procedure2()
		{
			@Override
			public void call(ComplexFloat16Member a, Float16Member b) {
				a.getR(b);
			}
		};

		Transform2.compute(G.CHLF, G.HLF, grabReals, a, results);

		// or
		
		// copy the imaginary values of the inputs to the results

		Procedure2 grabImags =
				new Procedure2()
		{
			@Override
			public void call(ComplexFloat16Member a, Float16Member b) {
				a.getI(b);
			}
		};

		Transform2.compute(G.CHLF, G.HLF, grabImags, a, results);
		
	}
	
	// Parallel transforms: ParallelTransform1, ParallelTransform2, ParallelTransform3, etc.
	//
	//   Use multiple threads to transform data quickly
	
	void example3() {

		// allocate a list
		
		IndexedDataSource a =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.DBL.construct(), 250000);
		
		// set all values in it to the mathematical constant PI
		
		Fill.compute(G.DBL, G.DBL.PI(), a);
		
		// allocate a second list
		
		IndexedDataSource b =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.DBL.construct(), a.size());
		
		// set all values in it to the mathematical constant E
		
		Fill.compute(G.DBL, G.DBL.E(), b);
		
		// allocate a third list
		
		IndexedDataSource c =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.DBL.construct(), a.size());
		
		// set all the values in it to random numbers between 0 and 1
		
		Fill.compute(G.DBL, G.DBL.random(), c);

		// allocate a list to hold the results
		
		IndexedDataSource results =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.DBL.construct(), a.size());
	
		// define a procedure that combines 3 data elements in a nonlinear fashion
		//
		//   d = 3.0*a^3 - 1.5*b^2 - 5.0*c + 17.0
		
		Procedure4 proc =
				new Procedure4()
		{
			@Override
			public void call(Float64Member a, Float64Member b, Float64Member c, Float64Member d) {
				double value = 3.0*a.v()*a.v()*a.v() - 1.5*b.v()*b.v() - 5.0*c.v() + 17;
				d.setV(value);
			}
		};
		
		// combine the data into results using as many threads as can be allocated to the app
		
		ParallelTransform4.compute(G.DBL, proc, a, b, c, results);
	}
	
	// Fixed transforms
	//
	//   Sometimes you want to transform data by passing in a list and a single value that
	//   can be thought of as a parameter. The parameter is combined with every element in
	//   the input data list and populates the output list. Zorbage has a couple of these:
	//   FixedTransform2a and FixedTransform2b. They differ only in whether the passed value
	//   is considered the left input argument or the right input argument. For most cases
	//   it does not make a difference which you choose. But imagine you want to subtract
	//   a value from a list of values. In this case it is easiest to treat the value as the
	//   second parameter and pass the already defined subtract() method of the appropriate
	//   algebra.
	
	void example5() {
		
		// create a list
		
		IndexedDataSource data =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.FLT.construct(), new float[27000]);

		// elsewhere : fill it with values
		
		// create a results list
		
		IndexedDataSource results =
				ArrayStorage.allocate(G.FLT.construct(), data.size());

		// set results to the scaling by 4.5 of the input data
		
		// 2a
		
		FixedTransform2a.compute(G.FLT, new Float32Member(4.5f), G.FLT.multiply(), data, results);
		
		// 2b: exact same results with this approach
		
		FixedTransform2b.compute(G.FLT, new Float32Member(4.5f), G.FLT.multiply(), data, results);
		
		// now here is a case where the order matters: subtract 4.5

		// 2a : result = 4.5 - input
		
		FixedTransform2a.compute(G.FLT, new Float32Member(4.5f), G.FLT.subtract(), data, results);

		// 2b : result = input - 4.5
		
		FixedTransform2b.compute(G.FLT, new Float32Member(4.5f), G.FLT.subtract(), data, results);
		
	}
	
	// Map
	//
	//   The Map algorithm is not exactly a Transform but it is similar enough that
	//   explaining it here makes sense. A map operation is common to many functional
	//   programming languages. You take an input list and create an output list
	//   by applying a transformation from the inputs to the outputs. Zorbage allows
	//   you to define transformations easily and in quite an open ended fashion.

	@SuppressWarnings("unused")
	void example6() {
		
		// define some input data
		
		IndexedDataSource input = SparseStorage.allocate(G.INT6.construct(), 1000);
		
		// elsewhere fill it with data
		
		// define a procedure that transforms INT6 data to FLT data
		
		Procedure2 proc =
				new Procedure2()
		{
			@Override
			public void call(SignedInt6Member a, Float32Member b) {

				b.setV(3f * a.v()); // scale by 3: not the most realistic example
			}
		};
		
		// get a resulting list which is the application of the procedure to every
		// element of the input list
		
		IndexedDataSource result = Map.compute(G.INT6, G.FLT, proc, input);
	}
	
	// Reduce
	//
	//   The Reduce algorithm is also not exactly a Transform. But it works hand in hand with
	//   Map and it does transform a list of values to a single value. This is another algo
	//   that is common in functional programming.
	
	void example7() {
		
		// define some input data
		
		IndexedDataSource input =
				nom.bdezonia.zorbage.storage.Storage.allocate(G.INT16.construct(), 
				new short[] {1,3,5,8,12,55,101}
				);
		
		SignedInt16Member reduction = G.INT16.construct();

		// reduce by summing values
		
		Reduce.compute(G.INT16, G.INT16.add(), input, reduction);  // reduction = 1+3+5+8+12+55+101
		
		// reduce by multiplying values
		
		Reduce.compute(G.INT16, G.INT16.multiply(), input, reduction);  // reduction = 1*3*5*8*12*55*101

		// Let's do a compound interest problem by defining our own code. Imagine money compounds at an
		// 8% annual interest rate. And we are going to deposit funds once every month and compound
		// monthly. How much money will we have at the end?
		
		IndexedDataSource monthlyDeposits =
				nom.bdezonia.zorbage.storage.Storage.allocate(
						G.DBL.construct(), 
						new double[] {1000,1250,500,300,0,475,950,200}
				);
		
		Procedure3 grow =
				new Procedure3()
		{
			@Override
			public void call(Float64Member a, Float64Member b, Float64Member c) {
				// calc the growth
				double newValue = (1 + 0.08/12)*a.v() + b.v();
				// now round to nearest cent
				newValue = Math.round(newValue * 100);
				newValue = newValue / 100;
				// and set output value
				c.setV(newValue);
			}
		};
		
		Float64Member balance = G.DBL.construct();
		
		Reduce.compute(G.DBL, grow, monthlyDeposits, balance);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy