Language Reference

MathViz is a statically-typed language with type inference, designed for mathematical computation and animation. It compiles to optimized Python with automatic NumPy conversions, Numba JIT injection, and runtime set operations. This reference covers every language construct with real compiled output from the MathViz compiler.

1. Variables & Types

MathViz provides three variable declaration keywords: let for mutable variables, const for compile-time constants, and optional type annotations for explicit typing. The compiler infers types when annotations are omitted.

let - Mutable Variables

let x = 42              // Type inferred as Int
let y: Float = 3.14     // Explicit type annotation
let name = "MathViz"    // String

x = 100                 // Variables can be reassigned
x = 42
y: float = 3.14
name = 'MathViz'

x = 100

const - Compile-Time Constants

const PI = 3.14159265358979
const MAX_SIZE = 1024
const TAU = 2.0 * PI
# Constants are inlined at compile time
PI = 3.14159265358979
MAX_SIZE = 1024
TAU = (2.0 * 3.14159265358979)

Type Annotations

MathViz supports a rich type system. Type annotations are optional thanks to inference, but recommended for function signatures.

fn typed_function(x: Int, y: Float) -> Float {
    return x * y + 1.0
}

fn with_collections(items: List[Int]) -> Int {
    let total = 0
    for item in items {
        total = total + item
    }
    return total
}
import numpy as np
from numba import jit, njit, vectorize, prange
import numba

@njit(cache=True)
def typed_function(x: int, y: float) -> float:
    return ((x * y) + 1.0)

@njit(cache=True)
def with_collections(items: list[int]) -> int:
    total = 0
    for item in items:
        total = (total + item)
    return total

All Supported Types

MathViz TypePython TypeDescription
IntintInteger numbers
FloatfloatFloating-point numbers
BoolboolBoolean values (true/false)
StringstrText strings
NoneNoneAbsence of value
List[T]list[T]Ordered, mutable collection
Set[T]set[T]Unordered, unique elements
Dict[K, V]dict[K, V]Key-value mapping
Tuple[T...]tuple[T...]Fixed-size, mixed types
Vec[T]np.ndarrayNumPy vector
Mat[T]np.ndarrayNumPy matrix
Array[T]np.ndarrayNumPy N-dimensional array
Optional[T]T | NoneMay or may not have a value
Result[T, E]T (with exceptions)Success or error

2. Functions

Functions are declared with fn. Use pub fn to make them public (exportable from modules). The compiler automatically adds @njit(cache=True) to pure numeric functions.

Basic Functions & Return Types

fn typed_function(x: Int, y: Float) -> Float {
    return x * y + 1.0
}

fn with_collections(items: List[Int]) -> Int {
    let total = 0
    for item in items {
        total = total + item
    }
    return total
}
@njit(cache=True)
def typed_function(x: int, y: float) -> float:
    return ((x * y) + 1.0)

@njit(cache=True)
def with_collections(items: list[int]) -> int:
    total = 0
    for item in items:
        total = (total + item)
    return total

Public Functions (Modules)

// math_utils.mviz - Module file
pub fn factorial(n) {
    if n <= 1 {
        return 1
    }
    return n * factorial(n - 1)
}

pub fn fibonacci(n) {
    if n <= 1 {
        return n
    }
    return fibonacci(n - 1) + fibonacci(n - 2)
}

fn private_helper() {
    return 42
}
@njit(cache=True)
def factorial(n):
    if (n <= 1):
        return 1
    return (n * factorial((n - 1)))

@njit(cache=True)
def fibonacci(n):
    if (n <= 1):
        return n
    return (fibonacci((n - 1)) + fibonacci((n - 2)))

@njit(cache=True)
def private_helper():
    return 42
Key Takeaway

The pub keyword controls visibility in the module system. Private functions (fn) cannot be imported from other modules. Both public and private functions receive JIT optimization when eligible.

Lambda Expressions

// Pipe-lambda syntax (Rust-like)
let double = |x| x * 2
let add = |a, b| a + b

