package com.acme.fourier; import church.lang.Array; import church.lang.Array.$CreateArray; import church.lang.JavaClasses.$Java_class; import church.lang.operators.Arithmetic.*; import church.math.Complex; import church.primitives.Integers; import static church.lang.Array.length; import static church.lang.operators.Arithmetic.*; import static church.math.Complex.complex; import static java.lang.Math.*; @SuppressWarnings("unchecked") public class Fourier { private static final $$rem<Integer> $S0 = Integers::$rem; private static final $Java_class<Complex<Double>> $S1 = () -> (Class<Complex<Double>>) (Object) Complex.class; private static final $CreateArray<Complex<Double>> $S2 = Array.createArray($S1); public static interface $Evens<T> { public T[] evens(T[] a); } public static <T> $Evens<T> evens($CreateArray<T> $L0) { return a -> $L0.createArray((length(a) / 2), i -> a[(2 * i)]); } public static interface $Odds<T> { public T[] odds(T[] a); } public static <T> $Odds<T> odds($CreateArray<T> $L0) { return a -> $L0.createArray(((length(a) + 1) / 2), i -> a[((2 * i) + 1)]); } public static interface $Transform_rec<T, U> { public U[] transform_rec(church.lang.Functions.Function1<Integer, T> exp, U[] vec, int stride); } public static <T, U> $Transform_rec<T, U> transform_rec($Evens<U> $L0, $Odds<U> $L1, $CreateArray<U> $L2, $$sum<U> $L3, $$prd<T, U> $L4) { return new $Transform_rec<T, U>() { public U[] transform_rec(church.lang.Functions.Function1<Integer, T> exp, U[] vec, int stride) { int N = length(vec); if (N == 1) { return vec; } U[] evens0 = transform_rec(exp, $L0.evens(vec), (2 * stride)); U[] odds0 = transform_rec(exp, $L1.odds(vec), (2 * stride)); int halfN = (N / 2); return $L2.createArray(vec.length, i -> { int k = $S0.$rem(i, halfN); return $L3.$sum(evens0[k], $L4.$prd(exp.of((stride * i)), odds0[k])); }); } }; } public static Complex<Double> exp_2PI_i(double i, double N) { double theta = (((2.0 * PI) * i) / N); return complex(cos(theta), sin(theta)); } public static interface $Transform<T> { public T[] transform(T[] v); } public static <T> $Transform<T> transform($Transform_rec<Complex<Double>, T> $L0) { return v -> { int N = length(v); Complex<Double>[] expCache = $S2.createArray(N, i -> exp_2PI_i(i, N)); return $L0.transform_rec(i -> expCache[$S0.$rem(i, N)], v, 1); }; } }