• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 #include "NeuralNetworksWrapper.h"
18 #include "NeuralNetworksOEM.h"
19 
20 #include <gtest/gtest.h>
21 
22 using namespace android::nn::wrapper;
23 
24 namespace {
25 
26 static const int32_t kAvailableOperandCodes[] = {
27     ANEURALNETWORKS_FLOAT32,
28     ANEURALNETWORKS_INT32,
29     ANEURALNETWORKS_UINT32,
30     ANEURALNETWORKS_TENSOR_FLOAT32,
31     ANEURALNETWORKS_TENSOR_INT32,
32     ANEURALNETWORKS_TENSOR_QUANT8_ASYMM,
33     ANEURALNETWORKS_TENSOR_OEM_BYTE
34 };
35 
36 class OperationTestBase {
37 public:
OperationTestBase(ANeuralNetworksOperationType opCode,std::vector<ANeuralNetworksOperandType> validInputs,std::vector<ANeuralNetworksOperandType> validOutputs)38     OperationTestBase(ANeuralNetworksOperationType opCode,
39                       std::vector<ANeuralNetworksOperandType> validInputs,
40                       std::vector<ANeuralNetworksOperandType> validOutputs)
41         : mOpCode(opCode),
42           mValidInputs(std::move(validInputs)),
43           mValidOutputs(std::move(validOutputs)) {}
44 
45     // Add each operand separately and add the operation using these operands.
46     // This function does not cover the cases that a operand used mutiple times.
addOperation(const std::vector<ANeuralNetworksOperandType> & inputs,const std::vector<ANeuralNetworksOperandType> & outputs)47     int32_t addOperation(const std::vector<ANeuralNetworksOperandType>& inputs,
48                          const std::vector<ANeuralNetworksOperandType>& outputs) {
49         ANeuralNetworksModel* model = nullptr;
50         ANeuralNetworksModel_create(&model);
51 
52         uint32_t opIdx = 0;
53         std::vector<uint32_t> inputIds;
54         std::vector<uint32_t> outputIds;
55         for (uint32_t i = 0; i < inputs.size(); i++) {
56             ANeuralNetworksModel_addOperand(model, &inputs[i]);
57             inputIds.push_back(opIdx++);
58         }
59         for (uint32_t i = 0; i < outputs.size(); i++) {
60             ANeuralNetworksModel_addOperand(model, &outputs[i]);
61             outputIds.push_back(opIdx++);
62         }
63 
64         int32_t result = ANeuralNetworksModel_addOperation(model, mOpCode,
65                                                  static_cast<uint32_t>(inputIds.size()),
66                                                  inputIds.data(),
67                                                  static_cast<uint32_t>(outputIds.size()),
68                                                  outputIds.data());
69         ANeuralNetworksModel_free(model);
70         return result;
71     }
72 
testMutatingInputOperandCode()73     bool testMutatingInputOperandCode() {
74         for (uint32_t i = 0; i < mValidInputs.size(); i++) {
75             // LSH_PROJECTION's second argument is allowed to have any type.
76             // This is the only operation that currently has a type that can be
77             // anything independent from any other type. Changing the operand
78             // type to any other type will result in a valid model for
79             // LSH_PROJECTION. If this is the case, skip the test.
80             if (mOpCode == ANEURALNETWORKS_LSH_PROJECTION && i == 1) {
81                 continue;
82             }
83             ANeuralNetworksOperandType newType = mValidInputs[i];
84             int32_t originalOperandCode = mValidInputs[i].type;
85             for (int32_t newOperandCode : kAvailableOperandCodes) {
86                 if (newOperandCode == originalOperandCode) {
87                     continue;
88                 }
89                 newType.type = newOperandCode;
90                 std::vector<ANeuralNetworksOperandType> inputs = mValidInputs;
91                 inputs[i] = newType;
92                 int32_t result = addOperation(inputs, mValidOutputs);
93                 if (ANEURALNETWORKS_NO_ERROR == result) {
94                     return false;
95                 }
96             }
97         }
98         return true;
99     }
100 
testMutatingOutputOperandCode()101     bool testMutatingOutputOperandCode() {
102         for (uint32_t i = 0; i < mValidOutputs.size(); i++) {
103             // LSH_PROJECTION's second argument is allowed to have any type.
104             // This is the only operation that currently has a type that can be
105             // anything independent from any other type. Changing the operand
106             // type to any other type will result in a valid model for
107             // LSH_PROJECTION. If this is the case, skip the test.
108             if (mOpCode == ANEURALNETWORKS_LSH_PROJECTION && i == 1) {
109                 continue;
110             }
111             ANeuralNetworksOperandType newType = mValidOutputs[i];
112             int32_t originalOperandCode = mValidOutputs[i].type;
113             for (int32_t newOperandCode : kAvailableOperandCodes) {
114                 if (newOperandCode == originalOperandCode) {
115                     continue;
116                 }
117                 newType.type = newOperandCode;
118                 std::vector<ANeuralNetworksOperandType> outputs = mValidOutputs;
119                 outputs[i] = newType;
120                 int32_t result = addOperation(mValidInputs, outputs);
121                 if (ANEURALNETWORKS_NO_ERROR == result) {
122                     return false;
123                 }
124             }
125         }
126         return true;
127     }
128 
testMutatingInputOperandCounts()129     bool testMutatingInputOperandCounts() {
130         std::vector<ANeuralNetworksOperandType> inputs = mValidInputs;
131         for (uint32_t i = 0; i < 5; i++) {
132             inputs.push_back(inputs[0]);
133             if (ANEURALNETWORKS_NO_ERROR == addOperation(inputs, mValidOutputs)) {
134                 return false;
135             }
136         }
137         return true;
138     }
139 
testMutatingOutputOperandCounts()140     bool testMutatingOutputOperandCounts() {
141         std::vector<ANeuralNetworksOperandType> outputs = mValidOutputs;
142         for (int i = 0; i < 5; i++) {
143             outputs.push_back(outputs[0]);
144             if (ANEURALNETWORKS_NO_ERROR == addOperation(mValidInputs, outputs)) {
145                 return false;
146             }
147         }
148         return true;
149     }
150 
151 private:
152     ANeuralNetworksOperationType mOpCode;
153     // The dimensions in the ANeuralNetworksOperandType must outlive the test object.
154     std::vector<ANeuralNetworksOperandType> mValidInputs;
155     std::vector<ANeuralNetworksOperandType> mValidOutputs;
156 };
157 
TEST(OperationValidationTest,DEQUANTIZE_float32)158 TEST(OperationValidationTest, DEQUANTIZE_float32) {
159     uint32_t inputDimensions[4] = {2, 2, 2, 2};
160     ANeuralNetworksOperandType input = {.type = ANEURALNETWORKS_TENSOR_QUANT8_ASYMM,
161                                         .dimensionCount = 4,
162                                         .dimensions = inputDimensions,
163                                         .scale = 1.0f,
164                                         .zeroPoint = 0};
165     ANeuralNetworksOperandType output = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
166                                          .dimensionCount = 4,
167                                          .dimensions = inputDimensions,
168                                          .scale = 0.0f,
169                                          .zeroPoint = 0};
170     OperationTestBase dequantizeTest(ANEURALNETWORKS_DEQUANTIZE, {input}, {output});
171 
172     EXPECT_TRUE(dequantizeTest.testMutatingInputOperandCode());
173     EXPECT_TRUE(dequantizeTest.testMutatingInputOperandCounts());
174     EXPECT_TRUE(dequantizeTest.testMutatingOutputOperandCode());
175     EXPECT_TRUE(dequantizeTest.testMutatingOutputOperandCounts());
176 }
177 
simpleMathOpTest(ANeuralNetworksOperationType operationCode,int32_t operandCode)178 void simpleMathOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
179     uint32_t inputDimensions[4] = {2, 2, 2, 2};
180     ANeuralNetworksOperandType input1 = {.type = operandCode,
181                                          .dimensionCount = 4,
182                                          .dimensions = inputDimensions,
183                                          .scale = 0.0f,
184                                          .zeroPoint = 0};
185     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
186         input1.scale = 0.5f;
187     }
188 
189     ANeuralNetworksOperandType input2 = input1;
190     ANeuralNetworksOperandType output = input1;
191     ANeuralNetworksOperandType activation = {.type = ANEURALNETWORKS_INT32,
192                                              .dimensionCount = 0,
193                                              .dimensions = nullptr,
194                                              .scale = 0.0f,
195                                              .zeroPoint = 0};
196 
197     OperationTestBase simpleMathTest(operationCode, {input1, input2, activation}, {output});
198 
199     EXPECT_TRUE(simpleMathTest.testMutatingInputOperandCode());
200     EXPECT_TRUE(simpleMathTest.testMutatingInputOperandCounts());
201     EXPECT_TRUE(simpleMathTest.testMutatingOutputOperandCode());
202     EXPECT_TRUE(simpleMathTest.testMutatingOutputOperandCounts());
203 }
204 
TEST(OperationValidationTest,ADD_float32)205 TEST(OperationValidationTest, ADD_float32) {
206     simpleMathOpTest(ANEURALNETWORKS_ADD, ANEURALNETWORKS_TENSOR_FLOAT32);
207 }
208 
TEST(OperationValidationTest,MUL_float32)209 TEST(OperationValidationTest, MUL_float32) {
210     simpleMathOpTest(ANEURALNETWORKS_MUL, ANEURALNETWORKS_TENSOR_FLOAT32);
211 }
212 
TEST(OperationValidationTest,SUB_float32)213 TEST(OperationValidationTest, SUB_float32) {
214     simpleMathOpTest(ANEURALNETWORKS_SUB, ANEURALNETWORKS_TENSOR_FLOAT32);
215 }
216 
TEST(OperationValidationTest,DIV_float32)217 TEST(OperationValidationTest, DIV_float32) {
218     simpleMathOpTest(ANEURALNETWORKS_DIV, ANEURALNETWORKS_TENSOR_FLOAT32);
219 }
220 
TEST(OperationValidationTest,ADD_quant8)221 TEST(OperationValidationTest, ADD_quant8) {
222     simpleMathOpTest(ANEURALNETWORKS_ADD, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
223 }
224 
TEST(OperationValidationTest,MUL_quant8)225 TEST(OperationValidationTest, MUL_quant8) {
226     simpleMathOpTest(ANEURALNETWORKS_MUL, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
227 }
228 
activationOpTest(ANeuralNetworksOperationType operationCode,int32_t operandCode)229 void activationOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
230     uint32_t inputDimensions[4] = {2, 2, 2, 2};
231     ANeuralNetworksOperandType input = {.type = operandCode,
232                                         .dimensionCount = 4,
233                                         .dimensions = inputDimensions,
234                                         .scale = 0.0f,
235                                         .zeroPoint = 0};
236     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
237         input.scale = 1.f / 256;
238     }
239 
240     ANeuralNetworksOperandType output = input;
241     OperationTestBase activationTest(operationCode, {input}, {output});
242 
243     EXPECT_TRUE(activationTest.testMutatingInputOperandCode());
244     EXPECT_TRUE(activationTest.testMutatingInputOperandCounts());
245     EXPECT_TRUE(activationTest.testMutatingOutputOperandCode());
246     EXPECT_TRUE(activationTest.testMutatingOutputOperandCounts());
247 }
248 
TEST(OperationValidationTest,L2_NORMALIZATION_float32)249 TEST(OperationValidationTest, L2_NORMALIZATION_float32) {
250     activationOpTest(ANEURALNETWORKS_L2_NORMALIZATION, ANEURALNETWORKS_TENSOR_FLOAT32);
251 }
252 
TEST(OperationValidationTest,FLOOR_float32)253 TEST(OperationValidationTest, FLOOR_float32) {
254     activationOpTest(ANEURALNETWORKS_FLOOR, ANEURALNETWORKS_TENSOR_FLOAT32);
255 }
256 
TEST(OperationValidationTest,TANH_float32)257 TEST(OperationValidationTest, TANH_float32) {
258     activationOpTest(ANEURALNETWORKS_TANH, ANEURALNETWORKS_TENSOR_FLOAT32);
259 }
260 
TEST(OperationValidationTest,RELU_float32)261 TEST(OperationValidationTest, RELU_float32) {
262     activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_FLOAT32);
263 }
264 
TEST(OperationValidationTest,RELU1_float32)265 TEST(OperationValidationTest, RELU1_float32) {
266     activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_FLOAT32);
267 }
268 
TEST(OperationValidationTest,RELU6_float32)269 TEST(OperationValidationTest, RELU6_float32) {
270     activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_FLOAT32);
271 }
272 
TEST(OperationValidationTest,LOGISTIC_float32)273 TEST(OperationValidationTest, LOGISTIC_float32) {
274     activationOpTest(ANEURALNETWORKS_LOGISTIC, ANEURALNETWORKS_TENSOR_FLOAT32);
275 }
276 
TEST(OperationValidationTest,RELU_quant8)277 TEST(OperationValidationTest, RELU_quant8) {
278     activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
279 }
280 
TEST(OperationValidationTest,RELU1_quant8)281 TEST(OperationValidationTest, RELU1_quant8) {
282     activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
283 }
284 
TEST(OperationValidationTest,RELU6_quant8)285 TEST(OperationValidationTest, RELU6_quant8) {
286     activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
287 }
288 
TEST(OperationValidationTest,LOGISTIC_quant8)289 TEST(OperationValidationTest, LOGISTIC_quant8) {
290     activationOpTest(ANEURALNETWORKS_LOGISTIC, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
291 }
292 
softmaxOpTest(int32_t operandCode)293 void softmaxOpTest(int32_t operandCode) {
294     uint32_t inputDimensions[4] = {2, 2, 2, 2};
295     ANeuralNetworksOperandType input = {.type = operandCode,
296                                          .dimensionCount = 4,
297                                          .dimensions = inputDimensions,
298                                          .scale = 0.0f,
299                                          .zeroPoint = 0};
300     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
301         input.scale = 1.f / 256;
302     }
303 
304     ANeuralNetworksOperandType output = input;
305     ANeuralNetworksOperandType beta = {.type = ANEURALNETWORKS_FLOAT32,
306                                        .dimensionCount = 0,
307                                        .dimensions = nullptr,
308                                        .scale = 0.0f,
309                                        .zeroPoint = 0};
310 
311     OperationTestBase softmaxTest(ANEURALNETWORKS_SOFTMAX, {input, beta}, {output});
312 
313     EXPECT_TRUE(softmaxTest.testMutatingInputOperandCode());
314     EXPECT_TRUE(softmaxTest.testMutatingInputOperandCounts());
315     EXPECT_TRUE(softmaxTest.testMutatingOutputOperandCode());
316     EXPECT_TRUE(softmaxTest.testMutatingOutputOperandCounts());
317 }
318 
TEST(OperationValidationTest,SOFTMAX_float32)319 TEST(OperationValidationTest, SOFTMAX_float32) {
320     softmaxOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
321 }
322 
TEST(OperationValidationTest,SOFTMAX_quant8)323 TEST(OperationValidationTest, SOFTMAX_quant8) {
324     softmaxOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
325 }
326 
poolingOpTest(ANeuralNetworksOperationType operationCode,int32_t operandCode)327 void poolingOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
328     uint32_t inputDimensions[4] = {2, 4, 4, 2};
329     ANeuralNetworksOperandType input = {.type = operandCode,
330                                         .dimensionCount = 4,
331                                         .dimensions = inputDimensions,
332                                         .scale = 0.0f,
333                                         .zeroPoint = 0};
334     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
335         input.scale = 1.f / 256;
336     }
337     ANeuralNetworksOperandType output = input;
338 
339     ANeuralNetworksOperandType scalar = {.type = ANEURALNETWORKS_INT32,
340                                          .dimensionCount = 0,
341                                          .dimensions = nullptr,
342                                          .scale = 0.0f,
343                                          .zeroPoint = 0};
344     ANeuralNetworksOperandType padLeft = scalar;
345     ANeuralNetworksOperandType padRight = scalar;
346     ANeuralNetworksOperandType padTop = scalar;
347     ANeuralNetworksOperandType padBottom = scalar;
348     ANeuralNetworksOperandType strideWidth = scalar;
349     ANeuralNetworksOperandType strideHeight = scalar;
350     ANeuralNetworksOperandType filterWidth = scalar;
351     ANeuralNetworksOperandType filterHeight = scalar;
352     ANeuralNetworksOperandType activation = scalar;
353 
354     OperationTestBase explicitPoolingTest(operationCode,
355                                           {input,
356                                            padLeft, padRight, padTop, padBottom,
357                                            strideWidth, strideHeight,
358                                            filterWidth, filterHeight,
359                                            activation},
360                                           {output});
361 
362     EXPECT_TRUE(explicitPoolingTest.testMutatingInputOperandCode());
363     EXPECT_TRUE(explicitPoolingTest.testMutatingInputOperandCounts());
364     EXPECT_TRUE(explicitPoolingTest.testMutatingOutputOperandCode());
365     EXPECT_TRUE(explicitPoolingTest.testMutatingOutputOperandCounts());
366 
367     ANeuralNetworksOperandType padImplicit = scalar;
368     OperationTestBase implicitPoolingTest(operationCode,
369                                           {input,
370                                            padImplicit,
371                                            strideWidth, strideHeight,
372                                            filterWidth, filterHeight,
373                                            activation},
374                                           {output});
375 
376     EXPECT_TRUE(implicitPoolingTest.testMutatingInputOperandCode());
377     EXPECT_TRUE(implicitPoolingTest.testMutatingInputOperandCounts());
378     EXPECT_TRUE(implicitPoolingTest.testMutatingOutputOperandCode());
379     EXPECT_TRUE(implicitPoolingTest.testMutatingOutputOperandCounts());
380 }
381 
TEST(OperationValidationTest,AVERAGE_POOL_2D_float32)382 TEST(OperationValidationTest, AVERAGE_POOL_2D_float32) {
383     poolingOpTest(ANEURALNETWORKS_AVERAGE_POOL_2D, ANEURALNETWORKS_TENSOR_FLOAT32);
384 }
385 
TEST(OperationValidationTest,MAX_POOL_2D_float32)386 TEST(OperationValidationTest, MAX_POOL_2D_float32) {
387     poolingOpTest(ANEURALNETWORKS_MAX_POOL_2D, ANEURALNETWORKS_TENSOR_FLOAT32);
388 }
389 
TEST(OperationValidationTest,L2_POOL_2D_float32)390 TEST(OperationValidationTest, L2_POOL_2D_float32) {
391     poolingOpTest(ANEURALNETWORKS_L2_POOL_2D, ANEURALNETWORKS_TENSOR_FLOAT32);
392 }
393 
TEST(OperationValidationTest,AVERAGE_POOL_2D_quant8)394 TEST(OperationValidationTest, AVERAGE_POOL_2D_quant8) {
395     poolingOpTest(ANEURALNETWORKS_AVERAGE_POOL_2D, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
396 }
397 
TEST(OperationValidationTest,MAX_POOL_2D_quant8)398 TEST(OperationValidationTest, MAX_POOL_2D_quant8) {
399     poolingOpTest(ANEURALNETWORKS_MAX_POOL_2D, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
400 }
401 
spaceDepthOpTest(ANeuralNetworksOperationType operationCode,int32_t operandCode)402 void spaceDepthOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
403     uint32_t inputDimensions[4] = {2, 2, 2, 2};
404     ANeuralNetworksOperandType input = {.type = operandCode,
405                                         .dimensionCount = 4,
406                                         .dimensions = inputDimensions,
407                                         .scale = 0.0f,
408                                         .zeroPoint = 0};
409     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
410         input.scale = 1.f / 256;
411     }
412 
413     ANeuralNetworksOperandType block_size = {.type = ANEURALNETWORKS_INT32,
414                                              .dimensionCount = 0,
415                                              .dimensions = nullptr,
416                                              .scale = 0.0f,
417                                              .zeroPoint = 0};
418 
419     ANeuralNetworksOperandType output = input;
420     OperationTestBase spaceDepthTest(operationCode, {input, block_size}, {output});
421 
422     EXPECT_TRUE(spaceDepthTest.testMutatingInputOperandCode());
423     EXPECT_TRUE(spaceDepthTest.testMutatingInputOperandCounts());
424     EXPECT_TRUE(spaceDepthTest.testMutatingOutputOperandCode());
425     EXPECT_TRUE(spaceDepthTest.testMutatingOutputOperandCounts());
426 }
427 
TEST(OperationValidationTest,SPACE_TO_DEPTH_float32)428 TEST(OperationValidationTest, SPACE_TO_DEPTH_float32) {
429     spaceDepthOpTest(ANEURALNETWORKS_SPACE_TO_DEPTH, ANEURALNETWORKS_TENSOR_FLOAT32);
430 }
431 
TEST(OperationValidationTest,DEPTH_TO_SPACE_float32)432 TEST(OperationValidationTest, DEPTH_TO_SPACE_float32) {
433     spaceDepthOpTest(ANEURALNETWORKS_DEPTH_TO_SPACE, ANEURALNETWORKS_TENSOR_FLOAT32);
434 }
435 
TEST(OperationValidationTest,SPACE_TO_DEPTH_quant8)436 TEST(OperationValidationTest, SPACE_TO_DEPTH_quant8) {
437     spaceDepthOpTest(ANEURALNETWORKS_SPACE_TO_DEPTH, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
438 }
439 
TEST(OperationValidationTest,DEPTH_TO_SPACE_quant8)440 TEST(OperationValidationTest, DEPTH_TO_SPACE_quant8) {
441     spaceDepthOpTest(ANEURALNETWORKS_DEPTH_TO_SPACE, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
442 }
443 
spaceBatchOpTest(ANeuralNetworksOperationType operationCode,int32_t operandCode)444 void spaceBatchOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
445     uint32_t inputDimensions[4] = {2, 2, 2, 2};
446     ANeuralNetworksOperandType input = {.type = operandCode,
447                                         .dimensionCount = 4,
448                                         .dimensions = inputDimensions,
449                                         .scale = 0.0f,
450                                         .zeroPoint = 0};
451     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
452         input.scale = 1.f / 256;
453     }
454 
455     uint32_t blockDimensions[1] = {2};
456     ANeuralNetworksOperandType blockShape = {.type = ANEURALNETWORKS_TENSOR_INT32,
457                                              .dimensionCount = 1,
458                                              .dimensions = blockDimensions,
459                                              .scale = 0.0f,
460                                              .zeroPoint = 0};
461 
462     ANeuralNetworksOperandType padding = blockShape;
463     ANeuralNetworksOperandType output = input;
464     if (operationCode == ANEURALNETWORKS_SPACE_TO_BATCH_ND) {
465         OperationTestBase spaceBatchTest(operationCode, {input, blockShape, padding}, {output});
466 
467         EXPECT_TRUE(spaceBatchTest.testMutatingInputOperandCode());
468         EXPECT_TRUE(spaceBatchTest.testMutatingInputOperandCounts());
469         EXPECT_TRUE(spaceBatchTest.testMutatingOutputOperandCode());
470         EXPECT_TRUE(spaceBatchTest.testMutatingOutputOperandCounts());
471     } else {
472         OperationTestBase spaceBatchTest(operationCode, {input, blockShape}, {output});
473 
474         EXPECT_TRUE(spaceBatchTest.testMutatingInputOperandCode());
475         EXPECT_TRUE(spaceBatchTest.testMutatingInputOperandCounts());
476         EXPECT_TRUE(spaceBatchTest.testMutatingOutputOperandCode());
477         EXPECT_TRUE(spaceBatchTest.testMutatingOutputOperandCounts());
478     }
479 }
480 
TEST(OperationValidationTest,SPACE_TO_BATCH_ND_float32)481 TEST(OperationValidationTest, SPACE_TO_BATCH_ND_float32) {
482     spaceBatchOpTest(ANEURALNETWORKS_SPACE_TO_BATCH_ND, ANEURALNETWORKS_TENSOR_FLOAT32);
483 }
484 
TEST(OperationValidationTest,BATCH_TO_SPACE_ND_float32)485 TEST(OperationValidationTest, BATCH_TO_SPACE_ND_float32) {
486     spaceBatchOpTest(ANEURALNETWORKS_BATCH_TO_SPACE_ND, ANEURALNETWORKS_TENSOR_FLOAT32);
487 }
488 
TEST(OperationValidationTest,SPACE_TO_BATCH_ND_quant8)489 TEST(OperationValidationTest, SPACE_TO_BATCH_ND_quant8) {
490     spaceBatchOpTest(ANEURALNETWORKS_SPACE_TO_BATCH_ND, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
491 }
492 
TEST(OperationValidationTest,BATCH_TO_SPACE_ND_quant8)493 TEST(OperationValidationTest, BATCH_TO_SPACE_ND_quant8) {
494     spaceBatchOpTest(ANEURALNETWORKS_BATCH_TO_SPACE_ND, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
495 }
496 
transposeAndSqueezeOpTest(ANeuralNetworksOperationType operationCode,int32_t operandCode)497 void transposeAndSqueezeOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
498     uint32_t inputDimensions[4] = {2, 2, 2, 2};
499     ANeuralNetworksOperandType input = {.type = operandCode,
500                                         .dimensionCount = 4,
501                                         .dimensions = inputDimensions,
502                                         .scale = 0.0f,
503                                         .zeroPoint = 0};
504     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
505         input.scale = 1.f / 256;
506     }
507 
508     uint32_t blockDimensions[1] = {4};
509     ANeuralNetworksOperandType dims = {.type = ANEURALNETWORKS_TENSOR_INT32,
510                                        .dimensionCount = 1,
511                                        .dimensions = blockDimensions,
512                                        .scale = 0.0f,
513                                        .zeroPoint = 0};
514 
515     ANeuralNetworksOperandType output = input;
516     OperationTestBase transposeAndSqueezeTest(operationCode, {input, dims}, {output});
517 
518     EXPECT_TRUE(transposeAndSqueezeTest.testMutatingInputOperandCode());
519     EXPECT_TRUE(transposeAndSqueezeTest.testMutatingInputOperandCounts());
520     EXPECT_TRUE(transposeAndSqueezeTest.testMutatingOutputOperandCode());
521     EXPECT_TRUE(transposeAndSqueezeTest.testMutatingOutputOperandCounts());
522 }
523 
TEST(OperationValidationTest,TRANSPOSE_float32)524 TEST(OperationValidationTest, TRANSPOSE_float32) {
525     transposeAndSqueezeOpTest(ANEURALNETWORKS_TRANSPOSE, ANEURALNETWORKS_TENSOR_FLOAT32);
526 }
527 
TEST(OperationValidationTest,SQUEEZE_float32)528 TEST(OperationValidationTest, SQUEEZE_float32) {
529     transposeAndSqueezeOpTest(ANEURALNETWORKS_SQUEEZE, ANEURALNETWORKS_TENSOR_FLOAT32);
530 }
531 
TEST(OperationValidationTest,TRANSPOSE_quant8)532 TEST(OperationValidationTest, TRANSPOSE_quant8) {
533     transposeAndSqueezeOpTest(ANEURALNETWORKS_TRANSPOSE, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
534 }
535 
TEST(OperationValidationTest,SQUEEZE_quant8)536 TEST(OperationValidationTest, SQUEEZE_quant8) {
537     transposeAndSqueezeOpTest(ANEURALNETWORKS_SQUEEZE, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
538 }
539 
convOpTest(int32_t operandCode)540 void convOpTest(int32_t operandCode) {
541     uint32_t inputDimensions[4] = {2, 4, 4, 2};
542     ANeuralNetworksOperandType input = {.type = operandCode,
543                                         .dimensionCount = 4,
544                                         .dimensions = inputDimensions,
545                                         .scale = 0.0f,
546                                         .zeroPoint = 0};
547     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
548         input.scale = 0.5f;
549     }
550 
551     ANeuralNetworksOperandType filter = input;
552     ANeuralNetworksOperandType output = input;
553 
554     uint32_t biasDimensions[1] = {2};
555     ANeuralNetworksOperandType bias = {.type = operandCode,
556                                        .dimensionCount = 1,
557                                        .dimensions = biasDimensions,
558                                        .scale = 0.0f,
559                                        .zeroPoint = 0};
560     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
561         bias.type = ANEURALNETWORKS_TENSOR_INT32;
562         bias.scale = 0.25f;
563     }
564 
565     ANeuralNetworksOperandType scalar = {.type = ANEURALNETWORKS_INT32,
566                                          .dimensionCount = 0,
567                                          .dimensions = nullptr,
568                                          .scale = 0.0f,
569                                          .zeroPoint = 0};
570     ANeuralNetworksOperandType padLeft = scalar;
571     ANeuralNetworksOperandType padRight = scalar;
572     ANeuralNetworksOperandType padTop = scalar;
573     ANeuralNetworksOperandType padBottom = scalar;
574     ANeuralNetworksOperandType strideWidth = scalar;
575     ANeuralNetworksOperandType strideHeight = scalar;
576     ANeuralNetworksOperandType activation = scalar;
577 
578     OperationTestBase explicitConvTest(ANEURALNETWORKS_CONV_2D,
579                                        {input, filter, bias,
580                                         padLeft, padRight, padTop, padBottom,
581                                         strideWidth, strideHeight,
582                                         activation},
583                                        {output});
584 
585     EXPECT_TRUE(explicitConvTest.testMutatingInputOperandCode());
586     EXPECT_TRUE(explicitConvTest.testMutatingInputOperandCounts());
587     EXPECT_TRUE(explicitConvTest.testMutatingOutputOperandCode());
588     EXPECT_TRUE(explicitConvTest.testMutatingOutputOperandCounts());
589 
590     ANeuralNetworksOperandType padImplicit = scalar;
591     OperationTestBase implicitConvTest(ANEURALNETWORKS_CONV_2D,
592                                        {input, filter, bias,
593                                         padImplicit,
594                                         strideWidth, strideHeight,
595                                         activation},
596                                        {output});
597 
598     EXPECT_TRUE(implicitConvTest.testMutatingInputOperandCode());
599     EXPECT_TRUE(implicitConvTest.testMutatingInputOperandCounts());
600     EXPECT_TRUE(implicitConvTest.testMutatingOutputOperandCode());
601     EXPECT_TRUE(implicitConvTest.testMutatingOutputOperandCounts());
602 }
603 
TEST(OperationValidationTest,CONV_2D_float32)604 TEST(OperationValidationTest, CONV_2D_float32) {
605     convOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
606 }
607 
TEST(OperationValidationTest,CONV_2D_quant8)608 TEST(OperationValidationTest, CONV_2D_quant8) {
609     convOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
610 }
611 
depthwiseConvOpTest(int32_t operandCode)612 void depthwiseConvOpTest(int32_t operandCode) {
613     uint32_t inputDimensions[4] = {1, 2, 2, 2};
614     ANeuralNetworksOperandType input = {.type = operandCode,
615                                         .dimensionCount = 4,
616                                         .dimensions = inputDimensions,
617                                         .scale = 0.0f,
618                                         .zeroPoint = 0};
619     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
620         input.scale = 0.5f;
621     }
622 
623     ANeuralNetworksOperandType filter = input;
624     ANeuralNetworksOperandType output = input;
625 
626     uint32_t biasDimensions[1] = {2};
627     ANeuralNetworksOperandType bias = {.type = operandCode,
628                                        .dimensionCount = 1,
629                                        .dimensions = biasDimensions,
630                                        .scale = 0.0f,
631                                        .zeroPoint = 0};
632     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
633         bias.type = ANEURALNETWORKS_TENSOR_INT32;
634         bias.scale = 0.25f;
635     }
636 
637     ANeuralNetworksOperandType scalar = {.type = ANEURALNETWORKS_INT32,
638                                          .dimensionCount = 0,
639                                          .dimensions = nullptr,
640                                          .scale = 0.0f,
641                                          .zeroPoint = 0};
642     ANeuralNetworksOperandType padLeft = scalar;
643     ANeuralNetworksOperandType padRight = scalar;
644     ANeuralNetworksOperandType padTop = scalar;
645     ANeuralNetworksOperandType padBottom = scalar;
646     ANeuralNetworksOperandType strideWidth = scalar;
647     ANeuralNetworksOperandType strideHeight = scalar;
648     ANeuralNetworksOperandType multiplier = scalar;
649     ANeuralNetworksOperandType activation = scalar;
650 
651     OperationTestBase explicitDepthwiseConvTest(ANEURALNETWORKS_DEPTHWISE_CONV_2D,
652                                                 {input, filter, bias,
653                                                  padLeft, padRight, padTop, padBottom,
654                                                  strideWidth, strideHeight,
655                                                  multiplier, activation},
656                                                 {output});
657 
658     EXPECT_TRUE(explicitDepthwiseConvTest.testMutatingInputOperandCode());
659     EXPECT_TRUE(explicitDepthwiseConvTest.testMutatingInputOperandCounts());
660     EXPECT_TRUE(explicitDepthwiseConvTest.testMutatingOutputOperandCode());
661     EXPECT_TRUE(explicitDepthwiseConvTest.testMutatingOutputOperandCounts());
662 
663     ANeuralNetworksOperandType padImplicit = scalar;
664     OperationTestBase implicitDepthwiseConvTest(ANEURALNETWORKS_DEPTHWISE_CONV_2D,
665                                                 {input, filter, bias,
666                                                  padImplicit,
667                                                  strideWidth, strideHeight,
668                                                  multiplier, activation},
669                                                 {output});
670 
671     EXPECT_TRUE(implicitDepthwiseConvTest.testMutatingInputOperandCode());
672     EXPECT_TRUE(implicitDepthwiseConvTest.testMutatingInputOperandCounts());
673     EXPECT_TRUE(implicitDepthwiseConvTest.testMutatingOutputOperandCode());
674     EXPECT_TRUE(implicitDepthwiseConvTest.testMutatingOutputOperandCounts());
675 }
676 
TEST(OperationValidationTest,DEPTHWISE_CONV_2D_float32)677 TEST(OperationValidationTest, DEPTHWISE_CONV_2D_float32) {
678     depthwiseConvOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
679 }
680 
TEST(OperationValidationTest,DEPTHWISE_CONV_2D_quant8)681 TEST(OperationValidationTest, DEPTHWISE_CONV_2D_quant8) {
682     depthwiseConvOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
683 }
684 
fullyConnectedOpTest(int32_t operandCode)685 void fullyConnectedOpTest(int32_t operandCode) {
686     uint32_t inputDimensions[2] = {5, 5};
687     ANeuralNetworksOperandType input = {.type = operandCode,
688                                         .dimensionCount = 2,
689                                         .dimensions = inputDimensions,
690                                         .scale = 0.0f,
691                                         .zeroPoint = 0};
692     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
693         input.scale = 0.5f;
694     }
695 
696     ANeuralNetworksOperandType weights = input;
697     ANeuralNetworksOperandType output = input;
698 
699     uint32_t biasDimensions[1] = {5};
700     ANeuralNetworksOperandType bias = {.type = operandCode,
701                                        .dimensionCount = 1,
702                                        .dimensions = biasDimensions,
703                                        .scale = 0.0f,
704                                        .zeroPoint = 0};
705     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
706         bias.type = ANEURALNETWORKS_TENSOR_INT32;
707         bias.scale = 0.25f;
708     }
709 
710     ANeuralNetworksOperandType activation = {.type = ANEURALNETWORKS_INT32,
711                                              .dimensionCount = 0,
712                                              .dimensions = nullptr,
713                                              .scale = 0.0f,
714                                              .zeroPoint = 0};
715 
716     OperationTestBase fullyConnectedTest(ANEURALNETWORKS_FULLY_CONNECTED,
717                                          {input, weights, bias, activation},
718                                          {output});
719 
720     EXPECT_TRUE(fullyConnectedTest.testMutatingInputOperandCode());
721     EXPECT_TRUE(fullyConnectedTest.testMutatingInputOperandCounts());
722     EXPECT_TRUE(fullyConnectedTest.testMutatingOutputOperandCode());
723     EXPECT_TRUE(fullyConnectedTest.testMutatingOutputOperandCounts());
724 }
725 
TEST(OperationValidationTest,FULLY_CONNECTED_float32)726 TEST(OperationValidationTest, FULLY_CONNECTED_float32) {
727     fullyConnectedOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
728 }
729 
TEST(OperationValidationTest,FULLY_CONNECTED_quant8)730 TEST(OperationValidationTest, FULLY_CONNECTED_quant8) {
731     fullyConnectedOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
732 }
733 
concatenationTest(int32_t operandCode)734 void concatenationTest(int32_t operandCode) {
735     uint32_t inputDimensions[2] = {5, 5};
736     ANeuralNetworksOperandType input1 = {.type = operandCode,
737                                         .dimensionCount = 2,
738                                         .dimensions = inputDimensions,
739                                         .scale = 0.0f,
740                                         .zeroPoint = 0};
741     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
742         input1.scale = 0.5f;
743     }
744     ANeuralNetworksOperandType input2 = input1;
745     ANeuralNetworksOperandType output = input1;
746 
747     ANeuralNetworksOperandType activation = {.type = ANEURALNETWORKS_INT32,
748                                              .dimensionCount = 0,
749                                              .dimensions = nullptr,
750                                              .scale = 0.0f,
751                                              .zeroPoint = 0};
752 
753     OperationTestBase concat2Test(ANEURALNETWORKS_CONCATENATION,
754                                   {input1, input2, activation}, {output});
755 
756     EXPECT_TRUE(concat2Test.testMutatingInputOperandCode());
757     EXPECT_TRUE(concat2Test.testMutatingOutputOperandCode());
758     EXPECT_TRUE(concat2Test.testMutatingOutputOperandCounts());
759 
760     OperationTestBase concat1Test(ANEURALNETWORKS_CONCATENATION,
761                                   {input1, activation}, {output});
762 
763     EXPECT_TRUE(concat1Test.testMutatingInputOperandCode());
764     EXPECT_TRUE(concat1Test.testMutatingOutputOperandCode());
765     EXPECT_TRUE(concat1Test.testMutatingOutputOperandCounts());
766 }
767 
TEST(OperationValidationTest,CONCATENATION_float32)768 TEST(OperationValidationTest, CONCATENATION_float32) {
769     concatenationTest(ANEURALNETWORKS_TENSOR_FLOAT32);
770 }
771 
TEST(OperationValidationTest,CONCATENATION_quant8)772 TEST(OperationValidationTest, CONCATENATION_quant8) {
773     concatenationTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
774 }
775 
TEST(OperationValidationTest,RESIZE_BILINEAR_float32)776 TEST(OperationValidationTest, RESIZE_BILINEAR_float32) {
777     uint32_t inputDimensions[4] = {2, 2, 2, 2};
778     ANeuralNetworksOperandType input = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
779                                         .dimensionCount = 4,
780                                         .dimensions = inputDimensions,
781                                         .scale = 0.0f,
782                                         .zeroPoint = 0};
783     ANeuralNetworksOperandType height = {.type = ANEURALNETWORKS_INT32,
784                                          .dimensionCount = 0,
785                                          .dimensions = nullptr,
786                                          .scale = 0.0f,
787                                          .zeroPoint = 0};
788     ANeuralNetworksOperandType width = height;
789     ANeuralNetworksOperandType output = input;
790     OperationTestBase resizeTest(ANEURALNETWORKS_RESIZE_BILINEAR,
791                                  {input, height, width}, {output});
792 
793     EXPECT_TRUE(resizeTest.testMutatingInputOperandCode());
794     EXPECT_TRUE(resizeTest.testMutatingInputOperandCounts());
795     EXPECT_TRUE(resizeTest.testMutatingOutputOperandCode());
796     EXPECT_TRUE(resizeTest.testMutatingOutputOperandCounts());
797 }
798 
embeddingLookupTest(int32_t operandCode)799 void embeddingLookupTest(int32_t operandCode) {
800     uint32_t lookupDimensions[1] = {5};
801     ANeuralNetworksOperandType lookup = {.type = ANEURALNETWORKS_TENSOR_INT32,
802                                          .dimensionCount = 1,
803                                          .dimensions = lookupDimensions,
804                                          .scale = 0.0f,
805                                          .zeroPoint = 0};
806 
807     uint32_t inputDimensions[2] = {5, 5};
808     ANeuralNetworksOperandType input = {.type = operandCode,
809                                         .dimensionCount = 2,
810                                         .dimensions = inputDimensions,
811                                         .scale = 0.0f,
812                                         .zeroPoint = 0};
813     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
814         input.scale = 0.5f;
815     }
816     ANeuralNetworksOperandType output = input;
817 
818     OperationTestBase embedLookupTest(ANEURALNETWORKS_EMBEDDING_LOOKUP,
819                                       {lookup, input}, {output});
820 
821     EXPECT_TRUE(embedLookupTest.testMutatingInputOperandCode());
822     EXPECT_TRUE(embedLookupTest.testMutatingInputOperandCounts());
823     EXPECT_TRUE(embedLookupTest.testMutatingOutputOperandCode());
824     EXPECT_TRUE(embedLookupTest.testMutatingOutputOperandCounts());
825 }
826 
TEST(OperationValidationTest,EMBEDDING_LOOKUP_float32)827 TEST(OperationValidationTest, EMBEDDING_LOOKUP_float32) {
828     embeddingLookupTest(ANEURALNETWORKS_TENSOR_FLOAT32);
829 }
830 
TEST(OperationValidationTest,EMBEDDING_LOOKUP_quant8)831 TEST(OperationValidationTest, EMBEDDING_LOOKUP_quant8) {
832     embeddingLookupTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
833 }
834 
hashtableLookupTest(int32_t operandCode)835 void hashtableLookupTest(int32_t operandCode) {
836     uint32_t lookupDimensions[1] = {5};
837     ANeuralNetworksOperandType lookup = {.type = ANEURALNETWORKS_TENSOR_INT32,
838                                          .dimensionCount = 1,
839                                          .dimensions = lookupDimensions,
840                                          .scale = 0.0f,
841                                          .zeroPoint = 0};
842     ANeuralNetworksOperandType keys = lookup;
843 
844     uint32_t valuesDimensions[2] = {5, 5};
845     ANeuralNetworksOperandType values = {.type = operandCode,
846                                          .dimensionCount = 2,
847                                          .dimensions = valuesDimensions,
848                                          .scale = 0.0f,
849                                          .zeroPoint = 0};
850     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
851         values.scale = 0.5f;
852     }
853     ANeuralNetworksOperandType output = values;
854 
855     ANeuralNetworksOperandType hits = lookup;
856     hits.type = ANEURALNETWORKS_TENSOR_QUANT8_ASYMM;
857     hits.scale = 1.0f;
858 
859     OperationTestBase hashLookupTest(ANEURALNETWORKS_HASHTABLE_LOOKUP,
860                                       {lookup, keys, values}, {output, hits});
861 
862     EXPECT_TRUE(hashLookupTest.testMutatingInputOperandCode());
863     EXPECT_TRUE(hashLookupTest.testMutatingInputOperandCounts());
864     EXPECT_TRUE(hashLookupTest.testMutatingOutputOperandCode());
865     EXPECT_TRUE(hashLookupTest.testMutatingOutputOperandCounts());
866 }
867 
TEST(OperationValidationTest,HASHTABLE_LOOKUP_float32)868 TEST(OperationValidationTest, HASHTABLE_LOOKUP_float32) {
869     hashtableLookupTest(ANEURALNETWORKS_TENSOR_FLOAT32);
870 }
871 
TEST(OperationValidationTest,HASHTABLE_LOOKUP_quant8)872 TEST(OperationValidationTest, HASHTABLE_LOOKUP_quant8) {
873     hashtableLookupTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
874 }
875 
lshProjectionTest(int32_t operandCode)876 void lshProjectionTest(int32_t operandCode) {
877     uint32_t inputDimensions[2] = {5, 5};
878     ANeuralNetworksOperandType hash = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
879                                        .dimensionCount = 2,
880                                        .dimensions = inputDimensions,
881                                        .scale = 0.0f,
882                                        .zeroPoint = 0};
883 
884     ANeuralNetworksOperandType input = hash;
885     input.type = operandCode;
886     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
887         input.scale = 0.5f;
888     }
889 
890     uint32_t weightDimensions[1] = {5};
891     ANeuralNetworksOperandType weight = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
892                                          .dimensionCount = 1,
893                                          .dimensions = weightDimensions,
894                                          .scale = 0.0f,
895                                          .zeroPoint = 0};
896 
897     ANeuralNetworksOperandType type = {.type = ANEURALNETWORKS_INT32,
898                                        .dimensionCount = 0,
899                                        .dimensions = nullptr,
900                                        .scale = 0.0f,
901                                        .zeroPoint = 0};
902 
903     ANeuralNetworksOperandType output = weight;
904     output.type = ANEURALNETWORKS_TENSOR_INT32;
905 
906     OperationTestBase lshProjTest(ANEURALNETWORKS_LSH_PROJECTION,
907                                   {hash, input, weight, type}, {output});
908 
909     EXPECT_TRUE(lshProjTest.testMutatingInputOperandCode());
910     EXPECT_TRUE(lshProjTest.testMutatingInputOperandCounts());
911     EXPECT_TRUE(lshProjTest.testMutatingOutputOperandCode());
912     EXPECT_TRUE(lshProjTest.testMutatingOutputOperandCounts());
913 }
914 
TEST(OperationValidationTest,LSH_PROJECTION_float32)915 TEST(OperationValidationTest, LSH_PROJECTION_float32) {
916     lshProjectionTest(ANEURALNETWORKS_TENSOR_FLOAT32);
917 }
918 
TEST(OperationValidationTest,LSH_PROJECTION_quant8)919 TEST(OperationValidationTest, LSH_PROJECTION_quant8) {
920     lshProjectionTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
921 }
922 
TEST(OperationValidationTest,LSTM_float32)923 TEST(OperationValidationTest, LSTM_float32) {
924     uint32_t oneDimensional[1] = {5};
925     uint32_t twoDimensional[2] = {5, 5};
926     ANeuralNetworksOperandType floatTensor1D = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
927                                                 .dimensionCount = 1,
928                                                 .dimensions = oneDimensional,
929                                                 .scale = 0.0f,
930                                                 .zeroPoint = 0};
931     ANeuralNetworksOperandType floatTensor2D = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
932                                                 .dimensionCount = 2,
933                                                 .dimensions = twoDimensional,
934                                                 .scale = 0.0f,
935                                                 .zeroPoint = 0};
936     ANeuralNetworksOperandType intScalar = {.type = ANEURALNETWORKS_INT32,
937                                             .dimensionCount = 0,
938                                             .dimensions = nullptr,
939                                             .scale = 0.0f,
940                                             .zeroPoint = 0};
941     ANeuralNetworksOperandType floatScalar = {.type = ANEURALNETWORKS_FLOAT32,
942                                               .dimensionCount = 0,
943                                               .dimensions = nullptr,
944                                               .scale = 0.0f,
945                                               .zeroPoint = 0};
946 
947     ANeuralNetworksOperandType input = floatTensor2D;
948     ANeuralNetworksOperandType inputToInput = floatTensor2D;
949     ANeuralNetworksOperandType inputToForget = floatTensor2D;
950     ANeuralNetworksOperandType inputToCell = floatTensor2D;
951     ANeuralNetworksOperandType inputToOutput = floatTensor2D;
952     ANeuralNetworksOperandType recurrentToInput = floatTensor2D;
953     ANeuralNetworksOperandType recurrentToForget = floatTensor2D;
954     ANeuralNetworksOperandType recurrentToCell = floatTensor2D;
955     ANeuralNetworksOperandType recurrentToOutput = floatTensor2D;
956     ANeuralNetworksOperandType cellToInput = floatTensor1D;
957     ANeuralNetworksOperandType cellToForget = floatTensor1D;
958     ANeuralNetworksOperandType cellToOutput = floatTensor1D;
959     ANeuralNetworksOperandType inputGateBias = floatTensor1D;
960     ANeuralNetworksOperandType forgetGateBias = floatTensor1D;
961     ANeuralNetworksOperandType cellBias = floatTensor1D;
962     ANeuralNetworksOperandType outputGateBias = floatTensor1D;
963     ANeuralNetworksOperandType projWeights = floatTensor2D;
964     ANeuralNetworksOperandType projBias = floatTensor1D;
965     ANeuralNetworksOperandType outputStateIn = floatTensor2D;
966     ANeuralNetworksOperandType cellStateIn = floatTensor2D;
967     ANeuralNetworksOperandType activation = intScalar;
968     ANeuralNetworksOperandType clipCellState = floatScalar;
969     ANeuralNetworksOperandType clipProjLayer = floatScalar;
970 
971     ANeuralNetworksOperandType scratch = floatTensor2D;
972     ANeuralNetworksOperandType outputStateOut = floatTensor2D;
973     ANeuralNetworksOperandType cellStateOut = floatTensor2D;
974     ANeuralNetworksOperandType output = floatTensor2D;
975 
976     OperationTestBase lstmTest(ANEURALNETWORKS_LSTM,
977         {input, inputToInput, inputToForget, inputToCell, inputToOutput, recurrentToInput,
978          recurrentToForget, recurrentToCell, recurrentToOutput, cellToInput, cellToForget,
979          cellToOutput, inputGateBias, forgetGateBias, cellBias, outputGateBias, projWeights,
980          projBias, outputStateIn, cellStateIn, activation, clipCellState, clipProjLayer},
981         {scratch, outputStateOut, cellStateOut, output});
982 
983     EXPECT_TRUE(lstmTest.testMutatingInputOperandCode());
984     EXPECT_TRUE(lstmTest.testMutatingInputOperandCounts());
985     EXPECT_TRUE(lstmTest.testMutatingOutputOperandCode());
986     EXPECT_TRUE(lstmTest.testMutatingOutputOperandCounts());
987 }
988 
TEST(OperationValidationTest,RNN_float32)989 TEST(OperationValidationTest, RNN_float32) {
990     uint32_t oneDimensional[1] = {5};
991     uint32_t twoDimensional[2] = {5, 5};
992     ANeuralNetworksOperandType floatTensor1D = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
993                                                 .dimensionCount = 1,
994                                                 .dimensions = oneDimensional,
995                                                 .scale = 0.0f,
996                                                 .zeroPoint = 0};
997     ANeuralNetworksOperandType floatTensor2D = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
998                                                 .dimensionCount = 2,
999                                                 .dimensions = twoDimensional,
1000                                                 .scale = 0.0f,
1001                                                 .zeroPoint = 0};
1002     ANeuralNetworksOperandType intScalar = {.type = ANEURALNETWORKS_INT32,
1003                                             .dimensionCount = 0,
1004                                             .dimensions = nullptr,
1005                                             .scale = 0.0f,
1006                                             .zeroPoint = 0};
1007 
1008     ANeuralNetworksOperandType input = floatTensor2D;
1009     ANeuralNetworksOperandType weights = floatTensor2D;
1010     ANeuralNetworksOperandType recurrentWeights = floatTensor2D;
1011     ANeuralNetworksOperandType bias = floatTensor1D;
1012     ANeuralNetworksOperandType hiddenStateIn = floatTensor2D;
1013     ANeuralNetworksOperandType activation = intScalar;
1014 
1015     ANeuralNetworksOperandType hiddenStateOut = floatTensor2D;
1016     ANeuralNetworksOperandType output = floatTensor2D;
1017 
1018     OperationTestBase rnnTest(ANEURALNETWORKS_RNN,
1019                               {input, weights, recurrentWeights, bias, hiddenStateIn, activation},
1020                               {hiddenStateOut, output});
1021 
1022     EXPECT_TRUE(rnnTest.testMutatingInputOperandCode());
1023     EXPECT_TRUE(rnnTest.testMutatingInputOperandCounts());
1024     EXPECT_TRUE(rnnTest.testMutatingOutputOperandCode());
1025     EXPECT_TRUE(rnnTest.testMutatingOutputOperandCounts());
1026 }
1027 
TEST(OperationValidationTest,SVDF_float32)1028 TEST(OperationValidationTest, SVDF_float32) {
1029     uint32_t oneDimensional[1] = {5};
1030     uint32_t twoDimensional[2] = {5, 5};
1031     ANeuralNetworksOperandType floatTensor1D = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
1032                                                 .dimensionCount = 1,
1033                                                 .dimensions = oneDimensional,
1034                                                 .scale = 0.0f,
1035                                                 .zeroPoint = 0};
1036     ANeuralNetworksOperandType floatTensor2D = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
1037                                                 .dimensionCount = 2,
1038                                                 .dimensions = twoDimensional,
1039                                                 .scale = 0.0f,
1040                                                 .zeroPoint = 0};
1041     ANeuralNetworksOperandType intScalar = {.type = ANEURALNETWORKS_INT32,
1042                                             .dimensionCount = 0,
1043                                             .dimensions = nullptr,
1044                                             .scale = 0.0f,
1045                                             .zeroPoint = 0};
1046 
1047     ANeuralNetworksOperandType input = floatTensor2D;
1048     ANeuralNetworksOperandType weightsFeature = floatTensor2D;
1049     ANeuralNetworksOperandType weightsTime = floatTensor2D;
1050     ANeuralNetworksOperandType bias = floatTensor1D;
1051     ANeuralNetworksOperandType stateIn = floatTensor2D;
1052     ANeuralNetworksOperandType rank = intScalar;
1053     ANeuralNetworksOperandType activation = intScalar;
1054 
1055     ANeuralNetworksOperandType stateOut = floatTensor2D;
1056     ANeuralNetworksOperandType output = floatTensor2D;
1057 
1058     OperationTestBase svdfTest(ANEURALNETWORKS_SVDF,
1059         {input, weightsFeature, weightsTime, bias, stateIn, rank, activation},
1060         {stateOut, output});
1061 
1062     EXPECT_TRUE(svdfTest.testMutatingInputOperandCode());
1063     EXPECT_TRUE(svdfTest.testMutatingInputOperandCounts());
1064     EXPECT_TRUE(svdfTest.testMutatingOutputOperandCode());
1065     EXPECT_TRUE(svdfTest.testMutatingOutputOperandCounts());
1066 }
1067 
stridedSliceOpTest(int32_t operandCode)1068 void stridedSliceOpTest(int32_t operandCode) {
1069     uint32_t inputDimensions[2] = {5, 5};
1070     ANeuralNetworksOperandType input = {.type = operandCode,
1071                                         .dimensionCount = 2,
1072                                         .dimensions = inputDimensions,
1073                                         .scale = 0.0f,
1074                                         .zeroPoint = 0};
1075     if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
1076         input.scale = 0.5f;
1077     }
1078     ANeuralNetworksOperandType output = input;
1079 
1080     uint32_t beginsDimensions[1] = {2};
1081     ANeuralNetworksOperandType begins = {.type = ANEURALNETWORKS_TENSOR_INT32,
1082                                          .dimensionCount = 1,
1083                                          .dimensions = beginsDimensions,
1084                                          .scale = 0.0f,
1085                                          .zeroPoint = 0};
1086 
1087     ANeuralNetworksOperandType ends = begins;
1088     ANeuralNetworksOperandType strides = begins;
1089 
1090     ANeuralNetworksOperandType beginMask = {.type = ANEURALNETWORKS_INT32,
1091                                             .dimensionCount = 0,
1092                                             .dimensions = nullptr,
1093                                             .scale = 0.0f,
1094                                             .zeroPoint = 0};
1095     ANeuralNetworksOperandType endMask = beginMask;
1096     ANeuralNetworksOperandType shrinkAxisMask = beginMask;
1097 
1098     OperationTestBase stridedSliceTest(ANEURALNETWORKS_STRIDED_SLICE,
1099                                        {input, begins, ends, strides,
1100                                         beginMask, endMask, shrinkAxisMask},
1101                                        {output});
1102 
1103     EXPECT_TRUE(stridedSliceTest.testMutatingInputOperandCode());
1104     EXPECT_TRUE(stridedSliceTest.testMutatingInputOperandCounts());
1105     EXPECT_TRUE(stridedSliceTest.testMutatingOutputOperandCode());
1106     EXPECT_TRUE(stridedSliceTest.testMutatingOutputOperandCounts());
1107 }
1108 
TEST(OperationValidationTest,STRIDED_SLICE_float32)1109 TEST(OperationValidationTest, STRIDED_SLICE_float32) {
1110     stridedSliceOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
1111 }
1112 
TEST(OperationValidationTest,STRIDED_SLICE_quant8)1113 TEST(OperationValidationTest, STRIDED_SLICE_quant8) {
1114     stridedSliceOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
1115 }
1116 
1117 }  // end namespace
1118