// Used with iterators
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let doubled = numbers.map(|x| x * 2)
let big = numbers.filter(|x| x > 5)
let total = numbers.reduce(0, |acc, x| acc + x)
double = lambda x: (x * 2)
add = lambda a, b: (a + b)

# Iterator methods use runtime library
numbers = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], dtype=np.int64)
doubled = iter_map(numbers, lambda x: (x * 2))
big = iter_filter(numbers, lambda x: (x > 5))
total = iter_reduce(numbers, 0, lambda acc, x: (acc + x))

3. Control Flow

if / elif / else

pub fn factorial(n) {
    if n <= 1 {
        return 1
    }
    return n * factorial(n - 1)
}

pub fn gcd(a, b) {
    if b == 0 {
        return a
    }
    return gcd(b, a % b)
}
@njit(cache=True)
def factorial(n):
    if (n <= 1):
        return 1
    return (n * factorial((n - 1)))

@njit(cache=True)
def gcd(a, b):
    if (b == 0):
        return a
    return gcd(b, (a % b))

for Loops & Ranges

MathViz supports 0..n (exclusive) and 0..=n (inclusive) range syntax. Ranges compile to Python's range().

// Pure numeric loop - gets @njit
fn compute_sum(n: Int) -> Float {
    let total = 0.0
    for i in 0..n {
        total = total + sqrt(i * 1.0)
    }
    return total
}
@njit(cache=True)
def compute_sum(n: int) -> float:
    total = 0.0
    for i in range(0, n):
        total = (total + np.sqrt((i * 1.0)))
    return total

while Loops

MathViz
let count = 0
while count < 10 {
    print(count)
    count += 1
}

break and continue

MathViz
for i in 0..100 {
    if i == 5 {
        continue  // Skip to next iteration
    }
    if i == 10 {
        break     // Exit loop
    }
    print(i)
}

4. Pattern Matching

MathViz supports match expressions that compile to chained ternary expressions in Python. This provides concise pattern-based branching.

fn classify(x: Int) -> String {
    let result = match x {
        0 -> "zero"
        1 -> "one"
        _ -> "other"
    }
    return result
}
def classify(x: int) -> str:
    result = (lambda _match_subj: (
        'zero' if _match_subj == 0
        else ('one' if _match_subj == 1
        else 'other')
    ))(x)
    return result
How Match Compiles

The compiler transforms match into an immediately-invoked lambda with chained ternary expressions. The wildcard _ becomes the final else clause. The subject is captured in _match_subj to avoid re-evaluation.

Match with Enums

MathViz
fn describe_number(n: Int) -> String {
    match n {
        0 -> "zero"
        1 -> "one"
        n where n < 0 -> "negative"
        n where n > 100 -> "large"
        _ -> "other"
    }
}

fn calculate_area(shape: Shape) -> Float {
    match shape {
        Shape::Circle(r) -> PI * r ^ 2
        Shape::Rectangle(w, h) -> w * h
        Shape::Point -> 0.0
    }
}

5. Comprehensions

MathViz supports list, set, and dict comprehensions with optional filters. Ranges in comprehensions compile to range(), and the ^ operator compiles to **.

fn list_ops() {
    // Basic list comprehension
    let squares = [x^2 for x in 0..10]

    // With filter
    let evens = [x for x in 0..20 if x % 2 == 0]

    // Nested comprehension
    let nested = [x * y for x in 1..4 for y in 1..4]

    return squares
}

fn set_comp() {
    // Set comprehension (unique values)
    let unique_squares = {x^2 for x in -5..6}
    return unique_squares
}
@njit(cache=True)
def list_ops():
    squares = [(x ** 2) for x in range(0, 10)]
    evens = [x for x in range(0, 20) if ((x % 2) == 0)]
    nested = [(x * y) for x in range(1, 4) for y in range(1, 4)]
    return squares

@njit(cache=True)
def set_comp():
    unique_squares = {(x ** 2) for x in range((-5), 6)}
    return unique_squares
Key Transformations

x^2 becomes (x ** 2), ranges 0..10 become range(0, 10), and negative bounds like -5..6 become range((-5), 6). Dict comprehensions use {k: v for ...} syntax.

