-module(viva_tensor@examples@backend). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/viva_tensor/examples/backend.gleam"). -export([main/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( " Backend Demo - Demonstrating pluggable backends\n" "\n" " Shows how to:\n" " 1. Auto-select the best available backend\n" " 2. Explicitly choose a specific backend\n" " 3. Compare performance across backends\n" "\n" " Execute: gleam run -m examples/backend_demo\n" ). -file("src/viva_tensor/examples/backend.gleam", 208). -spec benchmark_backend( viva_tensor@backend@protocol:backend(), list(float()), list(float()), integer(), integer(), integer() ) -> {float(), boolean()}. benchmark_backend(B, A, B_data, M, N, K) -> Start = viva_tensor@core@ffi:now_microseconds(), Result = viva_tensor@backend@protocol:matmul(B, A, B_data, M, N, K), End = viva_tensor@core@ffi:now_microseconds(), Time = erlang:float(End - Start) / 1000.0, {Time, gleam@result:is_ok(Result)}. -file("src/viva_tensor/examples/backend.gleam", 244). -spec random_floats(integer()) -> list(float()). random_floats(N) -> _pipe = gleam@list:range(0, N - 1), gleam@list:map(_pipe, fun(_) -> viva_tensor@core@ffi:random_uniform() end). -file("src/viva_tensor/examples/backend.gleam", 261). -spec float_to_str(float()) -> binary(). float_to_str(F) -> Rounded = begin _pipe = erlang:round(F * 100.0), erlang:float(_pipe) end, Result = Rounded / 100.0, gleam_stdlib:float_to_string(Result). -file("src/viva_tensor/examples/backend.gleam", 249). -spec format_time(float()) -> binary(). format_time(Ms) -> case Ms < 1.0 of true -> <<(float_to_str(Ms * 1000.0))/binary, " μs"/utf8>>; false -> case Ms < 1000.0 of true -> <<(float_to_str(Ms))/binary, " ms"/utf8>>; false -> <<(float_to_str(Ms / 1000.0))/binary, " s"/utf8>> end end. -file("src/viva_tensor/examples/backend.gleam", 276). -spec repeat_string(binary(), integer()) -> binary(). repeat_string(S, N) -> case N =< 0 of true -> <<""/utf8>>; false -> <> end. -file("src/viva_tensor/examples/backend.gleam", 267). -spec pad_right(binary(), integer()) -> binary(). pad_right(S, Width) -> Len = string:length(S), Padding = Width - Len, case Padding > 0 of true -> <>, Padding))/binary>>; false -> S end. -file("src/viva_tensor/examples/backend.gleam", 224). -spec print_backend_row(binary(), float(), boolean()) -> nil. print_backend_row(Name, Time, Ok) -> Time_str = case Time > +0.0 of true -> format_time(Time); false -> <<"N/A"/utf8>> end, Result_str = case Ok of true -> <<"✓ OK"/utf8>>; false -> <<"✗ Error/N/A"/utf8>> end, gleam_stdlib:println( <<<<<<<<<<<<" │ "/utf8, (pad_right(Name, 18))/binary>>/binary, " │ "/utf8>>/binary, (pad_right(Time_str, 12))/binary>>/binary, " │ "/utf8>>/binary, (pad_right(Result_str, 12))/binary>>/binary, " │"/utf8>> ). -file("src/viva_tensor/examples/backend.gleam", 22). -spec main() -> nil. main() -> gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println( <<"╔═══════════════════════════════════════════════════════════════════════════╗"/utf8>> ), gleam_stdlib:println( <<"║ viva_tensor - BACKEND PROTOCOL DEMO ║"/utf8>> ), gleam_stdlib:println( <<"║ Pluggable computation backends for BEAM ║"/utf8>> ), gleam_stdlib:println( <<"╚═══════════════════════════════════════════════════════════════════════════╝"/utf8>> ), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"━━━ AVAILABLE BACKENDS ━━━"/utf8>>), gleam_stdlib:println(<<""/utf8>>), Backends = [pure, accelerate, zig, {distributed, []}], gleam@list:each( Backends, fun(B) -> Status = case viva_tensor@backend@protocol:is_available(B) of true -> <<"✓ Available"/utf8>>; false -> <<"✗ Not available"/utf8>> end, gleam_stdlib:println( <<<<<<" "/utf8, (viva_tensor@backend@protocol:name(B))/binary>>/binary, ": "/utf8>>/binary, Status/binary>> ), case viva_tensor@backend@protocol:is_available(B) of true -> gleam_stdlib:println( <<" └─ "/utf8, (viva_tensor@backend@protocol:info(B))/binary>> ); false -> nil end end ), gleam_stdlib:println(<<""/utf8>>), Best = viva_tensor@backend@protocol:auto_select(), gleam_stdlib:println(<<"━━━ AUTO-SELECTED BACKEND ━━━"/utf8>>), gleam_stdlib:println( <<" Best available: "/utf8, (viva_tensor@backend@protocol:name(Best))/binary>> ), gleam_stdlib:println( <<" Info: "/utf8, (viva_tensor@backend@protocol:info(Best))/binary>> ), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"━━━ MATRIX MULTIPLICATION DEMO ━━━"/utf8>>), gleam_stdlib:println(<<""/utf8>>), M = 64, N = 64, K = 64, Size_str = <<<<<<<<<<<<(erlang:integer_to_binary(M))/binary, "x"/utf8>>/binary, (erlang:integer_to_binary(K))/binary>>/binary, " @ "/utf8>>/binary, (erlang:integer_to_binary(K))/binary>>/binary, "x"/utf8>>/binary, (erlang:integer_to_binary(N))/binary>>, gleam_stdlib:println(<<" Matrix size: "/utf8, Size_str/binary>>), gleam_stdlib:println(<<""/utf8>>), A = random_floats(M * K), B@1 = random_floats(K * N), gleam_stdlib:println( <<" ┌────────────────────┬──────────────┬──────────────┐"/utf8>> ), gleam_stdlib:println( <<" │ Backend │ Time │ Result │"/utf8>> ), gleam_stdlib:println( <<" ├────────────────────┼──────────────┼──────────────┤"/utf8>> ), {Pure_time, Pure_ok} = benchmark_backend(pure, A, B@1, M, N, K), print_backend_row(<<"Pure Erlang"/utf8>>, Pure_time, Pure_ok), case viva_tensor@backend@protocol:is_available(accelerate) of true -> {Acc_time, Acc_ok} = benchmark_backend(accelerate, A, B@1, M, N, K), print_backend_row(<<"Apple Accelerate"/utf8>>, Acc_time, Acc_ok); false -> print_backend_row(<<"Apple Accelerate"/utf8>>, +0.0, false) end, case viva_tensor@backend@protocol:is_available(zig) of true -> {Zig_time, Zig_ok} = benchmark_backend(zig, A, B@1, M, N, K), print_backend_row(<<"Zig SIMD"/utf8>>, Zig_time, Zig_ok); false -> print_backend_row(<<"Zig SIMD"/utf8>>, +0.0, false) end, gleam_stdlib:println( <<" └────────────────────┴──────────────┴──────────────┘"/utf8>> ), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"━━━ DOT PRODUCT DEMO ━━━"/utf8>>), gleam_stdlib:println(<<""/utf8>>), Vec_size = 10000, Vec_a = random_floats(Vec_size), Vec_b = random_floats(Vec_size), gleam_stdlib:println( <<" Vector size: "/utf8, (erlang:integer_to_binary(Vec_size))/binary>> ), gleam_stdlib:println(<<""/utf8>>), Dot_start = viva_tensor@core@ffi:now_microseconds(), Dot_result = viva_tensor@backend@protocol:dot(Best, Vec_a, Vec_b), Dot_end = viva_tensor@core@ffi:now_microseconds(), Dot_time = erlang:float(Dot_end - Dot_start) / 1000.0, case Dot_result of {ok, Value} -> gleam_stdlib:println( <<<<<<<<<<<<" Backend: "/utf8, (viva_tensor@backend@protocol:name(Best))/binary>>/binary, " → "/utf8>>/binary, (float_to_str(Value))/binary>>/binary, " ("/utf8>>/binary, (format_time(Dot_time))/binary>>/binary, ")"/utf8>> ); {error, _} -> gleam_stdlib:println(<<" Error computing dot product"/utf8>>) end, gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"━━━ REDUCTION OPERATIONS ━━━"/utf8>>), gleam_stdlib:println(<<""/utf8>>), Data = random_floats(100000), gleam_stdlib:println(<<" Data size: 100,000 elements"/utf8>>), gleam_stdlib:println(<<""/utf8>>), Sum_start = viva_tensor@core@ffi:now_microseconds(), Sum_result = viva_tensor@backend@protocol:sum(Best, Data), Sum_end = viva_tensor@core@ffi:now_microseconds(), Sum_time = erlang:float(Sum_end - Sum_start) / 1000.0, case Sum_result of {ok, Value@1} -> gleam_stdlib:println( <<<<<<<<" Sum: "/utf8, (float_to_str(Value@1))/binary>>/binary, " ("/utf8>>/binary, (format_time(Sum_time))/binary>>/binary, ")"/utf8>> ); {error, _} -> gleam_stdlib:println(<<" Error computing sum"/utf8>>) end, Scale_start = viva_tensor@core@ffi:now_microseconds(), Scale_result = viva_tensor@backend@protocol:scale( Best, gleam@list:take(Data, 1000), 2.0 ), Scale_end = viva_tensor@core@ffi:now_microseconds(), Scale_time = erlang:float(Scale_end - Scale_start) / 1000.0, case Scale_result of {ok, _} -> gleam_stdlib:println( <<" Scale (×2.0, 1000 elements): "/utf8, (format_time(Scale_time))/binary>> ); {error, _} -> gleam_stdlib:println(<<" Error computing scale"/utf8>>) end, gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println( <<"═══════════════════════════════════════════════════════════════════════════"/utf8>> ), gleam_stdlib:println(<<" DEMO COMPLETE!"/utf8>>), gleam_stdlib:println( <<"═══════════════════════════════════════════════════════════════════════════"/utf8>> ).