Rough estimates of the cost of implementing the ONNX operators listed as unsupported in the operator tracking issue, based on the ONNX operator specs. Last updated: 2026-07-12.
- Complexity is Small / Medium / Large, judging spec surface area (attributes, modes, type support), how much existing rten machinery can be reused, and how performance-sensitive the op is.
- Code size is very rough new-code line count including inline tests, but
excluding the fixed per-op glue every new operator pays: an entry in
rten-model-file/src/schema.fbs(plus regenerated code),rten-convertschema updates,src/op_registry.rsregistration, ONNX attribute reading and shape inference. That glue is typically ~50–150 lines per op. - Deps lists new crate dependencies. Most ops need none; the exceptions
are called out. Heavy deps would be feature-gated, like
rustfft(fftfeature) andfastrand(randomfeature) are today.
Some ops are cheap in themselves but blocked on missing infrastructure:
- String tensors.
DataTypecurrently supports onlyInt32,Float,Int8andUInt8.RegexFullMatch,StringConcat,StringNormalizer,StringSplitand (partly)TfIdfVectorizerneed a string tensor element type threaded throughrten-tensor,Value, the model file format and the ONNX loader. That is a Large standalone project (~1000+ lines) before any of those ops can be written. - Optional values.
Optional/OptionalGetElement/OptionalHasElementneed an "optional" value kind in theValuetype system and graph plumbing. The three ops are trivial once that exists. - MaxPool indices output.
MaxUnpoolconsumes theIndicesoutput ofMaxPool, which rten currently does not produce, so implementing it also means extendingMaxPool. - Wider dtypes.
BitCastbetween different-width types (e.g. f32 ↔ f16) is only meaningful once more dtypes exist; the same-width cases (f32 ↔ i32, i8 ↔ u8) are trivial today.
Note: BitShift, BitwiseAnd/Or/Xor/Not and wider DataType variants have
already been prototyped on the doom-onnx branch.
| Operator | Complexity | Est. code size | New deps | Notes |
|---|---|---|---|---|
| AffineGrid | Small–Medium | 200–350 | none | Generate 2D/3D sampling grids from affine matrices; pure index math, complements existing GridSample. |
| Bernoulli | Small | 100–150 | none | Elementwise random draw; reuses existing random feature infra (fastrand). |
| BitCast | Small | 100–200 | none | Same-width reinterpret (f32↔i32, i8↔u8) is near-trivial; cross-width variants blocked on unsupported dtypes. |
| BitShift | Small | 50–100 | none | Fits the binary-elementwise template; prototyped on doom-onnx. |
| BitwiseAnd | Small | 30–60 | none | Binary-elementwise template; prototyped on doom-onnx. |
| BitwiseNot | Small | ~30 | none | Unary-elementwise template; prototyped on doom-onnx. |
| BitwiseOr | Small | 30–60 | none | As BitwiseAnd. |
| BitwiseXor | Small | 30–60 | none | As BitwiseAnd. |
| BlackmanWindow | Small | ~150 shared | none | One shared cosine-window helper covers Blackman/Hamming/Hann; complements STFT/DFT. |
| Celu | Small | 40–60 | none | Elementwise with alpha attribute. |
| CenterCropPad | Small–Medium | 150–250 | none | Per-axis crop-or-pad to a target shape; composable from existing slice/pad logic, axes handling is the fiddly part. |
| Col2Im | Medium | 250–400 | none | Inverse of im2col. A 2D col2im core exists inside ConvTranspose; the spec requires N-D plus dilations/pads/strides. |
| Compress | Small | 100–200 | none | Boolean-mask selection, optionally along an axis; output size is data-dependent (like NonZero). |
| CumProd | Small | 80–120 | none | Direct clone of existing CumSum. |
| DeformConv | Large | 800–1500 | none | Deformable conv v2: per-output-pixel offset/mask bilinear sampling feeding grouped matmul. Perf-sensitive; the biggest pure-compute item on this list. |
| Det | Medium | 200–300 | none | Batched determinant; needs a small hand-rolled LU decomposition (not worth a linalg dep). |
| GlobalLpPool | Small | 60–100 | none | Reduce machinery exists (ReduceL1/ReduceL2); generalize to arbitrary integer p. |
| GroupNormalization | Small–Medium | 150–250 | none | Reshape + reuse of existing instance/layer-norm kernels. |
| HammingWindow | Small | (shared) | none | See BlackmanWindow. |
| HannWindow | Small | (shared) | none | See BlackmanWindow. |
| Hardmax | Small | 80–120 | none | ArgMax along axis → one-hot; both building blocks exist. |
| ImageDecoder | Medium code, Large deps | 150–300 glue | image codecs (image or zune-*/png crates) |
Decode JPEG/PNG/BMP/GIF/TIFF/WebP etc. Glue is small but codec deps are heavy; would be feature-gated. Rare in models. |
| LRN | Small–Medium | 150–250 | none | Sliding-window normalization across channels; legacy (AlexNet-era) op. |
| LpNormalization | Small | 60–100 | none | Normalize along one axis by L1/L2 norm. |
| LpPool | Medium | 150–300 | none | Extend existing pooling machinery with a p-norm accumulator; N-D spatial dims. |
| MaxRoiPool | Medium | 200–300 | none | Legacy ROI max-pooling; superseded by RoiAlign in practice. |
| MaxUnpool | Medium | 250–400 | none | Also requires adding the Indices output to MaxPool (currently not produced). |
| MeanVarianceNormalization | Small | 80–150 | none | Composable from existing reduce ops over the axes attribute. |
| MelWeightMatrix | Small–Medium | 150–250 | none | Generate mel filterbank matrix; formula-heavy but self-contained. Complements STFT. |
| Mish | Small | 40–60 | none | x * tanh(softplus(x)); add ~100 lines if a SIMD kernel in rten-vecmath is wanted. |
| NegativeLogLikelihoodLoss | Medium | 250–400 | none | Training-oriented: class weights, ignore_index, three reduction modes. Rare in inference models. |
| Optional | Medium (infra) | 150–300 shared | none | Cost is the new optional value kind in Value/graph plumbing; the op itself is trivial. |
| OptionalGetElement | Small¹ | 30–60 | none | Trivial once optional values exist. |
| OptionalHasElement | Small¹ | 30–60 | none | Trivial once optional values exist. |
| QLinearConv | Medium | 300–500 | none | Requantization (u8/i8 output, per-channel scales) layered on existing ConvInteger kernels; could partly be lowered at load time. |
| QLinearMatMul | Medium | 200–400 | none | Same story on top of MatMulInteger. |
| RNN | Medium | 200–350 | none | Vanilla RNN sharing the gate machinery in rnn.rs with GRU/LSTM; the activations attribute variants add some surface. |
| ReduceLogSum | Small | 60–100 | none | Reduce machinery exists; log(sum(x)). |
| ReduceLogSumExp | Small | 80–120 | none | Needs max-subtraction for numerical stability. |
| RegexFullMatch | Large¹ | ~100 + infra | regex (sizeable, Unicode tables) |
Blocked on string tensor support; the op itself is a one-liner over regex. |
| RoiAlign | Medium | 300–450 | none | Bilinear ROI sampling with avg/max modes and coordinate-transform modes; well-specified. |
| Scan | Medium–Large | 400–700 | none | Subgraph machinery exists (Loop/If), but state variables plus scan inputs/outputs with per-tensor axes/directions are fiddly. |
| Selu | Small | 40–60 | none | Elementwise with alpha/gamma. |
| SequenceMap | Medium | 150–300 | none | Run a subgraph per sequence element; sequence and subgraph infra both exist. |
| Shrink | Small | 40–60 | none | Elementwise with bias/lambd. |
| SoftmaxCrossEntropyLoss | Medium | 250–400 | none | Training-oriented; shares its core with NegativeLogLikelihoodLoss. |
| Softsign | Small | 30–50 | none | `x / (1 + |
| SpaceToDepth | Small | 100–150 | none | Inverse of existing DepthToSpace. |
| StringConcat | Small¹ | 50–100 | none | Blocked on string tensor support. |
| StringNormalizer | Medium¹ | 150–300 | none (or a case-folding crate) | Blocked on string tensors; case-folding and locale quirks in the spec. |
| StringSplit | Medium¹ | 150–250 | none | Blocked on string tensors; ragged output returned as padded tensor + lengths. |
| TensorScatter | Medium | 200–300 | none | Opset 24 KV-cache update op: past_cache/update/write_indices, linear and circular modes. Relevant to LLM inference. |
| TfIdfVectorizer | Large | 400–700 | none for int input; string infra for string input | N-grams with skips, pool matching, three weighting modes; notoriously messy spec. Rare outside classical-ML exports. |
| ThresholdedRelu | Small | 30–50 | none | Elementwise with alpha. |
| Unique | Medium | 250–400 | none | Four optional outputs, sorted/unsorted order, and an axis mode that dedups whole slices. |
¹ Estimate is for the op alone, assuming the blocking infrastructure (string tensors / optional values) already exists — see Cross-cutting infrastructure gaps.
- Small (quick wins, mostly template-based): the elementwise activations (Celu, Mish, Selu, Shrink, Softsign, ThresholdedRelu), bitwise ops and BitShift, the window functions, CumProd, ReduceLogSum(Exp), GlobalLpPool, LpNormalization, Hardmax, MeanVarianceNormalization, SpaceToDepth, Compress, Bernoulli, BitCast. Roughly 30–150 lines each on top of existing templates.
- Medium: QLinearConv/QLinearMatMul, RNN, RoiAlign, Unique, TensorScatter, Col2Im, LpPool, GroupNormalization, LRN, MaxUnpool, MaxRoiPool, Det, MelWeightMatrix, AffineGrid, CenterCropPad, SequenceMap, the loss ops.
- Large: DeformConv (compute kernel), Scan (control-flow surface), TfIdfVectorizer (spec complexity), ImageDecoder (dependency weight), and the string-tensor infrastructure that gates the four string ops.
- New dependencies are only needed for ImageDecoder (image codecs) and
RegexFullMatch (
regex); everything else is implementable with the existing dependency set.