6. Operators

Arithmetic Operators

MathVizPython OutputDescriptionExample
++Addition5 + 3
--Subtraction5 - 3
**Multiplication5 * 3
//Division5 / 3
////Floor division5 // 3
%%Modulo5 % 3
^**Exponentiation2 ^ 10(2 ** 10)
****Exponentiation (alt)2 ** 10

Comparison Operators

MathVizPython OutputDescription
====Equal to
!=!=Not equal to
<<Less than
<=<=Less than or equal
>>Greater than
>=>=Greater than or equal

Logical Operators

fn constant_folding_demo() {
    let a = 2 + 3
    let b = 10 * 4
    let c = "hello" + " world"
    let d = true and false
    let e = 2^10
    return a + b
}
def constant_folding_demo():
    a = (2 + 3)
    b = (10 * 4)
    c = ('hello' + ' world')
    d = (True and False)
    e = (2 ** 10)
    return (a + b)
MathVizPython OutputDescription
andandLogical AND
ororLogical OR
notnotLogical NOT
trueTrueBoolean true
falseFalseBoolean false

7. Unicode Math Operators

MathViz natively supports Unicode mathematical symbols. The compiler translates them into function calls from the mathviz.runtime library or literal values.

UnicodeNameMathViz UsageCompiled Python
Element of3 ∈ Ais_element(3, A)
Not element of10 ∉ Ais_not_element(10, A)
Subset or equal{1, 2} ⊆ Ais_subset({1, 2}, A)
Superset or equalA ⊇ {1, 2}is_superset(A, {1, 2})
UnionA ∪ Bset_union(A, B)
IntersectionA ∩ Bset_intersection(A, B)
Set differenceA ∖ Bset_difference(A, B)
πPilet x = πx = 3.141592653589793
Infinitylet x = ∞x = float('inf')
Square root√(x)np.sqrt(x)
Approximately equala ≈ bnp.isclose(a, b)
Not equala ≠ ba != b
Less or equala ≤ ba <= b
Greater or equala ≥ ba >= b
Summation∑(list)np.sum(list)
Product∏(list)np.prod(list)

8. Set Operations

MathViz provides first-class set operations using Unicode symbols. The compiler imports helper functions from mathviz.runtime and replaces each operator with the corresponding function call.

fn set_operations() {
    let a = {1, 2, 3, 4, 5}
    let b = {3, 4, 5, 6, 7}

    let u = a ∪ b          // Union
    let inter = a ∩ b      // Intersection
    let diff = a ∖ b       // Difference

    let is_sub = {1, 2} ⊆ a  // Subset check
    let is_in = 3 ∈ a        // Membership
    let not_in = 10 ∉ a      // Non-membership

    let pi_val = π           // Mathematical Pi
    let inf_val = ∞          // Infinity

    return u
}
from mathviz.runtime import (
    set_union,
    set_intersection,
    set_difference,
    is_subset,
    is_superset,
    is_element,
    is_not_element,
)

def set_operations():
    a = {1, 2, 3, 4, 5}
    b = {3, 4, 5, 6, 7}
    u = set_union(a, b)
    inter = set_intersection(a, b)
    diff = set_difference(a, b)
    is_sub = is_subset({1, 2}, a)
    is_in = is_element(3, a)
    not_in = is_not_element(10, a)
    pi_val = 3.141592653589793
    inf_val = float('inf')
    return u
Automatic Import Injection

When the compiler detects Unicode set operators, it automatically adds the from mathviz.runtime import ... block at the top of the generated file. Functions that use sets do not receive @njit because the runtime helpers are pure Python.

9. NumPy Auto-Conversions

The MathViz compiler automatically converts mathematical function calls to their NumPy equivalents. When any NumPy function is detected, the compiler adds import numpy as np and the Numba JIT imports to the generated file.

Math Functions

fn math_operations() {
    let x = 2.0
    let y = sqrt(x)
    let z = sin(x) + cos(x)
    let w = exp(x) + log(x)
    let t = floor(3.7) + ceil(3.2)
    return y + z + w + t
}
import numpy as np
from numba import jit, njit, vectorize, prange
import numba

