1 /*
2  * Copyright (C) 2019 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 #ifndef ANDROID_PACKAGES_MODULES_NEURALNETWORKS_RUNTIME_TEST_FUZZING_RANDOM_GRAPH_GENERATOR_H
18 #define ANDROID_PACKAGES_MODULES_NEURALNETWORKS_RUNTIME_TEST_FUZZING_RANDOM_GRAPH_GENERATOR_H
19 
20 #include <functional>
21 #include <memory>
22 #include <string>
23 #include <vector>
24 
25 #include "TestHarness.h"
26 #include "TestNeuralNetworksWrapper.h"
27 #include "fuzzing/RandomVariable.h"
28 
29 namespace android {
30 namespace nn {
31 namespace fuzzing_test {
32 
33 using OperandBuffer = std::vector<int32_t>;
34 
35 struct OperandSignature;
36 struct OperationSignature;
37 class OperationManager;
38 
39 enum class RandomOperandType { INPUT = 0, OUTPUT = 1, INTERNAL = 2, CONST = 3, NO_VALUE = 4 };
40 
41 struct RandomOperand {
42     // Describes the properties of the values of an operand. For operation inputs, this specifies
43     // what is required; for outputs, this specifies what is guaranteed.
44     // The graph generation algorithm will use this information to decide whether to wire an output
45     // to an input or not.
46     enum ValueProperty : int {
47         NON_ZERO = 1 << 0,
48         NON_NEGATIVE = 1 << 1,
49     };
50 
51     RandomOperandType type;
52     int valueProperties = 0;
53     test_helper::TestOperandType dataType;
54     float scale = 0.0f;
55     int32_t zeroPoint = 0;
56     std::vector<RandomVariable> dimensions;
57     OperandBuffer buffer;
58     std::vector<RandomVariable> randomBuffer;
59 
60     // The finalizer will be invoked after RandomVariableNetwork::freeze().
61     // Operand buffer will be set during this step (if not set before).
62     std::function<void(RandomOperand*)> finalizer = nullptr;
63 
64     // The index of the operand in the model as returned from model->addOperand(...).
65     int32_t opIndex = -1;
66     // The index of the input/output as specified in model->identifyInputsAndOutputs(...).
67     int32_t ioIndex = -1;
68 
69     // If set true, this operand will be ignored during the accuracy checking step.
70     bool doNotCheckAccuracy = false;
71 
72     // If set true, this operand will not be connected to another operation, e.g. if this operand is
73     // an operation output, then it will not be used as an input to another operation, and will
74     // eventually end up being a model output.
75     bool doNotConnect = false;
76 
77     RandomOperand(const OperandSignature& op, test_helper::TestOperandType dataType, uint32_t rank);
78 
79     // Resize the underlying operand buffer.
80     template <typename T>
resizeBufferRandomOperand81     void resizeBuffer(uint32_t len) {
82         constexpr size_t valueSize = sizeof(OperandBuffer::value_type);
83         uint32_t bufferSize = (sizeof(T) * len + valueSize - 1) / valueSize;
84         buffer.resize(bufferSize);
85     }
86 
87     // Get the operand value as the specified type. The caller is reponsible for making sure that
88     // the index is not out of range.
89     template <typename T>
90     T& value(uint32_t index = 0) {
91         return reinterpret_cast<T*>(buffer.data())[index];
92     }
93     template <>
94     RandomVariable& value<RandomVariable>(uint32_t index) {
95         return randomBuffer[index];
96     }
97 
98     // The caller is reponsible for making sure that the operand is indeed a scalar.
99     template <typename T>
setScalarValueRandomOperand100     void setScalarValue(const T& val) {
101         resizeBuffer<T>(/*len=*/1);
102         value<T>() = val;
103     }
104 
105     // Check if a directed edge between [other -> this] is valid. If yes, add the edge.
106     // Where "this" must be of type INPUT and "other" must be of type OUTPUT.
107     bool createEdgeIfValid(const RandomOperand& other) const;
108 
109     // The followings are only intended to be used after RandomVariableNetwork::freeze().
110     std::vector<uint32_t> getDimensions() const;
111     uint32_t getNumberOfElements() const;
112     size_t getBufferSize() const;
113 };
114 
115 struct RandomOperation {
116     test_helper::TestOperationType opType;
117     std::vector<std::shared_ptr<RandomOperand>> inputs;
118     std::vector<std::shared_ptr<RandomOperand>> outputs;
119     std::function<void(RandomOperation*)> finalizer = nullptr;
120     RandomOperation(const OperationSignature& operation);
121 };
122 
123 // The main interface of the random graph generator.
124 class RandomGraph {
125    public:
126     RandomGraph() = default;
127 
128     // Generate a random graph with numOperations and dimensionRange from a seed.
129     bool generate(uint32_t seed, uint32_t numOperations, uint32_t dimensionRange);
130 
131     // Create a test model of the generated graph. The operands will always have fully-specified
132     // dimensions. The output buffers are only allocated but not initialized.
133     test_helper::TestModel createTestModel();
134 
getOperations()135     const std::vector<RandomOperation>& getOperations() const { return mOperations; }
136 
137    private:
138     // Generate the graph structure.
139     bool generateGraph(uint32_t numOperations);
140 
141     // Fill in random values for dimensions, constants, and inputs.
142     bool generateValue();
143 
144     std::vector<RandomOperation> mOperations;
145     std::vector<std::shared_ptr<RandomOperand>> mOperands;
146 };
147 
148 }  // namespace fuzzing_test
149 }  // namespace nn
150 }  // namespace android
151 
152 #endif  // ANDROID_PACKAGES_MODULES_NEURALNETWORKS_RUNTIME_TEST_FUZZING_RANDOM_GRAPH_GENERATOR_H
153