Implementation:Tencent Ncnn Expression Evaluator
| Knowledge Sources | |
|---|---|
| Domains | Dynamic Shape Computation, Expression Parsing |
| Last Updated | 2026-02-09 19:00 GMT |
Overview
Stack-based prefix-notation expression evaluator that resolves dynamic tensor shape computations from string-encoded mathematical expressions referencing input blob dimensions.
Description
The expression evaluator enables ncnn to handle models with dynamic shapes by evaluating mathematical expressions at inference time. When ONNX or PyTorch models encode shape calculations as expressions during model conversion (e.g., reshape dimensions computed from input sizes), this evaluator resolves them based on actual input tensor dimensions.
The implementation has two main functions:
count_expression_blobs() tokenizes the expression string by splitting on parentheses and commas, then scans tokens for blob dimension references (patterns like 0w, 1h, 2d, 3c where the digit is the blob index and the letter is the dimension axis) to determine how many input blobs are needed.
eval_list_expression() uses a stack-based prefix-notation evaluator: it tokenizes the expression, then iterates tokens in reverse order, pushing operands onto a stack and applying operators. The typed_value union tracks whether each value is an integer or float to preserve integer precision where possible.
The expression syntax uses prefix notation with parenthesized argument lists separated by commas. For example, the expression /(0w,2),*(0h,2),0c means: divide blob 0's width by 2, multiply blob 0's height by 2, and pass through blob 0's channels.
Supported operations:
- Binary arithmetic:
+,-,*,//(integer division),max,min - Unary operations:
abs,neg,sign,square - Rounding functions:
trunc,ceil,floor,round - Transcendental functions:
sin,cos,exp,log,sqrt, and others - Blob dimension references:
0w,0h,0d,0cthrough9w,9h,9d,9c - Literal values: Integers and floating-point constants
Usage
Use the expression evaluator when implementing layers that require dynamic output shape computation based on input dimensions, such as Reshape, Slice, or other shape-manipulation operators. The expression strings are generated by model converters (e.g., PNNX) and stored in the layer's parameter dictionary.
Code Reference
Source Location
- Repository: Tencent_Ncnn
- Header: src/expression.h
- Implementation: src/expression.cpp (562 lines)
Signature
namespace ncnn {
// count how many blobs are referenced inside expression
NCNN_EXPORT int count_expression_blobs(const std::string& expr);
// resolve reshape shape from expression and input blobs
// resolve slice indices(starts, ends) from expression and input blobs
// return 0 if success
NCNN_EXPORT int eval_list_expression(const std::string& expr,
const std::vector<Mat>& blobs,
std::vector<int>& outlist);
} // namespace ncnn
Import
#include "ncnn/expression.h"
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| expr | const std::string& |
Yes | Prefix-notation expression string, e.g., "/(0w,2),*(0h,2),0c"
|
| blobs | const std::vector<Mat>& |
Yes (for eval) | Input blobs whose shapes are referenced in the expression (indexed 0-9) |
Outputs
| Name | Type | Description |
|---|---|---|
| return (count) | int |
Number of input blobs referenced in the expression (from count_expression_blobs)
|
| return (eval) | int |
0 on success, -1 on error (e.g., blob index out of bound, division by zero) |
| outlist | std::vector<int>& |
Evaluated integer results, one per comma-separated sub-expression |
Usage Examples
Counting Blob References
#include "ncnn/expression.h"
// Expression referencing blobs 0 and 1
std::string expr = "/(0w,2),*(1h,2),0c";
int num_blobs = ncnn::count_expression_blobs(expr);
// num_blobs == 2 (references blob 0 and blob 1)
Evaluating Dynamic Shape Expression
#include "ncnn/expression.h"
#include "ncnn/mat.h"
// Suppose input blob 0 has shape w=224, h=224, c=3
ncnn::Mat input_blob(224, 224, 3);
std::vector<ncnn::Mat> blobs = { input_blob };
// Expression: divide width by 2, multiply height by 2, keep channels
std::string expr = "/(0w,2),*(0h,2),0c";
std::vector<int> outlist;
int ret = ncnn::eval_list_expression(expr, blobs, outlist);
// ret == 0 (success)
// outlist == { 112, 448, 3 }