@njit(cache=True)
def math_operations():
    x = 2.0
    y = np.sqrt(x)
    z = (np.sin(x) + np.cos(x))
    w = (np.exp(x) + np.log(x))
    t = (np.floor(3.7) + np.ceil(3.2))
    return (((y + z) + w) + t)

Array Creation

fn array_operations() {
    let a = zeros(10)
    let b = ones(10)
    let c = linspace(0, 1, 100)
    let d = arange(0, 10, 1)
    let e = eye(3)
    return a
}
@njit(cache=True)
def array_operations():
    a = np.zeros(10)
    b = np.ones(10)
    c = np.linspace(0, 1, 100)
    d = np.arange(0, 10, 1)
    e = np.eye(3)
    return a

Complete NumPy Conversion Table

Below is the complete list of MathViz functions that auto-convert to NumPy. Write plain function names in MathViz; the compiler handles the np. prefix.

CategoryMathVizCompiled Python
Trigonometrysin(x)np.sin(x)
cos(x)np.cos(x)
tan(x)np.tan(x)
asin(x)np.arcsin(x)
acos(x)np.arccos(x)
atan(x)np.arctan(x)
Exponentialexp(x)np.exp(x)
log(x)np.log(x)
log2(x)np.log2(x)
log10(x)np.log10(x)
Roundingfloor(x)np.floor(x)
ceil(x)np.ceil(x)
round(x)np.round(x)
Powerssqrt(x)np.sqrt(x)
abs(x)np.abs(x)
Array Creationzeros(n)np.zeros(n)
ones(n)np.ones(n)
linspace(a, b, n)np.linspace(a, b, n)
arange(a, b, s)np.arange(a, b, s)
eye(n)np.eye(n)
Statisticsmean(x)np.mean(x)
std(x)np.std(x)
var(x)np.var(x)
max(x)np.max(x)
min(x)np.min(x)
Linear Algebramatmul(a, b)np.matmul(a, b)
dot(a, b)np.dot(a, b)
cross(a, b)np.cross(a, b)
transpose(a)np.transpose(a)
det(a)np.linalg.det(a)

10. Matrix & Vector Operations

MathViz supports matrix and vector operations that compile to NumPy. List literals used as matrices are converted to np.array with appropriate dtypes.

fn matrix_ops() {
    let a = [[1, 2], [3, 4]]
    let b = [[5, 6], [7, 8]]
    let c = matmul(a, b)
    let d = transpose(a)
    let e = dot([1, 2, 3], [4, 5, 6])
    return c
}
@njit(cache=True)
def matrix_ops():
    a = [np.array([1, 2], dtype=np.int64),
         np.array([3, 4], dtype=np.int64)]
    b = [np.array([5, 6], dtype=np.int64),
         np.array([7, 8], dtype=np.int64)]
    c = np.matmul(a, b)
    d = np.transpose(a)
    e = np.dot(
        np.array([1, 2, 3], dtype=np.int64),
        np.array([4, 5, 6], dtype=np.int64)
    )
    return c
Automatic dtype Detection

Integer lists compile to np.array([...], dtype=np.int64) while float lists compile to np.array([...], dtype=np.float64). The compiler infers the dtype from the literal values in the list.

Statistics on Arrays

fn stats() {
    let data = [1, 2, 3, 4, 5]
    let m = mean(data)
    let s = std(data)
    let v = var(data)
    let mx = max(data)
    let mn = min(data)
    return m
}
@njit(cache=True)
def stats():
    data = np.array([1, 2, 3, 4, 5], dtype=np.int64)
    m = np.mean(data)
    s = np.std(data)
    v = np.var(data)
    mx = np.max(data)
    mn = np.min(data)
    return m

11. Iterator Methods

MathViz provides Rust-inspired iterator methods that chain on collections. These compile to function calls from mathviz.runtime.iterators, a comprehensive functional programming toolkit.

