AIfES 2  2.0.0
aimath_q31_default.h File Reference

Math functions for Q31 data type, default implementation. More...

Go to the source code of this file.

Functions

void aimath_q31_default_linear32 (const aitensor_t *a, const aitensor_t *b, const aitensor_t *c, aitensor_t *result)
 Performs a matrix multiplication of Q31 matrices a and b and adds a vector c to each row. More...
 
void aimath_q31_default_mat_mul (const aitensor_t *a, const aitensor_t *b, aitensor_t *result)
 Performs a matrix multiplication of Q31 matrices a and b. More...
 
void aimath_q31_default_multiply (const aitensor_t *a, const aitensor_t *b, aitensor_t *result)
 Performs an element wise multiplication of Q31 tensors a and b (Hadamard product) More...
 
void aimath_q31_default_scalar_mul (const void *scalar, const aitensor_t *a, aitensor_t *result)
 Performs a scalar multiplication (scaling) of Q31 tensor a and a scalar. More...
 
void aimath_q31_default_tensor_add_different_shift (const aitensor_t *a, const aitensor_t *b, aitensor_t *result)
 Performs an element wise addition of Q31 tensors a and b with different shifts. More...
 
void aimath_q31_default_tensor_add_same_shift (const aitensor_t *a, const aitensor_t *b, aitensor_t *result)
 Performs an element wise addition of Q31 tensors a and b with same shifts. More...
 
void aimath_q31_default_tensor_sub_different_shift (const aitensor_t *a, const aitensor_t *b, aitensor_t *result)
 Performs an element wise subtraction of Q31 tensors a and b with different shifts. More...
 
void aimath_q31_default_tensor_sub_same_shift (const aitensor_t *a, const aitensor_t *b, aitensor_t *result)
 Performs an element wise subtraction of Q31 tensors a and b with same shifts. More...
 
void aimath_q31_default_copy_tensor (const aitensor_t *from, aitensor_t *to)
 Performs an element wise copy of Q31 tensors. More...
 
void aimath_q31_default_transpose_vector (aitensor_t *vector)
 Transposes a Q31 vector. More...
 
void aimath_q31_default_norm_squared (const aitensor_t *x, void *result)
 Calculates the squared sum of all elements in a Q31 tensor. More...
 
void aimath_q31_default_tensor_sqrt (const aitensor_t *x, aitensor_t *result)
 Calculates the element wise square root of a Q31 tensor. More...
 
void aimath_q31_default_sigmoid (const aitensor_t *x, aitensor_t *result)
 Calculates the sigmoid of each element in a Q31 tensor. More...
 
void aimath_q31_default_d_sigmoid (const aitensor_t *sigmoid_x, aitensor_t *result)
 Calculates the derivative sigmoid of each element in a Q31 tensor. More...
 
void aimath_q31_default_relu (const aitensor_t *x, aitensor_t *result)
 Calculates the rectifier (ReLU) value of each element in a Q31 tensor. More...
 
void aimath_q31_default_d_relu (const aitensor_t *x, aitensor_t *result)
 Calculates the rectifier (ReLU) derivative of each element in a Q31 tensor. More...
 
void aimath_q31_default_leaky_relu (const aitensor_t *x, const void *alpha, aitensor_t *result)
 Calculates the leaky rectifier (leaky ReLU) value of each element in a Q31 tensor. More...
 
void aimath_q31_default_d_leaky_relu (const aitensor_t *x, const void *alpha, aitensor_t *result)
 Calculates the leaky rectifier (leaky-ReLU) derivative of each element in a Q31 tensor. More...
 
void aimath_q31_default_tanh (const aitensor_t *x, aitensor_t *result)
 Calculates the tanh of each element in a Q31 tensor. More...
 
void aimath_q31_default_d_tanh (const aitensor_t *tanh_x, aitensor_t *result)
 Calculates the tanh derivative of each element in a Q31 tensor. More...
 
void aimath_q31_default_softsign (const aitensor_t *x, aitensor_t *result)
 Calculates the softsign value of each element in a Q31 tensor. More...
 
void aimath_q31_default_d_softsign (const aitensor_t *x, aitensor_t *result)
 Calculates the softsign activation derivative of each element in a Q31 tensor. More...
 
void aimath_q31_default_softmax (const aitensor_t *x, aitensor_t *result)
 Calculates the softmax value of each batch element (row) of a Q31 tensor. More...
 
void aimath_q31_default_elu (const aitensor_t *x, const void *alpha, aitensor_t *result)
 Calculates the exponential rectifier (ELU) value of each element in a Q31 tensor. More...
 
void aimath_q31_default_d_elu (const aitensor_t *x, const void *alpha, aitensor_t *result)
 Calculates the exponential rectifier (ELU) derivative of each element in a Q31 tensor. More...
 
void aimath_q31_default_zero_tensor (aitensor_t *tensor)
 Fills a Q31 tensor with zeros. More...
 
void aimath_q31_default_init_zeros (aitensor_t *tensor)
 Fills a Q31 tensor with zeros. More...
 
