-module(viva_tensor@core@ffi). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/viva_tensor/core/ffi.gleam"). -export([abs/1, list_to_array/1, array_get/2, array_size/1, array_to_list/1, array_dot/2, array_matmul/5, array_sum/1, array_scale/2, sqrt/1, log/1, exp/1, cos/1, sin/1, tan/1, tanh/1, pow/2, random_uniform/0, is_nif_loaded/0, nif_backend_info/0, nif_matmul/5, nif_dot/2, nif_sum/1, nif_scale/2, now_microseconds/0, nt_zeros/1, nt_ones/1, nt_fill/2, nt_from_list/2, nt_to_list/1, nt_shape/1, nt_size/1, nt_add/2, nt_sub/2, nt_mul/2, nt_scale/2, nt_negate/1, nt_dot/2, nt_sum/1, nt_max/1, nt_min/1, nt_matmul/5, nt_transpose/1, nt_relu/1, nt_sigmoid/1, nt_exp/1, nt_log/1, nt_add_mut/2, nt_scale_mut/2, nt_negate_mut/1, nt_relu_mut/1, nt_saturn_blend/3, nt_fused_linear_relu/6, nt_resonance_mul/2, nt_resonance_power/2, zig_is_loaded/0, zig_backend_info/0, zig_dot/2, zig_sum/1, zig_scale/2, zig_add/2, zig_mul/2, zig_matmul/5, lns_from_f64/1, lns_to_f64/1, lns_mul/2, lns_mul_corrected/2, lns_div/2, lns_sqrt/1, lns_rsqrt/1, horde_create/2, horde_set_positions/2, horde_set_velocities/2, horde_integrate/2, horde_dampen/2, horde_wrap/2, horde_get_positions/1, horde_get_velocities/1, horde_count/1, horde_kinetic_energy/1, hdc_create/1, hdc_random/2, hdc_bind/2, hdc_similarity/2, hdc_permute/2, hdc_dim/1, nt_matmul_nf4/7, ct_from_list/2, ct_to_list/1, ct_shape/1, ct_matmul/5, ct16_available/0, ct16_from_list/2, ct16_to_list/1, ct16_shape/1, ct16_matmul/5, ct_int8_available/0, ct_int8_from_list/2, ct_int8_to_list/1, ct_int8_shape/1, ct_int8_matmul/5, sparse_available/0, sparse_from_ct16/1, sparse_shape/1, sparse_compression_ratio/1, sparse_matmul/5]). -export_type([erlang_array/0, native_tensor_ref/0, lns_tensor_ref/0, horde_ref/0, hdc_vector_ref/0, cuda_tensor_ref/0, cuda_tensor16_ref/0, cuda_int8_tensor_ref/0, sparse_tensor_ref/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " FFI - Foreign Function Interface to Erlang\n" "\n" " The escape hatch from pure functional bliss into the world of\n" " mutable arrays and hardware-specific optimizations.\n" "\n" " Why we need this:\n" " 1. Erlang lists are O(n) for random access. That's death for matrix ops.\n" " 2. Erlang's :array gives us O(1) access (technically O(log32 n), close enough).\n" " 3. Native NIFs unlock SIMD, BLAS, and GPU backends.\n" "\n" " ## Performance Hierarchy (fastest to slowest)\n" "\n" " 1. Zig SIMD NIF: Hand-tuned SIMD for the hot paths. 10-100x vs pure Gleam.\n" " 2. Apple Accelerate NIF: cblas_dgemm on macOS. Ridiculously optimized.\n" " 3. Erlang :array: O(1) access, pure Erlang. 10-50x vs lists for matmul.\n" " 4. Pure Gleam lists: Beautiful, correct, slow. Fine for small tensors.\n" "\n" " ## Architecture\n" "\n" " We have three acceleration backends that we auto-select from:\n" " - viva_tensor_zig: Portable SIMD via Zig. Works everywhere Zig compiles.\n" " - viva_tensor_nif: Apple Accelerate on macOS (cblas, vDSP).\n" " - viva_tensor_ffi: Pure Erlang fallback. Always works, just slower.\n" "\n" " The ops module auto-selects the best available backend at runtime.\n" ). -type erlang_array() :: any(). -type native_tensor_ref() :: any(). -type lns_tensor_ref() :: any(). -type horde_ref() :: any(). -type hdc_vector_ref() :: any(). -type cuda_tensor_ref() :: any(). -type cuda_tensor16_ref() :: any(). -type cuda_int8_tensor_ref() :: any(). -type sparse_tensor_ref() :: any(). -file("src/viva_tensor/core/ffi.gleam", 243). ?DOC( " Absolute value.\n" "\n" " Implemented in pure Gleam because :math.abs/1 doesn't exist\n" " and erlang:abs/1 is polymorphic (returns same type as input).\n" ). -spec abs(float()) -> float(). abs(X) -> case X < +0.0 of true -> +0.0 - X; false -> X end. -file("src/viva_tensor/core/ffi.gleam", 56). ?DOC( " Convert list to Erlang array for O(1) access.\n" "\n" " O(n) to build, but subsequent access is O(1).\n" " Worth it for any tensor you'll index more than once.\n" ). -spec list_to_array(list(float())) -> erlang_array(). list_to_array(Lst) -> viva_tensor_ffi:list_to_array(Lst). -file("src/viva_tensor/core/ffi.gleam", 65). ?DOC( " Get element from array at index - O(1).\n" "\n" " Contrast with list indexing: O(n).\n" " For a 1000-element matmul (1000 iterations, each indexing both inputs),\n" " that's 2M list traversals vs 2K array lookups. Huge difference.\n" ). -spec array_get(erlang_array(), integer()) -> float(). array_get(Arr, Index) -> viva_tensor_ffi:array_get(Arr, Index). -file("src/viva_tensor/core/ffi.gleam", 70). ?DOC(" Get array size - O(1).\n"). -spec array_size(erlang_array()) -> integer(). array_size(Arr) -> viva_tensor_ffi:array_size(Arr). -file("src/viva_tensor/core/ffi.gleam", 78). ?DOC( " Convert array back to list - O(n).\n" "\n" " Use this for final output or when you need list operations.\n" " Try to stay in array-land as long as possible for hot paths.\n" ). -spec array_to_list(erlang_array()) -> list(float()). array_to_list(Arr) -> viva_tensor_ffi:array_to_list(Arr). -file("src/viva_tensor/core/ffi.gleam", 92). ?DOC( " Dot product using Erlang arrays.\n" "\n" " Performance: ~10-50x faster than list-based for large vectors.\n" " The speedup comes entirely from O(1) vs O(n) element access.\n" ). -spec array_dot(erlang_array(), erlang_array()) -> float(). array_dot(A, B) -> viva_tensor_ffi:array_dot(A, B). -file("src/viva_tensor/core/ffi.gleam", 105). ?DOC( " Matrix multiplication using Erlang arrays.\n" "\n" " C[m,n] = A[m,k] @ B[k,n]\n" "\n" " Naive O(mnk) algorithm but with O(1) element access.\n" " For 100x100 matrices: ~50x faster than list-based.\n" "\n" " For serious work, use the Zig SIMD or Accelerate NIF backends.\n" " This is the reliable fallback that works everywhere.\n" ). -spec array_matmul( erlang_array(), erlang_array(), integer(), integer(), integer() ) -> erlang_array(). array_matmul(A, B, M, N, K) -> viva_tensor_ffi:array_matmul(A, B, M, N, K). -file("src/viva_tensor/core/ffi.gleam", 116). ?DOC(" Sum all elements - O(n).\n"). -spec array_sum(erlang_array()) -> float(). array_sum(Arr) -> viva_tensor_ffi:array_sum(Arr). -file("src/viva_tensor/core/ffi.gleam", 121). ?DOC(" Scale all elements by scalar - O(n).\n"). -spec array_scale(erlang_array(), float()) -> erlang_array(). array_scale(Arr, Scalar) -> viva_tensor_ffi:array_scale(Arr, Scalar). -file("src/viva_tensor/core/ffi.gleam", 191). ?DOC(" Square root - wraps :math.sqrt/1\n"). -spec sqrt(float()) -> float(). sqrt(X) -> math:sqrt(X). -file("src/viva_tensor/core/ffi.gleam", 199). ?DOC( " Natural logarithm - wraps :math.log/1\n" "\n" " Undefined for x <= 0. Erlang will return -inf for 0, NaN for negative.\n" " Caller's responsibility to check input.\n" ). -spec log(float()) -> float(). log(X) -> math:log(X). -file("src/viva_tensor/core/ffi.gleam", 207). ?DOC( " Exponential e^x - wraps :math.exp/1\n" "\n" " Watch for overflow: exp(710) = inf in Float64.\n" " For softmax, subtract max first: exp(x - max(x)).\n" ). -spec exp(float()) -> float(). exp(X) -> math:exp(X). -file("src/viva_tensor/core/ffi.gleam", 212). ?DOC(" Cosine - wraps :math.cos/1\n"). -spec cos(float()) -> float(). cos(X) -> math:cos(X). -file("src/viva_tensor/core/ffi.gleam", 217). ?DOC(" Sine - wraps :math.sin/1\n"). -spec sin(float()) -> float(). sin(X) -> math:sin(X). -file("src/viva_tensor/core/ffi.gleam", 222). ?DOC(" Tangent - wraps :math.tan/1\n"). -spec tan(float()) -> float(). tan(X) -> math:tan(X). -file("src/viva_tensor/core/ffi.gleam", 230). ?DOC( " Hyperbolic tangent - wraps :math.tanh/1\n" "\n" " Range: (-1, 1). Saturates for |x| > ~20.\n" " Used in some activation functions, though ReLU dominates now.\n" ). -spec tanh(float()) -> float(). tanh(X) -> math:tanh(X). -file("src/viva_tensor/core/ffi.gleam", 235). ?DOC(" Power x^y - wraps :math.pow/2\n"). -spec pow(float(), float()) -> float(). pow(X, Y) -> math:pow(X, Y). -file("src/viva_tensor/core/ffi.gleam", 261). ?DOC( " Uniform random float in [0, 1).\n" "\n" " Uses Erlang's per-process PRNG (Xoroshiro116+ by default).\n" " Not suitable for cryptography, but fine for ML initialization.\n" "\n" " For reproducible results, seed with :rand.seed(Algorithm, Seed).\n" ). -spec random_uniform() -> float(). random_uniform() -> rand:uniform(). -file("src/viva_tensor/core/ffi.gleam", 140). ?DOC( " Check if the Apple Accelerate NIF is loaded.\n" "\n" " Returns True on macOS with the NIF built, False elsewhere.\n" " Use this to decide whether to use nif_* functions or fall back.\n" ). -spec is_nif_loaded() -> boolean(). is_nif_loaded() -> viva_tensor_nif:is_nif_loaded(). -file("src/viva_tensor/core/ffi.gleam", 147). ?DOC( " Get backend info string for debugging.\n" "\n" " Returns something like \"Apple Accelerate (cblas_dgemm, vDSP)\" on macOS.\n" ). -spec nif_backend_info() -> binary(). nif_backend_info() -> viva_tensor_nif:backend_info(). -file("src/viva_tensor/core/ffi.gleam", 157). ?DOC( " NIF-accelerated matrix multiplication via cblas_dgemm.\n" "\n" " This is where the magic happens on macOS. Apple has spent years\n" " optimizing BLAS for their chips. We just call their code.\n" "\n" " Falls back to pure Erlang if NIF not available.\n" ). -spec nif_matmul(list(float()), list(float()), integer(), integer(), integer()) -> {ok, list(float())} | {error, binary()}. nif_matmul(A, B, M, N, K) -> viva_tensor_nif:matmul(A, B, M, N, K). -file("src/viva_tensor/core/ffi.gleam", 168). ?DOC(" NIF-accelerated dot product via vDSP.\n"). -spec nif_dot(list(float()), list(float())) -> {ok, float()} | {error, binary()}. nif_dot(A, B) -> viva_tensor_nif:dot(A, B). -file("src/viva_tensor/core/ffi.gleam", 173). ?DOC(" NIF-accelerated sum via vDSP.\n"). -spec nif_sum(list(float())) -> {ok, float()} | {error, binary()}. nif_sum(Data) -> viva_tensor_nif:sum(Data). -file("src/viva_tensor/core/ffi.gleam", 178). ?DOC(" NIF-accelerated scale via vDSP.\n"). -spec nif_scale(list(float()), float()) -> {ok, list(float())} | {error, binary()}. nif_scale(Data, Scalar) -> viva_tensor_nif:scale(Data, Scalar). -file("src/viva_tensor/core/ffi.gleam", 373). ?DOC( " Get current time in microseconds.\n" "\n" " Use for benchmarking: before/after difference gives wall-clock time.\n" " For production profiling, use Erlang's :fprof or :eprof instead.\n" ). -spec now_microseconds() -> integer(). now_microseconds() -> viva_tensor_ffi:now_microseconds(). -file("src/viva_tensor/core/ffi.gleam", 459). ?DOC(" Create native tensor of zeros\n"). -spec nt_zeros(list(integer())) -> {ok, native_tensor_ref()} | {error, binary()}. nt_zeros(Shape) -> viva_tensor_zig:nt_zeros(Shape). -file("src/viva_tensor/core/ffi.gleam", 464). ?DOC(" Create native tensor of ones\n"). -spec nt_ones(list(integer())) -> {ok, native_tensor_ref()} | {error, binary()}. nt_ones(Shape) -> viva_tensor_zig:nt_ones(Shape). -file("src/viva_tensor/core/ffi.gleam", 469). ?DOC(" Create native tensor filled with value\n"). -spec nt_fill(list(integer()), float()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_fill(Shape, Value) -> viva_tensor_zig:nt_fill(Shape, Value). -file("src/viva_tensor/core/ffi.gleam", 477). ?DOC(" Create native tensor from list data + shape\n"). -spec nt_from_list(list(float()), list(integer())) -> {ok, native_tensor_ref()} | {error, binary()}. nt_from_list(Data, Shape) -> viva_tensor_zig:nt_from_list(Data, Shape). -file("src/viva_tensor/core/ffi.gleam", 485). ?DOC(" Extract data as list (one-time conversion at boundaries)\n"). -spec nt_to_list(native_tensor_ref()) -> {ok, list(float())} | {error, binary()}. nt_to_list(Ref) -> viva_tensor_zig:nt_to_list(Ref). -file("src/viva_tensor/core/ffi.gleam", 490). ?DOC(" Get shape from native tensor\n"). -spec nt_shape(native_tensor_ref()) -> {ok, list(integer())} | {error, binary()}. nt_shape(Ref) -> viva_tensor_zig:nt_shape(Ref). -file("src/viva_tensor/core/ffi.gleam", 495). ?DOC(" Get total element count\n"). -spec nt_size(native_tensor_ref()) -> {ok, integer()} | {error, binary()}. nt_size(Ref) -> viva_tensor_zig:nt_size(Ref). -file("src/viva_tensor/core/ffi.gleam", 500). ?DOC(" Native add: ref + ref → ref (zero copy)\n"). -spec nt_add(native_tensor_ref(), native_tensor_ref()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_add(A, B) -> viva_tensor_zig:nt_add(A, B). -file("src/viva_tensor/core/ffi.gleam", 508). ?DOC(" Native sub: ref - ref → ref\n"). -spec nt_sub(native_tensor_ref(), native_tensor_ref()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_sub(A, B) -> viva_tensor_zig:nt_sub(A, B). -file("src/viva_tensor/core/ffi.gleam", 516). ?DOC(" Native element-wise mul: ref * ref → ref\n"). -spec nt_mul(native_tensor_ref(), native_tensor_ref()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_mul(A, B) -> viva_tensor_zig:nt_mul(A, B). -file("src/viva_tensor/core/ffi.gleam", 524). ?DOC(" Native scale: ref * scalar → ref\n"). -spec nt_scale(native_tensor_ref(), float()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_scale(A, Scalar) -> viva_tensor_zig:nt_scale(A, Scalar). -file("src/viva_tensor/core/ffi.gleam", 532). ?DOC(" Native negate: -ref → ref\n"). -spec nt_negate(native_tensor_ref()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_negate(A) -> viva_tensor_zig:nt_negate(A). -file("src/viva_tensor/core/ffi.gleam", 537). ?DOC(" Native dot product: ref · ref → scalar\n"). -spec nt_dot(native_tensor_ref(), native_tensor_ref()) -> {ok, float()} | {error, binary()}. nt_dot(A, B) -> viva_tensor_zig:nt_dot(A, B). -file("src/viva_tensor/core/ffi.gleam", 542). ?DOC(" Native sum reduction → scalar\n"). -spec nt_sum(native_tensor_ref()) -> {ok, float()} | {error, binary()}. nt_sum(A) -> viva_tensor_zig:nt_sum(A). -file("src/viva_tensor/core/ffi.gleam", 547). ?DOC(" Native max → scalar\n"). -spec nt_max(native_tensor_ref()) -> {ok, float()} | {error, binary()}. nt_max(A) -> viva_tensor_zig:nt_max(A). -file("src/viva_tensor/core/ffi.gleam", 552). ?DOC(" Native min → scalar\n"). -spec nt_min(native_tensor_ref()) -> {ok, float()} | {error, binary()}. nt_min(A) -> viva_tensor_zig:nt_min(A). -file("src/viva_tensor/core/ffi.gleam", 557). ?DOC(" Native matmul: [m,k] @ [k,n] → [m,n] in native memory\n"). -spec nt_matmul( native_tensor_ref(), native_tensor_ref(), integer(), integer(), integer() ) -> {ok, native_tensor_ref()} | {error, binary()}. nt_matmul(A, B, M, N, K) -> viva_tensor_zig:nt_matmul(A, B, M, N, K). -file("src/viva_tensor/core/ffi.gleam", 568). ?DOC(" Native transpose: [m,n] → [n,m] contiguous copy\n"). -spec nt_transpose(native_tensor_ref()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_transpose(A) -> viva_tensor_zig:nt_transpose(A). -file("src/viva_tensor/core/ffi.gleam", 573). ?DOC(" Native ReLU activation\n"). -spec nt_relu(native_tensor_ref()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_relu(A) -> viva_tensor_zig:nt_relu(A). -file("src/viva_tensor/core/ffi.gleam", 578). ?DOC(" Native sigmoid activation\n"). -spec nt_sigmoid(native_tensor_ref()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_sigmoid(A) -> viva_tensor_zig:nt_sigmoid(A). -file("src/viva_tensor/core/ffi.gleam", 583). ?DOC(" Native exp\n"). -spec nt_exp(native_tensor_ref()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_exp(A) -> viva_tensor_zig:nt_exp(A). -file("src/viva_tensor/core/ffi.gleam", 588). ?DOC(" Native log\n"). -spec nt_log(native_tensor_ref()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_log(A) -> viva_tensor_zig:nt_log(A). -file("src/viva_tensor/core/ffi.gleam", 599). ?DOC(" In-place add: a += b. Returns ok. MUTATES a.\n"). -spec nt_add_mut(native_tensor_ref(), native_tensor_ref()) -> {ok, nil} | {error, binary()}. nt_add_mut(A, B) -> viva_tensor_zig:nt_add_mut(A, B). -file("src/viva_tensor/core/ffi.gleam", 604). ?DOC(" In-place scale: a *= scalar. Returns ok. MUTATES a.\n"). -spec nt_scale_mut(native_tensor_ref(), float()) -> {ok, nil} | {error, binary()}. nt_scale_mut(A, Scalar) -> viva_tensor_zig:nt_scale_mut(A, Scalar). -file("src/viva_tensor/core/ffi.gleam", 609). ?DOC(" In-place negate: a = -a. Returns ok. MUTATES a.\n"). -spec nt_negate_mut(native_tensor_ref()) -> {ok, nil} | {error, binary()}. nt_negate_mut(A) -> viva_tensor_zig:nt_negate_mut(A). -file("src/viva_tensor/core/ffi.gleam", 614). ?DOC(" In-place ReLU: a = max(0, a). Returns ok. MUTATES a.\n"). -spec nt_relu_mut(native_tensor_ref()) -> {ok, nil} | {error, binary()}. nt_relu_mut(A) -> viva_tensor_zig:nt_relu_mut(A). -file("src/viva_tensor/core/ffi.gleam", 622). ?DOC( " Saturn Blend: result = texture + (shade - bias)\n" " VDP1-inspired lighting with pure SIMD addition.\n" ). -spec nt_saturn_blend(native_tensor_ref(), native_tensor_ref(), float()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_saturn_blend(Texture, Shade, Bias) -> viva_tensor_zig:nt_saturn_blend(Texture, Shade, Bias). -file("src/viva_tensor/core/ffi.gleam", 632). ?DOC( " Fused MatMul + Bias + ReLU: C = max(0, A@B + bias)\n" " Single pass, saves 2 full tensor traversals.\n" ). -spec nt_fused_linear_relu( native_tensor_ref(), native_tensor_ref(), native_tensor_ref(), integer(), integer(), integer() ) -> {ok, native_tensor_ref()} | {error, binary()}. nt_fused_linear_relu(A, B, Bias, M, N, K) -> viva_tensor_zig:nt_fused_linear_relu(A, B, Bias, M, N, K). -file("src/viva_tensor/core/ffi.gleam", 646). ?DOC( " Resonance Multiply: LNS element-wise multiply.\n" " result[i] = sign * exp(log|a[i]| + log|b[i]|)\n" " Multiplication via addition in log domain — better precision for chains.\n" ). -spec nt_resonance_mul(native_tensor_ref(), native_tensor_ref()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_resonance_mul(A, B) -> viva_tensor_zig:nt_resonance_mul(A, B). -file("src/viva_tensor/core/ffi.gleam", 656). ?DOC( " Resonance Power: LNS element-wise power.\n" " result[i] = sign(x) * |x|^exponent via exp(exponent * log|x|)\n" " Power = multiply in log domain. Sign preserved for bipolar states.\n" ). -spec nt_resonance_power(native_tensor_ref(), float()) -> {ok, native_tensor_ref()} | {error, binary()}. nt_resonance_power(Data, Exponent) -> viva_tensor_zig:nt_resonance_power(Data, Exponent). -file("src/viva_tensor/core/ffi.gleam", 395). ?DOC(" Check if Zig SIMD NIF is loaded.\n"). -spec zig_is_loaded() -> boolean(). zig_is_loaded() -> viva_tensor_zig:is_loaded(). -file("src/viva_tensor/core/ffi.gleam", 402). ?DOC( " Get Zig backend info for debugging.\n" "\n" " Returns SIMD capability info: \"Zig SIMD (AVX2)\" or \"Zig SIMD (NEON)\" etc.\n" ). -spec zig_backend_info() -> binary(). zig_backend_info() -> viva_tensor_zig:backend_info(). -file("src/viva_tensor/core/ffi.gleam", 410). ?DOC( " Zig SIMD dot product.\n" "\n" " Uses 4-way or 8-way SIMD depending on platform.\n" " Unrolled loop with accumulator to maximize throughput.\n" ). -spec zig_dot(list(float()), list(float())) -> {ok, float()} | {error, binary()}. zig_dot(A, B) -> viva_tensor_zig:simd_dot(A, B). -file("src/viva_tensor/core/ffi.gleam", 415). ?DOC(" Zig SIMD sum reduction.\n"). -spec zig_sum(list(float())) -> {ok, float()} | {error, binary()}. zig_sum(Data) -> viva_tensor_zig:simd_sum(Data). -file("src/viva_tensor/core/ffi.gleam", 420). ?DOC(" Zig SIMD scale (multiply all elements by scalar).\n"). -spec zig_scale(list(float()), float()) -> {ok, list(float())} | {error, binary()}. zig_scale(Data, Scalar) -> viva_tensor_zig:simd_scale(Data, Scalar). -file("src/viva_tensor/core/ffi.gleam", 428). ?DOC(" Zig SIMD element-wise add.\n"). -spec zig_add(list(float()), list(float())) -> {ok, list(float())} | {error, binary()}. zig_add(A, B) -> viva_tensor_zig:simd_add(A, B). -file("src/viva_tensor/core/ffi.gleam", 433). ?DOC(" Zig SIMD element-wise multiply.\n"). -spec zig_mul(list(float()), list(float())) -> {ok, list(float())} | {error, binary()}. zig_mul(A, B) -> viva_tensor_zig:simd_mul(A, B). -file("src/viva_tensor/core/ffi.gleam", 441). ?DOC( " Zig SIMD matrix multiplication.\n" "\n" " Tiled implementation with SIMD inner loops.\n" " Not quite BLAS-level but respectable: ~10-50 GFLOPS depending on platform.\n" ). -spec zig_matmul(list(float()), list(float()), integer(), integer(), integer()) -> {ok, list(float())} | {error, binary()}. zig_matmul(A, B, M, N, K) -> viva_tensor_zig:simd_matmul(A, B, M, N, K). -file("src/viva_tensor/core/ffi.gleam", 850). ?DOC(" Convert f64 NativeTensor to f32 LNS tensor\n"). -spec lns_from_f64(native_tensor_ref()) -> {ok, lns_tensor_ref()} | {error, binary()}. lns_from_f64(Ref) -> viva_tensor_zig:lns_from_f64(Ref). -file("src/viva_tensor/core/ffi.gleam", 855). ?DOC(" Convert LNS tensor back to f64 NativeTensor\n"). -spec lns_to_f64(lns_tensor_ref()) -> {ok, native_tensor_ref()} | {error, binary()}. lns_to_f64(Ref) -> viva_tensor_zig:lns_to_f64(Ref). -file("src/viva_tensor/core/ffi.gleam", 860). ?DOC(" Fast LNS multiply via IADD (~11% max error, 8x throughput)\n"). -spec lns_mul(lns_tensor_ref(), lns_tensor_ref()) -> {ok, lns_tensor_ref()} | {error, binary()}. lns_mul(A, B) -> viva_tensor_zig:lns_mul(A, B). -file("src/viva_tensor/core/ffi.gleam", 865). ?DOC(" Mitchell's corrected LNS multiply (~2% max error)\n"). -spec lns_mul_corrected(lns_tensor_ref(), lns_tensor_ref()) -> {ok, lns_tensor_ref()} | {error, binary()}. lns_mul_corrected(A, B) -> viva_tensor_zig:lns_mul_corrected(A, B). -file("src/viva_tensor/core/ffi.gleam", 873). ?DOC(" LNS division via ISUB\n"). -spec lns_div(lns_tensor_ref(), lns_tensor_ref()) -> {ok, lns_tensor_ref()} | {error, binary()}. lns_div(A, B) -> viva_tensor_zig:lns_div(A, B). -file("src/viva_tensor/core/ffi.gleam", 878). ?DOC(" LNS sqrt via bit shift\n"). -spec lns_sqrt(lns_tensor_ref()) -> {ok, lns_tensor_ref()} | {error, binary()}. lns_sqrt(A) -> viva_tensor_zig:lns_sqrt(A). -file("src/viva_tensor/core/ffi.gleam", 883). ?DOC(" Fast inverse sqrt (Quake III trick)\n"). -spec lns_rsqrt(lns_tensor_ref()) -> {ok, lns_tensor_ref()} | {error, binary()}. lns_rsqrt(A) -> viva_tensor_zig:lns_rsqrt(A). -file("src/viva_tensor/core/ffi.gleam", 926). ?DOC(" Create new Horde with entity count and dimensionality (1, 2, or 3)\n"). -spec horde_create(integer(), integer()) -> {ok, horde_ref()} | {error, binary()}. horde_create(Entity_count, Dims) -> viva_tensor_zig:horde_create(Entity_count, Dims). -file("src/viva_tensor/core/ffi.gleam", 931). ?DOC(" Set all positions from flat list [x0, y0, x1, y1, ...] for 2D\n"). -spec horde_set_positions(horde_ref(), list(float())) -> {ok, nil} | {error, binary()}. horde_set_positions(Horde, Data) -> viva_tensor_zig:horde_set_positions(Horde, Data). -file("src/viva_tensor/core/ffi.gleam", 939). ?DOC(" Set all velocities from flat list\n"). -spec horde_set_velocities(horde_ref(), list(float())) -> {ok, nil} | {error, binary()}. horde_set_velocities(Horde, Data) -> viva_tensor_zig:horde_set_velocities(Horde, Data). -file("src/viva_tensor/core/ffi.gleam", 947). ?DOC(" Euler integration step: positions += velocities * dt (FMA)\n"). -spec horde_integrate(horde_ref(), float()) -> {ok, nil} | {error, binary()}. horde_integrate(Horde, Dt) -> viva_tensor_zig:horde_integrate(Horde, Dt). -file("src/viva_tensor/core/ffi.gleam", 952). ?DOC(" Apply velocity damping: velocities *= friction\n"). -spec horde_dampen(horde_ref(), float()) -> {ok, nil} | {error, binary()}. horde_dampen(Horde, Friction) -> viva_tensor_zig:horde_dampen(Horde, Friction). -file("src/viva_tensor/core/ffi.gleam", 957). ?DOC(" Toroidal wrap: positions mod max_bound\n"). -spec horde_wrap(horde_ref(), float()) -> {ok, nil} | {error, binary()}. horde_wrap(Horde, Max_bound) -> viva_tensor_zig:horde_wrap(Horde, Max_bound). -file("src/viva_tensor/core/ffi.gleam", 962). ?DOC(" Get current positions as flat list\n"). -spec horde_get_positions(horde_ref()) -> {ok, list(float())} | {error, binary()}. horde_get_positions(Horde) -> viva_tensor_zig:horde_get_positions(Horde). -file("src/viva_tensor/core/ffi.gleam", 967). ?DOC(" Get current velocities as flat list\n"). -spec horde_get_velocities(horde_ref()) -> {ok, list(float())} | {error, binary()}. horde_get_velocities(Horde) -> viva_tensor_zig:horde_get_velocities(Horde). -file("src/viva_tensor/core/ffi.gleam", 972). ?DOC(" Get entity count\n"). -spec horde_count(horde_ref()) -> {ok, integer()} | {error, binary()}. horde_count(Horde) -> viva_tensor_zig:horde_count(Horde). -file("src/viva_tensor/core/ffi.gleam", 977). ?DOC(" Compute total kinetic energy: 0.5 * sum(vel^2)\n"). -spec horde_kinetic_energy(horde_ref()) -> {ok, float()} | {error, binary()}. horde_kinetic_energy(Horde) -> viva_tensor_zig:horde_kinetic_energy(Horde). -file("src/viva_tensor/core/ffi.gleam", 1039). ?DOC(" Create empty hypervector (dim must be multiple of 64)\n"). -spec hdc_create(integer()) -> {ok, hdc_vector_ref()} | {error, binary()}. hdc_create(Dim) -> viva_tensor_zig:hdc_create(Dim). -file("src/viva_tensor/core/ffi.gleam", 1044). ?DOC(" Create random hypervector (seed for reproducibility)\n"). -spec hdc_random(integer(), integer()) -> {ok, hdc_vector_ref()} | {error, binary()}. hdc_random(Dim, Seed) -> viva_tensor_zig:hdc_random(Dim, Seed). -file("src/viva_tensor/core/ffi.gleam", 1049). ?DOC(" XOR binding: associates two concepts (invertible: A XOR B XOR B = A)\n"). -spec hdc_bind(hdc_vector_ref(), hdc_vector_ref()) -> {ok, hdc_vector_ref()} | {error, binary()}. hdc_bind(A, B) -> viva_tensor_zig:hdc_bind(A, B). -file("src/viva_tensor/core/ffi.gleam", 1058). ?DOC( " Cosine-like similarity via Hamming distance [0, 1]\n" " 1 = identical, 0.5 = orthogonal (random), 0 = opposite\n" ). -spec hdc_similarity(hdc_vector_ref(), hdc_vector_ref()) -> {ok, float()} | {error, binary()}. hdc_similarity(A, B) -> viva_tensor_zig:hdc_similarity(A, B). -file("src/viva_tensor/core/ffi.gleam", 1064). ?DOC( " Circular permutation for sequence encoding\n" " encode(ABC) = A XOR perm(B,1) XOR perm(C,2)\n" ). -spec hdc_permute(hdc_vector_ref(), integer()) -> {ok, hdc_vector_ref()} | {error, binary()}. hdc_permute(Vec, Shift) -> viva_tensor_zig:hdc_permute(Vec, Shift). -file("src/viva_tensor/core/ffi.gleam", 1072). ?DOC(" Get dimensionality (total bits)\n"). -spec hdc_dim(hdc_vector_ref()) -> {ok, integer()} | {error, binary()}. hdc_dim(Vec) -> viva_tensor_zig:hdc_dim(Vec). -file("src/viva_tensor/core/ffi.gleam", 1106). ?DOC(" Matrix multiplication with NF4 quantized weights\n"). -spec nt_matmul_nf4( native_tensor_ref(), list(integer()), list(float()), integer(), integer(), integer(), integer() ) -> {ok, native_tensor_ref()} | {error, binary()}. nt_matmul_nf4(A, B_indices, B_scales, M, N, K, Block_size) -> viva_tensor_zig:nt_matmul_nf4(A, B_indices, B_scales, M, N, K, Block_size). -file("src/viva_tensor/core/ffi.gleam", 1137). -spec ct_from_list(list(float()), list(integer())) -> {ok, cuda_tensor_ref()} | {error, binary()}. ct_from_list(Data, Shape) -> viva_tensor_zig:ct_from_list(Data, Shape). -file("src/viva_tensor/core/ffi.gleam", 1143). -spec ct_to_list(cuda_tensor_ref()) -> {ok, list(float())} | {error, binary()}. ct_to_list(Ref) -> viva_tensor_zig:ct_to_list(Ref). -file("src/viva_tensor/core/ffi.gleam", 1146). -spec ct_shape(cuda_tensor_ref()) -> {ok, list(integer())} | {error, binary()}. ct_shape(Ref) -> viva_tensor_zig:ct_shape(Ref). -file("src/viva_tensor/core/ffi.gleam", 1149). -spec ct_matmul( cuda_tensor_ref(), cuda_tensor_ref(), integer(), integer(), integer() ) -> {ok, cuda_tensor_ref()} | {error, binary()}. ct_matmul(A, B, M, N, K) -> viva_tensor_zig:ct_matmul(A, B, M, N, K). -file("src/viva_tensor/core/ffi.gleam", 1164). -spec ct16_available() -> boolean(). ct16_available() -> viva_tensor_zig:ct16_available(). -file("src/viva_tensor/core/ffi.gleam", 1167). -spec ct16_from_list(list(float()), list(integer())) -> {ok, cuda_tensor16_ref()} | {error, binary()}. ct16_from_list(Data, Shape) -> viva_tensor_zig:ct16_from_list(Data, Shape). -file("src/viva_tensor/core/ffi.gleam", 1173). -spec ct16_to_list(cuda_tensor16_ref()) -> {ok, list(float())} | {error, binary()}. ct16_to_list(Ref) -> viva_tensor_zig:ct16_to_list(Ref). -file("src/viva_tensor/core/ffi.gleam", 1176). -spec ct16_shape(cuda_tensor16_ref()) -> {ok, list(integer())} | {error, binary()}. ct16_shape(Ref) -> viva_tensor_zig:ct16_shape(Ref). -file("src/viva_tensor/core/ffi.gleam", 1179). -spec ct16_matmul( cuda_tensor16_ref(), cuda_tensor16_ref(), integer(), integer(), integer() ) -> {ok, cuda_tensor16_ref()} | {error, binary()}. ct16_matmul(A, B, M, N, K) -> viva_tensor_zig:ct16_matmul(A, B, M, N, K). -file("src/viva_tensor/core/ffi.gleam", 1194). -spec ct_int8_available() -> boolean(). ct_int8_available() -> viva_tensor_zig:ct_int8_available(). -file("src/viva_tensor/core/ffi.gleam", 1197). -spec ct_int8_from_list(list(float()), list(integer())) -> {ok, cuda_int8_tensor_ref()} | {error, binary()}. ct_int8_from_list(Data, Shape) -> viva_tensor_zig:ct_int8_from_list(Data, Shape). -file("src/viva_tensor/core/ffi.gleam", 1203). -spec ct_int8_to_list(cuda_int8_tensor_ref()) -> {ok, list(float())} | {error, binary()}. ct_int8_to_list(Ref) -> viva_tensor_zig:ct_int8_to_list(Ref). -file("src/viva_tensor/core/ffi.gleam", 1206). -spec ct_int8_shape(cuda_int8_tensor_ref()) -> {ok, list(integer())} | {error, binary()}. ct_int8_shape(Ref) -> viva_tensor_zig:ct_int8_shape(Ref). -file("src/viva_tensor/core/ffi.gleam", 1209). -spec ct_int8_matmul( cuda_int8_tensor_ref(), cuda_int8_tensor_ref(), integer(), integer(), integer() ) -> {ok, cuda_int8_tensor_ref()} | {error, binary()}. ct_int8_matmul(A, B, M, N, K) -> viva_tensor_zig:ct_int8_matmul(A, B, M, N, K). -file("src/viva_tensor/core/ffi.gleam", 1224). -spec sparse_available() -> boolean(). sparse_available() -> viva_tensor_zig:sparse_available(). -file("src/viva_tensor/core/ffi.gleam", 1227). -spec sparse_from_ct16(cuda_tensor16_ref()) -> {ok, sparse_tensor_ref()} | {error, binary()}. sparse_from_ct16(Ref) -> viva_tensor_zig:sparse_from_ct16(Ref). -file("src/viva_tensor/core/ffi.gleam", 1230). -spec sparse_shape(sparse_tensor_ref()) -> {ok, list(integer())} | {error, binary()}. sparse_shape(Ref) -> viva_tensor_zig:sparse_shape(Ref). -file("src/viva_tensor/core/ffi.gleam", 1233). -spec sparse_compression_ratio(sparse_tensor_ref()) -> {ok, float()} | {error, binary()}. sparse_compression_ratio(Ref) -> viva_tensor_zig:sparse_compression_ratio(Ref). -file("src/viva_tensor/core/ffi.gleam", 1236). -spec sparse_matmul( sparse_tensor_ref(), cuda_tensor16_ref(), integer(), integer(), integer() ) -> {ok, cuda_tensor16_ref()} | {error, binary()}. sparse_matmul(A_sparse, B_dense, M, N, K) -> viva_tensor_zig:sparse_matmul(A_sparse, B_dense, M, N, K).