fn iterator_demo() {
    let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    // Transform
    let doubled = numbers.map(|x| x * 2)

    // Filter
    let big = numbers.filter(|x| x > 5)

    // Reduce with initial value
    let total = numbers.reduce(0, |acc, x| acc + x)

    return doubled
}
from mathviz.runtime.iterators import (
    # Transformation
    iter_map, iter_filter, iter_reduce, iter_fold,
    iter_flat_map, iter_flatten,
    # Access
    iter_first, iter_last, iter_nth, iter_find,
    iter_position,
    # Predicate
    iter_any, iter_all, iter_none, iter_count,
    iter_count_if,
    # Numeric
    iter_sum, iter_product, iter_min, iter_max,
    iter_average, iter_min_by, iter_max_by,
    # Slicing
    iter_take, iter_skip, iter_take_while,
    iter_skip_while,
    # Ordering
    iter_sorted, iter_sorted_by, iter_sorted_by_desc,
    iter_reversed,
    # Combination
    iter_zip, iter_enumerate, iter_chain, iter_chunk,
    iter_unique,
    # Collection
    iter_collect_list, iter_collect_set,
    iter_collect_dict, iter_join, iter_group_by,
    iter_partition,
    # Dict-specific
    dict_keys, dict_values, dict_items,
    dict_map_values, dict_filter_keys,
    dict_filter_values,
)

