/*
 * Zorbage: an algebraic data hierarchy for use in numeric processing.
 *
 * Copyright (C) 2016-2017 Barry DeZonia
 * 
 * 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.
 */
package zorbage.example;

import zorbage.type.data.ComplexFloat64Group;
import zorbage.type.data.ComplexFloat64Member;
import zorbage.type.data.SignedInt32Member;
import zorbage.type.storage.LinearStorage;
import zorbage.type.storage.linear.array.ArrayStorageComplexFloat64;
import zorbage.type.storage.linear.array.ArrayStorageSignedInt32;

/**
 * 
 * @author Barry DeZonia
 *
 */
public class DFTExample {

	private ComplexFloat64Group g = new ComplexFloat64Group();
	
	public void run() {
		final int size = 500;
		LinearStorage<?,SignedInt32Member> inputData = makeIntData(size);
		fillIntData(inputData);
		LinearStorage<?,ComplexFloat64Member> outputComplexData = makeComplexData(size);
		dft(inputData, outputComplexData);
	}
	
	
	private LinearStorage<?,SignedInt32Member> makeIntData(int size) {
		return new ArrayStorageSignedInt32(size);
	}
	
	private LinearStorage<?,ComplexFloat64Member> makeComplexData(int size) {
		return new ArrayStorageComplexFloat64(size);
	}
	
	private void fillIntData(LinearStorage<?,SignedInt32Member> input) {
		// an example of straight index access to low level data
		SignedInt32Member value = new SignedInt32Member();
		int count = 0;
		for (int i = 0; i < input.size(); i++) {
			value.setV(count++);
			input.set(i, value);
		}
	}
	
	// algorithm from https://users.cs.cf.ac.uk/Dave.Marshall/Multimedia/node228.html
	
	// note this could be further optimized by doing some multiplication in reals rather than complexes
	
	private void dft(LinearStorage<?,SignedInt32Member> input, LinearStorage<?,ComplexFloat64Member> output) {
		ComplexFloat64Member FofU = new ComplexFloat64Member();
		ComplexFloat64Member fOfX = new ComplexFloat64Member();
		ComplexFloat64Member sum = new ComplexFloat64Member();
		ComplexFloat64Member term = new ComplexFloat64Member();
		ComplexFloat64Member multiplier = new ComplexFloat64Member();
		ComplexFloat64Member power = new ComplexFloat64Member();
		ComplexFloat64Member uTmp = new ComplexFloat64Member();
		ComplexFloat64Member xTmp = new ComplexFloat64Member();
		ComplexFloat64Member I = new ComplexFloat64Member(0,1);
		ComplexFloat64Member MINUS_2 = new ComplexFloat64Member(-2,0);
		ComplexFloat64Member N = new ComplexFloat64Member(input.size(), 0);
		ComplexFloat64Member E = new ComplexFloat64Member();
		ComplexFloat64Member PI = new ComplexFloat64Member();
		SignedInt32Member in = new SignedInt32Member();
		
		g.E(E);
		g.PI(PI);
		
		for (int u = 0; u < input.size(); u++) {
			g.zero(sum);
			uTmp.setR(u);
			for (int x = 0; x < input.size(); x++) {
				input.get(x, in);
				fOfX.setR(in.v());
				xTmp.setR(x);
				g.multiply(MINUS_2, PI, power);
				g.multiply(power, I, power);
				g.multiply(power, xTmp, power);
				g.multiply(power, uTmp, power);
				g.divide(power, N, power);
				g.exp(power, multiplier);
				g.multiply(fOfX, multiplier, term);
				g.add(sum, term, sum);
			}
			g.divide(sum, N, FofU);
			output.set(u, FofU);
		}
	}

}

@@ -1862,17 +1862,20 @@
 64Group 
-g
+cdbl
  = new C
@@ -3832,17 +3832,20 @@
 );%0A%09%09%0A%09%09
-g
+cdbl
 .E(E);%0A%09
@@ -3845,17 +3845,20 @@
 E(E);%0A%09%09
-g
+cdbl
 .PI(PI);
@@ -3907,17 +3907,20 @@
 +) %7B%0A%09%09%09
-g
+cdbl
 .zero(su
@@ -4047,25 +4047,28 @@
 etR(x);%0A%09%09%09%09
-g
+cdbl
 .multiply(MI
@@ -4082,33 +4082,36 @@
 PI, power);%0A%09%09%09%09
-g
+cdbl
 .multiply(power,
@@ -4118,33 +4118,36 @@
  I, power);%0A%09%09%09%09
-g
+cdbl
 .multiply(power,
@@ -4157,33 +4157,36 @@
 mp, power);%0A%09%09%09%09
-g
+cdbl
 .multiply(power,
@@ -4204,17 +4204,20 @@
 r);%0A%09%09%09%09
-g
+cdbl
 .divide(
@@ -4238,17 +4238,20 @@
 r);%0A%09%09%09%09
-g
+cdbl
 .exp(pow
@@ -4271,17 +4271,20 @@
 r);%0A%09%09%09%09
-g
+cdbl
 .multipl
@@ -4314,17 +4314,20 @@
 m);%0A%09%09%09%09
-g
+cdbl
 .add(sum
@@ -4348,17 +4348,20 @@
 %09%09%09%7D%0A%09%09%09
-g
+cdbl
 .divide(

Make example code clearer