void aimath_q31_default_tensor_init_uniform (aitensor_t *tensor, float from, float to)
 Fills a Q31 tensor with random numbers created from a uniform distribution within given range. More...
 
void aimath_q31_default_init_glorot_uniform (aitensor_t *tensor)
 Fills a Q31 tensor with random numbers uniformly within given range, according to Glorot et al. More...
 
int64_t aimath_q31_default_sqrt (int64_t x)
 Calculates square root of an int64 value. More...
 

Detailed Description

Math functions for Q31 data type, default implementation.

Version
2.0alpha

These functions can be used when no hardware specific implementation is available.

Function Documentation

◆ aimath_q31_default_copy_tensor()

void aimath_q31_default_copy_tensor ( const aitensor_t from,
aitensor_t to 
)

Performs an element wise copy of Q31 tensors.

\[ to \leftarrow from \]

Dimension, shape and quantization parameters of from and to tensors have to be the same.

Example:

uint16_t from_shape[2] = {2, 3};
aimath_q31_params_t from_params = {1, 0}; // {shift, zero point}
int32_t from_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t from = AITENSOR_2D_Q31(from_shape, &from_params, from_data);
uint16_t to_shape[2] = {2, 3};
aimath_q31_params_t to_params = {1, 0}; // {shift, zero point}
int32_t to_data[2*3];
aitensor_t to = AITENSOR_2D_Q31(to_shape, &to_params, to_data);
void print_aitensor(const aitensor_t *tensor)
Printing a tensor to console.
void aimath_q31_default_copy_tensor(const aitensor_t *from, aitensor_t *to)
Performs an element wise copy of Q31 tensors.
Parameters used for the quantized Q31 values, used as property of a tensor.
Definition: aimath_q31.h:149
A tensor in AIfES.
Definition: aifes_math.h:89
Parameters
*fromQ31 tensor to copy from (N-D tensor)
*toQ31 tensor to copy to (N-D tensor)

◆ aimath_q31_default_d_elu()

void aimath_q31_default_d_elu ( const aitensor_t x,
const void *  alpha,
aitensor_t result 
)

Calculates the exponential rectifier (ELU) derivative of each element in a Q31 tensor.

\[ result_{i} = \begin{cases} \alpha \cdot e^{x_i} & \text{if } x_i < 0\\ 1 & \text{if } x_i \geq 0 \end{cases} \]

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
aiscalar_q31_t alpha = AISCALAR_Q31(1.0f, 0, 0);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params; // {shift, zero point}
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
aimath_q31_default_d_elu(&x, &alpha, &result);
print_aitensor(&result);
void aimath_q31_default_d_elu(const aitensor_t *x, const void *alpha, aitensor_t *result)
Calculates the exponential rectifier (ELU) derivative of each element in a Q31 tensor.
Single quantized Q31 value/scalar.
Definition: aimath_q31.h:156
Parameters
*xQ31 tensor to calculate the ELU derivative from (N-D tensor)
*alphaScalar \( \alpha \) (type aiscalar_q31_t)
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_d_leaky_relu()

void aimath_q31_default_d_leaky_relu ( const aitensor_t x,
const void *  alpha,
aitensor_t result 
)

Calculates the leaky rectifier (leaky-ReLU) derivative of each element in a Q31 tensor.

\[ result_{ij} = \begin{cases} alpha & \text{if } x_i < 0\\ 1 & \text{if } x_i \geq 0 \end{cases} \]

The quantization parameters of the result tensor are set to {shift = 0, zero_point = 0} by the function because the output values are either alpha or 1.

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params; // {shift, zero point}
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
print_aitensor(&result);
void aimath_q31_default_d_leaky_relu(const aitensor_t *x, const void *alpha, aitensor_t *result)
Calculates the leaky rectifier (leaky-ReLU) derivative of each element in a Q31 tensor.
Parameters
*xQ31 tensor to calculate the leaky-ReLU derivative from (N-D tensor)
*alphaScalar \( \alpha \) (type aiscalar_q31_t) for the leakage
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_d_relu()

void aimath_q31_default_d_relu ( const aitensor_t x,
aitensor_t result 
)

Calculates the rectifier (ReLU) derivative of each element in a Q31 tensor.

\[ result_{ij} = \begin{cases} 0 & \text{if } x_i < 0\\ 1 & \text{if } x_i \geq 0 \end{cases} \]

The quantization parameters of the result tensor are set to {shift = 0, zero_point = 0} by the function because the output values are either 0 or 1.

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params; // {shift, zero point}
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
print_aitensor(&result);
void aimath_q31_default_d_relu(const aitensor_t *x, aitensor_t *result)
Calculates the rectifier (ReLU) derivative of each element in a Q31 tensor.
Parameters
*xQ31 tensor to calculate the ReLU derivative from (N-D tensor)
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_d_sigmoid()

void aimath_q31_default_d_sigmoid ( const aitensor_t sigmoid_x,
aitensor_t result 
)

Calculates the derivative sigmoid of each element in a Q31 tensor.

