การเรนเดอร์th-TH

เทนเซอร์

Translation status: ภาษาไทย reader-locale proof. Term names and code fences follow the th-TH 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

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.