1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.renderscript.cts;
18 
19 import android.renderscript.*;
20 import java.lang.Float;
21 import java.lang.Math;
22 import java.util.Arrays;
23 import java.util.Random;
24 
25 public class ReduceTest extends RSBaseCompute {
26     private ScriptC_reduce mScript;
27 
28     @Override
setUp()29     protected void setUp() throws Exception {
30         super.setUp();
31         mScript = new ScriptC_reduce(mRS);
32         mScript.set_negInf(Float.NEGATIVE_INFINITY);
33         mScript.set_posInf(Float.POSITIVE_INFINITY);
34         mScript.invoke_setInfsHalf(RSUtils.FLOAT16_NEGATIVE_INFINITY, RSUtils.FLOAT16_POSITIVE_INFINITY);
35     }
36 
37     ///////////////////////////////////////////////////////////////////
38 
assertEquals(final float[] javaRslt, final float[] rsRslt)39     private void assertEquals(final float[] javaRslt, final float[] rsRslt) {
40         assertEquals("length", javaRslt.length, rsRslt.length);
41         for (int i = 0; i < javaRslt.length; ++i)
42             assertEquals(String.valueOf(i), javaRslt[i], rsRslt[i]);
43     }
44 
assertEquals(final short[] javaRslt, final short[] rsRslt)45     private void assertEquals(final short[] javaRslt, final short[] rsRslt) {
46         assertEquals("length", javaRslt.length, rsRslt.length);
47         for (int i = 0; i < javaRslt.length; ++i)
48             assertEquals(String.valueOf(i), javaRslt[i], rsRslt[i]);
49     }
50 
assertEquals(final Short2[] javaRslt, final Short2[] rsRslt)51     private void assertEquals(final Short2[] javaRslt, final Short2[] rsRslt) {
52         assertEquals("length", javaRslt.length, rsRslt.length);
53         for (int i = 0; i < javaRslt.length; ++i)
54             assertEquals(String.valueOf(i), javaRslt[i], rsRslt[i]);
55     }
56 
assertEquals(final String msg, final Float2 javaRslt, final Float2 rsRslt)57     private void assertEquals(final String msg, final Float2 javaRslt, final Float2 rsRslt) {
58         assertEquals(msg + "(x)", javaRslt.x, rsRslt.x);
59         assertEquals(msg + "(y)", javaRslt.y, rsRslt.y);
60     }
61 
assertEquals(final Float2 javaRslt, final Float2 rsRslt)62     private void assertEquals(final Float2 javaRslt, final Float2 rsRslt) {
63         assertEquals("", javaRslt, rsRslt);
64     }
65 
assertEquals(final String msg, final Int2 javaRslt, final Int2 rsRslt)66     private void assertEquals(final String msg, final Int2 javaRslt, final Int2 rsRslt) {
67         assertEquals(msg + "(x)", javaRslt.x, rsRslt.x);
68         assertEquals(msg + "(y)", javaRslt.y, rsRslt.y);
69     }
70 
assertEquals(final Int2 javaRslt, final Int2 rsRslt)71     private void assertEquals(final Int2 javaRslt, final Int2 rsRslt) {
72         assertEquals("", javaRslt, rsRslt);
73     }
74 
assertEquals(final String msg, final Short2 javaRslt, final Short2 rsRslt)75     private void assertEquals(final String msg, final Short2 javaRslt, final Short2 rsRslt) {
76         assertEquals(msg + "(x)", javaRslt.x, rsRslt.x);
77         assertEquals(msg + "(y)", javaRslt.y, rsRslt.y);
78     }
79 
assertEquals(final Short2 javaRslt, final Short2 rsRslt)80     private void assertEquals(final Short2 javaRslt, final Short2 rsRslt) {
81         assertEquals("", javaRslt, rsRslt);
82     }
83 
84     // Create a zero-initialized Allocation.
85     // 1D: ylen == 0, zlen == 0
86     // 2D: ylen != 0, zlen == 0
87     // 3D: ylen != 0, zlen != 0
createInputAllocation(Element elt, int xlen, int ylen, int zlen)88     private Allocation createInputAllocation(Element elt, int xlen, int ylen, int zlen) {
89         assertTrue(xlen >= 1);
90         assertTrue((zlen==0) || (ylen >= 1));
91 
92         Allocation alloc;
93 
94         if (zlen != 0)
95             alloc = Allocation.createTyped(mRS, Type.createXYZ(mRS, elt, xlen, ylen, zlen));
96         else if (ylen != 0)
97             alloc = Allocation.createTyped(mRS, Type.createXY(mRS, elt, xlen, ylen));
98         else
99             alloc = Allocation.createSized(mRS, elt, xlen);
100         if (elt.getVectorSize() == 3)
101             alloc.setAutoPadding(true);
102 
103         byte[] init = new byte[alloc.getBytesSize()];
104         Arrays.fill(init, (byte)0);
105         alloc.copyFromUnchecked(init);
106         return alloc;
107     }
108 
109     // Create an arry of zero-initialized Allocations of various dimensions --
110     // all possible 1D, 2D, and 3D Allocations where no dimension exceeds max.
createInputAllocations(Element elt, int max)111     private Allocation[] createInputAllocations(Element elt, int max) {
112         // 1D Allocations: { 1..max }
113         // 2D Allocations: { 1..max }^2
114         // 3D Allocations: { 1..max }^3
115         final int numAllocs = max + max*max + max*max*max;
116         Allocation alloc[] = new Allocation[numAllocs];
117         int count = 0;
118         for (int xlen = 1; xlen <= max; ++xlen) {
119             for (int ylen = 0; ylen <= max; ++ylen) {
120                 final int zlim = ((ylen!=0) ? max : 0);
121                 for (int zlen = 0; zlen <= zlim; ++zlen)
122                     alloc[count++] = createInputAllocation(elt, xlen, ylen, zlen);
123             }
124         }
125         assertTrue(count == numAllocs);
126         return alloc;
127     }
128 
createInputArrayByte(int len, int seed)129     private static byte[] createInputArrayByte(int len, int seed) {
130         byte[] array = new byte[len];
131         (new Random(seed)).nextBytes(array);
132         return array;
133     }
134 
createInputArrayHalf(int len, int seed)135     private static short[] createInputArrayHalf(int len, int seed) {
136         short[] array = new short[len];
137         RSUtils.genRandomFloat16s(seed, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, array,
138             false);
139         return array;
140     }
141 
createInputArrayFloat(int len, int seed)142     private static float[] createInputArrayFloat(int len, int seed) {
143         Random rand = new Random(seed);
144         float[] array = new float[len];
145         for (int i = 0; i < len; ++i)
146             array[i] = rand.nextFloat();
147         return array;
148     }
149 
createInputArrayInt(int len, int seed)150     private static int[] createInputArrayInt(int len, int seed) {
151         Random rand = new Random(seed);
152         int[] array = new int[len];
153         for (int i = 0; i < len; ++i)
154             array[i] = rand.nextInt();
155         return array;
156     }
157 
createInputArrayInt(int len, int seed, int eltRange)158     private static int[] createInputArrayInt(int len, int seed, int eltRange) {
159         Random rand = new Random(seed);
160         int[] array = new int[len];
161         for (int i = 0; i < len; ++i)
162             array[i] = rand.nextInt(eltRange);
163         return array;
164     }
165 
166     ///////////////////////////////////////////////////////////////////
167 
addint(final int[] input)168     private int addint(final int[] input) {
169         int rslt = 0;
170         for (int idx = 0; idx < input.length; ++idx)
171             rslt += input[idx];
172         return rslt;
173     }
174 
testAddInt1D()175     public void testAddInt1D() {
176         final int[] input = createInputArrayInt(100000, 0, 1 << 13);
177 
178         final int javaRslt = addint(input);
179         final int rsRslt = mScript.reduce_addint(input).get();
180 
181         assertEquals(javaRslt, rsRslt);
182     }
183 
testAddInt2D()184     public void testAddInt2D() {
185         final int dimX = 450, dimY = 225;
186 
187         final int[] inputArray = createInputArrayInt(dimX * dimY, 1, 1 << 13);
188         Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32(mRS));
189         typeBuilder.setX(dimX).setY(dimY);
190         Allocation inputAllocation = Allocation.createTyped(mRS, typeBuilder.create());
191         inputAllocation.copy2DRangeFrom(0, 0, dimX, dimY, inputArray);
192 
193         final int javaRslt = addint(inputArray);
194         final int rsRslt = mScript.reduce_addint(inputAllocation).get();
195 
196         assertEquals(javaRslt, rsRslt);
197     }
198 
199     ///////////////////////////////////////////////////////////////////
200 
findMinAndMax(final float[] input)201     private Int2 findMinAndMax(final float[] input) {
202         float minVal = Float.POSITIVE_INFINITY;
203         int minIdx = -1;
204         float maxVal = Float.NEGATIVE_INFINITY;
205         int maxIdx = -1;
206 
207         for (int idx = 0; idx < input.length; ++idx) {
208             if (input[idx] < minVal) {
209                 minVal = input[idx];
210                 minIdx = idx;
211             }
212             if (input[idx] > maxVal) {
213                 maxVal = input[idx];
214                 maxIdx = idx;
215             }
216         }
217 
218         return new Int2(minIdx, maxIdx);
219     }
220 
testFindMinAndMax()221     public void testFindMinAndMax() {
222         final float[] input = createInputArrayFloat(100000, 4);
223 
224         final Int2 javaRslt = findMinAndMax(input);
225         final Int2 rsRslt = mScript.reduce_findMinAndMax(input).get();
226 
227         // Note that the Java and RenderScript algorithms are not
228         // guaranteed to find the same cells -- but they should
229         // find cells of the same value.
230         final Float2 javaVal = new Float2(input[javaRslt.x], input[javaRslt.y]);
231         final Float2 rsVal = new Float2(input[rsRslt.x], input[rsRslt.y]);
232 
233         assertEquals(javaVal, rsVal);
234     }
235 
236     ///////////////////////////////////////////////////////////////////
237 
findMinAndMaxHalf(final short[] inputArray)238     private Short2 findMinAndMaxHalf(final short[] inputArray) {
239         Allocation inputAllocation = Allocation.createSized(mRS, Element.F16(mRS), inputArray.length);
240         inputAllocation.copyFrom(inputArray);
241 
242         Allocation outputAllocation = Allocation.createSized(mRS, Element.F16_2(mRS), 1);
243 
244         mScript.invoke_findMinAndMaxHalf(outputAllocation, inputAllocation);
245 
246         short[] outputArray = new short[2];
247         outputAllocation.copyTo(outputArray);
248         return new Short2(outputArray[0], outputArray[1]);
249     }
250 
findMinAndMaxHalfIntoArray(final short[] inputArray)251     private short[] findMinAndMaxHalfIntoArray(final short[] inputArray) {
252         final Short2 vectorResult = findMinAndMaxHalf(inputArray);
253         final short[] arrayResult = new short[] { vectorResult.x, vectorResult.y };
254         return arrayResult;
255     }
256 
testFindMinAndMaxHalf()257     public void testFindMinAndMaxHalf() {
258         // fewer members in the array than there are distinct half values
259         final short[] input = createInputArrayHalf(1000, 23);
260 
261         // test Short2 result
262         final Short2 javaRslt = findMinAndMaxHalf(input);
263         final Short2 rsRslt = mScript.reduce_findMinAndMaxHalf(input).get();
264         assertEquals(javaRslt, rsRslt);
265 
266         // test short[2] result
267         final short[] javaRsltIntoArray = findMinAndMaxHalfIntoArray(input);
268         final short[] rsRsltIntoArray = mScript.reduce_findMinAndMaxHalfIntoArray(input).get();
269         assertEquals(javaRsltIntoArray, rsRsltIntoArray);
270     }
271 
272     ///////////////////////////////////////////////////////////////////
273 
274     // The input is a flattened representation of an array of 2-vector
findMinAndMaxHalf2(final short[] inputArray)275     private Short2[] findMinAndMaxHalf2(final short[] inputArray) {
276         assertEquals(inputArray.length % 2, 0);
277 
278         Allocation inputAllocation = Allocation.createSized(mRS, Element.F16_2(mRS), inputArray.length / 2);
279         inputAllocation.copyFrom(inputArray);
280 
281         Allocation outputAllocation = Allocation.createSized(mRS, Element.F16_2(mRS), 2);
282 
283         mScript.invoke_findMinAndMaxHalf2(outputAllocation, inputAllocation);
284 
285         short[] outputArray = new short[4];
286         outputAllocation.copyTo(outputArray);
287         return new Short2[] { new Short2(outputArray[0], outputArray[1]),
288                               new Short2(outputArray[2], outputArray[3]) };
289     }
290 
testFindMinAndMaxHalf2()291     public void testFindMinAndMaxHalf2() {
292         // fewer members in the array than there are distinct half values
293         final short[] input = createInputArrayHalf(1000, 25);
294 
295         final Short2[] javaRslt = findMinAndMaxHalf2(input);
296         final Short2[] rsRslt = mScript.reduce_findMinAndMaxHalf2(input).get();
297 
298         assertEquals(javaRslt, rsRslt);
299     }
300 
301     ///////////////////////////////////////////////////////////////////
302 
303     // Both the input and the result are linearized representations of 2x2 matrices.
findMinMat(final float[] inputArray)304     private float[] findMinMat(final float[] inputArray) {
305         float[] result = new float[4];
306         for (int i = 0; i < 4; ++i)
307             result[i] = Float.POSITIVE_INFINITY;
308 
309         for (int i = 0; i < inputArray.length; ++i)
310             result[i % 4] = Math.min(result[i % 4], inputArray[i]);
311 
312         return result;
313     }
314 
testFindMinMat()315     public void testFindMinMat() {
316         final int length = 100000;
317 
318         final float[] inputArray = createInputArrayFloat(4 * length, 24);
319         Allocation inputAllocation = Allocation.createSized(mRS, Element.MATRIX_2X2(mRS), length);
320         inputAllocation.copyFromUnchecked(inputArray);
321 
322         final float[] javaRslt = findMinMat(inputArray);
323         final float[] rsRslt = mScript.reduce_findMinMat(inputAllocation).get();
324 
325         assertEquals(javaRslt, rsRslt);
326     }
327 
328     ///////////////////////////////////////////////////////////////////
329 
330     // Both the input and the result are linearized representations of 2x2 matrices.
findMinAndMaxMat(final float[] inputArray)331     private float[] findMinAndMaxMat(final float[] inputArray) {
332         float[] result = new float[8];
333         for (int i = 0; i < 4; ++i) {
334             result[i+0] = Float.POSITIVE_INFINITY;
335             result[i+4] = Float.NEGATIVE_INFINITY;
336         }
337 
338         for (int i = 0; i < inputArray.length; ++i) {
339             result[0 + i % 4] = Math.min(result[0 + i % 4], inputArray[i]);
340             result[4 + i % 4] = Math.max(result[4 + i % 4], inputArray[i]);
341         }
342 
343         return result;
344     }
345 
testFindMinAndMaxMat()346     public void testFindMinAndMaxMat() {
347         final int length = 100000;
348 
349         final float[] inputArray = createInputArrayFloat(4 * length, 26);
350         Allocation inputAllocation = Allocation.createSized(mRS, Element.MATRIX_2X2(mRS), length);
351         inputAllocation.copyFromUnchecked(inputArray);
352 
353         final float[] javaRslt = findMinAndMaxMat(inputArray);
354         final float[] rsRslt = mScript.reduce_findMinAndMaxMat(inputAllocation).get();
355 
356         assertEquals(javaRslt, rsRslt);
357     }
358 
359     ///////////////////////////////////////////////////////////////////
360 
testFz()361     public void testFz() {
362         final int inputLen = 100000;
363         int[] input = createInputArrayInt(inputLen, 5);
364         // just in case we got unlucky
365         input[(new Random(6)).nextInt(inputLen)] = 0;
366 
367         final int rsRslt = mScript.reduce_fz(input).get();
368 
369         assertEquals("input[" + rsRslt + "]", 0, input[rsRslt]);
370     }
371 
372     ///////////////////////////////////////////////////////////////////
373 
testFz2()374     public void testFz2() {
375         final int dimX = 225, dimY = 450;
376         final int inputLen = dimX * dimY;
377 
378         int[] inputArray = createInputArrayInt(inputLen, 7);
379         // just in case we got unlucky
380         inputArray[(new Random(8)).nextInt(inputLen)] = 0;
381 
382         Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32(mRS));
383         typeBuilder.setX(dimX).setY(dimY);
384         Allocation inputAllocation = Allocation.createTyped(mRS, typeBuilder.create());
385         inputAllocation.copy2DRangeFrom(0, 0, dimX, dimY, inputArray);
386 
387         final Int2 rsRslt = mScript.reduce_fz2(inputAllocation).get();
388 
389         final int cellVal = inputArray[rsRslt.x + dimX * rsRslt.y];
390 
391         assertEquals("input[" + rsRslt.x + ", " + rsRslt.y + "]", 0, cellVal);
392     }
393 
394     ///////////////////////////////////////////////////////////////////
395 
testFz3()396     public void testFz3() {
397         final int dimX = 59, dimY = 48, dimZ = 37;
398         final int inputLen = dimX * dimY * dimZ;
399 
400         int[] inputArray = createInputArrayInt(inputLen, 9);
401         // just in case we got unlucky
402         inputArray[(new Random(10)).nextInt(inputLen)] = 0;
403 
404         Type.Builder typeBuilder = new Type.Builder(mRS, Element.I32(mRS));
405         typeBuilder.setX(dimX).setY(dimY).setZ(dimZ);
406         Allocation inputAllocation = Allocation.createTyped(mRS, typeBuilder.create());
407         inputAllocation.copy3DRangeFrom(0, 0, 0, dimX, dimY, dimZ, inputArray);
408 
409         final Int3 rsRslt = mScript.reduce_fz3(inputAllocation).get();
410 
411         final int cellVal = inputArray[rsRslt.x + dimX * rsRslt.y + dimX * dimY * rsRslt.z];
412 
413         assertEquals("input[" + rsRslt.x + ", " + rsRslt.y + ", " + rsRslt.z + "]", 0, cellVal);
414     }
415 
416     ///////////////////////////////////////////////////////////////////
417 
418     private static final int histogramBucketCount = 256;
419 
histogram(final byte[] inputArray)420     private long[] histogram(final byte[] inputArray) {
421         Allocation inputAllocation = Allocation.createSized(mRS, Element.U8(mRS), inputArray.length);
422         inputAllocation.copyFrom(inputArray);
423 
424         Allocation outputAllocation = Allocation.createSized(mRS, Element.U32(mRS), histogramBucketCount);
425 
426         ScriptIntrinsicHistogram scriptHsg = ScriptIntrinsicHistogram.create(mRS, Element.U8(mRS));
427         scriptHsg.setOutput(outputAllocation);
428         scriptHsg.forEach(inputAllocation);
429 
430         int[] outputArrayMistyped = new int[histogramBucketCount];
431         outputAllocation.copyTo(outputArrayMistyped);
432 
433         long[] outputArray = new long[histogramBucketCount];
434         for (int i = 0; i < histogramBucketCount; ++i)
435             outputArray[i] = outputArrayMistyped[i] & (long)0xffffffff;
436         return outputArray;
437     }
438 
testHistogram()439     public void testHistogram() {
440         final byte[] inputArray = createInputArrayByte(100000, 11);
441 
442         final long[] javaRslt = histogram(inputArray);
443         assertEquals("javaRslt unexpected length", histogramBucketCount, javaRslt.length);
444         final long[] rsRslt = mScript.reduce_histogram(inputArray).get();
445         assertEquals("rsRslt unexpected length", histogramBucketCount, rsRslt.length);
446 
447         for (int i = 0; i < histogramBucketCount; ++i) {
448             assertEquals("histogram[" + i + "]", javaRslt[i], rsRslt[i]);
449         }
450     }
451 
452     //-----------------------------------------------------------------
453 
mode(final byte[] inputArray)454     private Int2 mode(final byte[] inputArray) {
455         long[] hsg = histogram(inputArray);
456 
457         int modeIdx = 0;
458         for (int i = 1; i < hsg.length; ++i)
459             if (hsg[i] > hsg[modeIdx]) modeIdx =i;
460         return new Int2(modeIdx, (int)hsg[modeIdx]);
461     }
462 
testMode()463     public void testMode() {
464         final byte[] inputArray = createInputArrayByte(100000, 12);
465 
466         final Int2 javaRslt = mode(inputArray);
467         final Int2 rsRslt = mScript.reduce_mode(inputArray).get();
468 
469         assertEquals(javaRslt, rsRslt);
470     }
471 
472     ///////////////////////////////////////////////////////////////////
473 
sumXor(final int[] input1, final int[] input2)474     private int sumXor(final int[] input1, final int[] input2) {
475         int sum = 0;
476         for (int idx = 0; idx < input1.length; ++idx)
477             sum += (input1[idx] ^ input2[idx]);
478         return sum;
479     }
480 
testSumXor()481     public void testSumXor() {
482         final int[] input1 = createInputArrayInt(100000, 13, 1 << 13);
483         final int[] input2 = createInputArrayInt(100000, 14, 1 << 13);
484 
485         final int javaRslt = sumXor(input1, input2);
486         final int rsRslt = mScript.reduce_sumxor(input1, input2).get();
487 
488         assertEquals(javaRslt, rsRslt);
489     }
490 
testBadSumXorInputDimensionMismatch()491     public void testBadSumXorInputDimensionMismatch() {
492         Allocation[] inputs = createInputAllocations(Element.I32(mRS), 3);
493 
494         // try all pairwise combinations of Allocations; we don't care
495         // about the result, only whether we correctly recognize
496         // whether or not the input Allocations have the same
497         // dimensions.
498         for (int i = 0; i < inputs.length; ++i) {
499             for (int j = 0; j < inputs.length; ++j) {
500                 try {
501                     mScript.reduce_sumxor(inputs[i], inputs[j]);
502                     if (i != j)
503                         fail("expected RSRuntimeException for dimension mismatch: inputs " + i + " and " + j);
504                 } catch (RSRuntimeException e) {
505                     if (i == j)
506                         fail("did not expect RSRuntimeException for dimension match: inputs " + i);
507                 }
508             }
509         }
510     }
511 
testBadSumXorInputLengthMismatch()512     public void testBadSumXorInputLengthMismatch() {
513         final int[] input1 = createInputArrayInt(90000, 16, 1 << 13);
514         final int[] input2 = createInputArrayInt(100000, 17, 1 << 13);
515 
516         // we don't care about the result, only whether we correctly recognize
517         // that the input arrays have different dimensions.
518         try {
519             mScript.reduce_sumxor(input1, input2);
520             fail("expected RSRuntimeException for mismatched array input lengths");
521         } catch (RSRuntimeException e) {
522         }
523     }
524 
testBadSumXorInputNull()525     public void testBadSumXorInputNull() {
526         final int[] input = createInputArrayInt(100000, 15, 1 << 13);
527 
528         // we don't care about the result, only whether we correctly recognize
529         // that the input array is null.
530 
531         try {
532             mScript.reduce_sumxor(input, null);
533             fail("expected RSIllegalArgumentException for null array input");
534         } catch (RSIllegalArgumentException e) {
535         }
536 
537         try {
538             mScript.reduce_sumxor(null, input);
539             fail("expected RSIllegalArgumentException for null array input");
540         } catch (RSIllegalArgumentException e) {
541         }
542     }
543 
testBadSumXorInputWrongType()544     public void testBadSumXorInputWrongType() {
545         Allocation inputI32 = Allocation.createSized(mRS, Element.I32(mRS), 1);
546 
547         Allocation badInput[] = new Allocation[]{
548             Allocation.createSized(mRS, Element.I16(mRS), 1),
549             Allocation.createSized(mRS, Element.I16_2(mRS), 1),
550             Allocation.createSized(mRS, Element.I32_2(mRS), 1),
551             Allocation.createSized(mRS, Element.U32(mRS), 1)
552         };
553 
554         // we don't care about the result, only whether we correctly recognize
555         // that the input Allocation has the wrong type.
556 
557         for (int i = 0; i < badInput.length; ++i) {
558             try {
559                 mScript.reduce_sumxor(inputI32, badInput[i]);
560                 fail("badInput[" + i + "]: expected RSRuntimeException for wrong input data type");
561             } catch (RSRuntimeException e) {
562             }
563 
564             try {
565                 mScript.reduce_sumxor(badInput[i], inputI32);
566                 fail("badInput[" + i + "]: expected RSRuntimeException for wrong input data type");
567             } catch (RSRuntimeException e) {
568             }
569         }
570     }
571 
572     ///////////////////////////////////////////////////////////////////
573 
sillySum(final byte[] input1, final float[] input2, final int[] input3)574     private long sillySum(final byte[] input1, final float[] input2, final int[] input3) {
575         // input3 is a flattened 3-vector
576         assertEquals(input1.length, input2.length);
577         assertEquals(input1.length * 3, input3.length);
578 
579         long sum = 0;
580         for (int i = 0; i < input1.length; ++i)
581             sum += ((((input1[i] + (long)Math.ceil(Math.log(input2[i]))) + input3[3*i + 0]) + input3[3*i + 1]) + input3[3*i + 2]);
582         return sum;
583     }
584 
testSillySum()585     public void testSillySum() {
586         final int length = 100000;
587 
588         final byte[] input1 = createInputArrayByte(length, 16);
589         final float[] input2 = createInputArrayFloat(length, 17);
590         // input3 is a flattened 3-vector
591         final int[] input3 = createInputArrayInt(3 * length, 18);
592 
593         final long javaRslt = sillySum(input1, input2, input3);
594         final long rsRslt = mScript.reduce_sillysum(input1, input2, input3).get();
595 
596         assertEquals(javaRslt, rsRslt);
597     }
598 
testBadSillySumInputDimensionMismatch()599     public void testBadSillySumInputDimensionMismatch() {
600         Allocation[] allocs1 = createInputAllocations(Element.I8(mRS), 3);
601         Allocation[] allocs2 = createInputAllocations(Element.F32(mRS), 3);
602         Allocation[] allocs3 = createInputAllocations(Element.I32_3(mRS), 3);
603 
604         // try all tuples of Allocations; we don't care about the
605         // result, only whether we correctly recognize whether or not
606         // the input Allocations have the same dimensions.
607         for (int i = 0; i < allocs1.length; ++i) {
608             for (int j = 0; j < allocs2.length; ++j) {
609                 for (int k = 0; k < allocs3.length; ++k) {
610                     final boolean expectException = !((i == j) && (j == k));
611                     try {
612                         mScript.reduce_sillysum(allocs1[i], allocs2[j], allocs3[k]);
613                         if (expectException)
614                             fail("expected RSRuntimeException for dimension mismatch: inputs " + i + ", " + j + ", " + k);
615                     } catch (RSRuntimeException e) {
616                         if (!expectException) {
617                             fail("did not expect RSRuntimeException for dimension match: inputs " + i);
618                         }
619                     }
620                 }
621             }
622         }
623     }
624 
testBadSillySumInputLengthMismatch()625     public void testBadSillySumInputLengthMismatch() {
626         final int[] lengths = new int[]{ 10, 100, 1000 };
627 
628         // try all pairwise combinations of lengths; we don't care
629         // about the result, only whether we correctly recognize
630         // whether or not the input Allocations have the same lengths.
631         for (int len1idx = 0; len1idx < lengths.length; ++len1idx) {
632             for (int len2idx = 0; len2idx < lengths.length; ++len2idx) {
633                 for (int len3idx = 0; len3idx < lengths.length; ++len3idx) {
634 
635                     final byte[] input1 = createInputArrayByte(lengths[len1idx], 19);
636                     final float[] input2 = createInputArrayFloat(lengths[len2idx], 20);
637                     // input3 is a flattened 3-vector
638                     final int[] input3 = createInputArrayInt(3 * lengths[len3idx], 21);
639 
640                     try {
641                         mScript.reduce_sillysum(input1, input2, input3);
642                         if ((len1idx != len2idx) || (len1idx != len3idx))
643                             fail("expected RSRuntimeException for dimension mismatch: inputs " +
644                                     len1idx + ", " + len2idx + ", " + len3idx);
645                     } catch (RSRuntimeException e) {
646                         if ((len1idx == len2idx) && (len1idx == len3idx))
647                             fail("did not expect RSRuntimeException for dimension match: inputs " + len1idx);
648                     }
649                 }
650             }
651         }
652     }
653 
654     ///////////////////////////////////////////////////////////////////
655 
656     private static final long[] oorrGoodResults = new long[]{0L, 1L, 0x7fff_ffff_ffff_ffffL};
657     private static final long[] oorrBadResultHalfs = new long[]{0x4000_0000_0000_0000L, 0x4567_89ab_cdef_0123L};
658 
659     private static final int[] oorInput = createInputArrayInt(1, 22);
660 
testBadOorrSca()661     public void testBadOorrSca() {
662         final int[] oorrBadPositions = new int[]{-1, 0};
663 
664         for (long goodResult : oorrGoodResults) {
665             mScript.set_oorrGoodResult(goodResult);
666             for (long badResultHalf : oorrBadResultHalfs) {
667                 mScript.set_oorrBadResultHalf(badResultHalf);
668                 for (int badPosition : oorrBadPositions) {
669                     mScript.set_oorrBadPos(badPosition);
670 
671                     // we don't care about the result, only whether
672                     // it's representible.  note that no exception is
673                     // thrown until "get()".
674                     try {
675                         mScript.reduce_oorrSca(oorInput).get();
676                         if (badPosition >= 0)
677                             fail("expected RSRuntimeException for non-representible result; expected 2*" + badResultHalf);
678                     } catch (RSRuntimeException e) {
679                         if (badPosition < 0)
680                             fail("did not expect RSRuntimeException for representible result; expected " + goodResult);
681                     }
682                 }
683             }
684         }
685     }
686 
testBadOorrVec4()687     public void testBadOorrVec4() {
688         final int[] oorrBadPositions = new int[]{-1, 0, 1, 2, 3};
689 
690         for (long goodResult : oorrGoodResults) {
691             mScript.set_oorrGoodResult(goodResult);
692             for (long badResultHalf : oorrBadResultHalfs) {
693                 mScript.set_oorrBadResultHalf(badResultHalf);
694                 for (int badPosition : oorrBadPositions) {
695                     mScript.set_oorrBadPos(badPosition);
696 
697                     // we don't care about the result, only whether
698                     // it's representible.  note that no exception is
699                     // thrown until "get()".
700                     try {
701                         mScript.reduce_oorrVec4(oorInput).get();
702                         if (badPosition >= 0)
703                             fail("expected RSRuntimeException for non-representible result; expected 2*" + badResultHalf
704                                     + " at position " + badPosition);
705                     } catch (RSRuntimeException e) {
706                         if (badPosition < 0)
707                             fail("did not expect RSRuntimeException for representible result; expected " + goodResult);
708                     }
709                 }
710             }
711         }
712     }
713 
testBadOorrArr9()714     public void testBadOorrArr9() {
715         final int[] oorrBadPositions = new int[]{-1, 0, 1, 2, 3, 4, 5, 6, 7, 8};
716 
717         for (long goodResult : oorrGoodResults) {
718             mScript.set_oorrGoodResult(goodResult);
719             for (long badResultHalf : oorrBadResultHalfs) {
720                 mScript.set_oorrBadResultHalf(badResultHalf);
721                 for (int badPosition : oorrBadPositions) {
722                     mScript.set_oorrBadPos(badPosition);
723 
724                     // we don't care about the result, only whether
725                     // it's representible.  note that no exception is
726                     // thrown until "get()".
727                     try {
728                         mScript.reduce_oorrArr9(oorInput).get();
729                         if (badPosition >= 0)
730                             fail("expected RSRuntimeException for non-representible result; expected 2*" + badResultHalf
731                                     + " at position " + badPosition);
732                     } catch (RSRuntimeException e) {
733                         if (badPosition < 0)
734                             fail("did not expect RSRuntimeException for representible result; expected " + goodResult);
735                     }
736                 }
737             }
738         }
739     }
740 
testBadOorrArr9Vec4()741     public void testBadOorrArr9Vec4() {
742         for (long goodResult : oorrGoodResults) {
743             mScript.set_oorrGoodResult(goodResult);
744             for (long badResultHalf : oorrBadResultHalfs) {
745                 mScript.set_oorrBadResultHalf(badResultHalf);
746                 for (int badPosition = -1; badPosition < 36; ++badPosition) {
747                     mScript.set_oorrBadPos(badPosition);
748 
749                     // we don't care about the result, only whether
750                     // it's representible.  note that no exception is
751                     // thrown until "get()".
752                     try {
753                         mScript.reduce_oorrArr9Vec4(oorInput).get();
754                         if (badPosition >= 0)
755                             fail("expected RSRuntimeException for non-representible result; expected 2*" + badResultHalf
756                                     + " at position " + badPosition);
757                     } catch (RSRuntimeException e) {
758                         if (badPosition < 0)
759                             fail("did not expect RSRuntimeException for representible result; expected " + goodResult);
760                     }
761                 }
762             }
763         }
764     }
765 }
766