1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.transform;
23
24 import org.hipparchus.analysis.UnivariateFunction;
25 import org.hipparchus.analysis.function.Sin;
26 import org.hipparchus.analysis.function.Sinc;
27 import org.hipparchus.exception.LocalizedCoreFormats;
28 import org.hipparchus.exception.MathIllegalArgumentException;
29 import org.hipparchus.exception.MathIllegalStateException;
30 import org.hipparchus.util.FastMath;
31 import org.junit.jupiter.params.ParameterizedTest;
32 import org.junit.jupiter.params.provider.MethodSource;
33
34 import java.util.Arrays;
35 import java.util.Collection;
36
37 import static org.junit.jupiter.api.Assertions.assertEquals;
38 import static org.junit.jupiter.api.Assertions.fail;
39
40
41
42
43
44
45
46
47 public final class FastCosineTransformerTest
48 extends RealTransformerAbstractTest<DctNormalization> {
49
50 private DctNormalization normalization;
51
52 private int[] invalidDataSize;
53
54 private double[] relativeTolerance;
55
56 private int[] validDataSize;
57
58 public void initFastCosineTransformerTest(final DctNormalization normalization) {
59 this.normalization = normalization;
60 this.validDataSize = new int[] {
61 2, 3, 5, 9, 17, 33, 65, 129
62 };
63 this.invalidDataSize = new int[] {
64 128
65 };
66 this.relativeTolerance = new double[] {
67 1E-15, 1E-15, 1E-14, 1E-13, 1E-13, 1E-12, 1E-11, 1E-10
68 };
69 }
70
71 @Override
72 void init(DctNormalization normalization) {
73 initFastCosineTransformerTest(normalization);
74 }
75
76
77
78
79
80
81
82 public static Collection<Object[]> data() {
83 final DctNormalization[] normalization = DctNormalization.values();
84 final Object[][] data = new DctNormalization[normalization.length][1];
85 for (int i = 0; i < normalization.length; i++){
86 data[i][0] = normalization[i];
87 }
88 return Arrays.asList(data);
89 }
90
91 @Override
92 RealTransformer createRealTransformer() {
93 return new FastCosineTransformer(normalization);
94 }
95
96 @Override
97 int getInvalidDataSize(final int i) {
98 return invalidDataSize[i];
99 }
100
101 @Override
102 int getNumberOfInvalidDataSizes() {
103 return invalidDataSize.length;
104 }
105
106 @Override
107 int getNumberOfValidDataSizes() {
108 return validDataSize.length;
109 }
110
111 @Override
112 double getRelativeTolerance(final int i) {
113 return relativeTolerance[i];
114 }
115
116 @Override
117 int getValidDataSize(final int i) {
118 return validDataSize[i];
119 }
120
121 @Override
122 UnivariateFunction getValidFunction() {
123 return new Sinc();
124 }
125
126 @Override
127 double getValidLowerBound() {
128 return 0.0;
129 }
130
131 @Override
132 double getValidUpperBound() {
133 return FastMath.PI;
134 }
135
136 @Override
137 double[] transform(final double[] x, final TransformType type) {
138 final int n = x.length;
139 final double[] y = new double[n];
140 final double[] cos = new double[2 * (n - 1)];
141 for (int i = 0; i < cos.length; i++) {
142 cos[i] = FastMath.cos(FastMath.PI * i / (n - 1.0));
143 }
144 int sgn = 1;
145 for (int j = 0; j < n; j++) {
146 double yj = 0.5 * (x[0] + sgn * x[n - 1]);
147 for (int i = 1; i < n - 1; i++) {
148 yj += x[i] * cos[(i * j) % cos.length];
149 }
150 y[j] = yj;
151 sgn *= -1;
152 }
153 final double s;
154 if (type == TransformType.FORWARD) {
155 if (normalization == DctNormalization.STANDARD_DCT_I) {
156 s = 1.0;
157 } else if (normalization == DctNormalization.ORTHOGONAL_DCT_I) {
158 s = FastMath.sqrt(2.0 / (n - 1.0));
159 } else {
160 throw new MathIllegalStateException(LocalizedCoreFormats.ILLEGAL_STATE);
161 }
162 } else if (type == TransformType.INVERSE) {
163 if (normalization == DctNormalization.STANDARD_DCT_I) {
164 s = 2.0 / (n - 1.0);
165 } else if (normalization == DctNormalization.ORTHOGONAL_DCT_I) {
166 s = FastMath.sqrt(2.0 / (n - 1.0));
167 } else {
168 throw new MathIllegalStateException(LocalizedCoreFormats.ILLEGAL_STATE);
169 }
170 } else {
171
172
173
174
175 throw new MathIllegalStateException(LocalizedCoreFormats.ILLEGAL_STATE);
176 }
177 TransformUtils.scaleArray(y, s);
178 return y;
179 }
180
181
182
183
184
185
186 @MethodSource("data")
187 @ParameterizedTest
188 void testParameters(final DctNormalization normalization)
189 throws Exception {
190 initFastCosineTransformerTest(normalization);
191 UnivariateFunction f = new Sin();
192 FastCosineTransformer transformer;
193 transformer = new FastCosineTransformer(DctNormalization.STANDARD_DCT_I);
194
195 try {
196
197 transformer.transform(f, 1, -1, 65, TransformType.FORWARD);
198 fail("Expecting MathIllegalArgumentException - bad interval");
199 } catch (MathIllegalArgumentException ex) {
200
201 }
202 try {
203
204 transformer.transform(f, -1, 1, 1, TransformType.FORWARD);
205 fail("Expecting MathIllegalArgumentException - bad samples number");
206 } catch (MathIllegalArgumentException ex) {
207
208 }
209 try {
210
211 transformer.transform(f, -1, 1, 64, TransformType.FORWARD);
212 fail("Expecting MathIllegalArgumentException - bad samples number");
213 } catch (MathIllegalArgumentException ex) {
214
215 }
216 }
217
218
219 @MethodSource("data")
220 @ParameterizedTest
221 void testSinFunction(final DctNormalization normalization) {
222 initFastCosineTransformerTest(normalization);
223 UnivariateFunction f = new Sin();
224 FastCosineTransformer transformer;
225 transformer = new FastCosineTransformer(DctNormalization.STANDARD_DCT_I);
226 double min;
227 double max;
228 double[] result;
229 double tolerance = 1E-12;
230 int N = 9;
231
232 double[] expected =
233 {
234 0.0, 3.26197262739567, 0.0, -2.17958042710327, 0.0,
235 -0.648846697642915, 0.0, -0.433545502649478, 0.0
236 };
237 min = 0.0;
238 max = 2.0 * FastMath.PI * N / (N - 1);
239 result = transformer.transform(f, min, max, N, TransformType.FORWARD);
240 for (int i = 0; i < N; i++) {
241 assertEquals(expected[i], result[i], tolerance);
242 }
243
244 min = -FastMath.PI;
245 max = FastMath.PI * (N + 1) / (N - 1);
246 result = transformer.transform(f, min, max, N, TransformType.FORWARD);
247 for (int i = 0; i < N; i++) {
248 assertEquals(-expected[i], result[i], tolerance);
249 }
250 }
251
252
253 @MethodSource("data")
254 @ParameterizedTest
255 void testAdHocData(final DctNormalization normalization) {
256 initFastCosineTransformerTest(normalization);
257 FastCosineTransformer transformer;
258 transformer = new FastCosineTransformer(DctNormalization.STANDARD_DCT_I);
259 double[] result;
260 double tolerance = 1E-12;
261
262 double[] x = {
263 0.0, 1.0, 4.0, 9.0, 16.0, 25.0, 36.0, 49.0, 64.0
264 };
265 double[] y =
266 {
267 172.0, -105.096569476353, 27.3137084989848, -12.9593152353742,
268 8.0, -5.78585076868676, 4.68629150101524, -4.15826451958632,
269 4.0
270 };
271
272 result = transformer.transform(x, TransformType.FORWARD);
273 for (int i = 0; i < result.length; i++) {
274 assertEquals(y[i], result[i], tolerance);
275 }
276
277 result = transformer.transform(y, TransformType.INVERSE);
278 for (int i = 0; i < result.length; i++) {
279 assertEquals(x[i], result[i], tolerance);
280 }
281
282 TransformUtils.scaleArray(x, FastMath.sqrt(0.5 * (x.length - 1)));
283
284 transformer = new FastCosineTransformer(DctNormalization.ORTHOGONAL_DCT_I);
285 result = transformer.transform(y, TransformType.FORWARD);
286 for (int i = 0; i < result.length; i++) {
287 assertEquals(x[i], result[i], tolerance);
288 }
289
290 result = transformer.transform(x, TransformType.INVERSE);
291 for (int i = 0; i < result.length; i++) {
292 assertEquals(y[i], result[i], tolerance);
293 }
294 }
295 }