Contents Menu Expand Light mode Dark mode Auto light/dark, in light mode Auto light/dark, in dark mode Skip to content
Python-Blosc2 documentation
Logo
Python-Blosc2 documentation
  • Getting Started
    • Overview
    • Installation
  • Tutorials
    • NDArray: A NDim, Compressed Data Container
    • Expressions containing NDArray objects
    • User Defined Functions
    • Lazy array kernels with Menudet
    • Optimizing data reductions with NDArrays
    • Advanced Lazy Expressions and Persistent Reductions
    • Using Proxies for Efficient Handling of Remote Multidimensional Data
    • Compressing data with the SChunk class
    • Slicing, extending and serializing with SChunks
    • User-defined codecs and filters
    • Prefilters, postfilters and fillers
    • Working with Containers
    • Working with ObjectArray
    • Working with BatchArray
    • CTable Tutorial
    • Indexing Arrays
    • Indexing CTables
  • Guides
    • Performance & Benchmarks
    • Optimization tips
    • Menudet: portable computation
    • Migrating to Menudet
    • Working with Remote Data
    • Working with Remote Arrays
    • Working with Remote Tables
    • Sharing Containers Across Processes
    • Using Blosc2 with pandas
    • b2view: Browse TreeStore Bundles in the Terminal
    • Parquet to Blosc2 Walkthrough
  • API Reference
    • Blosc2 Classes
      • NDArray
      • C2Array
      • LazyArray
      • BatchArray
      • ListArray
      • ObjectArray
      • Proxy
      • RemoteObject
      • RemoteArray
      • RemoteStore
      • RemoteRepository
      • RemoteFile
      • RemoteCTable
      • ProxySource
      • ProxyNDSource
      • ByteRangeNDSource
      • FsspecNDSource
      • ZarrNDSource
      • HDF5NDSource
      • B2ZNDSource
      • SimpleProxy
      • Traffic
      • EmbedStore
      • DictStore
      • TreeStore
      • CTable
      • Column
      • NestedColumn
      • Schema Specs
      • Index
      • SChunk
      • Array
      • NDField
      • Ref
    • Operations with arrays
      • Universal Functions (ufuncs)
      • Reduction Functions
      • Linear Algebra
      • Random Functions
      • Additional Functions and Type Utilities
      • Indexing and Manipulation Functions and Utilities
    • Miscellaneous
    • Compression Utilities
      • blosc2.compress
      • blosc2.compress2
      • blosc2.decompress
      • blosc2.decompress2
      • blosc2.pack
      • blosc2.pack_array
      • blosc2.pack_array2
      • blosc2.pack_tensor
      • blosc2.unpack
      • blosc2.unpack_array
      • blosc2.unpack_array2
      • blosc2.unpack_tensor
      • blosc2.clib_info
      • blosc2.compressor_list
      • blosc2.detect_number_of_cores
      • blosc2.free_resources
      • blosc2.get_clib
      • blosc2.nthreads
      • blosc2.print_versions
      • blosc2.register_codec
      • blosc2.register_filter
      • blosc2.set_blocksize
      • blosc2.set_nthreads
      • blosc2.set_prefetch
      • blosc2.set_releasegil
      • blosc2.set_compressor
      • blosc2.get_compressor
      • blosc2.get_blocksize
      • blosc2.get_cbuffer_sizes
      • blosc2.cparams_dflts
      • blosc2.dparams_dflts
      • blosc2.storage_dflts
      • blosc2.Codec
      • blosc2.Filter
      • blosc2.SpecialValue
      • blosc2.SplitMode
      • blosc2.Tuner
      • blosc2.compute_chunks_blocks
      • blosc2.get_slice_nchunks
      • blosc2.remove_urlpath
      • blosc2.blosclib_version
      • blosc2.DEFINED_CODECS_STOP
      • blosc2.GLOBAL_REGISTERED_CODECS_STOP
      • blosc2.USER_REGISTERED_CODECS_STOP
      • blosc2.EXTENDED_HEADER_LENGTH
      • blosc2.MAX_BUFFERSIZE
      • blosc2.MAX_BLOCKSIZE
      • blosc2.MAX_OVERHEAD
      • blosc2.MAX_TYPESIZE
      • blosc2.MIN_HEADER_LENGTH
      • blosc2.prefilter_funcs
      • blosc2.postfilter_funcs
      • blosc2.ucodecs_registry
      • blosc2.ufilters_registry
      • blosc2.VERSION_DATE
      • blosc2.VERSION_STRING
      • blosc2.__version__
    • Compression, decompression and storage parameters
    • Save and load
    • Expression Utilities
    • Menudet syntax
    • Menudet API
    • Menudet numerical behavior
    • JIT execution options
  • Glossary
  • Development
    • Contributing guidelines
    • Code of Conduct
    • List of desired features for a 4.0 release
    • Remote cache design
    • Menudet numerical qualification
    • Typed expression evaluator rollout
  • Release Notes