\[ result_{i} = \sigma'(x_{i}) = \sigma(x_{i}) \cdot (1 - \sigma(x_{i})) \]

The quantization parameters of the result tensor are set to {shift = 34, zero_point = -2^31} by the function because the output values are in the interval (0, 0.25].

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params;
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
aimath_q31_default_d_sigmoid(&result, &result);
print_aitensor(&result);
void aimath_q31_default_sigmoid(const aitensor_t *x, aitensor_t *result)
Calculates the sigmoid of each element in a Q31 tensor.
void aimath_q31_default_d_sigmoid(const aitensor_t *sigmoid_x, aitensor_t *result)
Calculates the derivative sigmoid of each element in a Q31 tensor.
Parameters
*sigmoid_xQ31 tensor with the sigmoid values \( \sigma(x_{i}) \) (N-D tensor)
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_d_softsign()

void aimath_q31_default_d_softsign ( const aitensor_t x,
aitensor_t result 
)

Calculates the softsign activation derivative of each element in a Q31 tensor.

\[ result_{i} = \frac {1} {(1 + |x_i|)^2} \]

The quantization parameters of the result tensor are set to {shift = 32, zero_point = -2^31} by the function because the output values are in the interval (0, 1).

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params; // {shift, zero point}
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
print_aitensor(&result);
void aimath_q31_default_d_softsign(const aitensor_t *x, aitensor_t *result)
Calculates the softsign activation derivative of each element in a Q31 tensor.
Parameters
*xQ31 tensor to calculate the softsign derivative from (N-D tensor)
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_d_tanh()

void aimath_q31_default_d_tanh ( const aitensor_t tanh_x,
aitensor_t result 
)

Calculates the tanh derivative of each element in a Q31 tensor.

\[ result_{i} = \tanh'(x_{i}) = 1 - \tanh(x_{i}) * \tanh(x_{i}) \]

The quantization parameters of the result tensor are set to {shift = 32, zero_point = -2^31} by the function because the output values are in the interval (0, 1].

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params;
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
aimath_q31_default_d_tanh(&result, &result);
print_aitensor(&result);
void aimath_q31_default_d_tanh(const aitensor_t *tanh_x, aitensor_t *result)
Calculates the tanh derivative of each element in a Q31 tensor.
void aimath_q31_default_tanh(const aitensor_t *x, aitensor_t *result)
Calculates the tanh of each element in a Q31 tensor.
Parameters
*tanh_xQ31 tensor with the tanh values \( \tanh(x_{i}) \) (N-D tensor)
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_elu()

void aimath_q31_default_elu ( const aitensor_t x,
const void *  alpha,
aitensor_t result 
)

Calculates the exponential rectifier (ELU) value of each element in a Q31 tensor.

\[ result_{i} = \begin{cases} \alpha \cdot (e^{x_i} - 1) & \text{if } x_i < 0 \\ x_i & \text{if } x_i \geq 0 \end{cases} \]

The ELU is calculated with a piecewise linear approximation to avoid using exponential functions.

\[ result_{i} = \begin{cases} x_i & \text{if } 0 \leq x_i\\ \alpha \cdot 0.625 \cdot x_i & \text{if } -1 \leq x < 0\\ \alpha \cdot (0.25 \cdot x_i - 0.375) & \text{if } -2 \leq x < -1\\ \alpha \cdot (0.09375 \cdot x_i - 0.6875) & \text{if } -3 \leq x < -2\\ \alpha \cdot (0.03125 \cdot x_i - 0.875) & \text{if } -4 \leq x < -3\\ - \alpha & \text{if } x < -4 \end{cases} \]

The quantization parameters of the result tensor are set to {shift = x.shift, zero_point = x.zero_point} by the function because the output values are in the interval (max(-alpha, min(x)), max(x)].

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
aiscalar_q31_t alpha = AISCALAR_Q31(1.0f, 0, 0);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params; // {shift, zero point}
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
aimath_q31_default_elu(&x, &alpha, &result);
print_aitensor(&result);
void aimath_q31_default_elu(const aitensor_t *x, const void *alpha, aitensor_t *result)
Calculates the exponential rectifier (ELU) value of each element in a Q31 tensor.
Parameters
*xQ31 tensor to calculate the ELU from (N-D tensor)
*alphaScalar \( \alpha \) (type aiscalar_q31_t)
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_init_glorot_uniform()

void aimath_q31_default_init_glorot_uniform ( aitensor_t tensor)

Fills a Q31 tensor with random numbers uniformly within given range, according to Glorot et al.

\[ fan_{avg} = \frac{fan_{in} + fan_{out}}{2} \]

\[ r = \sqrt{\frac{3}{fan_{avg}}} \]

\[ tensor_i \in \mathcal{U(-r, r)} \]

Example:

uint16_t tensor_shape[2] = {2, 3};
aimath_q31_params_t tensor_params = {20, 0}; // {shift, zero point}
int32_t tensor_data[2*3];
aitensor_t tensor = AITENSOR_2D_Q31(tensor_shape, &tensor_params, tensor_data);
print_aitensor(&tensor);
void aimath_q31_default_init_glorot_uniform(aitensor_t *tensor)
Fills a Q31 tensor with random numbers uniformly within given range, according to Glorot et al.
See also
Glorot et al., 2010 ( http://jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdf )
Parameters
*tensorQ31 tensor to initialize with random numbers (N-D tensor)

◆ aimath_q31_default_init_zeros()

void aimath_q31_default_init_zeros ( aitensor_t tensor)

Fills a Q31 tensor with zeros.

\[ tensor_{i} = 0 \]

The function sets all tensor elements, the shift and the zero_point to 0.

Example:

uint16_t tensor_shape[2] = {2, 3};
aimath_q31_params_t tensor_params;
int32_t tensor_data[2*3];
aitensor_t tensor = AITENSOR_2D_Q31(tensor_shape, &tensor_params, tensor_data);
print_aitensor(&tensor);
void aimath_q31_default_init_zeros(aitensor_t *tensor)
Fills a Q31 tensor with zeros.
Parameters
*tensorQ31 tensor to set to zero (N-D tensor)

◆ aimath_q31_default_leaky_relu()

void aimath_q31_default_leaky_relu ( const aitensor_t x,
const void *  alpha,
aitensor_t result 
)

Calculates the leaky rectifier (leaky ReLU) value of each element in a Q31 tensor.

\[ result_{i} = \begin{cases} \alpha \cdot x_i & \text{if } x_i < 0 \\ x_i & \text{if } x_i \geq 0 \end{cases} \]

The quantization parameters of the result tensor are set to {shift = x.shift, zero_point = x.zero_point} by the function because the output values are in the interval (alpha * min(x), max(x)].

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {6, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
aiscalar_q31_t alpha = AISCALAR_Q31(0.01f, 10, 0);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params; // {shift, zero point}
int31_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
aimath_q31_default_leaky_relu(&x, &alpha, &result);
print_aitensor(&result);
void aimath_q31_default_leaky_relu(const aitensor_t *x, const void *alpha, aitensor_t *result)
Calculates the leaky rectifier (leaky ReLU) value of each element in a Q31 tensor.
Parameters
*xQ31 tensor to calculate the leaky ReLU from (N-D tensor)
*alphaScalar \( \alpha \) (type aiscalar_q31_t) for the leakage
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_linear32()

void aimath_q31_default_linear32 ( const aitensor_t a,
const aitensor_t b,
const aitensor_t c,
aitensor_t result 
)

Performs a matrix multiplication of Q31 matrices a and b and adds a vector c to each row.

The addition of the horizontal vector c is performed via broadcast, i.e. element wise in each column Mathematically this broadcast is equal to multiplying c with an vertical vector (with the same number of elements as c) and adding the result to a * b.

** The quantization parameters of the vector c have to be {zero_point = 0, shift = a.shift + b.shift}! **

\[ result = a \cdot b + \left( \begin{array}{c} 1 \\ 1 \\ \vdots \\ 1 \\ \end{array}\right) \cdot c \]

Example:

\[ a = \left( \begin{array}{rrr} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{array}\right) \]

\[ b = \left( \begin{array}{rr} 1 & 0 \\ 0 & 1 \\ 0 & 0 \end{array}\right) \]

\[ c = \left( \begin{array}{rr} 2 & 5 \end{array}\right) \]

\[ result = a \cdot b + \left( \begin{array}{r} 1 \\ 1 \\ 1 \\ \end{array}\right) \cdot c \]

\[ = \left( \begin{array}{rr} 1 & 2 \\ 4 & 5 \\ 7 & 8 \end{array}\right) + \left( \begin{array}{rr} 2 & 5 \\ 2 & 5 \\ 2 & 5 \end{array}\right) \]

\[ = \left( \begin{array}{rr} 3 & 7 \\ 6 & 10 \\ 9 & 13 \end{array}\right) \]

Example:

uint16_t a_shape[2] = {3, 3};
aimath_q31_params_t a_params = {1, 0}; // {shift, zero point}
int32_t a_data[3*3] = { 2, 4, 6,
8, 10, 12,
14, 16, 18};
aitensor_t a = AITENSOR_2D_Q31(a_shape, &a_params, a_data);
uint16_t b_shape[2] = {3, 2};
aimath_q31_params_t b_params = {2, 0}; // {shift, zero point}
int32_t b_data[3*2] = {4, 0,
0, 4,
0, 0};
aitensor_t b = AITENSOR_2D_Q31(b_shape, &b_params, b_data);
uint16_t c_shape[2] = {1, 2};
aimath_q31_params_t c_params = {3, 0}; // {shift, zero point}
int32_t c_data[1*2] = {16, 40};
aitensor_t c = AITENSOR_2D_Q31(c_shape, &c_params, c_data);
uint16_t result_shape[2] = {3, 2};
aimath_q31_params_t result_params = {4, 0}; // {shift, zero point}
int32_t result_data[3*2];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
aimath_q31_default_linear32(&a, &b, &c, &result);
print_aitensor(&result);
void aimath_q31_default_linear32(const aitensor_t *a, const aitensor_t *b, const aitensor_t *c, aitensor_t *result)
Performs a matrix multiplication of Q31 matrices a and b and adds a vector c to each row.
Parameters
*aQ31 matrix a (2D tensor of shape [N x K])
*bQ31 matrix b (2D tensor of shape [K x M])
*cQ31 vector c (2D tensor of shape [1 x M])
*resultResulting Q31 matrix (2D tensor of shape [N x M])

◆ aimath_q31_default_mat_mul()

void aimath_q31_default_mat_mul ( const aitensor_t a,
const aitensor_t b,
aitensor_t result 
)

Performs a matrix multiplication of Q31 matrices a and b.

\[ result = a \cdot b \]

Example:

uint16_t a_shape[2] = {3, 3};
aimath_q31_params_t a_params = {1, 0}; // {shift, zero point}
int32_t a_data[3*3] = { 2, 4, 6,
8, 10, 12,
14, 16, 18};
aitensor_t a = AITENSOR_2D_Q31(a_shape, &a_params, a_data);
uint16_t b_shape[2] = {3, 2};
aimath_q31_params_t b_params = {2, 0}; // {shift, zero point}
int32_t b_data[3*2] = {4, 0,
0, 4,
0, 0};
aitensor_t b = AITENSOR_2D_Q31(b_shape, &b_params, b_data);
uint16_t result_shape[2] = {3, 2};
aimath_q31_params_t result_params = {1, 0}; // {shift, zero point}
int32_t result_data[3*2];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
aimath_q31_default_mat_mul(&a, &b, &result);
print_aitensor(&result);
void aimath_q31_default_mat_mul(const aitensor_t *a, const aitensor_t *b, aitensor_t *result)
Performs a matrix multiplication of Q31 matrices a and b.
Parameters
*aQ31 matrix a (2D tensor of shape [N x K])
*bQ31 matrix b (2D tensor of shape [K x M])
*resultResulting Q31 matrix of the multiplication (2D tensor of shape [N x M])

◆ aimath_q31_default_multiply()

void aimath_q31_default_multiply ( const aitensor_t a,
const aitensor_t b,
aitensor_t result 
)

Performs an element wise multiplication of Q31 tensors a and b (Hadamard product)

\[ result = a \circ b \]

Example:

uint16_t a_shape[2] = {2, 3};
aimath_q31_params_t a_params = {1, 0}; // {shift, zero point}
int32_t a_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t a = AITENSOR_2D_Q31(a_shape, &a_params, a_data);
uint16_t b_shape[2] = {2, 3};
aimath_q31_params_t b_params = {2, 0}; // {shift, zero point}
int32_t b_data[2*3] = { 4, -8, 12,
-16, 20, -24};
aitensor_t b = AITENSOR_2D_Q31(b_shape, &b_params, b_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params = {1, 0}; // {shift, zero point}
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
aimath_q31_default_multiply(&a, &b, &result);
print_aitensor(&result);
void aimath_q31_default_multiply(const aitensor_t *a, const aitensor_t *b, aitensor_t *result)
Performs an element wise multiplication of Q31 tensors a and b (Hadamard product)
Parameters
*aQ31 tensor a (N-D tensor)
*bQ31 tensor b (N-D tensor)
*resultResulting Q31 tensor of the element wise multiplication (N-D tensor)

◆ aimath_q31_default_norm_squared()

void aimath_q31_default_norm_squared ( const aitensor_t x,
void *  result 
)

Calculates the squared sum of all elements in a Q31 tensor.

\[ result = \sum_i x_{i}^2 \]

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
aiscalar_q31_t result = {0, 2, 0}; // Value, shift, zero_point
void print_aiscalar(const void *scalar, const aimath_dtype_t *dtype)
Printing a scalar to console.
const aimath_dtype_t * aiq31
The Q31 data-type indicator.
void aimath_q31_default_norm_squared(const aitensor_t *x, void *result)
Calculates the squared sum of all elements in a Q31 tensor.
Parameters
*xQ31 tensor x (N-D tensor)
*resultScalar result (type aiscalar_q31_t)

◆ aimath_q31_default_relu()

void aimath_q31_default_relu ( const aitensor_t x,
aitensor_t result 
)

Calculates the rectifier (ReLU) value of each element in a Q31 tensor.

\[ result_{i} = max(0, x_{i}) \]

The quantization parameters of the result tensor are set to {shift = x.shift, zero_point = x.zero_point} by the function because the output values are in the interval [0, max(x)].

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params;
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
print_aitensor(&result);
void aimath_q31_default_relu(const aitensor_t *x, aitensor_t *result)
Calculates the rectifier (ReLU) value of each element in a Q31 tensor.
Parameters
*xQ31 tensor to calculate the ReLU from (N-D tensor)
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_scalar_mul()

void aimath_q31_default_scalar_mul ( const void *  scalar,
const aitensor_t a,
aitensor_t result 
)

Performs a scalar multiplication (scaling) of Q31 tensor a and a scalar.

\[ result = scalar \cdot a \]

Example:

uint16_t a_shape[2] = {2, 3};
aimath_q31_params_t a_params = {1, 0}; // {shift, zero point}
int32_t a_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t a = AITENSOR_2D_Q31(a_shape, &a_params, a_data);
aiscalar_q31_t scalar = AISCALAR_Q31(0.1f, 10, 0); // (value, shift, zero_point)
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params = {7, 0}; // {shift, zero point}
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
aimath_q31_default_scalar_mul(&scalar, &a, &result);
print_aitensor(&result);
void aimath_q31_default_scalar_mul(const void *scalar, const aitensor_t *a, aitensor_t *result)
Performs a scalar multiplication (scaling) of Q31 tensor a and a scalar.
Parameters
*scalarScalar (type aiscalar_q31_t)
*aQ31 tensor a (N-D tensor)
*resultResulting Q31 tensor of the scalar multiplication (N-D tensor)

◆ aimath_q31_default_sigmoid()

void aimath_q31_default_sigmoid ( const aitensor_t x,
aitensor_t result 
)

Calculates the sigmoid of each element in a Q31 tensor.

\[ result_{i} = \sigma(x_{i}) = \frac{1}{1 + e^{-x_{i}}} \]

The sigmoid is calculated with a piecewise linear approximation (PLAN) to avoid using exponential functions.

\[ result_{i} = \sigma_{PLAN}(x_i) = \begin{cases} 1 & \text{if } 5 \leq x_i\\ 0.03125 \cdot |x_i| + 0.84375 & \text{if } 2.375 \leq x_i < 5\\ 0,0125 \cdot |x_i| + 0,625 & \text{if } 1 \leq x_i < 2.375\\ 0,25 \cdot |x_i| + 0.5 & \text{if } 0 \leq x_i < 1\\ 1 - \sigma_{PLAN}(- x_i) & \text{if } x_i < 0\\ \end{cases} \]

The quantization parameters of the result tensor are set to {shift = 32, zero_point = -2^31} by the function because the output values are in the interval (0, 1).

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params;
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
print_aitensor(&result);
See also
Sigmoid PLAN: https://www.researchgate.net/figure/Comparative-representation-of-the-sigmoid-function-and-PLAN-approximation_fig7_228618304
Parameters
*xQ31 tensor to calculate the sigmoid from (N-D tensor)
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_softmax()

void aimath_q31_default_softmax ( const aitensor_t x,
aitensor_t result 
)

Calculates the softmax value of each batch element (row) of a Q31 tensor.

\[ result_{i} = \frac{e^{x_i}}{\sum_{j=1}^{K} e^{x_j}} = \frac{e^{x_i - x_{max}}}{\sum_{j=1}^{K} e^{x_j - x_{max}}} \]

The exponential function within softmax is calculated with a piecewise linear approximation (PLA) in the interval [-inf, 0].

\[ result_{i} = e_{PLA}(x_i - x_{max}) = \begin{cases} 0.63 \cdot (x_i - x_{max}) + 1 & \text{if } -1 \leq (x_i - x_{max}) < 0\\ 0.23 \cdot (x_i - x_{max}) + 0.6 & \text{if } -2 \leq (x_i - x_{max}) < -1\\ 0.09 \cdot (x_i - x_{max}) + 0.32 & \text{if } -3 \leq (x_i - x_{max}) < -2\\ 0.025 \cdot (x_i - x_{max}) + 0.125 & \text{if } -5 \leq (x_i - x_{max}) < -3\\ 0 & \text{if } (x_i - x_{max}) < -5\\ \end{cases} \]

The quantization parameters of the result tensor are set to {shift = 32, zero_point = -2147483648} by the function because the output values are in the interval (0, 1).

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params;
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
print_aitensor(&result);
void aimath_q31_default_softmax(const aitensor_t *x, aitensor_t *result)
Calculates the softmax value of each batch element (row) of a Q31 tensor.
Parameters
*xQ31 tensor to calculate the softmax from (N-D tensor)
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_softsign()

void aimath_q31_default_softsign ( const aitensor_t x,
aitensor_t result 
)

Calculates the softsign value of each element in a Q31 tensor.

\[ result_{i} = \frac {x_i} {1 + |x_i|} \]

The quantization parameters of the result tensor are set to {shift = 31, zero_point = 0} by the function because the output values are in the interval (-1, 1).

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params;
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
print_aitensor(&result);
void aimath_q31_default_softsign(const aitensor_t *x, aitensor_t *result)
Calculates the softsign value of each element in a Q31 tensor.
Parameters
*xQ31 tensor to calculate the softsign from (N-D tensor)
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_sqrt()

int64_t aimath_q31_default_sqrt ( int64_t  x)

Calculates square root of an int64 value.

Parameters
xq31 Value to calculate square root of
Returns
Square root of x

◆ aimath_q31_default_tanh()

void aimath_q31_default_tanh ( const aitensor_t x,
aitensor_t result 
)

Calculates the tanh of each element in a Q31 tensor.

\[ result_{i} = \tanh(x_{i}) = \frac{e^{x_i} - e^{-x_i}}{e^{x_i} + e^{-x_i}} \]

The tanh is calculated with a piecewise linear approximation (PLA) to avoid using exponential functions.

\[ result_{i} = \tanh_{PLA}(x_i) = 2 \cdot \sigma(2x_i) - 1 = \begin{cases} 1 & \text{if } 5 \leq x_i\\ 0.0625 \cdot |x_i| + 0.6875 & \text{if } 2.375 \leq x_i < 5\\ 0.25 \cdot |x_i| + 0.25 & \text{if } 1 \leq x_i < 2.375\\ 0.5 \cdot |x_i| & \text{if } 0 \leq x_i < 1\\ - \tanh_{PLA}(- x_i) & \text{if } x_i < 0\\ \end{cases} \]

The quantization parameters of the result tensor are set to {shift = 31, zero_point = 0} by the function because the output values are in the interval (-1, 1).

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params;
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
print_aitensor(&result);
Parameters
*xQ31 tensor to calculate the tanh from (N-D tensor)
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_tensor_add_different_shift()

void aimath_q31_default_tensor_add_different_shift ( const aitensor_t a,
const aitensor_t b,
aitensor_t result 
)

Performs an element wise addition of Q31 tensors a and b with different shifts.

\[ result = a + b \]

The tensors a, b and result can have different shifts. The function will rescale the tensors internally to perform the addition. If a, b and result have the same shift, use aimath_q31_default_tensor_add_same_shift() instead because it is more efficient.

Example:

uint16_t a_shape[2] = {2, 3};
aimath_q31_params_t a_params = {1, 0}; // {shift, zero point}
int32_t a_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t a = AITENSOR_2D_Q31(a_shape, &a_params, a_data);
uint16_t b_shape[2] = {2, 3};
aimath_q31_params_t b_params = {2, 0}; // {shift, zero point}
int32_t b_data[2*3] = { 4, -8, 12,
-16, 20, -24};
aitensor_t b = AITENSOR_2D_Q31(b_shape, &b_params, b_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params = {0, 0}; // {shift, zero point}
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
print_aitensor(&result);
void aimath_q31_default_tensor_add_different_shift(const aitensor_t *a, const aitensor_t *b, aitensor_t *result)
Performs an element wise addition of Q31 tensors a and b with different shifts.
Parameters
*aQ31 tensor a (N-D tensor)
*bQ31 tensor b (N-D tensor)
*resultResulting Q31 tensor of the element wise addition (N-D tensor)

◆ aimath_q31_default_tensor_add_same_shift()

void aimath_q31_default_tensor_add_same_shift ( const aitensor_t a,
const aitensor_t b,
aitensor_t result 
)

Performs an element wise addition of Q31 tensors a and b with same shifts.

\[ result = a + b \]

The tensors a, b and result must have the same shift. If a, b and result have the different shifts, use aimath_q31_default_tensor_add_different_shift() instead.

Example:

uint16_t a_shape[2] = {2, 3};
aimath_q31_params_t a_params = {1, 0}; // {shift, zero point}
int32_t a_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t a = AITENSOR_2D_Q31(a_shape, &a_params, a_data);
uint16_t b_shape[2] = {2, 3};
aimath_q31_params_t b_params = {1, 0}; // {shift, zero point}
int32_t b_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t b = AITENSOR_2D_Q31(b_shape, &b_params, b_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params = {1, 0}; // {shift, zero point}
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
print_aitensor(&result);
void aimath_q31_default_tensor_add_same_shift(const aitensor_t *a, const aitensor_t *b, aitensor_t *result)
Performs an element wise addition of Q31 tensors a and b with same shifts.
Parameters
*aQ31 tensor a (N-D tensor)
*bQ31 tensor b (N-D tensor)
*resultResulting Q31 tensor of the element wise addition (N-D tensor)

◆ aimath_q31_default_tensor_init_uniform()

void aimath_q31_default_tensor_init_uniform ( aitensor_t tensor,
float  from,
float  to 
)

Fills a Q31 tensor with random numbers created from a uniform distribution within given range.

\[ tensor_i \in \mathcal{U(from, to)} \]

Example:

uint16_t tensor_shape[2] = {2, 3};
aimath_q31_params_t tensor_params = {20, 0}; // {shift, zero point}
int32_t tensor_data[2*3];
aitensor_t tensor = AITENSOR_2D_Q31(tensor_shape, &tensor_params, tensor_data);
print_aitensor(&tensor);
void aimath_q31_default_tensor_init_uniform(aitensor_t *tensor, float from, float to)
Fills a Q31 tensor with random numbers created from a uniform distribution within given range.
Parameters
*tensorQ31 tensor to initialize with random numbers (N-D tensor)
fromMinimum value of the uniform distribution
toMaximum value of the uniform distribution

◆ aimath_q31_default_tensor_sqrt()

void aimath_q31_default_tensor_sqrt ( const aitensor_t x,
aitensor_t result 
)

Calculates the element wise square root of a Q31 tensor.

\[ result_{i} = \sqrt{x_{i}} \]

Example:

uint16_t x_shape[2] = {2, 3};
aimath_q31_params_t x_params = {1, 0}; // {shift, zero point}
int32_t x_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t x = AITENSOR_2D_Q31(x_shape, &x_params, x_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params = {10, 0}; // {shift, zero point}
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
print_aitensor(&result);
void aimath_q31_default_tensor_sqrt(const aitensor_t *x, aitensor_t *result)
Calculates the element wise square root of a Q31 tensor.
Parameters
*xQ31 tensor to calculate the square root from (N-D tensor)
*resultResulting Q31 tensor (N-D tensor)

◆ aimath_q31_default_tensor_sub_different_shift()

void aimath_q31_default_tensor_sub_different_shift ( const aitensor_t a,
const aitensor_t b,
aitensor_t result 
)

Performs an element wise subtraction of Q31 tensors a and b with different shifts.

\[ result = a - b \]

The tensors a, b and result can have different shifts. The function will rescale the tensors internally to perform the subtraction. If a, b and result have the same shift, use aimath_q31_default_tensor_sub_same_shift() instead because it is more efficient.

Example:

uint16_t a_shape[2] = {2, 3};
aimath_q31_params_t a_params = {1, 0}; // {shift, zero point}
int32_t a_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t a = AITENSOR_2D_Q31(a_shape, &a_params, a_data);
uint16_t b_shape[2] = {2, 3};
aimath_q31_params_t b_params = {2, 0}; // {shift, zero point}
int32_t b_data[2*3] = { 4, 8, 12,
16, 20, 24};
aitensor_t b = AITENSOR_2D_Q31(b_shape, &b_params, b_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params = {0, 0}; // {shift, zero point}
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
print_aitensor(&result);
void aimath_q31_default_tensor_sub_different_shift(const aitensor_t *a, const aitensor_t *b, aitensor_t *result)
Performs an element wise subtraction of Q31 tensors a and b with different shifts.
Parameters
*aQ31 tensor a (N-D tensor)
*bQ31 tensor b (N-D tensor)
*resultResulting Q31 tensor of the element wise subtraction (N-D tensor)

◆ aimath_q31_default_tensor_sub_same_shift()

void aimath_q31_default_tensor_sub_same_shift ( const aitensor_t a,
const aitensor_t b,
aitensor_t result 
)

Performs an element wise subtraction of Q31 tensors a and b with same shifts.

\[ result = a - b \]

The tensors a, b and result must have the same shift. If a, b and result have the different shifts, use aimath_q31_default_tensor_sub_different_shift() instead.

Example:

uint16_t a_shape[2] = {2, 3};
aimath_q31_params_t a_params = {1, 0}; // {shift, zero point}
int32_t a_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t a = AITENSOR_2D_Q31(a_shape, &a_params, a_data);
uint16_t b_shape[2] = {2, 3};
aimath_q31_params_t b_params = {1, 0}; // {shift, zero point}
int32_t b_data[2*3] = { 2, 4, 6,
8, 10, 12};
aitensor_t b = AITENSOR_2D_Q31(b_shape, &b_params, b_data);
uint16_t result_shape[2] = {2, 3};
aimath_q31_params_t result_params = {1, 0}; // {shift, zero point}
int32_t result_data[2*3];
aitensor_t result = AITENSOR_2D_Q31(result_shape, &result_params, result_data);
print_aitensor(&result);
void aimath_q31_default_tensor_sub_same_shift(const aitensor_t *a, const aitensor_t *b, aitensor_t *result)
Performs an element wise subtraction of Q31 tensors a and b with same shifts.
Parameters
*aQ31 tensor a (N-D tensor)
*bQ31 tensor b (N-D tensor)
*resultResulting Q31 tensor of the element wise subtraction (N-D tensor)

◆ aimath_q31_default_transpose_vector()

void aimath_q31_default_transpose_vector ( aitensor_t vector)

Transposes a Q31 vector.

The given tensor must be a vector (2D tensor of shape [1 x N] or [N x 1]).

\[ vector \leftarrow vector^T \]

Example:

uint16_t vector_shape[2] = {1, 3};
aimath_q31_params_t vector_params = {1, 0}; // {shift, zero point}
int32_t vector_data[2*3] = { 2, -4, 6};
aitensor_t vector = AITENSOR_2D_Q31(vector_shape, &vector_params, vector_data);
print_aitensor(&vector);
void aimath_q31_default_transpose_vector(aitensor_t *vector)
Transposes a Q31 vector.
Parameters
*vectorQ31 vector (2D tensor of shape [1 x N] or [N x 1])

◆ aimath_q31_default_zero_tensor()

void aimath_q31_default_zero_tensor ( aitensor_t tensor)

Fills a Q31 tensor with zeros.

\[ tensor_{i} = 0 \]

The function sets all tensor elements to the zero_point given in the tensor parameters.

Example:

uint16_t tensor_shape[2] = {2, 3};
aimath_q31_params_t tensor_params = {1, 0}; // {shift, zero point}
int32_t tensor_data[2*3] = { 2, -4, 6,
-8, 10, -12};
aitensor_t tensor = AITENSOR_2D_Q31(tensor_shape, &tensor_params, tensor_data);
print_aitensor(&tensor);
void aimath_q31_default_zero_tensor(aitensor_t *tensor)
Fills a Q31 tensor with zeros.
Parameters
*tensorQ31 tensor to set to zero (N-D tensor)