Tensor literals
Generated by tools/gen_example_pages.py from mnd_scripts/examples/example_tensor_literals.mnd — the output below is a real run, not a transcription. Regenerating the page reruns it.
defining a tensor BY ITS NUMBERS — literal syntax, rank, shape, and the rules the parser enforces on them.
The program#
# ============================================================================
# example_tensor_literals.mnd
# ----------------------------------------------------------------------------
# FUNCTIONALITY: defining a tensor BY ITS NUMBERS -- literal syntax, rank,
# shape, and the rules the parser enforces on them.
#
# This is the companion to example_tensor_from_properties.mnd. There you
# describe a matrix and let a constructor build it; here you write the entries
# out. Both produce the identical runtime value: a shape plus row-major int64
# data. Once built, nothing downstream can tell them apart.
#
# LITERAL FORMS
# 42 a scalar (rank 0)
# -7 negative: the minus binds to the digits with no space
# [1, 2, 3] rank 1, shape [3]
# [[1,2],[3,4]] rank 2, shape [2,2] -- rows, then columns
# nest further for rank 3, 4, ...
#
# THE RECTANGULARITY RULE. A tensor literal must be rectangular, and the parser
# rejects a ragged one at its source location rather than discovering the
# problem at run time:
#
# in::bad = [[1, 2], [3]]; -> parse error, rows have different lengths
#
# INTEGERS ONLY. The execution engine has no floating point. A literal with a
# decimal point is lexed and belongs to the wider quantization model, but the
# value that reaches the interpreter is an integer at the declared scale (see
# example_quantization.mnd). Write 0.25 at quantres=2 as 25.
#
# Literals are legal in three places: an `in::` declaration, directly inside a
# flow body as a constant, and on the command line via
# `--in name=SHAPE:DATA` (see example_inputs_and_outputs.mnd).
#
# RUN: ../maned-run examples/example_tensor_literals.mnd
# ============================================================================
mnd::quantmax=1000;
mnd::quantmin=-1000;
mnd::quantres=0;
# --- rank 0: a scalar -------------------------------------------------------
in::count = 42;
in::below = -7;
# --- rank 1: a vector, shape [4] --------------------------------------------
in::weights = [3, 1, 4, 1];
# --- rank 2: a matrix, shape [2,3] -- rows first ---------------------------
in::matrix = [[1, 2, 3],
[4, 5, 6]];
# --- rank 2 with negative entries ------------------------------------------
in::signed_matrix = [[-1, 2], [3, -4]];
# --- rank 3: shape [2,2,2] --------------------------------------------------
in::volume = [[[1,2],[3,4]],
[[5,6],[7,8]]];
# --- rank 4: shape [1,1,2,2] -- the layout conv2d wants for a kernel -------
in::kernel = [[[[1, 0], [0, -1]]]];
calc::lambda_flow numbers(count, below, weights, matrix, signed_matrix,
volume, kernel) {
# A literal written straight into the flow body is a graph CONSTANT: it
# is folded into the dataflow node, not looked up as an external input.
#
# GOTCHA: a `[` immediately after an IDENTIFIER is read as indexing
# (`a[0]`), not as a new literal -- so `matrix [[1,0],...] matmul` does not
# mean what it looks like. Start the statement with the literal and bind
# it, then use the name. This is clearer to read anyway.
[[1,0],[0,1],[1,1]] basis =
matrix basis matmul projected =
# A scalar literal broadcasts against a tensor.
matrix 10 mul amplified =
# Rank is what makes an operator legal. matmul needs rank 2 on both sides;
# a reduction accepts any rank and always returns one scalar.
volume tensor_sum volume_total =
weights tensor_sum weight_total =
signed_matrix relu clamped =
# Shape can be read back with the profiler rather than assumed. `count`
# and `below` are here just to show scalars flowing through unchanged.
count below add offset =
} return basis, projected, amplified, volume_total, weight_total, clamped,
offset, kernel;
The run#
$ maned-run mnd_scripts/examples/example_tensor_literals.mnd
flow 'numbers' outputs:
basis : [3x2] = [1, 0, 0, 1, 1, 1]
projected : [2x2] = [4, 5, 10, 11]
amplified : [2x3] = [10, 20, 30, 40, 50, 60]
volume_total : [1] = [36]
weight_total : [1] = [9]
clamped : [2x2] = [0, 2, 3, 0]
offset : scalar = 35
kernel : [1x1x2x2] = [1, 0, 0, -1]
Next#
- Language guide — every operation the examples use, in the full table.
- RPN syntax specification — the normative rules.