@njit(cache=True)
def iterator_demo():
    numbers = np.array(
        [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
        dtype=np.int64
    )
    doubled = iter_map(numbers, lambda x: (x * 2))
    big = iter_filter(numbers, lambda x: (x > 5))
    total = iter_reduce(
        numbers, 0, lambda acc, x: (acc + x)
    )
    return doubled

Complete Iterator Method Table

CategoryMathViz MethodCompiled FunctionDescription
Transform.map(|x| expr)iter_map(seq, fn)Apply function to each element
.filter(|x| cond)iter_filter(seq, fn)Keep elements matching predicate
.flat_map(|x| expr)iter_flat_map(seq, fn)Map then flatten
.flatten()iter_flatten(seq)Flatten nested lists
Reduce.reduce(init, |a,x| expr)iter_reduce(seq, init, fn)Reduce to single value
.fold(init, |a,x| expr)iter_fold(seq, init, fn)Same as reduce (alias)
.sum()iter_sum(seq)Sum all elements
Access.first()iter_first(seq)First element
.last()iter_last(seq)Last element
.nth(n)iter_nth(seq, n)Nth element
.find(|x| cond)iter_find(seq, fn)First matching element
.position(|x| cond)iter_position(seq, fn)Index of first match
Predicate.any(|x| cond)iter_any(seq, fn)Any element matches?
.all(|x| cond)iter_all(seq, fn)All elements match?
.count()iter_count(seq)Count elements
Slice.take(n)iter_take(seq, n)First n elements
.skip(n)iter_skip(seq, n)Skip first n elements
.take_while(|x| cond)iter_take_while(seq, fn)Take while predicate holds
.skip_while(|x| cond)iter_skip_while(seq, fn)Skip while predicate holds
Combine.zip(other)iter_zip(seq, other)Pair elements from two lists
.enumerate()iter_enumerate(seq)Add index to each element
.chain(other)iter_chain(seq, other)Concatenate two sequences
.chunk(n)iter_chunk(seq, n)Split into n-sized groups
.unique()iter_unique(seq)Remove duplicates
Order.sorted()iter_sorted(seq)Sort ascending
.sorted_by(|x| key)iter_sorted_by(seq, fn)Sort by key function
.reversed()iter_reversed(seq)Reverse order

12. Automatic JIT Optimization

The MathViz compiler automatically injects Numba @njit(cache=True) decorators on functions that are eligible for JIT compilation. This happens transparently -- you write plain MathViz code, and the compiler optimizes it.

Pure Numeric Functions Get @njit

// Pure numeric function - auto @njit
fn compute_sum(n: Int) -> Float {
    let total = 0.0
    for i in 0..n {
        total = total + sqrt(i * 1.0)
    }
    return total
}

// Math-heavy function - auto @njit
fn transcendental(x: Float) -> Float {
    return sin(x) * cos(x) + exp(-x) * log(x + 1)
}

// Has print() - still gets @njit
fn display_result(x: Float) {
    print(x)
}
import numpy as np
from numba import jit, njit, vectorize, prange
import numba

@njit(cache=True)
def compute_sum(n: int) -> float:
    total = 0.0
    for i in range(0, n):
        total = (total + np.sqrt((i * 1.0)))
    return total

@njit(cache=True)
def transcendental(x: float) -> float:
    return ((np.sin(x) * np.cos(x))
        + (np.exp((-x)) * np.log((x + 1))))

@njit(cache=True)
def display_result(x: float):
    print(x, end='')

JIT Eligibility Rules

ConditionJIT Applied?Explanation
Pure numeric (int, float, numpy)Yes - @njit(cache=True)No Python objects involved
Uses NumPy functions (sin, sqrt...)Yes - @njit(cache=True)NumPy is Numba-compatible
Uses print()Yes - @njit(cache=True)Numba supports basic print
Uses set operations (Unicode)NoRuntime helpers are pure Python
Uses string concatenationNoString ops not Numba-compatible
Scene methods (Manim)NoManim objects not Numba-compatible
Numba Import Always Present

When any function in a file uses numeric types, the compiler adds the full Numba import block (from numba import jit, njit, vectorize, prange) even if not all imports are used. This is by design for consistency.

13. Automatic Vectorization

When the compiler detects loop patterns operating on numeric arrays, it can auto-vectorize them using NumPy array operations. Combined with the @njit decorator, this enables SIMD-level parallelism through Numba's LLVM backend.

fn array_operations() {
    let a = zeros(10)
    let b = ones(10)
    let c = linspace(0, 1, 100)
    let d = arange(0, 10, 1)
    let e = eye(3)
    return a
}
@njit(cache=True)
def array_operations():
    a = np.zeros(10)
    b = np.ones(10)
    c = np.linspace(0, 1, 100)
    d = np.arange(0, 10, 1)
    e = np.eye(3)
    return a

Array operations combined with @njit are automatically compiled to optimized machine code. For explicit parallel loops, use the @parallel decorator with prange:

MathViz
@njit(parallel=true)
fn parallel_sum(arr: List[Float]) -> Float {
    let total = 0.0
    for i in prange(0, len(arr)) {
        total += arr[i]
    }
    return total
}

14. Constant Folding

The compiler evaluates constant expressions at compile time. Literal arithmetic, string concatenation, and boolean expressions with known values are pre-computed.

fn constant_folding_demo() {
    let a = 2 + 3          // Constant arithmetic
    let b = 10 * 4         // Constant multiplication
    let c = "hello" + " world"  // String concat
    let d = true and false // Boolean logic
    let e = 2^10           // Power expression
    return a + b
}
def constant_folding_demo():
    a = (2 + 3)
    b = (10 * 4)
    c = ('hello' + ' world')
    d = (True and False)
    e = (2 ** 10)
    return (a + b)
Note on String Operations

Functions containing string operations (like "hello" + " world") do not receive @njit because Numba does not support Python string concatenation. The compiler detects this and omits the decorator.

15. Algebraic Simplification

The compiler performs algebraic identity simplifications. Expressions involving identity elements (multiply by 1, add 0, power of 1) can be optimized.

fn algebraic_simplification(x: Float) {
    let a = x * 1      // Identity multiplication
    let b = x + 0      // Identity addition
    let c = x * 0      // Zero multiplication
    let d = x^1        // Identity power
    return a + b + c + d
}
@njit(cache=True)
def algebraic_simplification(x: float):
    a = (x * 1)
    b = (x + 0)
    c = (x * 0)
    d = (x ** 1)
    return (((a + b) + c) + d)

The current compiler preserves algebraic identities in the output for debugging clarity. Python and Numba handle these optimizations at runtime via their own constant-folding passes. Future compiler versions may inline these simplifications directly.

16. Mathematical Constants

MathViz provides built-in mathematical constants that compile to their numeric values or NumPy equivalents.

MathViz ConstantUnicode AltCompiled PythonValue
PIπ3.141592653589793Ratio of circumference to diameter
E-2.718281828459045Euler's number
TAU-6.2831853071795862 * PI
PHI-1.618033988749895Golden ratio
INFfloat('inf')Positive infinity
NAN-float('nan')Not a number
MathViz
// Using Unicode constant
let pi_val = π         // Compiles to: 3.141592653589793
let inf_val = ∞        // Compiles to: float('inf')

// Using named constants
let area = PI * radius^2
let circumference = TAU * radius

17. Decorators

While the compiler automatically injects @njit where appropriate, you can also use explicit decorators for fine-grained control.

MathViz
// Explicit JIT with options
@jit
fn compute(arr: List[Float]) -> Float {
    let total = 0.0
    for x in arr {
        total += x * x
    }
    return total
}

// No-Python-mode JIT with parallelism
@njit(parallel=true)
fn parallel_sum(arr: List[Float]) -> Float {
    let total = 0.0
    for i in prange(0, len(arr)) {
        total += arr[i]
    }
    return total
}

// Vectorize for element-wise ufuncs
@vectorize
fn add_one(x: Float) -> Float {
    return x + 1.0
}
DecoratorPurposeWhen to Use
@jitGeneral JIT compilationFunctions that may fall back to Python
@njitNo-Python-mode JITPure numeric functions (fastest)
@njit(cache=True)Cached JITAutomatic -- compiler default
@njit(parallel=true)Parallel JITLoop-heavy functions with prange
@vectorizeNumPy ufunc creationElement-wise array operations

18. Error Handling

MathViz supports Rust-inspired error handling with Result and Optional types, plus try/catch blocks.

Result Type

MathViz
fn divide(a: Float, b: Float) -> Result[Float, String] {
    if b == 0.0 {
        return Err("Division by zero")
    }
    return Ok(a / b)
}

// Using match with Result
let result = divide(10.0, 2.0)
match result {
    Ok(value) -> print(value)
    Err(msg) -> print(msg)
}

// Error propagation with ?
fn compute() -> Result[Float, String] {
    let x = divide(10.0, 2.0)?
    let y = divide(x, 3.0)?
    return Ok(y)
}

Optional Type

MathViz
let maybe_value: Optional[Int] = Some(42)
let nothing: Optional[Int] = None

// Pattern match on Optional
match maybe_value {
    Some(v) -> print(v)
    None -> print("No value")
}

19. Structs & Traits

Struct Definition

MathViz
struct Point {
    x: Float
    y: Float
}

impl Point {
    fn new(x: Float, y: Float) -> Point {
        return Point { x: x, y: y }
    }

    fn distance(self, other: Point) -> Float {
        let dx = self.x - other.x
        let dy = self.y - other.y
        return sqrt(dx*dx + dy*dy)
    }
}

// Usage
let p1 = Point.new(0.0, 0.0)
let p2 = Point.new(3.0, 4.0)
let d = p1.distance(p2)  // 5.0

Traits

MathViz
trait Shape {
    fn area(self) -> Float
    fn perimeter(self) -> Float
}

struct Circle {
    radius: Float
}

impl Shape for Circle {
    fn area(self) -> Float {
        return PI * self.radius ^ 2
    }

    fn perimeter(self) -> Float {
        return 2.0 * PI * self.radius
    }
}

20. Enums

MathViz
enum Color {
    Red
    Green
    Blue
    RGB(Int, Int, Int)
}

enum Shape {
    Circle(Float)           // radius
    Rectangle(Float, Float) // width, height
    Point
}

let c = Color::RGB(255, 128, 0)
let s = Shape::Circle(5.0)

// Pattern matching with enums
fn area(shape: Shape) -> Float {
    match shape {
        Shape::Circle(r) -> PI * r ^ 2
        Shape::Rectangle(w, h) -> w * h
        Shape::Point -> 0.0
    }
}

Navigation

Previous

Getting Started - Installation and first program

Next

Module System - Organizing and reusing code

Related

Scenes & Manim - Animation integration

Examples

Tutorials - Step-by-step walkthrough