API Reference
Setup
- jask.set_memory_budget(max_memory, scratch_dir=None, allow_tmpfs=False)[source]
Set the process-wide configuration used by every jask op.
Call this once at the start of your program, not per-op-call. Every op (
jask.dot,jask.add, etc.) that doesn’t receive an explicit Config uses this to decide how large a tile (“page”) of an array it reads into memory at a time, and where it writes its own internal files (op outputs, gradient buffers, spill files).The effective memory budget is
min(max_memory, 0.8 * currently available RAM)- a one-time safety clamp taken at the moment this function is called, so a budget that doesn’t match actual conditions on this machine doesn’t go completely unchecked. This is checked once here, not continuously during execution - block size stays fixed for the rest of the session once set. It does not protect against available memory dropping significantly after this call, only against a mismatch that already exists when you call it.scratch_dir is checked against RAM-backed filesystems (tmpfs, ramfs - e.g. /tmp on many modern Linux systems and most containers) and rejected by default: writing “disk-backed” array data there would silently consume real memory instead of disk, defeating jask’s out-of-core guarantee entirely and invisibly.
- Parameters:
max_memory (int or str) – The memory budget, either in bytes (int) or as a string with a unit suffix, e.g.
"4GB","512MB".scratch_dir (str, optional) – Directory for jask’s own internal files. Defaults to
.jask_scratchunder the current working directory - still subject to the same RAM-backed-filesystem check, so a bad default is caught, not trusted blindly. Created if it doesn’t exist.allow_tmpfs (bool, optional) – Set True to allow scratch_dir to be RAM-backed anyway (e.g. deliberately testing with small data). Default False.
- Raises:
RuntimeError – If the resolved scratch_dir is on a RAM-backed filesystem and allow_tmpfs is False.
Examples
>>> import jask >>> jask.set_memory_budget("4GB", scratch_dir="/data/jask_scratch")
The array type
- class jask.DiskArray(filename, shape, dtype, _lo_tracer=None)[source]
A disk-backed array that behaves as a native JAX value.
DiskArray represents an array whose data lives entirely on disk and is streamed through JAX one tile at a time - never fully loaded into memory - while still composing with jax.grad, jax.jit, and optax exactly like an ordinary jax.Array would.
- Parameters:
filename (str) – Path to the memmap file backing this array’s data.
dtype (numpy.dtype) – The array’s dtype.
_lo_tracer (object)
Notes
_lo_tracer is an internal field, set only transiently by DiskArrayType.raise_val or a primitive’s own expand, and is always a trivial marker (never real array data - see DiskArrayType for the zero-materialization mechanism). Real data always lives at filename. Not part of equality or repr.
Examples
>>> import numpy as np >>> import jask >>> jask.set_memory_budget("1GB") >>> a = jask.DiskArray.from_numpy(np.ones((4, 4), dtype=np.float32)) >>> a.shape (4, 4)
- to_memmap()[source]
Return a read/write numpy.memmap view of this array’s file.
- Returns:
A memmap of shape self.shape and dtype self.dtype. Reads and writes go straight to the backing file; no data is copied into memory until a specific region is accessed.
- Return type:
- classmethod from_numpy(arr)[source]
Write a numpy array to a temp file and wrap it as a DiskArray.
Intended for quick experiments with arrays small enough to build in memory first. For genuinely large data, construct DiskArray directly with an existing file’s path instead.
- Parameters:
arr (numpy.ndarray) – The array to write to disk.
- Returns:
A new disk-backed array holding a copy of arr’s data.
- Return type:
Examples
>>> import numpy as np >>> import jask >>> a = jask.DiskArray.from_numpy(np.arange(4, dtype=np.float32)) >>> np.asarray(a.to_memmap()) array([0., 1., 2., 3.], dtype=float32)
- update_(new_value)[source]
Overwrite this array’s file in place with new_value’s data.
Copies new_value’s data into this array’s own backing file, tile by tile (never a full in-memory copy), and returns a DiskArray with the same filename/identity as self.
This is the mechanism for loop-carried state (parameters, optimizer buffers) under jax.jit. Reassigning
a = a + updatesgives a a fresh filename every call, which makes jax.jit retrace on every single step (a new filename is a new type, so it’s a cache miss).a = a.update_(a + updates)keeps a’s filename identical across calls, so jax.jit compiles once and reuses that executable for the rest of the loop.- Parameters:
new_value (DiskArray) – The array whose data should replace this array’s contents. Must have the same shape and dtype as self.
- Returns:
A DiskArray with the same filename as self, now holding new_value’s data.
- Return type:
Examples
>>> import numpy as np >>> import jask >>> jask.set_memory_budget("1GB") >>> a = jask.DiskArray.from_numpy(np.zeros((4, 4), dtype=np.float32)) >>> original_path = a.filename >>> new_value = jask.DiskArray.from_numpy(np.ones((4, 4), dtype=np.float32)) >>> a = a.update_(new_value) >>> a.filename == original_path True >>> np.asarray(a.to_memmap())[0, 0] 1.0
Operations
- jask.add(*args, **kwargs)
Elementwise sum of two disk-backed arrays.
Computes
a + bone tile at a time, never materializing either input or the output in full. Equivalent toa + bviaDiskArray’s__add__.- Parameters:
- Returns:
A new disk-backed array of the same shape as a, holding
a + b.- Return type:
Examples
>>> import numpy as np >>> import jask >>> jask.set_memory_budget("1GB") >>> a = jask.DiskArray.from_numpy(np.ones((4, 4), dtype=np.float32)) >>> b = jask.DiskArray.from_numpy(np.ones((4, 4), dtype=np.float32)) >>> c = jask.add(a, b) >>> np.asarray(c.to_memmap())[0, 0] 2.0
- jask.sub(*args, **kwargs)
Elementwise difference of two disk-backed arrays.
Computes
a - bone tile at a time, never materializing either input or the output in full. Equivalent toa - bviaDiskArray’s__sub__.- Parameters:
- Returns:
A new disk-backed array of the same shape as a, holding
a - b.- Return type:
Examples
>>> import numpy as np >>> import jask >>> jask.set_memory_budget("1GB") >>> a = jask.DiskArray.from_numpy(np.full((4, 4), 5.0, dtype=np.float32)) >>> b = jask.DiskArray.from_numpy(np.ones((4, 4), dtype=np.float32)) >>> c = jask.sub(a, b) >>> np.asarray(c.to_memmap())[0, 0] 4.0
- jask.mul(a, b)[source]
Elementwise or scalar multiplication of disk-backed arrays.
Computes
a * bone tile at a time, never materializing either input or the output in full. If either argument is not a DiskArray (a Python number or a jax scalar, concrete or traced - e.g. a learning rate passed as a jitted argument), the other is scaled by it elementwise. Order-independent:mul(a, 3.5)andmul(3.5, a)both work. Equivalent toa * bviaDiskArray’s__mul__/__rmul__.- Parameters:
- Returns:
A new disk-backed array of the same shape as whichever operand is a DiskArray.
- Return type:
- Raises:
TypeError – If neither a nor b is a DiskArray.
Examples
>>> import numpy as np >>> import jask >>> jask.set_memory_budget("1GB") >>> a = jask.DiskArray.from_numpy(np.full((4, 4), 2.0, dtype=np.float32))
Elementwise, both operands DiskArray:
>>> b = jask.DiskArray.from_numpy(np.full((4, 4), 3.0, dtype=np.float32)) >>> np.asarray(jask.mul(a, b).to_memmap())[0, 0] 6.0
Scalar, either order - the scalar can be a Python literal or a real (even jit-traced) jax value:
>>> np.asarray(jask.mul(a, 2.5).to_memmap())[0, 0] 5.0 >>> np.asarray(jask.mul(2.5, a).to_memmap())[0, 0] 5.0
- jask.square(*args, **kwargs)
Elementwise square of a disk-backed array.
Computes
a ** 2one tile at a time, never materializing the input or output in full.- Parameters:
a (DiskArray) – The array to square.
- Returns:
A new disk-backed array of the same shape as a, holding
a ** 2.- Return type:
Examples
>>> import numpy as np >>> import jask >>> jask.set_memory_budget("1GB") >>> a = jask.DiskArray.from_numpy(np.full((4, 4), 3.0, dtype=np.float32)) >>> b = jask.square(a) >>> np.asarray(b.to_memmap())[0, 0] 9.0
- jask.transpose(*args, **kwargs)
Permute the axes of a disk-backed array.
Computes the transpose one tile at a time, never materializing the input or output in full.
- Parameters:
- Returns:
A new disk-backed array with axes permuted according to axes.
- Return type:
Examples
>>> import numpy as np >>> import jask >>> jask.set_memory_budget("1GB") >>> a = jask.DiskArray.from_numpy(np.arange(6, dtype=np.float32).reshape(2, 3)) >>> t = jask.transpose(a) >>> np.asarray(t.to_memmap()).shape (3, 2)
Permute a 3D array’s axes explicitly:
>>> b = jask.DiskArray.from_numpy(np.zeros((3, 4, 5), dtype=np.float32)) >>> jask.transpose(b, axes=(2, 0, 1)).shape (5, 3, 4)
- jask.sum(*args, **kwargs)
Sum all elements of a disk-backed array to a scalar.
Reduces the whole array one tile at a time, never materializing it in full. Unlike every other jask op, the result is small enough to return as a real
jax.Arraydirectly rather than a DiskArray.- Parameters:
a (DiskArray) – The array to reduce.
- Returns:
A real (not disk-backed) scalar jax.Array holding the sum of every element of a.
- Return type:
Examples
>>> import numpy as np >>> import jask >>> jask.set_memory_budget("1GB") >>> a = jask.DiskArray.from_numpy(np.ones((4, 4), dtype=np.float32)) >>> float(jask.sum(a)) 16.0
- jask.dot(*args, **kwargs)
Matrix multiplication of two disk-backed arrays, with batching.
Computes
a @ bone tile at a time along the contraction dimension, never materializing either input or the output in full. Matchesjnp.matmul/@semantics: for 2D inputs this is plain matrix multiplication; for higher-rank inputs, leading dimensions are treated as batch dimensions (broadcast, not contracted). Equivalent toa @ bviaDiskArray’s__matmul__.Note this differs from numpy.dot/jnp.dot’s own N-D contraction rule (which sums over a’s last axis and b’s second-to-last axis without batching) - jask.dot always matches @.
- Parameters:
- Returns:
A new disk-backed array of shape
(*batch, M, N).- Return type:
Examples
>>> import numpy as np >>> import jask >>> jask.set_memory_budget("1GB") >>> a = jask.DiskArray.from_numpy(np.ones((4, 6), dtype=np.float32)) >>> b = jask.DiskArray.from_numpy(np.ones((6, 3), dtype=np.float32)) >>> c = jask.dot(a, b) >>> np.asarray(c.to_memmap())[0, 0] 6.0
Batched (leading dim broadcasts, only the last two axes multiply):
>>> a3 = jask.DiskArray.from_numpy(np.ones((5, 4, 6), dtype=np.float32)) >>> b3 = jask.DiskArray.from_numpy(np.ones((5, 6, 3), dtype=np.float32)) >>> jask.dot(a3, b3).shape (5, 4, 3)
- jask.materialize(x)
Bring a disk-backed array fully into memory as a real jax.Array.
Reads the whole array in one shot - only use this when x is known to fit comfortably in memory, typically at the end of a disk-backed pipeline (e.g. right before handing a small result to jax.pmap, or computing a scalar loss). Differentiable: the backward pass writes the incoming cotangent back to a disk-backed gradient.
- Parameters:
x (DiskArray) – The disk-backed array to materialize. Its full contents will be loaded into memory.
- Returns:
An ordinary, in-memory jax.Array with the same shape, dtype, and values as x.
- Return type:
Examples
>>> import numpy as np >>> import jask >>> jask.set_memory_budget("1GB") >>> a = jask.DiskArray.from_numpy(np.ones((4, 4), dtype=np.float32)) >>> real = jask.materialize(a) >>> type(real).__name__ 'ArrayImpl'