Back to top

Menudet: portable computation¶

Menudet is a little language for portable computation on arrays and tables. Saved computations run natively without reconstructing or executing Python functions.

Note

Menudet 0.1 is beta and is the supported language going forward. API and format changes remain possible and will come with migration guidance. For old DSL code or files, see Migrating to Menudet.

Getting started¶

Decorate a function, then call it with NumPy or Blosc2 arrays:

import blosc2
import numpy as np


@blosc2.menudet
def adjusted(x, y):
    return x + (y - 1)


x = np.array([1, 2, 3], dtype="float64")
y = np.array([4, 5, 6], dtype="float64")
values = adjusted(x, y)[:]  # NumPy values: [4., 6., 8.]
result = adjusted(x, y).compute()  # Materialized Blosc2 NDArray.

The decorated object is a blosc2.MenudetFunction. Calls specialize automatically for the input dtypes and return lazy arrays. The Python body is never executed, including after native errors.

@blosc2.menudet and @blosc2.jit serve different purposes. Menudet authors validated lazy kernels with specialization and persistence. Ordinary @jit keeps its NumPy-style eager results, tracing/control-flow dispatch, out=, disable= and pandas integration. strict=True is an eager @jit parsing contract, not an alias for Menudet. Execution policy (interpretation or JIT) is independent of the authoring decorator.

For example, both functions compute the same values but return different kinds of objects:

@blosc2.menudet
def menudet_adjusted(x, y):
    return x + (y - 1)


@blosc2.jit
def jit_adjusted(x, y):
    return x + (y - 1)


lazy = menudet_adjusted(x, y)  # Lazy result; values are not yet computed.
values = lazy[:]  # NumPy values.
stored = lazy.compute()  # Blosc2 NDArray, written directly into storage.

eager = jit_adjusted(x, y)  # NumPy array, computed immediately.

Menudet’s lazy result is what enables explicit specialization, partition/domain binding and saving a validated recipe. In contrast, @jit is the convenient route when NumPy-style eager evaluation or pandas integration is desired:

import pandas as pd

frame = pd.DataFrame({"x": x, "y": y})
doubled = blosc2.jit(lambda column: column * 2)
eager = frame.apply(doubled, engine=blosc2.jit)  # One eager NumPy result per column.

Execution policy is independent of the authoring decorator. Without an explicit or environment override, this single-return expression is interpreted by default; use @menudet(jit=True) or a blosc2.jit_options(jit=True) context to prefer JIT, and require_jit=True to require it. Interpretation is still native Menudet execution, not evaluation of the Python body.

Menudet kernels vs. LazyExpr execution plans¶

It is helpful to understand how Menudet kernels fit into Blosc2’s compute architecture:

  • Menudet (:func:`@blosc2.menudet`, :class:`blosc2.MenudetKernel`): This is the kernel language for expressing transformations on small, cache-friendly blocks or partitions. Menudet focuses on local computations: elementwise arithmetic, multi-statement branching, and block-level reductions. It compiles to a standalone JSON computational artifact that can be saved, inspected, or executed across platforms without Python.

  • Lazy expressions & computational graphs (:class:`blosc2.LazyExpr`): This is the dataset-level execution engine. When you compute with whole Blosc2 arrays, a native computational graph (an execution plan managed by miniexpr) orchestrates the computation across entire multidimensional datasets. It streams compressed chunks, manages memory buffers via read hooks, and performs axis reductions. Inside this graph execution plan, individual stage operations are evaluated as Menudet kernels.

Types and scalar arguments¶

Array inputs supply their element dtypes and can broadcast. Numeric output dtypes are inferred. Annotations specify element dtypes, not shapes; annotated inputs must match exactly. Scalar parameters and nonnumeric returns require annotations:

@blosc2.menudet
def shifted(x: np.float64, offset: np.float64 = 1.0) -> np.float64:
    return x + offset


values = shifted(x)[:]

Scalar globals and closure values are captured at decoration. Arrays, objects and callbacks cannot be captured; pass arrays as arguments instead. See Menudet syntax for supported syntax and Menudet numerical behavior for numerical rules.

Execution policy¶

The default chooses native interpretation or JIT. Use jit=False for interpretation, jit=True to prefer JIT, or require_jit=True to require it. Complex kernels currently use the interpreter only. Computation errors propagate without replay through Python. See JIT execution options for advanced controls.

Select other execution controls with blosc2.jit_options(...) when calling or specializing a Menudet function, for example:

