Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions skainet-lang/skainet-lang-core/api/jvm/skainet-lang-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,17 @@ public final class sk/ainet/lang/memory/AllocationSpec$Companion {
public static synthetic fun of$default (Lsk/ainet/lang/memory/AllocationSpec$Companion;Lsk/ainet/lang/memory/Format;Lsk/ainet/lang/tensor/Shape;Lsk/ainet/lang/tensor/storage/MemoryDomain;Lsk/ainet/lang/memory/ScopeKind;ZIILjava/lang/Object;)Lsk/ainet/lang/memory/AllocationSpec;
}

public abstract interface class sk/ainet/lang/memory/BlockDecoder {
public abstract fun decodeBlock (Lsk/ainet/lang/memory/Storage;J[FI)V
public fun decodeElement (Lsk/ainet/lang/memory/Storage;Lsk/ainet/lang/memory/Layout;J)F
public abstract fun getBlockSize ()I
public abstract fun getBytesPerBlock ()I
}

public final class sk/ainet/lang/memory/BlockDecoder$DefaultImpls {
public static fun decodeElement (Lsk/ainet/lang/memory/BlockDecoder;Lsk/ainet/lang/memory/Storage;Lsk/ainet/lang/memory/Layout;J)F
}

public final class sk/ainet/lang/memory/DescribeKt {
public static final fun describe (Lsk/ainet/lang/tensor/Tensor;)Ljava/lang/String;
public static final fun describe (Lsk/ainet/lang/tensor/storage/TensorStorage;Lsk/ainet/lang/tensor/TensorId;)Ljava/lang/String;
Expand Down Expand Up @@ -751,6 +762,39 @@ public final class sk/ainet/lang/memory/ForwardScope : sk/ainet/lang/memory/Scop
public static synthetic fun retain$default (Lsk/ainet/lang/memory/ForwardScope;Lsk/ainet/lang/memory/Storage$Heap;Lsk/ainet/lang/memory/Scope;Lsk/ainet/lang/tensor/TensorId;ILjava/lang/Object;)Lsk/ainet/lang/memory/Storage$Heap;
}

public final class sk/ainet/lang/memory/Layout {
public static final field Companion Lsk/ainet/lang/memory/Layout$Companion;
public fun <init> (Lsk/ainet/lang/tensor/Shape;[IJIZ)V
public synthetic fun <init> (Lsk/ainet/lang/tensor/Shape;[IJIZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun byteOffsetOf ([I)J
public fun equals (Ljava/lang/Object;)Z
public final fun getBlocked ()Z
public final fun getElementBytes ()I
public final fun getElementCount ()J
public final fun getOffsetBytes ()J
public final fun getOffsetElements ()J
public final fun getShape ()Lsk/ainet/lang/tensor/Shape;
public final fun getStrides ()[I
public fun hashCode ()I
public final fun indexOf ([I)J
public final fun isContiguous ()Z
public final fun isRowMajor ()Z
public final fun narrow (III)Lsk/ainet/lang/memory/Layout;
public final fun squeeze (I)Lsk/ainet/lang/memory/Layout;
public fun toString ()Ljava/lang/String;
public final fun transpose (II)Lsk/ainet/lang/memory/Layout;
public static synthetic fun transpose$default (Lsk/ainet/lang/memory/Layout;IIILjava/lang/Object;)Lsk/ainet/lang/memory/Layout;
public final fun unsqueeze (I)Lsk/ainet/lang/memory/Layout;
}

public final class sk/ainet/lang/memory/Layout$Companion {
public final fun blocked (Lsk/ainet/lang/tensor/Shape;IIJ)Lsk/ainet/lang/memory/Layout;
public static synthetic fun blocked$default (Lsk/ainet/lang/memory/Layout$Companion;Lsk/ainet/lang/tensor/Shape;IIJILjava/lang/Object;)Lsk/ainet/lang/memory/Layout;
public final fun rowMajor (Lsk/ainet/lang/tensor/Shape;Lsk/ainet/lang/memory/Format;J)Lsk/ainet/lang/memory/Layout;
public static synthetic fun rowMajor$default (Lsk/ainet/lang/memory/Layout$Companion;Lsk/ainet/lang/tensor/Shape;Lsk/ainet/lang/memory/Format;JILjava/lang/Object;)Lsk/ainet/lang/memory/Layout;
public final fun rowMajorStrides (Lsk/ainet/lang/tensor/Shape;)[I
}

public final class sk/ainet/lang/memory/MappedBufferStorage : sk/ainet/lang/memory/Storage$Mapped {
public static final field Companion Lsk/ainet/lang/memory/MappedBufferStorage$Companion;
public synthetic fun <init> (JLjava/nio/file/Path;JLjava/nio/ByteBuffer;Lsk/ainet/lang/memory/Owner;Lsk/ainet/lang/tensor/TensorId;Lsk/ainet/lang/memory/trace/TraceSink;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
Expand Down Expand Up @@ -843,6 +887,14 @@ public final class sk/ainet/lang/memory/Owner$Owned : sk/ainet/lang/memory/Owner
public fun toString ()Ljava/lang/String;
}

public final class sk/ainet/lang/memory/PackedBlockDecoder : sk/ainet/lang/memory/BlockDecoder {
public fun <init> (Lsk/ainet/lang/tensor/storage/PackedBlockStorage;)V
public fun decodeBlock (Lsk/ainet/lang/memory/Storage;J[FI)V
public fun decodeElement (Lsk/ainet/lang/memory/Storage;Lsk/ainet/lang/memory/Layout;J)F
public fun getBlockSize ()I
public fun getBytesPerBlock ()I
}

public final class sk/ainet/lang/memory/PlatformStorage {
public static final field INSTANCE Lsk/ainet/lang/memory/PlatformStorage;
public final fun allocate (JLsk/ainet/lang/tensor/storage/MemoryDomain;Lsk/ainet/lang/memory/ScopeKind;Lsk/ainet/lang/tensor/TensorId;Lsk/ainet/lang/memory/trace/TraceSink;)Lsk/ainet/lang/memory/Storage;
Expand Down Expand Up @@ -1016,6 +1068,38 @@ public final class sk/ainet/lang/memory/StorageId$Companion {
public final fun next-TPZW6QE ()J
}

public final class sk/ainet/lang/memory/TensorView {
public static final field Companion Lsk/ainet/lang/memory/TensorView$Companion;
public fun <init> (Lsk/ainet/lang/tensor/Shape;Lsk/ainet/lang/memory/Format;Lsk/ainet/lang/memory/Layout;Lsk/ainet/lang/memory/Storage;Lsk/ainet/lang/tensor/TensorId;Lsk/ainet/lang/memory/BlockDecoder;)V
public synthetic fun <init> (Lsk/ainet/lang/tensor/Shape;Lsk/ainet/lang/memory/Format;Lsk/ainet/lang/memory/Layout;Lsk/ainet/lang/memory/Storage;Lsk/ainet/lang/tensor/TensorId;Lsk/ainet/lang/memory/BlockDecoder;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun get ([I)F
public final fun getElementCount ()J
public final fun getFormat ()Lsk/ainet/lang/memory/Format;
public final fun getId ()Lsk/ainet/lang/tensor/TensorId;
public final fun getLayout ()Lsk/ainet/lang/memory/Layout;
public final fun getShape ()Lsk/ainet/lang/tensor/Shape;
public final fun getStorage ()Lsk/ainet/lang/memory/Storage;
public final fun isContiguous ()Z
public final fun isMutable ()Z
public final fun materialize (Lsk/ainet/lang/memory/Format;Lsk/ainet/lang/memory/Scope;)Lsk/ainet/lang/memory/TensorView;
public static synthetic fun materialize$default (Lsk/ainet/lang/memory/TensorView;Lsk/ainet/lang/memory/Format;Lsk/ainet/lang/memory/Scope;ILjava/lang/Object;)Lsk/ainet/lang/memory/TensorView;
public final fun narrow (III)Lsk/ainet/lang/memory/TensorView;
public final fun set ([IF)V
public final fun squeeze (I)Lsk/ainet/lang/memory/TensorView;
public final fun toFloatArray ()[F
public fun toString ()Ljava/lang/String;
public final fun transpose (II)Lsk/ainet/lang/memory/TensorView;
public static synthetic fun transpose$default (Lsk/ainet/lang/memory/TensorView;IIILjava/lang/Object;)Lsk/ainet/lang/memory/TensorView;
public final fun unsqueeze (I)Lsk/ainet/lang/memory/TensorView;
}

public final class sk/ainet/lang/memory/TensorView$Companion {
public final fun dense (Lsk/ainet/lang/memory/Storage;Lsk/ainet/lang/tensor/Shape;Lsk/ainet/lang/types/DType;Lsk/ainet/lang/tensor/TensorId;)Lsk/ainet/lang/memory/TensorView;
public static synthetic fun dense$default (Lsk/ainet/lang/memory/TensorView$Companion;Lsk/ainet/lang/memory/Storage;Lsk/ainet/lang/tensor/Shape;Lsk/ainet/lang/types/DType;Lsk/ainet/lang/tensor/TensorId;ILjava/lang/Object;)Lsk/ainet/lang/memory/TensorView;
public final fun packed (Lsk/ainet/lang/memory/Storage;Lsk/ainet/lang/tensor/Shape;Lsk/ainet/lang/tensor/storage/TensorEncoding;Lsk/ainet/lang/memory/BlockDecoder;Lsk/ainet/lang/types/DType;Lsk/ainet/lang/tensor/TensorId;)Lsk/ainet/lang/memory/TensorView;
public static synthetic fun packed$default (Lsk/ainet/lang/memory/TensorView$Companion;Lsk/ainet/lang/memory/Storage;Lsk/ainet/lang/tensor/Shape;Lsk/ainet/lang/tensor/storage/TensorEncoding;Lsk/ainet/lang/memory/BlockDecoder;Lsk/ainet/lang/types/DType;Lsk/ainet/lang/tensor/TensorId;ILjava/lang/Object;)Lsk/ainet/lang/memory/TensorView;
}

public final class sk/ainet/lang/memory/plan/Budget {
public static final field Companion Lsk/ainet/lang/memory/plan/Budget$Companion;
public static final field RESERVE_ANDROID_JVM J
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package sk.ainet.lang.memory

import sk.ainet.lang.tensor.Shape

/**
* Strides, byte offset and contiguity of a view over a [Storage] (SKEEP-003 §0 *Layout*). Pure
* metadata: it says *where* the elements of a shape live inside a byte range, never what they mean
* (that is [Format]) and never who owns them (that is [Storage]).
*
* Strides are in **elements** of the layout's unit — for a dense format one element is
* `format.dtype.sizeInBytes`; for a block-packed format ([blocked]) a stride step addresses one
* *block*, which is what makes a packed weight sliceable and transposable without touching bytes
* (rule 5: "a view is a TensorView with the same Storage, different Layout").
*
* @property shape the extents this layout addresses
* @property strides one stride per dimension, in elements (or blocks for a blocked layout)
* @property offsetElements element (or block) offset of the first element inside the storage
* @property elementBytes bytes per element (dense) or per block (blocked)
*/
@ExperimentalMemoryApi
public class Layout(
public val shape: Shape,
public val strides: IntArray,
public val offsetElements: Long = 0L,
public val elementBytes: Int = 4,
public val blocked: Boolean = false,
) {
init {
require(strides.size == shape.rank) { "strides (${strides.size}) must match rank (${shape.rank})" }
require(offsetElements >= 0) { "offsetElements must be >= 0" }
require(elementBytes > 0) { "elementBytes must be > 0" }
}

/** Number of elements addressed (the shape's volume). */
public val elementCount: Long get() = shape.volume.toLong()

/** Byte offset of the first element. */
public val offsetBytes: Long get() = offsetElements * elementBytes

/** Row-major (C-order) strides for [shape] — the canonical layout. */
public val isRowMajor: Boolean get() = strides.contentEquals(rowMajorStrides(shape))

/** Whether the elements occupy one gap-free run, i.e. the layout can be handed to a kernel as a flat range. */
public val isContiguous: Boolean
get() {
if (shape.rank == 0) return true
var expected = 1
for (d in shape.rank - 1 downTo 0) {
val extent = shape[d]
if (extent == 1) continue // a unit extent's stride is irrelevant
if (strides[d] != expected) return false
expected *= extent
}
return true
}

/** Flat element (or block) index of [indices] inside the storage, including [offsetElements]. */
public fun indexOf(vararg indices: Int): Long {
require(indices.size == shape.rank) { "expected ${shape.rank} indices, got ${indices.size}" }
var flat = offsetElements
for (d in indices.indices) {
val i = indices[d]
require(i in 0 until shape[d]) { "index $i out of range for axis $d (extent ${shape[d]})" }
flat += i.toLong() * strides[d]
}
return flat
}

/** Byte offset of [indices]. */
public fun byteOffsetOf(vararg indices: Int): Long = indexOf(*indices) * elementBytes

/** A layout over `[from, to)` of [axis] — same strides, shifted offset (zero-copy slicing). */
public fun narrow(axis: Int, from: Int, size: Int): Layout {
require(axis in 0 until shape.rank) { "axis $axis out of range for rank ${shape.rank}" }
require(from >= 0 && size >= 0 && from + size <= shape[axis]) { "narrow($axis, $from, $size) outside extent ${shape[axis]}" }
val dims = shape.dimensions.copyOf(); dims[axis] = size
return Layout(Shape(dims), strides.copyOf(), offsetElements + from.toLong() * strides[axis], elementBytes, blocked)
}

/** Swap two axes — metadata only; the bytes are untouched (the packed-transpose trick, rule 5). */
public fun transpose(axis0: Int = shape.rank - 2, axis1: Int = shape.rank - 1): Layout {
require(shape.rank >= 2) { "transpose needs rank >= 2" }
require(axis0 in 0 until shape.rank && axis1 in 0 until shape.rank) { "axes out of range" }
val dims = shape.dimensions.copyOf(); val st = strides.copyOf()
val d = dims[axis0]; dims[axis0] = dims[axis1]; dims[axis1] = d
val s = st[axis0]; st[axis0] = st[axis1]; st[axis1] = s
return Layout(Shape(dims), st, offsetElements, elementBytes, blocked)
}

/** Insert a unit axis at [axis] (stride 0 — it is never stepped). */
public fun unsqueeze(axis: Int): Layout {
require(axis in 0..shape.rank) { "axis $axis out of range for rank ${shape.rank}" }
val dims = IntArray(shape.rank + 1); val st = IntArray(shape.rank + 1)
var j = 0
for (i in 0..shape.rank) {
if (i == axis) { dims[i] = 1; st[i] = 0 } else { dims[i] = shape[j]; st[i] = strides[j]; j++ }
}
return Layout(Shape(dims), st, offsetElements, elementBytes, blocked)
}

/** Drop the unit axis at [axis]. */
public fun squeeze(axis: Int): Layout {
require(axis in 0 until shape.rank) { "axis $axis out of range for rank ${shape.rank}" }
require(shape[axis] == 1) { "axis $axis has extent ${shape[axis]}, not 1" }
val dims = ArrayList<Int>(shape.rank - 1); val st = ArrayList<Int>(shape.rank - 1)
for (i in 0 until shape.rank) if (i != axis) { dims += shape[i]; st += strides[i] }
return Layout(Shape(dims.toIntArray()), st.toIntArray(), offsetElements, elementBytes, blocked)
}

override fun toString(): String =
"Layout($shape, strides=${strides.joinToString(",", "[", "]")}, offset=$offsetElements${if (blocked) " blocks" else ""}, ${if (isContiguous) "contiguous" else "strided"})"

override fun equals(other: Any?): Boolean = other is Layout && other.shape == shape &&
other.strides.contentEquals(strides) && other.offsetElements == offsetElements &&
other.elementBytes == elementBytes && other.blocked == blocked

override fun hashCode(): Int {
var h = shape.hashCode()
h = 31 * h + strides.contentHashCode(); h = 31 * h + offsetElements.hashCode()
h = 31 * h + elementBytes; h = 31 * h + blocked.hashCode()
return h
}

public companion object {
/** Row-major strides of [shape], in elements. */
public fun rowMajorStrides(shape: Shape): IntArray {
val st = IntArray(shape.rank)
var acc = 1
for (d in shape.rank - 1 downTo 0) { st[d] = acc; acc *= shape[d] }
return st
}

/** The canonical dense row-major layout of [shape] for [format]. */
public fun rowMajor(shape: Shape, format: Format, offsetElements: Long = 0L): Layout =
Layout(shape, rowMajorStrides(shape), offsetElements, format.dtype.sizeInBytes, blocked = false)

/**
* A blocked layout: the last axis is measured in blocks of `blockSize` elements, one
* "element" of the layout being one packed block of `bytesPerBlock` bytes. Used for the
* GGML block formats, where a view addresses whole blocks (rule 5).
*/
public fun blocked(shape: Shape, blockSize: Int, bytesPerBlock: Int, offsetBlocks: Long = 0L): Layout {
require(blockSize > 0 && bytesPerBlock > 0) { "block geometry must be positive" }
require(shape.rank >= 1) { "blocked layout needs rank >= 1" }
require(shape[shape.rank - 1] % blockSize == 0) { "last extent ${shape[shape.rank - 1]} is not a multiple of the block size $blockSize" }
val dims = shape.dimensions.copyOf()
dims[dims.size - 1] = dims[dims.size - 1] / blockSize
val blockShape = Shape(dims)
return Layout(blockShape, rowMajorStrides(blockShape), offsetBlocks, bytesPerBlock, blocked = true)
}
}
}
Loading
Loading