張量
Translation status: 繁體中文 reader-locale proof. Term names and code fences follow the zh-Hant pack; supporting prose may still be English.
Tensor comparisons and logic lift per element: comparisons give a bool tensor, and/or/not and the ✓ ✗ select evaluate both sides, and vel fills the none elements.
Syntax: 張量 > 張量 | 張量 ≤ scalar | mask and mask | not mask | mask ✓ a ✗ b | 張量 coalesce fallback
Category#
collection
Related#
Examples#
radix/corpus/tensor/decl.fab (canonical · type)#
tensor<T, Figura> declaration shell with rank-0 空集.
# =============================================================================
# 張量 — 張量<T, Figura> declaration shell with rank-0 空集.
# =============================================================================
#
# What this teaches:
# • Tensor declaration — `張量<T, Figura>` type syntax with `空集` as the empty initializer
# • Identity functions — passing tensors through functions preserves shape and rank
#
# Common mistakes:
# • declaring 張量<T> without a Figura shape parameter — use 張量<T, Figura> with explicit dimensions
#
# See also: 張量, 列表
# =============================================================================
# 張量 — declaration shell for 張量<T, Figura>
#
# 張量<T, []> name ← 空集
# 函式 f(張量<T, []> value) → 張量<T, []>
#
# GRAMMAR:
# type :← '張量' '<' type ',' shape '>'
#
# EXPECTED OUTPUT:
# Rank-0 張量 longitudo after round-trip identity call.
fn identity(張量<f32, []> value) → 張量<f32, []> {
return value
}
main {
const 張量<f32, []> empty ← empty
const 張量<f32, []> roundtrip ← identity(empty)
print roundtrip.length()
}Expected output:
0
radix/corpus/tensor/lift-arith.fab (canonical · operator-group)#
Tensor arithmetic lifts over a scalar: + - * / % ÷ and unary minus apply per element; ⤒ ⤓ take the elementwise extremum of two tensors.
# =============================================================================
# 張量 — Elementwise arithmetic lifted over a scalar.
# =============================================================================
#
# What this teaches:
# • Lifting — a scalar operator applied per element: `a + 1.0`, `10.0 - a`, `a * 0.5`
# • `* / %` lift only against a scalar; a 張量 times a 張量 is `⊙` (elementwise) or `·` (contraction)
# • Division has two kinds — `/` floors on integers, `÷` is true division (16-bit and narrower integers give f32)
# • Extrema — `a ⤒ b` and `a ⤓ b` pick the larger or smaller element of two same-shape tensors
# • Widths follow the scalar rules: an untyped constant adopts the element type, a family crossing needs `↦`
#
# Common mistakes:
# • writing `a * b` for an elementwise product — use `a ⊙ b`
# • mixing a float scalar with an integer 張量 (`n * 0.5`) — convert the 張量 with `↦` first
# • expecting tensors of different shapes to stretch — shapes must be identical
#
# See also: 張量, ⊙, ÷
# =============================================================================
# 張量 lift — arithmetic against a scalar
#
# WHY: each operator is the scalar operator applied to every element, so the
# runner's answer for one element is the answer for the whole 張量. Results
# are stored per element under the element type.
#
# EXPECTED stdout:
# [2.0, 3.0, 4.0, 5.0]
# [9.0, 8.0, 7.0, 6.0]
# [0.5, 1.0, 1.5, 2.0]
# [0.25, 0.5, 0.75, 1.0]
# [1.0, 2.0, 0.0, 1.0]
# [-1.0, -2.0, -3.0, -4.0]
# [0, 1, 1, 2]
# [1, 0, 1, 0]
# [0.5, 1.0, 1.5, 2.0]
# [4.0, 3.0, 3.0, 4.0]
# [1.0, 2.0, 2.0, 1.0]
main {
const list<f32> flat_a ← [1.0, 2.0, 3.0, 4.0]
const list<f32> flat_b ← [4.0, 3.0, 2.0, 1.0]
const 張量<f32, []> seed ← empty
var 張量<f32, [2, 2]> a ← seed.from_flat(flat_a, [2, 2])
var 張量<f32, [2, 2]> b ← seed.from_flat(flat_b, [2, 2])
const 張量<f32, [2, 2]> plus ← a + 1.0
const list<f32> plus_out ← plus.flatten()
print plus_out
const 張量<f32, [2, 2]> minus ← 10.0 - a
const list<f32> minus_out ← minus.flatten()
print minus_out
const 張量<f32, [2, 2]> times ← a * 0.5
const list<f32> times_out ← times.flatten()
print times_out
const 張量<f32, [2, 2]> divided ← a / 4.0
const list<f32> divided_out ← divided.flatten()
print divided_out
const 張量<f32, [2, 2]> rest ← a % 3.0
const list<f32> rest_out ← rest.flatten()
print rest_out
const 張量<f32, [2, 2]> negated ← -a
const list<f32> negated_out ← negated.flatten()
print negated_out
const list<i16> flat_n ← [1, 2, 3, 4]
const 張量<i16, []> nseed ← empty
var 張量<i16, [4]> n ← nseed.from_flat(flat_n, [4])
const 張量<i16, [4]> floored ← n / 2
const list<i16> floored_out ← floored.flatten()
print floored_out
const 張量<i16, [4]> odd ← n % 2
const list<i16> odd_out ← odd.flatten()
print odd_out
const 張量<f32, [4]> true_half ← n ÷ 2
const list<f32> true_half_out ← true_half.flatten()
print true_half_out
const 張量<f32, [2, 2]> larger ← a ⤒ b
const list<f32> larger_out ← larger.flatten()
print larger_out
const 張量<f32, [2, 2]> smaller ← a ⤓ b
const list<f32> smaller_out ← smaller.flatten()
print smaller_out
}Expected output:
[2.0, 3.0, 4.0, 5.0]
[9.0, 8.0, 7.0, 6.0]
[0.5, 1.0, 1.5, 2.0]
[0.25, 0.5, 0.75, 1.0]
[1.0, 2.0, 0.0, 1.0]
[-1.0, -2.0, -3.0, -4.0]
[0, 1, 1, 2]
[1, 0, 1, 0]
[0.5, 1.0, 1.5, 2.0]
[4.0, 3.0, 3.0, 4.0]
[1.0, 2.0, 2.0, 1.0]
radix/corpus/tensor/lift-compare.fab (canonical · operator-group)#
Tensor comparisons and logic lift per element: comparisons give a bool tensor, and/or/not and the ✓ ✗ select evaluate both sides, and vel fills the none elements.
# =============================================================================
# 張量 — Elementwise comparison, logic, select and vel.
# =============================================================================
#
# What this teaches:
# • Comparisons — `< > ≤ ≥ ≡ ≠ ≅ ≇` on tensors give `張量<bool, S>`, one verdict per element
# • Logic — `and`, `or`, `not` act per element on bool tensors and always evaluate both sides
# • Select — `mask ✓ a ✗ b` takes `a` where the mask is true and `b` elsewhere; both branches are evaluated
# • vel (spelled `coalesce` in English) — `t coalesce fallback` fills the `none` elements of a `T ∪ none` 張量
# • NaN compares false to everything, including itself
#
# Common mistakes:
# • using a 張量 mask as an `if` condition — a mask is a 張量; select or reduce it
# • expecting `and` to skip its right side on a mask — both sides run
# • using `coalesce` on a 張量 whose elements can never be none
#
# See also: 張量, vel, ✓ ✗
# =============================================================================
# 張量 lift — comparisons, logic, select, vel
#
# WHY: a comparison is the scalar comparison per element, and its result is a
# bool 張量 of the same shape. Logic and select take such masks.
#
# EXPECTED stdout:
# [假, 假, 真, 真]
# [真, 真, 假, 假]
# [假, 假, 真, 真]
# [真, 假, 假, 真]
# [假, 真, 假, 假]
# [4.0, 3.0, 3.0, 4.0]
# [0.0, 0.0, 1.0, 1.0]
# [1, 0, 3, 0]
# [1, 20, 3, 40]
main {
const list<f32> flat_a ← [1.0, 2.0, 3.0, 4.0]
const list<f32> flat_b ← [4.0, 3.0, 2.0, 1.0]
const 張量<f32, []> seed ← empty
var 張量<f32, [2, 2]> a ← seed.from_flat(flat_a, [2, 2])
var 張量<f32, [2, 2]> b ← seed.from_flat(flat_b, [2, 2])
const 張量<bool, [2, 2]> greater ← a > b
const list<bool> greater_out ← greater.flatten()
print greater_out
const 張量<bool, [2, 2]> small ← a ≤ 2.0
const list<bool> small_out ← small.flatten()
print small_out
const 張量<bool, [2, 2]> not_small ← not small
const list<bool> not_small_out ← not_small.flatten()
print not_small_out
const 張量<bool, [2, 2]> outer ← (a < 2.0) or (a > 3.0)
const list<bool> outer_out ← outer.flatten()
print outer_out
const 張量<bool, [2, 2]> inner ← (a > 1.0) and small
const list<bool> inner_out ← inner.flatten()
print inner_out
const 張量<f32, [2, 2]> bigger ← greater ✓ a ✗ b
const list<f32> bigger_out ← bigger.flatten()
print bigger_out
const 張量<f32, [2, 2]> clipped ← (a > 2.5) ✓ 1.0 ✗ 0.0
const list<f32> clipped_out ← clipped.flatten()
print clipped_out
const list<int ∪ none> flat_h ← [1, 無, 3, 無]
const 張量<int ∪ none, []> hseed ← empty
var 張量<int ∪ none, [2, 2]> holes ← hseed.from_flat(flat_h, [2, 2])
const 張量<int, [2, 2]> zeroed ← holes coalesce 0
const list<int> zeroed_out ← zeroed.flatten()
print zeroed_out
const list<int> flat_d ← [10, 20, 30, 40]
const 張量<int, []> dseed ← empty
var 張量<int, [2, 2]> defaults ← dseed.from_flat(flat_d, [2, 2])
const 張量<int, [2, 2]> filled ← holes coalesce defaults
const list<int> filled_out ← filled.flatten()
print filled_out
}Expected output:
[falsum, falsum, verum, verum]
[verum, verum, falsum, falsum]
[falsum, falsum, verum, verum]
[verum, falsum, falsum, verum]
[falsum, verum, falsum, falsum]
[4.0, 3.0, 3.0, 4.0]
[0.0, 0.0, 1.0, 1.0]
[1, 0, 3, 0]
[1, 20, 3, 40]
radix/corpus/tensor/arithmetic-reject.fab (supporting · reject)#
Tensor arithmetic rejects non-numeric elements and mixed numeric widths.
# =============================================================================
# 張量 — Tensor arithmetic rejects non-numeric elements and mixed numeric widths.
# =============================================================================
#
# What this teaches:
# • Type guard — elementwise arithmetic rejects non-numeric element types at compile time
# • Width safety — mixed-width operations (e.g. i32 + i64) require explicit `↦` 變換
#
# Common mistakes:
# • expecting silent numeric widening between i32 and i64 — use explicit ↦ 變換 instead
#
# See also: 張量, 型別, 轉換
# =============================================================================
# 張量 arithmetic reject cases — expected compile failure
#
# WHY: documents the typecheck contract for elementwise 張量 arithmetic.
# Both cases must reject:
# 1. 張量<文字, …> — non-numeric element (numeric gate).
# 2. i32 + i64 — mixed width is a ↦ 轉換 problem,
# never silent promotion at the kernel.
#
# This exemplum intentionally fails to compile; it is registered in the
# per-backend EXPECTED_FAILURES lists.
main {
const 張量<string, [2]> words_a ← empty
const 張量<string, [2]> words_b ← empty
const 張量<string, [2]> words_sum ← words_a.added(words_b)
print words_sum.length()
const 張量<i32, [2]> i32_a ← empty
const 張量<i64, [2]> i64_b ← empty
const 張量<i32, [2]> mixed ← i32_a.added(i64_b)
print mixed.length()
}Expected: compilation rejects this example.