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