utils
Operators Utilities API
The utils module provides utility functions for AOT operators.
Copyright 2025 Ambiq. All Rights Reserved.
Classes
Functions
float_activation_range
float_activation_range(activation: AirActivationType | AirReluType, dtype: DTypeLike = np.float32) -> tuple[str, str]
Return the float-space (activation_min, activation_max) C literals.
The returned strings are ready to interpolate into templates. Unbounded
sides expand to the largest finite value representable by the target
dtype: -FLT_MAX / FLT_MAX for float32, and
ARM_NN_F16_FINITE_LOWEST / ARM_NN_F16_FINITE_MAX for float16
(heliaCore macros from arm_nn_math_types_flt.h, transitively included
via arm_nnfunctions_flt.h).
This matches upstream TFLite CalculateActivationRange (which returns
std::numeric_limits<T>::lowest()/max() for kTfLiteActNone) and
heliaCore's own no-clamp convention. Finite bounds are chosen over
INFINITY because heliaCore explicitly exposes ARM_NN_F16_FINITE_MAX
to remain correct under toolchains that lack a portable f16 infinity or
are built with -ffinite-math-only. For any legitimate finite output
both bounds are semantic no-ops; the clamp instruction runs either way.
Parameters:
-
(activationAirActivationType | AirReluType) –The fused activation type (from op options or relu type).
-
(dtypeDTypeLike, default:float32) –Float dtype driving the sentinel choice.
Returns:
Raises:
-
ValueError–If
activationhas no defined float-space clamp.
pad_shape_to_4d
Pad a tensor shape to 4D (N, H, W, C) order, filling missing dims with 1.
clamp_to_int_range
lut_populate_s16
lut_populate_s16(input_scale: float, input_zero_point: int, output_scale: float, output_zero_point: int, transform_fn) -> np.ndarray
Recreates TFLM's LUTPopulate
Args input_scale, input_zero_point: affine scale for LUT input domain output_scale, output_zero_point: affine scale for LUT output domain transform_fn: function f: R -> R (e.g., exp, 1/(1+x))
Returns np.int16 array of length 513.
calculate_input_radius
Mimics litert::CalculateInputRadius (non-emulated version).
This computes the maximum representable difference in the scaled domain.
Parameters:
-
(input_integer_bitsint) –Number of integer bits reserved (e.g., kScaledDiffIntegerBits, typically 5).
-
(input_left_shiftint) –The left shift computed from PreprocessSoftmaxScaling.
-
(total_signed_bitsint, default:31) –Total bits available in the representation (typically 31 for Q31 arithmetic).
Returns:
-
int(int) –The computed input radius.
tflite_round
TFLM's TfLiteRound: round half away from zero, implemented with +/-0.5 then trunc. Args: x (float): The float to round.
Returns:
-
int(int) –The rounded integer.
checked_log2
Exact port of TFLM's CheckedLog2: - Uses log(x) / log(2) (not math.log2) - Rounds with TfLiteRound - 'Power-of-two' if |fracpart| < 1e-3
Parameters:
-
(xfloat) –The positive float to compute log2 for.
-
(tolfloat, default:0.001) –The tolerance for determining if the value is a power of two.
Returns:
downscale_q31_to_q15
vector_sum_s8
vector_sum_s8(vector_data: ndarray, vector_cols: int, vector_rows: int, lhs_offset: int, rhs_offset: int, bias_data: ndarray | None = None) -> np.ndarray
Pure-Python port of CMSIS-NN's arm_vector_sum_s8 helper.
Parameters:
-
(vector_datandarray) –Flattened (rows * cols) int8 buffer containing the kernel matrix.
-
(vector_colsint) –Number of columns per output channel (accumulation depth).
-
(vector_rowsint) –Number of rows/output channels.
-
(lhs_offsetint) –Input offset applied during accumulation.
-
(rhs_offsetint) –Filter/weight offset applied during accumulation.
-
(bias_datandarray | None, default:None) –Optional per-output bias (length == vector_rows), int32.
Returns:
-
ndarray–np.ndarray: int32 array with the kernel sums, matching CMSIS-NN behaviour.
validate_slice_extent
Reject slice configurations that strided_slice.c.j2 cannot emit safely.
Shared by SLICE and STRIDED_SLICE, which lower through the same template.
Both checks are dtype-independent because the template is: it sizes the
arm_strided_slice_* call from <name>_computed_output_dims, derived
from the slice bounds, for every dtype. The declared output tensor's shape
never reaches the kernel.
Two consequences, and this is the only place either is caught:
- A non-positive stride breaks the template's extent formula,
(end - begin + stride - 1) // stride, which is only correct for a positive stride. This is a template limitation, not a kernel one -- the library'sARM_STRIDED_SLICE_DEFINEwalks negative strides correctly -- so lifting it is a codegen fix rather than a kernel gap. - An axis whose
endis below itsbeginselects nothing, but the template's formula is unclamped, so it renders a NEGATIVEcmsis_nn_dimsmember (.w = -5for begin 7, end 2, stride 1). The clamp below hides that from the element count, so the extent check alone would let it through. - A declared output smaller than the selected extent is written past its end, because memory planning sizes that buffer from the declared shape while the kernel writes what the computed dims say. A declared output LARGER than the extent is not an overrun, but the model is still malformed: the kernel fills only part of the buffer and leaves the rest undefined, so both directions are rejected with their own message.
The stride check runs first on purpose: the extent below divides by the stride, so a zero stride must be rejected before it reaches that division.
Parameters:
-
(operatorAotOperator) –The operator being validated; supplies
TYPEandop.idfor the message. -
(sliceslist) –Per-axis
begin/end/striderecords fromoptions.get_slices(input_shape).
Raises:
-
ConfigValueError–If any stride is non-positive, any axis selects a reversed (empty) span, or the declared output element count differs from the extent the slice selects.
validate_transpose_perm
Reject TRANSPOSE arguments the ns-cmsis-nn kernels refuse at runtime.
arm_transpose_s8/s16/f16/f32 return ARM_CMSIS_NN_ARG_ERROR and write
nothing when num_dims falls outside 1..4, perm is not a bijection
over range(num_dims), output_dims is not input_dims permuted by
perm, or any extent is below 1 (see AmbiqAI/ns-cmsis-nn#443).
transpose.c.j2 fills every one of those arguments straight from the
model, so without this check a malformed model compiles and links cleanly
and fails only as a nonzero invoke status with an untouched output buffer.
Parameters:
-
(operatorAotOperator) –The operator being validated; supplies
TYPE,op.idand the input/output tensors for the message. -
(permSequence[int]) –The permutation from
options.permutations.
Raises:
-
ConfigValueError–If the rank is outside 1..4,
permis not a permutation ofrange(rank),permdoes not match the input rank, any extent is below 1, or the declared output shape is not the input shape permuted byperm.