DIPHA's own binary container format -- little-endian throughout, every file starting with the magic number 8067171840 followed by an Int64 file-type tag -- verified directly against DIPHA/dipha's own include/dipha/file_types.h and README.md (see .claude/WORKLOG-io-module.md), not reconstructed from a secondhand description.
'''Axis order''': DIPHA's IMAGE_DATA format is explicitly "x-fastest" (g(1) varies fastest) -- the OPPOSITE of CubicalImage.fromFlatArray's own convention (its LAST shape axis is fastest, matching ordinary row-major Array[Array[...]].flatten). readImageData/writeImageData reverse the shape to line the two conventions up (a flat array with axis-0 fastest is, by definition, already in row-major order for the REVERSED shape) -- pinned with a hand-built asymmetric-shape fixture, not just reasoned through, since transposing an image preserves its homology and a barcode-only test cannot catch getting this backwards.
DISTANCE_MATRIX (file type 7): magic, type, n (Int64), then n*nFloat64 values in plain row-major order (d(1,1)...d(1,n) d(2,1)...d(n,n) per the README) -- the FULL matrix, diagonal included, not a triangular packing.
DISTANCE_MATRIX (file type 7): magic, type, n (Int64), then n*nFloat64 values in plain row-major order (d(1,1)...d(1,n) d(2,1)...d(n,n) per the README) -- the FULL matrix, diagonal included, not a triangular packing.
IMAGE_DATA (file type 1): magic, type, n (Int64, total value count), d (Int64, dimension), d Int64 grid sizes g(1)...g(d) (g(1) fastest-varying), then nFloat64 values in "x-fastest" order. Returned as (shape, flatValues) in CubicalImage.fromFlatArray's own last-axis-fastest convention -- i.e. shape here is g.reverse, not g -- ready to pass straight to fromFlatArray/readCubicalGridStream.
IMAGE_DATA (file type 1): magic, type, n (Int64, total value count), d (Int64, dimension), d Int64 grid sizes g(1)...g(d) (g(1) fastest-varying), then nFloat64 values in "x-fastest" order. Returned as (shape, flatValues) in CubicalImage.fromFlatArray's own last-axis-fastest convention -- i.e. shape here is g.reverse, not g -- ready to pass straight to fromFlatArray/readCubicalGridStream.
PERSISTENCE_DIAGRAM (file type 2): magic, type, p (Int64), then p(dim, birth, death) triples as Int64/Float64/Float64. A negative dim value -k encodes an ESSENTIAL class of real dimension k - 1 (the README's own convention -- the -1 offset exists specifically so a dimension-0 essential class, the single most common case, doesn't collide with an ordinary finite dim == 0); confirmed with a dedicated dimension-0-essential fixture, not just read from the README (see .claude/WORKLOG-io-module.md). The death field of an essential triple is unspecified by the format and is written here as 0.0, ignored on read.
PERSISTENCE_DIAGRAM (file type 2): magic, type, p (Int64), then p(dim, birth, death) triples as Int64/Float64/Float64. A negative dim value -k encodes an ESSENTIAL class of real dimension k - 1 (the README's own convention -- the -1 offset exists specifically so a dimension-0 essential class, the single most common case, doesn't collide with an ordinary finite dim == 0); confirmed with a dedicated dimension-0-essential fixture, not just read from the README (see .claude/WORKLOG-io-module.md). The death field of an essential triple is unspecified by the format and is written here as 0.0, ignored on read.
def writeImageData(path: String, shape: IndexedSeq[Int], flatValues: IndexedSeq[Double]): Unit
shape/flatValues in CubicalImage.fromFlatArray's own last-axis-fastest convention -- reversed internally to DIPHA's own g(1)-fastest convention before writing (the inverse of readImageData's own reversal).
shape/flatValues in CubicalImage.fromFlatArray's own last-axis-fastest convention -- reversed internally to DIPHA's own g(1)-fastest convention before writing (the inverse of readImageData's own reversal).