1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.math4.transform;
18
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.function.DoubleUnaryOperator;
22
23 import org.junit.Assert;
24 import org.junit.Test;
25 import org.junit.runner.RunWith;
26 import org.junit.runners.Parameterized;
27 import org.junit.runners.Parameterized.Parameters;
28
29 import org.apache.commons.math3.analysis.UnivariateFunction;
30 import org.apache.commons.math3.analysis.function.Sin;
31 import org.apache.commons.math3.analysis.function.Sinc;
32
33
34
35
36
37
38
39 @RunWith(value = Parameterized.class)
40 public final class FastSineTransformerTest extends RealTransformerAbstractTest {
41
42 private final FastSineTransform.Norm normalization;
43
44 private final int[] invalidDataSize;
45
46 private final double[] relativeTolerance;
47
48 private final int[] validDataSize;
49
50 public FastSineTransformerTest(final FastSineTransform.Norm normalization) {
51 this.normalization = normalization;
52 this.validDataSize = new int[] {
53 1, 2, 4, 8, 16, 32, 64, 128
54 };
55 this.invalidDataSize = new int[] {
56 129
57 };
58 this.relativeTolerance = new double[] {
59 1e-15, 1e-15, 1e-14, 1e-14, 1e-13, 1e-12, 1e-11, 1e-11
60 };
61 }
62
63
64
65
66
67
68
69 @Parameters
70 public static Collection<Object[]> data() {
71 final FastSineTransform.Norm[] normalization = FastSineTransform.Norm.values();
72 final Object[][] data = new FastSineTransform.Norm[normalization.length][1];
73 for (int i = 0; i < normalization.length; i++) {
74 data[i][0] = normalization[i];
75 }
76 return Arrays.asList(data);
77 }
78
79
80
81
82
83
84
85 @Override
86 double[] createRealData(final int n) {
87 final double[] data = super.createRealData(n);
88 data[0] = 0;
89 return data;
90 }
91
92 @Override
93 RealTransform createRealTransformer(boolean inverse) {
94 return new FastSineTransform(normalization, inverse);
95 }
96
97 @Override
98 int getInvalidDataSize(final int i) {
99 return invalidDataSize[i];
100 }
101
102 @Override
103 int getNumberOfInvalidDataSizes() {
104 return invalidDataSize.length;
105 }
106
107 @Override
108 int getNumberOfValidDataSizes() {
109 return validDataSize.length;
110 }
111
112 @Override
113 double getRelativeTolerance(final int i) {
114 return relativeTolerance[i];
115 }
116
117 @Override
118 int getValidDataSize(final int i) {
119 return validDataSize[i];
120 }
121
122 @Override
123 DoubleUnaryOperator getValidFunction() {
124 final UnivariateFunction sinc = new Sinc();
125 return x -> sinc.value(x);
126 }
127
128 @Override
129 double getValidLowerBound() {
130 return 0.0;
131 }
132
133 @Override
134 double getValidUpperBound() {
135 return Math.PI;
136 }
137
138 @Override
139 double[] transform(final double[] x, boolean inverse) {
140 final int n = x.length;
141 final double[] y = new double[n];
142 final double[] sin = new double[2 * n];
143 for (int i = 0; i < sin.length; i++) {
144 sin[i] = Math.sin(Math.PI * i / n);
145 }
146 for (int j = 0; j < n; j++) {
147 double yj = 0.0;
148 for (int i = 0; i < n; i++) {
149 yj += x[i] * sin[(i * j) % sin.length];
150 }
151 y[j] = yj;
152 }
153 final double s;
154 if (!inverse) {
155 if (normalization == FastSineTransform.Norm.STD) {
156 s = 1;
157 } else if (normalization == FastSineTransform.Norm.ORTHO) {
158 s = Math.sqrt(2d / n);
159 } else {
160 throw new IllegalStateException();
161 }
162 } else {
163 if (normalization == FastSineTransform.Norm.STD) {
164 s = 2d / n;
165 } else if (normalization == FastSineTransform.Norm.ORTHO) {
166 s = Math.sqrt(2d / n);
167 } else {
168 throw new IllegalStateException();
169 }
170 }
171
172 TransformUtils.scaleInPlace(y, s);
173 return y;
174 }
175
176
177
178 @Test
179 public void testTransformRealFirstElementNotZero() {
180 final double[] data = new double[] {
181 1, 1, 1, 1
182 };
183 for (boolean type : new boolean[] {true, false}) {
184 try {
185 final RealTransform transformer = createRealTransformer(type);
186 transformer.apply(data);
187 Assert.fail("type=" + type);
188 } catch (IllegalArgumentException e) {
189
190 }
191 }
192 }
193
194
195
196
197
198
199 @Test
200 public void testAdHocData() {
201 FastSineTransform transformer;
202 double tolerance = 1e-12;
203
204 final double[] x = {
205 0, 1, 2, 3, 4, 5, 6, 7
206 };
207 final double[] y = {
208 0.0, 20.1093579685034, -9.65685424949238,
209 5.98642305066196, -4.0, 2.67271455167720,
210 -1.65685424949238, 0.795649469518633
211 };
212
213 transformer = new FastSineTransform(FastSineTransform.Norm.STD);
214 double[] result = transformer.apply(x);
215 for (int i = 0; i < result.length; i++) {
216 Assert.assertEquals(y[i], result[i], tolerance);
217 }
218
219 transformer = new FastSineTransform(FastSineTransform.Norm.STD, true);
220 result = transformer.apply(y);
221 for (int i = 0; i < result.length; i++) {
222 Assert.assertEquals(x[i], result[i], tolerance);
223 }
224
225 TransformUtils.scaleInPlace(x, Math.sqrt(x.length / 2d));
226 transformer = new FastSineTransform(FastSineTransform.Norm.ORTHO);
227
228 result = transformer.apply(y);
229 for (int i = 0; i < result.length; i++) {
230 Assert.assertEquals(x[i], result[i], tolerance);
231 }
232
233 transformer = new FastSineTransform(FastSineTransform.Norm.ORTHO, true);
234 result = transformer.apply(x);
235 for (int i = 0; i < result.length; i++) {
236 Assert.assertEquals(y[i], result[i], tolerance);
237 }
238 }
239
240
241
242
243 @Test
244 public void testSinFunction() {
245 final UnivariateFunction sinFunction = new Sin();
246 final DoubleUnaryOperator f = x -> sinFunction.value(x);
247 final FastSineTransform transformer = new FastSineTransform(FastSineTransform.Norm.STD);
248 double tolerance = 1e-12;
249 int size = 1 << 8;
250
251 double min = 0.0;
252 double max = 2 * Math.PI;
253 double[] result = transformer.apply(f, min, max, size);
254 Assert.assertEquals(size >> 1, result[2], tolerance);
255 for (int i = 0; i < size; i += i == 1 ? 2 : 1) {
256 Assert.assertEquals(0.0, result[i], tolerance);
257 }
258
259 min = -Math.PI;
260 max = Math.PI;
261 result = transformer.apply(f, min, max, size);
262 Assert.assertEquals(-(size >> 1), result[2], tolerance);
263 for (int i = 0; i < size; i += i == 1 ? 2 : 1) {
264 Assert.assertEquals(0.0, result[i], tolerance);
265 }
266 }
267
268
269
270
271 @Test
272 public void testParameters() throws Exception {
273 final UnivariateFunction sinFunction = new Sin();
274 final DoubleUnaryOperator f = x -> sinFunction.value(x);
275 final FastSineTransform transformer = new FastSineTransform(FastSineTransform.Norm.STD);
276
277 try {
278
279 transformer.apply(f, 1, -1, 64);
280 Assert.fail("Expecting IllegalArgumentException - bad interval");
281 } catch (IllegalArgumentException ex) {
282
283 }
284 try {
285
286 transformer.apply(f, -1, 1, 0);
287 Assert.fail("Expecting IllegalArgumentException - bad samples number");
288 } catch (IllegalArgumentException ex) {
289
290 }
291 try {
292
293 transformer.apply(f, -1, 1, 100);
294 Assert.fail("Expecting IllegalArgumentException - bad samples number");
295 } catch (IllegalArgumentException ex) {
296
297 }
298 }
299 }