The default implementation on the base interface (skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/data/TensorData.kt) iterates a single flat index and calls get(idx) — one vararg argument — regardless of tensor rank. Every concrete implementation's get begins with require(indices.size == shape.dimensions.size), so for any rank ≥ 2 tensor the default throws on the first element.
It is masked today because the implementations that matter override copyToFloatArray() — which makes this a latent trap for the next implementor: write a new TensorData, forget the override, and dense-looking code fails at runtime with a confusing arity error (or worse, works only for rank-1 test fixtures and fails on real tensors).
Also worth a look while in there: the default does get(idx) as Number and .toFloat(), which for packed-quant implementations (TensorData<DType, Byte>) would silently widen raw quantized bytes to floats if any of them ever inherited the default — semantically wrong, not just slow.
Options, cheapest first:
- Fix the default to do proper multi-dimensional index iteration (row-major unravel of the flat index) — correct for any rank.
- Or drop the default body entirely and make it abstract, forcing each implementor to decide — turns the latent runtime trap into a compile error.
- Either way, a commonTest contract test that runs
copyToFloatArray() against a rank-2 instance of each implementation would pin the behavior.
Happy to open a PR.
The default implementation on the base interface (
skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/data/TensorData.kt) iterates a single flat index and callsget(idx)— one vararg argument — regardless of tensor rank. Every concrete implementation'sgetbegins withrequire(indices.size == shape.dimensions.size), so for any rank ≥ 2 tensor the default throws on the first element.It is masked today because the implementations that matter override
copyToFloatArray()— which makes this a latent trap for the next implementor: write a newTensorData, forget the override, and dense-looking code fails at runtime with a confusing arity error (or worse, works only for rank-1 test fixtures and fails on real tensors).Also worth a look while in there: the default does
get(idx) as Numberand.toFloat(), which for packed-quant implementations (TensorData<DType, Byte>) would silently widen raw quantized bytes to floats if any of them ever inherited the default — semantically wrong, not just slow.Options, cheapest first:
copyToFloatArray()against a rank-2 instance of each implementation would pin the behavior.Happy to open a PR.