with blosc2.jit_options(jit=True, jit_backend="cc"):
    kernel = adjusted.specialize(x, y)

jit_backend selects TCC or system CC; compiler= specifies the CC command, not the backend. Existing native environment/source-pragma precedence is unchanged. Kernel preparation fixes the execution policy; changing a context later does not recompile an existing lazy result. Specialize/call again to select another policy. Runtime compiler defaults are not embedded in saved artifact source. Menudet’s native floating-point policy is distinct from the expression evaluator’s fp_accuracy knob; see Menudet numerical behavior.

The Menudet decorator takes kernel-authoring options, not storage controls. Materialize with result.compute(cparams=..., chunks=...) instead. Menudet is not a pandas engine: pass NumPy/Blosc2 arrays explicitly and materialize the lazy result. Ordinary @jit pandas integration is unchanged.

Specialized kernels¶

MenudetFunction knows how to specialize; MenudetKernel is already specialized. Calling a decorated function specializes automatically for the input dtypes and returns a lazy computation. Explicit specialization is only needed when you want to work with the typed kernel itself.

For inspection, eager evaluation or table registration, specialize() prepares a blosc2.MenudetKernel without evaluating arrays:

kernel = adjusted.specialize(x, y)
values = kernel.evaluate({"x": x, "y": y})

evaluate() takes named NumPy inputs with matching shapes and exact dtypes. For broadcasting and lazy evaluation, call the decorated function or use kernel.lazy(...). When binding a specialized kernel directly, supply its logical domain/partitions explicitly as needed; decorator partition defaults apply to decorated calls.

Input-free generators need an explicit logical domain. For example:

@blosc2.menudet(ndim=1, jit=False)
def indices() -> np.int64:
    return _flat_idx


kernel = indices.specialize()
lazy = kernel.lazy({}, shape=(19,), partitions=(4,))
values = lazy[:]

ndim declares the native coordinate rank. shape and partitions on the bound kernel define the domain and original logical groups; they are not storage options. Input-free numeric 1-D generators can materialize through native parallel workers when output blocks exactly match these partitions and chunks contain whole blocks. Other layouts preserve groups through the general path.

Block reductions and partitions¶

block_sum, block_prod, block_min, block_max, block_mean, block_any and block_all reduce elements within each logical partition. Set cardinality="block_scalar" to return one value per partition:

@blosc2.menudet(cardinality="block_scalar", partitions=(3,))
def total(x):
    return block_sum(x)


values = total(np.arange(6, dtype="int64"))[:]
# array([3, 12])

Partitions are independent of storage chunks and blocks. Slicing or rechunking a result does not change its reduction groups. These operations do not accept axis or keepdims; use ordinary lazy expressions for whole-array or axis reductions.

Saving and loading¶

Save a lazy computation with save() and reopen it with blosc2.open(). Array operands need persistent references:

stored = blosc2.asarray(x, urlpath="input.b2nd", mode="w")
lazy = adjusted(stored, stored)
lazy.save("recipe.b2nd")
reopened = blosc2.open("recipe.b2nd")
values = reopened[:]

This saves the computation, captures, operand references and partitions—not its computed values. To save values instead, use lazy.compute(urlpath="values.b2nd", mode="w").

For fixed scalar configuration in persistent recipes, use captured scalars. Scalar parameters, including defaults, currently create temporary bindings that cannot be saved as durable references.

Table columns¶

For an existing table with an int64 column named amount, specialize a kernel and register its named inputs:

from dataclasses import dataclass


@dataclass
class Row:
    amount: int = 0


table = blosc2.CTable(Row, new_data={"amount": [10, 20, 30]})


@blosc2.menudet
def twice(x):
    return x * 2


kernel = twice.specialize(np.empty(0, dtype="int64"))
table.add_computed_column("twice", kernel, inputs={"x": "amount"})
table.add_generated_column("stored_twice", values=kernel, inputs={"x": "amount"})

Each row is independent. A fixed-shape array row can be reduced as one complete group; reductions never combine different rows. See CTable.

Errors and further reading¶

Unsupported constructs and numerical errors raise rather than executing Python. Optional raw-source validation is described in Menudet syntax. Menudet is not a sandbox for arbitrary untrusted source or data.

See Menudet API for the API and Migrating to Menudet for retired DSL interfaces and historical files.

Next
Migrating to Menudet
Previous
Optimization tips
Copyright © 2019-present, The Blosc Developers
Made with Sphinx and @pradyunsg's Furo
On this page
  • Menudet: portable computation
    • Getting started
    • Menudet kernels vs. LazyExpr execution plans
    • Types and scalar arguments
    • Execution policy
    • Specialized kernels
    • Block reductions and partitions
    • Saving and loading
    • Table columns
    • Errors and further reading