// spatio_temporal.mbt — 5D [T, B, C, H, W] tensor for spiking-CNN
// time-series input (v0.14.1).
//
// Layout convention (matching SNN.jl / Conv-STDP / most time-major
// spiking CNN literature):
// - `t` (outermost): time step index, 0.. STImage {
{ data: Array::make(t * b * c * h * w, 0.0F), t, b, c, h, w }
}
///|
/// Total element count (T * B * C * H * W).
pub fn STImage::numel(self : STImage) -> Int {
self.data.length()
}
///|
/// Shape as `(t, b, c, h, w)`.
pub fn STImage::shape(self : STImage) -> (Int, Int, Int, Int, Int) {
(self.t, self.b, self.c, self.h, self.w)
}
///|
/// Stride helper: number of elements per [B, C, H, W] "frame block".
pub fn STImage::frame_block(self : STImage) -> Int {
self.b * self.c * self.h * self.w
}
///|
/// Stride helper: number of elements per [C, H, W] "batch slice".
pub fn STImage::batch_slice(self : STImage) -> Int {
self.c * self.h * self.w
}
///|
/// Flat offset of `[t, b, c, h, w]` in `data`.
pub fn STImage::offset(
self : STImage,
t : Int,
b : Int,
c : Int,
h : Int,
w : Int,
) -> Int {
t * self.frame_block() + b * self.batch_slice() + c * (self.h * self.w) +
h * self.w +
w
}
///|
/// Read `[t, b, c, h, w]`.
pub fn STImage::get(
self : STImage,
t : Int,
b : Int,
c : Int,
h : Int,
w : Int,
) -> Float {
self.data[self.offset(t, b, c, h, w)]
}
///|
/// Write `[t, b, c, h, w]`.
pub fn STImage::set(
self : STImage,
t : Int,
b : Int,
c : Int,
h : Int,
w : Int,
v : Float,
) -> Unit {
self.data[self.offset(t, b, c, h, w)] = v
}
///|
/// Extract a single time step `t` as a 4D `Image { n: 1, c, h, w }`.
/// Returns a fresh `Image` (data is copied, not aliased).
pub fn STImage::get_frame(self : STImage, t : Int) -> Image {
let block = self.frame_block()
let plane = self.c * self.h * self.w
let out : Array[Float] = Array::make(plane, 0.0F)
let src_off = t * block
for i in 0.. Image {
let slice = self.batch_slice()
let out : Array[Float] = Array::make(self.t * slice, 0.0F)
for t_idx in 0.. STImage raise Failure {
if frames.length() == 0 { raise Failure::Failure("from_frames: empty array") }
let f0 = frames[0]
let (_, c, h, w) = f0.shape()
let t = frames.length()
let plane = c * h * w
let out : Array[Float] = Array::make(t * plane, 0.0F)
for t_idx in 0.. STImage raise Failure {
if a.b != b.b || a.c != b.c || a.h != b.h || a.w != b.w {
raise Failure::Failure(
"st_image_concat_t: shape mismatch (\{a.b},\{a.c},\{a.h},\{a.w}) vs (\{b.b},\{b.c},\{b.h},\{b.w})",
)
}
let t = a.t + b.t
let slice = a.batch_slice()
let out : Array[Float] = Array::make(t * a.b * slice, 0.0F)
let frame_block_a = a.frame_block()
let frame_block_b = b.frame_block()
for t_idx in 0.. STImage {
let (_, c, h, w) = img.shape()
let plane = c * h * w
let out : Array[Float] = Array::make(t * plane, 0.0F)
for t_idx in 0..