From 8e537c7d6490836734e2cf7b093cc3a449deff8f Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Thu, 27 Nov 2025 13:33:13 +0000 Subject: [PATCH 01/33] feat: add Rotations extension --- Project.toml | 9 ++++- .../SymbolicCompilerPassesRotationsExt.jl | 11 ++++++ .../rotations_opt.jl | 35 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 ext/SymbolicCompilerPassesRotationsExt/SymbolicCompilerPassesRotationsExt.jl create mode 100644 ext/SymbolicCompilerPassesRotationsExt/rotations_opt.jl diff --git a/Project.toml b/Project.toml index dd8c10d..78b14bb 100644 --- a/Project.toml +++ b/Project.toml @@ -9,11 +9,18 @@ PreallocationTools = "d236fae5-4411-538c-8e31-a6e3d9e00b46" SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b" [sources] -SymbolicUtils = {url = "https://github.com/DhairyaLGandhi/SymbolicUtils.jl", rev = "dg/opt_api"} +SymbolicUtils = {rev = "dg/opt_api", url = "https://github.com/DhairyaLGandhi/SymbolicUtils.jl"} + +[weakdeps] +Rotations = "6038ab10-8711-5258-84ad-4b1120ba62dc" + +[extensions] +SymbolicCompilerPassesRotationsExt = ["Rotations",] [compat] LinearAlgebra = "1.11.0" PreallocationTools = "0.4.34" +Rotations = "1.7.1" SymbolicUtils = "4.1.0" julia = "1.11" diff --git a/ext/SymbolicCompilerPassesRotationsExt/SymbolicCompilerPassesRotationsExt.jl b/ext/SymbolicCompilerPassesRotationsExt/SymbolicCompilerPassesRotationsExt.jl new file mode 100644 index 0000000..6a4543b --- /dev/null +++ b/ext/SymbolicCompilerPassesRotationsExt/SymbolicCompilerPassesRotationsExt.jl @@ -0,0 +1,11 @@ +module SymbolicCompilerPassesRotationsExt + +using SymbolicCompilerPasses +using SymbolicUtils +using Rotations +using LinearAlgebra + + +include("rotations_opt.jl") + +end \ No newline at end of file diff --git a/ext/SymbolicCompilerPassesRotationsExt/rotations_opt.jl b/ext/SymbolicCompilerPassesRotationsExt/rotations_opt.jl new file mode 100644 index 0000000..1017be7 --- /dev/null +++ b/ext/SymbolicCompilerPassesRotationsExt/rotations_opt.jl @@ -0,0 +1,35 @@ +is_orthogonal_matrix(A) = A * A' ≈ I(size(A, 1)) +is_orthogonal_type(::Rotations.Rotation) = true +is_orthogonal_type(x) = false + + +# ie = SU.Code.IfElse(SU.Const{SymReal}(true), SU.Code.Let([], nothing, false), SU.Code.Let([], nothing, false)) +# ie = SU.Code.IfElse(is_orthogonal, SU.Code.Let([], nothing, false), SU.Code.Let([], nothing, false)) +# toexpr(ie) + +function detect_orthogonal_matrix(expr, state::Code.CSEState) + orthogonal_candidates_idx = findall(expr.pairs) do x + r = rhs(x) + iscall(r) || return false + op = operation(r) + op === Symbol("is_orthogonal") || return false + + args = arguments(r) + length(args) == 1 || return false + + arg = args[1] + symtype(arg) <: AbstractMatrix || return false + + true + end + + orthogonal_candidates = expr.pairs[orthogonal_candidates_idx] + + matches = map(orthogonal_candidates_idx, orthogonal_candidates) do idx, candidate + A = arguments(rhs(candidate))[1] + (A, candidate, idx, "is_orthogonal(A)") + end + + f = filter(!isnothing, matches) + isempty(f) ? nothing : f +end \ No newline at end of file From 8da87ba9bf75ef15a6163177c54214735fcae901 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 1 Dec 2025 13:45:51 +0000 Subject: [PATCH 02/33] chore: working tree --- ext/SymbolicCompilerPassesRotationsExt/rotations_opt.jl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ext/SymbolicCompilerPassesRotationsExt/rotations_opt.jl b/ext/SymbolicCompilerPassesRotationsExt/rotations_opt.jl index 1017be7..1d67be7 100644 --- a/ext/SymbolicCompilerPassesRotationsExt/rotations_opt.jl +++ b/ext/SymbolicCompilerPassesRotationsExt/rotations_opt.jl @@ -3,10 +3,6 @@ is_orthogonal_type(::Rotations.Rotation) = true is_orthogonal_type(x) = false -# ie = SU.Code.IfElse(SU.Const{SymReal}(true), SU.Code.Let([], nothing, false), SU.Code.Let([], nothing, false)) -# ie = SU.Code.IfElse(is_orthogonal, SU.Code.Let([], nothing, false), SU.Code.Let([], nothing, false)) -# toexpr(ie) - function detect_orthogonal_matrix(expr, state::Code.CSEState) orthogonal_candidates_idx = findall(expr.pairs) do x r = rhs(x) @@ -32,4 +28,5 @@ function detect_orthogonal_matrix(expr, state::Code.CSEState) f = filter(!isnothing, matches) isempty(f) ? nothing : f -end \ No newline at end of file +end + From 97dd026ff152a3f0ca557502ba0c5646e0862b82 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Thu, 4 Dec 2025 16:20:31 +0000 Subject: [PATCH 03/33] feat: convert orthogonal matrices to transpose --- Project.toml | 2 +- .../SymbolicCompilerPassesRotationsExt.jl | 8 +- .../rotations_opt.jl | 32 ------ src/SymbolicCompilerPasses.jl | 5 +- src/ortho_inv_opt.jl | 102 ++++++++++++++++++ test/ortho_inv_opt.jl | 101 +++++++++++++++++ 6 files changed, 209 insertions(+), 41 deletions(-) delete mode 100644 ext/SymbolicCompilerPassesRotationsExt/rotations_opt.jl create mode 100644 src/ortho_inv_opt.jl create mode 100644 test/ortho_inv_opt.jl diff --git a/Project.toml b/Project.toml index 78b14bb..67a825c 100644 --- a/Project.toml +++ b/Project.toml @@ -18,7 +18,7 @@ Rotations = "6038ab10-8711-5258-84ad-4b1120ba62dc" SymbolicCompilerPassesRotationsExt = ["Rotations",] [compat] -LinearAlgebra = "1.11.0" +LinearAlgebra = "1.11.0, 1.10" PreallocationTools = "0.4.34" Rotations = "1.7.1" SymbolicUtils = "4.1.0" diff --git a/ext/SymbolicCompilerPassesRotationsExt/SymbolicCompilerPassesRotationsExt.jl b/ext/SymbolicCompilerPassesRotationsExt/SymbolicCompilerPassesRotationsExt.jl index 6a4543b..d9d4dac 100644 --- a/ext/SymbolicCompilerPassesRotationsExt/SymbolicCompilerPassesRotationsExt.jl +++ b/ext/SymbolicCompilerPassesRotationsExt/SymbolicCompilerPassesRotationsExt.jl @@ -1,11 +1,7 @@ module SymbolicCompilerPassesRotationsExt using SymbolicCompilerPasses -using SymbolicUtils -using Rotations -using LinearAlgebra - - -include("rotations_opt.jl") +import SymbolicCompilerPasses: is_orthogonal_type +is_orthogonal_type(::Rotations.Rotation) = true end \ No newline at end of file diff --git a/ext/SymbolicCompilerPassesRotationsExt/rotations_opt.jl b/ext/SymbolicCompilerPassesRotationsExt/rotations_opt.jl deleted file mode 100644 index 1d67be7..0000000 --- a/ext/SymbolicCompilerPassesRotationsExt/rotations_opt.jl +++ /dev/null @@ -1,32 +0,0 @@ -is_orthogonal_matrix(A) = A * A' ≈ I(size(A, 1)) -is_orthogonal_type(::Rotations.Rotation) = true -is_orthogonal_type(x) = false - - -function detect_orthogonal_matrix(expr, state::Code.CSEState) - orthogonal_candidates_idx = findall(expr.pairs) do x - r = rhs(x) - iscall(r) || return false - op = operation(r) - op === Symbol("is_orthogonal") || return false - - args = arguments(r) - length(args) == 1 || return false - - arg = args[1] - symtype(arg) <: AbstractMatrix || return false - - true - end - - orthogonal_candidates = expr.pairs[orthogonal_candidates_idx] - - matches = map(orthogonal_candidates_idx, orthogonal_candidates) do idx, candidate - A = arguments(rhs(candidate))[1] - (A, candidate, idx, "is_orthogonal(A)") - end - - f = filter(!isnothing, matches) - isempty(f) ? nothing : f -end - diff --git a/src/SymbolicCompilerPasses.jl b/src/SymbolicCompilerPasses.jl index 05eb4d6..85725be 100644 --- a/src/SymbolicCompilerPasses.jl +++ b/src/SymbolicCompilerPasses.jl @@ -3,9 +3,9 @@ module SymbolicCompilerPasses using LinearAlgebra using PreallocationTools using SymbolicUtils -import SymbolicUtils: symtype, vartype, Sym, BasicSymbolic, Term, iscall, operation, arguments, maketerm, Const +import SymbolicUtils: symtype, vartype, Sym, BasicSymbolic, Term, iscall, operation, arguments, maketerm, Const, search_variables!, search_variables, issym, iscall, isterm import SymbolicUtils.Code: Code, OptimizationRule, substitute_in_ir, apply_optimization_rules, AbstractMatched, - Assignment, CSEState, lhs, rhs, apply_substitution_map + Assignment, CSEState, lhs, rhs, apply_substitution_map, IfElse function bank(dic, key, value) if haskey(dic, key) @@ -16,5 +16,6 @@ function bank(dic, key, value) end include("matmuladd.jl") +include("ortho_inv_opt.jl") end # module SymbolicCompilerPasses diff --git a/src/ortho_inv_opt.jl b/src/ortho_inv_opt.jl new file mode 100644 index 0000000..d398e13 --- /dev/null +++ b/src/ortho_inv_opt.jl @@ -0,0 +1,102 @@ +is_orthogonal_matrix(A) = A * A' ≈ I(size(A, 1)) +# is_orthogonal_type(::Rotations.Rotation) = true +is_orthogonal_type(x) = begin + if issym(x) + return getmetadata(x, IsOrthogonal, false) + else + return false + end + false +end + +struct IsOrthogonal end + +struct InvMatched{T, C} <: AbstractMatched + A::T + candidate::C + idx::Int +end + +function detect_orthogonal_matrix(expr, state::Code.CSEState) + # var_to_ortho = Dict() + # ortho_to_var = Dict() + # for v in search_variables(expr) + # @show symtype(v) + # bank(var_to_ortho, v, getmetadata(v, IsOrthogonal, false)) + # bank(ortho_to_var, getmetadata(v, IsOrthogonal, false), v) + # end + + # if !haskey(ortho_to_var, true) + # @warn "not found any metadata arrays" + # return nothing + # end + + idxs = findall(expr.pairs) do p + r = rhs(p) + iscall(r) || return false + op = operation(r) + if op === inv + args = arguments(r) + length(args) == 1 || return false + return true + end + false + end + + candidates = expr.pairs[idxs] + + matches = map(idxs, candidates) do idx, candidate + A = arguments(rhs(candidate))[1] + InvMatched(A, candidate, idx) + end + + f = filter(!isnothing, matches) + isempty(f) ? nothing : f +end + +function transform_inv_optimization(expr, matches, state::Code.CSEState) + + expr_copy = deepcopy(expr) + map(matches) do match + A = match.A + if getmetadata(A, IsOrthogonal, false) == true + expr_copy.pairs[match.idx] = Code.Assignment( + lhs(match.candidate), + transpose(A) + ) + else + t = term(is_orthogonal_type, A) + @show t + + code = IfElse( + t, + transpose(A), + inv(A) + ) + expr_copy.pairs[match.idx] = Code.Assignment( + lhs(match.candidate), + code + ) + end + end + expr_copy +end + +const ORTHO_INV_RULE = OptimizationRule( + "Ortho_Inv", + detect_orthogonal_matrix, + transform_inv_optimization, + 10 +) + +function ortho_inv_opt(expr, state::Code.CSEState) + + # Try to apply optimization rules + optimized = apply_optimization_rules(expr, state, ORTHO_INV_RULE) + if optimized !== nothing + return optimized + end + + # If no optimization applied, return original expression + return expr +end \ No newline at end of file diff --git a/test/ortho_inv_opt.jl b/test/ortho_inv_opt.jl new file mode 100644 index 0000000..7408e9a --- /dev/null +++ b/test/ortho_inv_opt.jl @@ -0,0 +1,101 @@ +using Revise, BenchmarkTools + +using SymbolicUtils +using SymbolicUtils.Code +import SymbolicUtils as SU +import SymbolicCompilerPasses as SC +using Symbolics +# using ModelingToolkit +# using ModelingToolkit: t_nounits as t, D_nounits as D + +using LinearAlgebra +using Rotations +using Test + +function has_ortho_opt(expr::Code.Let) + return any(expr.pairs) do assignment + rhs_expr = Code.rhs(assignment) + if SU.iscall(rhs_expr) + # op = SU.operation(rhs_expr) + # return op === transpose || op === SC.is_orthogonal_type + return has_ortho_opt(rhs_expr) + elseif rhs_expr isa SU.Code.IfElse + return has_ortho_opt(rhs_expr.ifbody) || has_ortho_opt(rhs_expr.elsebody) + end + false + end +end + +function has_ortho_opt(expr) + if SU.iscall(expr) + op = SU.operation(expr) + return op === transpose || op === SC.is_orthogonal_type + end +end + +function check_ortho_opt(expr, A, B) + current = SU.Code.cse(expr) + toexpr(current) + + optimized = SC.ortho_inv_opt(current, SU.Code.CSEState()) + # return optimized + # return toexpr(optimized) + + @test has_ortho_opt(optimized) + + current_fun = Func([A, B], [], current) + optimized_fun = Func([A, B], [], optimized) + + current_f = eval(toexpr(current_fun)) + optimized_f = eval(toexpr(optimized_fun)) + + a = rand(3,3) + b = rand(3,3) + R_euler = RotMatrix{3, Float64}(rand(3, 3)) + + # res1 = invokelatest(current_f, a, b) + # res2 = invokelatest(optimized_f, a, b) + # @test isapprox(res1, res2, rtol=1e-10, atol=1e-10) + + res1 = invokelatest(current_f, R_euler, b) + res2 = invokelatest(optimized_f, R_euler, b) + @test isapprox(res1, res2, rtol=1e-10, atol=1e-10) +end + + +@testset "Orthogonal Matrices: inv -> transpose" begin + @syms A[1:3, 1:3] B[1:3, 1:3] C[1:3, 1:3] D[1:3, 1:3] E[1:3, 1:3] + Ao = SU.setmetadata(A, SC.IsOrthogonal, true) + + + expr = inv(Ao) * B + check_ortho_opt(expr, Ao, B) + + expr2 = inv(A) * B + c = check_ortho_opt(expr2, A, B) +end + + + + +a = rand(3,3) +b = rand(3,3) +# R_euler = RotXYZ(1,2,3) +R_euler = RotMatrix{3, Float64}(rand(3, 3)) +res1 = invokelatest(current2_f, a, b) +res2 = invokelatest(optimized2_f, a, b) + +res1 = invokelatest(current2_f, R_euler, b) +res2 = invokelatest(optimized2_f, R_euler, b) + +@btime $current2_f($R_euler, $b); +@btime $optimized2_f($R_euler, $b); + +@code_warntype optimized2_f(R_euler, b) + +# @variables mewx(t)[1:3, 1:3] mewy(t)[1:3, 1:3] mewz(t)[1:3, 1:3] +# @syms mewx[1:3, 1:3] mewy[1:3, 1:3] mewz(t)[1:3, 1:3] +# expr = mewx \ mewy +# SU.Code.cse(expr), SU.Code.CSEState() + +# SC.count_occurrences(mewx, SU.Code.cse(expr)) \ No newline at end of file From 46cd8393a3a4db0930274599e1427cf4a555c6f1 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 8 Dec 2025 07:12:39 +0000 Subject: [PATCH 04/33] test: check different inv calls --- src/ortho_inv_opt.jl | 1 - test/ortho_inv_opt.jl | 54 +++++++++++-------------------------------- 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/src/ortho_inv_opt.jl b/src/ortho_inv_opt.jl index d398e13..9207106 100644 --- a/src/ortho_inv_opt.jl +++ b/src/ortho_inv_opt.jl @@ -1,5 +1,4 @@ is_orthogonal_matrix(A) = A * A' ≈ I(size(A, 1)) -# is_orthogonal_type(::Rotations.Rotation) = true is_orthogonal_type(x) = begin if issym(x) return getmetadata(x, IsOrthogonal, false) diff --git a/test/ortho_inv_opt.jl b/test/ortho_inv_opt.jl index 7408e9a..fd7a3cc 100644 --- a/test/ortho_inv_opt.jl +++ b/test/ortho_inv_opt.jl @@ -5,8 +5,6 @@ using SymbolicUtils.Code import SymbolicUtils as SU import SymbolicCompilerPasses as SC using Symbolics -# using ModelingToolkit -# using ModelingToolkit: t_nounits as t, D_nounits as D using LinearAlgebra using Rotations @@ -15,22 +13,17 @@ using Test function has_ortho_opt(expr::Code.Let) return any(expr.pairs) do assignment rhs_expr = Code.rhs(assignment) - if SU.iscall(rhs_expr) - # op = SU.operation(rhs_expr) - # return op === transpose || op === SC.is_orthogonal_type - return has_ortho_opt(rhs_expr) - elseif rhs_expr isa SU.Code.IfElse - return has_ortho_opt(rhs_expr.ifbody) || has_ortho_opt(rhs_expr.elsebody) - end - false + has_ortho_opt(rhs_expr) end end +has_ortho_opt(expr::Code.IfElse) = has_ortho_opt(expr.ifbody) || has_ortho_opt(expr.elsebody) function has_ortho_opt(expr) - if SU.iscall(expr) + if SU.iscall(expr) op = SU.operation(expr) return op === transpose || op === SC.is_orthogonal_type - end + end + false end function check_ortho_opt(expr, A, B) @@ -39,7 +32,7 @@ function check_ortho_opt(expr, A, B) optimized = SC.ortho_inv_opt(current, SU.Code.CSEState()) # return optimized - # return toexpr(optimized) + return toexpr(optimized) @test has_ortho_opt(optimized) @@ -72,30 +65,11 @@ end check_ortho_opt(expr, Ao, B) expr2 = inv(A) * B - c = check_ortho_opt(expr2, A, B) -end - - - - -a = rand(3,3) -b = rand(3,3) -# R_euler = RotXYZ(1,2,3) -R_euler = RotMatrix{3, Float64}(rand(3, 3)) -res1 = invokelatest(current2_f, a, b) -res2 = invokelatest(optimized2_f, a, b) - -res1 = invokelatest(current2_f, R_euler, b) -res2 = invokelatest(optimized2_f, R_euler, b) - -@btime $current2_f($R_euler, $b); -@btime $optimized2_f($R_euler, $b); - -@code_warntype optimized2_f(R_euler, b) - -# @variables mewx(t)[1:3, 1:3] mewy(t)[1:3, 1:3] mewz(t)[1:3, 1:3] -# @syms mewx[1:3, 1:3] mewy[1:3, 1:3] mewz(t)[1:3, 1:3] -# expr = mewx \ mewy -# SU.Code.cse(expr), SU.Code.CSEState() - -# SC.count_occurrences(mewx, SU.Code.cse(expr)) \ No newline at end of file + check_ortho_opt(expr2, A, B) + + expr3 = inv(A) * B * inv(Ao) + check_ortho_opt(expr3, A, B) + + expr4 = inv(Ao * B) + B + check_ortho_opt(expr4, A, B) +end \ No newline at end of file From 221c1f737c38409120e5b01743c3cb9b434d7df8 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 15 Dec 2025 07:54:16 +0000 Subject: [PATCH 05/33] chore: working state --- .../SymbolicCompilerPassesRotationsExt.jl | 2 + test/ortho_inv_opt.jl | 45 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/ext/SymbolicCompilerPassesRotationsExt/SymbolicCompilerPassesRotationsExt.jl b/ext/SymbolicCompilerPassesRotationsExt/SymbolicCompilerPassesRotationsExt.jl index d9d4dac..93a258b 100644 --- a/ext/SymbolicCompilerPassesRotationsExt/SymbolicCompilerPassesRotationsExt.jl +++ b/ext/SymbolicCompilerPassesRotationsExt/SymbolicCompilerPassesRotationsExt.jl @@ -2,6 +2,8 @@ module SymbolicCompilerPassesRotationsExt using SymbolicCompilerPasses import SymbolicCompilerPasses: is_orthogonal_type + +using Rotations is_orthogonal_type(::Rotations.Rotation) = true end \ No newline at end of file diff --git a/test/ortho_inv_opt.jl b/test/ortho_inv_opt.jl index fd7a3cc..7d1d432 100644 --- a/test/ortho_inv_opt.jl +++ b/test/ortho_inv_opt.jl @@ -56,7 +56,7 @@ function check_ortho_opt(expr, A, B) end -@testset "Orthogonal Matrices: inv -> transpose" begin +# @testset "Orthogonal Matrices: inv -> transpose" begin @syms A[1:3, 1:3] B[1:3, 1:3] C[1:3, 1:3] D[1:3, 1:3] E[1:3, 1:3] Ao = SU.setmetadata(A, SC.IsOrthogonal, true) @@ -72,4 +72,45 @@ end expr4 = inv(Ao * B) + B check_ortho_opt(expr4, A, B) -end \ No newline at end of file +# end + + +function all_rules(mod) + f = filter(x -> getproperty(SC, x) isa Code.OptimizationRule, names(SC, all = true)) + getproperty.(Ref(SC), f) +end + +rules = all_rules(SC) + + +expr3 = inv(A) * B * inv(Ao) + C + + +ir = Code.cse(expr3) +optimized = ir +for rule in sort(rules, by = r -> r.priority) + st = SU.Code.CSEState() + cand = Code.apply_optimization_rules(optimized, st, rule) + if !isnothing(cand) + optimized = cand + end +end +toexpr(optimized) + +current_fun = Func([A, B, C], [], ir) +optimized_fun = Func([A, B, C], [], optimized) + +current_f = eval(toexpr(current_fun)) +optimized_f = eval(toexpr(optimized_fun)) + +N = 32 +a = rand(N, N) +b = rand(N, N) +c = rand(N, N) +R_euler = RotMatrix{N, Float64}(rand(N, N)) +res1 = invokelatest(current_f, R_euler, b, c) +res2 = invokelatest(optimized_f, R_euler, b, c) +res1 ≈ res2 + +@btime invokelatest($current_f, $a, $b, $c); +@btime invokelatest($optimized_f, $a, $b, $c); \ No newline at end of file From 07e420bdf3f28cc67b81667ca16d07245d8c90ce Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 5 Jan 2026 14:37:22 +0000 Subject: [PATCH 06/33] test: check multiple optimizations apply in parallel --- src/SymbolicCompilerPasses.jl | 9 +++++++++ src/ortho_inv_opt.jl | 1 + test/multiple.jl | 33 +++++++++++++++++++++++++++++++++ test/runtests.jl | 4 ++-- 4 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 test/multiple.jl diff --git a/src/SymbolicCompilerPasses.jl b/src/SymbolicCompilerPasses.jl index 1463e93..4463686 100644 --- a/src/SymbolicCompilerPasses.jl +++ b/src/SymbolicCompilerPasses.jl @@ -25,4 +25,13 @@ include("hvncat_static_opt.jl") include("ldiv_opt.jl") include("la_opt.jl") +function apply_optimizations(ir, state, rules) + for rule in sort(rules, by = x -> x.priority) + ir_new = apply_optimization_rules(ir, state, rule) + ir = ir_new + end + + ir +end + end # module SymbolicCompilerPasses diff --git a/src/ortho_inv_opt.jl b/src/ortho_inv_opt.jl index 9207106..d573b2b 100644 --- a/src/ortho_inv_opt.jl +++ b/src/ortho_inv_opt.jl @@ -37,6 +37,7 @@ function detect_orthogonal_matrix(expr, state::Code.CSEState) if op === inv args = arguments(r) length(args) == 1 || return false + getmetadata(args[1], IsOrthogonal, false) == true || return false return true end false diff --git a/test/multiple.jl b/test/multiple.jl new file mode 100644 index 0000000..c7208d5 --- /dev/null +++ b/test/multiple.jl @@ -0,0 +1,33 @@ +function test_codegen(expr, rules, args...) + current = SU.Code.cse(expr) + optimized = SC.apply_optimizations(current, SU.Code.CSEState(), rules) + + current_expr = Func([args...], [], current) + optimized_expr = Func([args...], [], optimized) + + current_f = eval(toexpr(current_expr)) + optimized_f = eval(toexpr(optimized_expr)) + + N = 3 + # test_args = collect(randn(N, N) for _ in 1:length(args)) + test_args = [rand(size(x)...) for x in args] + + current_res = @invokelatest current_f(test_args...) + optimized_res = @invokelatest optimized_f(test_args...) + + @test isapprox(current_res, optimized_res, rtol=1e-10, atol=1e-10) +end + + +@testset "Combined Optimizations" begin + @syms A[1:3, 1:3] B[1:3, 1:2] C[1:3, 1:2] D[1:2, 1:2] E[1:2, 1:3] + + P = A \ B + expr = P + C * D + test_codegen(expr, [SC.LDIV_RULE, SC.MATMUL_ADD_RULE], A, B, C, D) + + # note that LDIV_RULE should not apply because A is reused + P = A \ B + expr2 = P * E + A + test_codegen(expr2, [SC.LDIV_RULE, SC.MATMUL_ADD_RULE], A, B, E) +end diff --git a/test/runtests.jl b/test/runtests.jl index b82d2a6..c13257a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,5 +5,5 @@ using Pkg, Test, SafeTestsets @safetestset "MatmulAdd Optimization" begin include("mul5_opt.jl") end @safetestset "Literal Small Array Allocation" begin include("array_literal.jl") end @safetestset "Ldiv Factorization Optimization" begin include("ldiv_opt.jl") end -end - + @safetestset "Apply Multiple Rules" begin include("multiple.jl") end +end \ No newline at end of file From 3476e5bc635ccd08b8fb58cd64a25b4e1e38b7c7 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 5 Jan 2026 14:39:02 +0000 Subject: [PATCH 07/33] chore: rotations ext --- Project.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Project.toml b/Project.toml index 9273602..dc77d68 100644 --- a/Project.toml +++ b/Project.toml @@ -13,12 +13,9 @@ SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b" LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" Rotations = "6038ab10-8711-5258-84ad-4b1120ba62dc" -[sources] -SymbolicUtils = {rev = "dg/opt_api", url = "https://github.com/DhairyaLGandhi/SymbolicUtils.jl"} - [extensions] -SymbolicCompilerPassesRotationsExt = ["Rotations",] SCPLinearSolveExt = ["LinearSolve"] +SymbolicCompilerPassesRotationsExt = ["Rotations"] [compat] LinearAlgebra = "1.11.0, 1.10" From 56bf1186594e1e482d46b551c3c6dace91f36a0d Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 5 Jan 2026 14:57:32 +0000 Subject: [PATCH 08/33] chore: unused code --- test/ortho_inv_opt.jl | 45 ++----------------------------------------- 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/test/ortho_inv_opt.jl b/test/ortho_inv_opt.jl index 7d1d432..fd7a3cc 100644 --- a/test/ortho_inv_opt.jl +++ b/test/ortho_inv_opt.jl @@ -56,7 +56,7 @@ function check_ortho_opt(expr, A, B) end -# @testset "Orthogonal Matrices: inv -> transpose" begin +@testset "Orthogonal Matrices: inv -> transpose" begin @syms A[1:3, 1:3] B[1:3, 1:3] C[1:3, 1:3] D[1:3, 1:3] E[1:3, 1:3] Ao = SU.setmetadata(A, SC.IsOrthogonal, true) @@ -72,45 +72,4 @@ end expr4 = inv(Ao * B) + B check_ortho_opt(expr4, A, B) -# end - - -function all_rules(mod) - f = filter(x -> getproperty(SC, x) isa Code.OptimizationRule, names(SC, all = true)) - getproperty.(Ref(SC), f) -end - -rules = all_rules(SC) - - -expr3 = inv(A) * B * inv(Ao) + C - - -ir = Code.cse(expr3) -optimized = ir -for rule in sort(rules, by = r -> r.priority) - st = SU.Code.CSEState() - cand = Code.apply_optimization_rules(optimized, st, rule) - if !isnothing(cand) - optimized = cand - end -end -toexpr(optimized) - -current_fun = Func([A, B, C], [], ir) -optimized_fun = Func([A, B, C], [], optimized) - -current_f = eval(toexpr(current_fun)) -optimized_f = eval(toexpr(optimized_fun)) - -N = 32 -a = rand(N, N) -b = rand(N, N) -c = rand(N, N) -R_euler = RotMatrix{N, Float64}(rand(N, N)) -res1 = invokelatest(current_f, R_euler, b, c) -res2 = invokelatest(optimized_f, R_euler, b, c) -res1 ≈ res2 - -@btime invokelatest($current_f, $a, $b, $c); -@btime invokelatest($optimized_f, $a, $b, $c); \ No newline at end of file +end \ No newline at end of file From 698cd4f4de024313f3f949be9fb909d83ed22e03 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Thu, 8 Jan 2026 14:43:42 +0000 Subject: [PATCH 09/33] test(multiple): add ortho -> inv example --- test/multiple.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/multiple.jl b/test/multiple.jl index c7208d5..788675c 100644 --- a/test/multiple.jl +++ b/test/multiple.jl @@ -1,6 +1,6 @@ function test_codegen(expr, rules, args...) current = SU.Code.cse(expr) - optimized = SC.apply_optimizations(current, SU.Code.CSEState(), rules) + optimized = SU.Code.apply_optimization_rules(current, SU.Code.CSEState(), rules) current_expr = Func([args...], [], current) optimized_expr = Func([args...], [], optimized) @@ -30,4 +30,11 @@ end P = A \ B expr2 = P * E + A test_codegen(expr2, [SC.LDIV_RULE, SC.MATMUL_ADD_RULE], A, B, E) + + @syms R[1:3, 1:3] + Ro = setmetadata(R, SC.IsOrthogonal, true) + P = A \ B + # expr3 = P + C * inv(Ro) + expr3 = tril(P) + C * inv(Ro) + test_codegen(expr3, [SC.LDIV_RULE, SC.MATMUL_ADD_RULE, SC.ORTHO_INV_RULE], A, B, C, R) end From 6516a64e8c1ec41719779fd13aea24f7c59030e8 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 12 Jan 2026 13:01:55 +0000 Subject: [PATCH 10/33] chore: remove dispatch on CSEState --- src/SymbolicCompilerPasses.jl | 16 +++++++++------- src/hvncat_static_opt.jl | 11 ++++++----- src/ldiv_opt.jl | 4 +++- src/matmuladd.jl | 6 +++--- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/SymbolicCompilerPasses.jl b/src/SymbolicCompilerPasses.jl index 4463686..e9ca14d 100644 --- a/src/SymbolicCompilerPasses.jl +++ b/src/SymbolicCompilerPasses.jl @@ -25,13 +25,15 @@ include("hvncat_static_opt.jl") include("ldiv_opt.jl") include("la_opt.jl") -function apply_optimizations(ir, state, rules) - for rule in sort(rules, by = x -> x.priority) - ir_new = apply_optimization_rules(ir, state, rule) - ir = ir_new - end +include("mb_opt.jl") - ir -end +# function apply_optimizations(ir, state, rules) +# for rule in sort(rules, by = x -> x.priority) +# ir_new = apply_optimization_rules(ir, state, rule) +# ir = ir_new +# end + +# ir +# end end # module SymbolicCompilerPasses diff --git a/src/hvncat_static_opt.jl b/src/hvncat_static_opt.jl index 575c64b..55bc8f6 100644 --- a/src/hvncat_static_opt.jl +++ b/src/hvncat_static_opt.jl @@ -129,7 +129,7 @@ Examples of what this detects: For small arrays (≤ 4×4), these will be converted to StaticArrays. """ -function detect_hvncat_pattern(expr::Code.Let, state::Code.CSEState) +function detect_hvncat_pattern(expr::Code.Let, state) matches = HvncatMatch[] for (idx, pair) in enumerate(expr.pairs) @@ -176,7 +176,7 @@ end """ transform_hvncat_to_static(expr::Code.Let, match_data::Union{Nothing, Vector{HvncatMatch}}, - state::Code.CSEState) -> Code.Let + state) -> Code.Let Transform hvncat operations to StaticArray constructors. @@ -184,9 +184,10 @@ Converts: - `A = [1 2; 3 4]` → `A = SMatrix{2,2}(1, 2, 3, 4)` - `v = [1, 2, 3]` → `v = SVector{3}(1, 2, 3)` """ -transform_hvncat_to_static(expr, ::Nothing, state::Code.CSEState) = expr +transform_hvncat_to_static(expr, ::Nothing, state) = expr function transform_hvncat_to_static(expr::Code.Let, match_data::Vector{HvncatMatch}, - state::Code.CSEState) + state) + # @show match_data isempty(match_data) && return expr # Build transformation plan @@ -251,7 +252,7 @@ const HVNCAT_STATIC_RULE = OptimizationRule( function literal_static_opt(expr, state::CSEState) # Try to apply optimization rules - optimized = apply_optimization_rules(expr, state, HVNCAT_STATIC_RULE) + optimized = apply_optimization_rule(expr, state, HVNCAT_STATIC_RULE) if optimized !== nothing return optimized end diff --git a/src/ldiv_opt.jl b/src/ldiv_opt.jl index faeb4d8..0d353ec 100644 --- a/src/ldiv_opt.jl +++ b/src/ldiv_opt.jl @@ -13,7 +13,9 @@ end Detect patterns of the form `result = A \\ B` where both A and B are arrays. """ -function detect_ldiv_pattern(expr::Code.Let, state::Code.CSEState) +# function detect_ldiv_pattern(expr::Code.Let, state::Code.CSEState) +function detect_ldiv_pattern(expr::Code.Let, state) + global gex = expr ldiv_candidates_idx = findall(expr.pairs) do x r = rhs(x) iscall(r) || return false diff --git a/src/matmuladd.jl b/src/matmuladd.jl index 155d708..c4d0be2 100644 --- a/src/matmuladd.jl +++ b/src/matmuladd.jl @@ -30,7 +30,7 @@ result = temp `A` and `B` must not be aliased. """ -function detect_matmul_add_pattern(expr::Code.Let, state::Code.CSEState) +function detect_matmul_add_pattern(expr::Code.Let, state) mul_candidates_idx = findall(expr.pairs) do x r = rhs(x) iscall(r) || return false @@ -88,8 +88,8 @@ function get_from_cache(x) end end -transform_to_mul5_assignment(expr, ::Tuple{Union{Nothing, AbstractVector{Nothing}, Tuple{Nothing, Nothing}}, <:Any}, state::Code.CSEState) = expr -function transform_to_mul5_assignment(expr, match_data_, state::Code.CSEState) +transform_to_mul5_assignment(expr, ::Tuple{Union{Nothing, AbstractVector{Nothing}, Tuple{Nothing, Nothing}}, <:Any}, state) = expr +function transform_to_mul5_assignment(expr, match_data_, state) match_data_, net_additive_terms = match_data_ match_data_ === nothing && return expr Cset = Set(Iterators.flatten(getproperty.(match_data_, :Cs))) From c905f158391c998f39cfabbf582c976624096287 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 12 Jan 2026 13:02:14 +0000 Subject: [PATCH 11/33] chore: convert small views to static arrays --- src/mb_opt.jl | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/mb_opt.jl diff --git a/src/mb_opt.jl b/src/mb_opt.jl new file mode 100644 index 0000000..55d5164 --- /dev/null +++ b/src/mb_opt.jl @@ -0,0 +1,59 @@ +function detect_small_views(expr::Code.Let, state) + matches = [] + for (i, p) in enumerate(expr.pairs) + r = rhs(p) + iscall(r) || continue + if operation(r) === view + push!(matches, (idx = i, expr = r)) + end + end + matches +end + +function construct_type(dims) + # if length(dims) == 1 + # return Core.apply_type(SVector, dims[1]) + # else + # return Core.apply_type(SVector, Tuple(dims)) + # end + Core.apply_type(SVector, length(dims)) +end + +function transform_view(expr, match_data, state) + new_pairs = [] + idxs = Set(getproperty.(match_data, :idx)) + transformations = Dict() + for match in match_data + idx = match.idx + r = match.expr + T = symtype(r) + V = vartype(r) + arr, inds... = arguments(r) + @show length.(inds) + t = @show term(construct_type, inds[1]) + # transformations[idx] = term(Core.apply_type(SVector, size(inds[1])), r) + # @show Term{V}(t, [r], type = T) + # transformations[idx] = term(term(construct_type, inds[1]), r) + transformations[idx] = Term{V}(t, [r], type = T) + end + + # @show transformations[3] + for (i, p) in enumerate(expr.pairs) + if i in idxs + new_rhs = transformations[i] + push!(new_pairs, Code.Assignment(lhs(p), new_rhs)) + else + push!(new_pairs, p) + end + end + + Code.Let(new_pairs, expr.body, expr.let_block) +end + + +const MB_VIEW_RULE = OptimizationRule( + "MB_VIEW_RULE", + detect_small_views, + transform_view, + 10, +) \ No newline at end of file From 76e8000d5eb27e89f1927397726896365ba086fb Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 12 Jan 2026 16:38:22 +0000 Subject: [PATCH 12/33] test(multiple): import packages --- test/multiple.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/multiple.jl b/test/multiple.jl index 788675c..32de9a2 100644 --- a/test/multiple.jl +++ b/test/multiple.jl @@ -1,3 +1,10 @@ +using SymbolicUtils +using SymbolicUtils.Code +import SymbolicUtils as SU +import SymbolicCompilerPasses as SC +using LinearAlgebra +using Test + function test_codegen(expr, rules, args...) current = SU.Code.cse(expr) optimized = SU.Code.apply_optimization_rules(current, SU.Code.CSEState(), rules) From e63dfa0898137d310e422b0c5486d8e210477247 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 19 Jan 2026 14:16:45 +0000 Subject: [PATCH 13/33] chore: check for sizes of views --- src/mb_opt.jl | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/mb_opt.jl b/src/mb_opt.jl index 55d5164..f9d0efe 100644 --- a/src/mb_opt.jl +++ b/src/mb_opt.jl @@ -4,6 +4,9 @@ function detect_small_views(expr::Code.Let, state) r = rhs(p) iscall(r) || continue if operation(r) === view + arr, inds... = arguments(r) + myt = find_term(inds[1], expr) + is_small_hvncat(size(Code.rhs(myt))...) || continue push!(matches, (idx = i, expr = r)) end end @@ -19,6 +22,12 @@ function construct_type(dims) Core.apply_type(SVector, length(dims)) end +function find_term(target, expr::Code.Let) + filter(expr.pairs) do p + Code.lhs(p) === target + end |> only +end + function transform_view(expr, match_data, state) new_pairs = [] idxs = Set(getproperty.(match_data, :idx)) @@ -29,15 +38,10 @@ function transform_view(expr, match_data, state) T = symtype(r) V = vartype(r) arr, inds... = arguments(r) - @show length.(inds) - t = @show term(construct_type, inds[1]) - # transformations[idx] = term(Core.apply_type(SVector, size(inds[1])), r) - # @show Term{V}(t, [r], type = T) - # transformations[idx] = term(term(construct_type, inds[1]), r) + t = term(construct_type, inds[1]) transformations[idx] = Term{V}(t, [r], type = T) end - # @show transformations[3] for (i, p) in enumerate(expr.pairs) if i in idxs new_rhs = transformations[i] From 20d0a5bfa08a8fea47bfb0395b96a299fe937ab3 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Thu, 29 Jan 2026 12:22:12 +0000 Subject: [PATCH 14/33] chore: working state --- Project.toml | 4 +++- src/SymbolicCompilerPasses.jl | 3 +++ src/ortho_inv_opt.jl | 15 +++++++-------- test/ortho_inv_opt.jl | 9 +++++---- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/Project.toml b/Project.toml index 9273602..04a7197 100644 --- a/Project.toml +++ b/Project.toml @@ -4,6 +4,7 @@ authors = ["Dhairya Gandhi "] version = "0.1.0" [deps] +DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" PreallocationTools = "d236fae5-4411-538c-8e31-a6e3d9e00b46" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" @@ -17,10 +18,11 @@ Rotations = "6038ab10-8711-5258-84ad-4b1120ba62dc" SymbolicUtils = {rev = "dg/opt_api", url = "https://github.com/DhairyaLGandhi/SymbolicUtils.jl"} [extensions] -SymbolicCompilerPassesRotationsExt = ["Rotations",] SCPLinearSolveExt = ["LinearSolve"] +SymbolicCompilerPassesRotationsExt = ["Rotations"] [compat] +DataStructures = "0.19.3" LinearAlgebra = "1.11.0, 1.10" LinearSolve = "3.53.0" PreallocationTools = "0.4.34" diff --git a/src/SymbolicCompilerPasses.jl b/src/SymbolicCompilerPasses.jl index e9ca14d..3b9c3bc 100644 --- a/src/SymbolicCompilerPasses.jl +++ b/src/SymbolicCompilerPasses.jl @@ -11,6 +11,8 @@ import SymbolicUtils.Code: Code, OptimizationRule, substitute_in_ir, apply_optim import SymbolicUtils: search_variables, search_variables! using StaticArrays +using DataStructures + function bank(dic, key, value) if haskey(dic, key) dic[key] = vcat(dic[key], value) @@ -26,6 +28,7 @@ include("ldiv_opt.jl") include("la_opt.jl") include("mb_opt.jl") +include("scalar_to_vec_opt.jl") # function apply_optimizations(ir, state, rules) # for rule in sort(rules, by = x -> x.priority) diff --git a/src/ortho_inv_opt.jl b/src/ortho_inv_opt.jl index d573b2b..38232a4 100644 --- a/src/ortho_inv_opt.jl +++ b/src/ortho_inv_opt.jl @@ -66,13 +66,12 @@ function transform_inv_optimization(expr, matches, state::Code.CSEState) ) else t = term(is_orthogonal_type, A) - @show t - - code = IfElse( - t, - transpose(A), - inv(A) - ) + # code = IfElse( + # t, + # transpose(A), + # inv(A) + # ) + code = ifelse(t, transpose(A), inv(A)) expr_copy.pairs[match.idx] = Code.Assignment( lhs(match.candidate), code @@ -92,7 +91,7 @@ const ORTHO_INV_RULE = OptimizationRule( function ortho_inv_opt(expr, state::Code.CSEState) # Try to apply optimization rules - optimized = apply_optimization_rules(expr, state, ORTHO_INV_RULE) + optimized = apply_optimization_rule(expr, state, ORTHO_INV_RULE) if optimized !== nothing return optimized end diff --git a/test/ortho_inv_opt.jl b/test/ortho_inv_opt.jl index fd7a3cc..1b0a335 100644 --- a/test/ortho_inv_opt.jl +++ b/test/ortho_inv_opt.jl @@ -30,9 +30,10 @@ function check_ortho_opt(expr, A, B) current = SU.Code.cse(expr) toexpr(current) - optimized = SC.ortho_inv_opt(current, SU.Code.CSEState()) + # optimized = SC.ortho_inv_opt(current, SU.Code.CSEState()) + optimized = Code.apply_optimization_rule(current, SU.Code.CSEState(), SC.ORTHO_INV_RULE) # return optimized - return toexpr(optimized) + # return toexpr(optimized) @test has_ortho_opt(optimized) @@ -56,7 +57,7 @@ function check_ortho_opt(expr, A, B) end -@testset "Orthogonal Matrices: inv -> transpose" begin +# @testset "Orthogonal Matrices: inv -> transpose" begin @syms A[1:3, 1:3] B[1:3, 1:3] C[1:3, 1:3] D[1:3, 1:3] E[1:3, 1:3] Ao = SU.setmetadata(A, SC.IsOrthogonal, true) @@ -72,4 +73,4 @@ end expr4 = inv(Ao * B) + B check_ortho_opt(expr4, A, B) -end \ No newline at end of file +# end \ No newline at end of file From 598018e5b3ecfac2512536dced5739afd5d11454 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 2 Feb 2026 11:54:16 +0000 Subject: [PATCH 15/33] chore: working state --- ext/SCPLinearSolveExt/SCPLinearSolveExt.jl | 1 + src/ldiv_opt.jl | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl b/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl index b9037b1..fda1dea 100644 --- a/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl +++ b/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl @@ -10,6 +10,7 @@ SymbolicCompilerPasses.LINEARSOLVE_LIB[] = true function linear_solve(A, B) linsolve = get_factorization(A, B) + # linsolve = init(LinearSolve.LinearProblem(A, B)) linsolve.b = B sol = solve!(linsolve) return sol.u diff --git a/src/ldiv_opt.jl b/src/ldiv_opt.jl index 0d353ec..bb412e3 100644 --- a/src/ldiv_opt.jl +++ b/src/ldiv_opt.jl @@ -29,6 +29,7 @@ function detect_ldiv_pattern(expr::Code.Let, state) all_arrays || return false A, B = args + @show validate_ldiv_shapes(A, B) validate_ldiv_shapes(A, B) end @@ -52,6 +53,7 @@ For A \\ B: - B must have n rows: (n, m) or (n,) """ function validate_ldiv_shapes(A, B) + return true A_shape = shape(A) B_shape = shape(B) @@ -151,6 +153,7 @@ function get_factorization(A) qr_A = get!(FACTORIZATION_CACHE, A) do qr(A) end + # qr_A = qr(A) qr_A end @@ -201,7 +204,7 @@ Transform `result = A \\ B` to: This performs in-place linear solve, overwriting B with the result. """ -function transform_to_ldiv_inplace(expr::Code.Let, match_data::AbstractVector, state::Code.CSEState) +function transform_to_ldiv_inplace(expr::Code.Let, match_data::AbstractVector, state) # Validate all matches safe_matches = filter(match_data) do match is_safe = is_safe_to_optimize_ldiv(match, expr) From a645ac8027f6c164cfe531aba1e5d8c206c4133c Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 2 Feb 2026 14:45:17 +0000 Subject: [PATCH 16/33] chore: use Base.ifelse instead of IfElse --- src/SymbolicCompilerPasses.jl | 9 --------- src/ortho_inv_opt.jl | 15 ++++++++------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/SymbolicCompilerPasses.jl b/src/SymbolicCompilerPasses.jl index 4463686..1463e93 100644 --- a/src/SymbolicCompilerPasses.jl +++ b/src/SymbolicCompilerPasses.jl @@ -25,13 +25,4 @@ include("hvncat_static_opt.jl") include("ldiv_opt.jl") include("la_opt.jl") -function apply_optimizations(ir, state, rules) - for rule in sort(rules, by = x -> x.priority) - ir_new = apply_optimization_rules(ir, state, rule) - ir = ir_new - end - - ir -end - end # module SymbolicCompilerPasses diff --git a/src/ortho_inv_opt.jl b/src/ortho_inv_opt.jl index d573b2b..9d1fb74 100644 --- a/src/ortho_inv_opt.jl +++ b/src/ortho_inv_opt.jl @@ -66,13 +66,14 @@ function transform_inv_optimization(expr, matches, state::Code.CSEState) ) else t = term(is_orthogonal_type, A) - @show t + # @show t - code = IfElse( - t, - transpose(A), - inv(A) - ) + # code = IfElse( + # t, + # transpose(A), + # inv(A) + # ) + code = ifelse(t, transpose(A), inv(A)) expr_copy.pairs[match.idx] = Code.Assignment( lhs(match.candidate), code @@ -92,7 +93,7 @@ const ORTHO_INV_RULE = OptimizationRule( function ortho_inv_opt(expr, state::Code.CSEState) # Try to apply optimization rules - optimized = apply_optimization_rules(expr, state, ORTHO_INV_RULE) + optimized = apply_optimization_rules(expr, state, [ORTHO_INV_RULE]) if optimized !== nothing return optimized end From 9df123f845fc9606eaaf340b44fc5cddea65e6cb Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 2 Feb 2026 14:55:37 +0000 Subject: [PATCH 17/33] test: add Symbolics to test deps --- Project.toml | 6 ++++-- test/multiple.jl | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 7f86bee..2382ee6 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "SymbolicCompilerPasses" uuid = "3384d301-0fbe-4b40-9ae0-b0e68bedb069" -version = "0.1.2" authors = ["Dhairya Gandhi "] +version = "0.1.2" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" @@ -23,12 +23,14 @@ LinearSolve = "3.53.0" PreallocationTools = "0.4.34, 1" StaticArrays = "1.9.15, 1" SymbolicUtils = "4.1.0" +Symbolics = "7.2" julia = "1" [extras] Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" +Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Pkg", "SafeTestsets", "Test"] +test = ["Pkg", "SafeTestsets", "Test", "Symbolics"] diff --git a/test/multiple.jl b/test/multiple.jl index 32de9a2..f84dcd6 100644 --- a/test/multiple.jl +++ b/test/multiple.jl @@ -3,6 +3,7 @@ using SymbolicUtils.Code import SymbolicUtils as SU import SymbolicCompilerPasses as SC using LinearAlgebra +using Symbolics using Test function test_codegen(expr, rules, args...) From de0b22fd27cacd1f63cfa6afa7b724fac5d28c68 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Tue, 3 Feb 2026 10:44:46 +0000 Subject: [PATCH 18/33] test: add ortho tests to runtests --- test/ortho_inv_opt.jl | 6 ++---- test/runtests.jl | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/ortho_inv_opt.jl b/test/ortho_inv_opt.jl index fd7a3cc..7377e20 100644 --- a/test/ortho_inv_opt.jl +++ b/test/ortho_inv_opt.jl @@ -1,5 +1,3 @@ -using Revise, BenchmarkTools - using SymbolicUtils using SymbolicUtils.Code import SymbolicUtils as SU @@ -16,7 +14,7 @@ function has_ortho_opt(expr::Code.Let) has_ortho_opt(rhs_expr) end end -has_ortho_opt(expr::Code.IfElse) = has_ortho_opt(expr.ifbody) || has_ortho_opt(expr.elsebody) +# has_ortho_opt(expr::Code.IfElse) = has_ortho_opt(expr.ifbody) || has_ortho_opt(expr.elsebody) function has_ortho_opt(expr) if SU.iscall(expr) @@ -32,7 +30,7 @@ function check_ortho_opt(expr, A, B) optimized = SC.ortho_inv_opt(current, SU.Code.CSEState()) # return optimized - return toexpr(optimized) + # return toexpr(optimized) @test has_ortho_opt(optimized) diff --git a/test/runtests.jl b/test/runtests.jl index c13257a..22632ca 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,5 +5,6 @@ using Pkg, Test, SafeTestsets @safetestset "MatmulAdd Optimization" begin include("mul5_opt.jl") end @safetestset "Literal Small Array Allocation" begin include("array_literal.jl") end @safetestset "Ldiv Factorization Optimization" begin include("ldiv_opt.jl") end + @safetestset "Orthogonal Inverse Optimization" begin include("ortho_inv_opt.jl") end @safetestset "Apply Multiple Rules" begin include("multiple.jl") end end \ No newline at end of file From c21bed4ad5627713ab52349fec1747350feb5851 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Tue, 3 Feb 2026 16:21:33 +0530 Subject: [PATCH 19/33] Update test/multiple.jl --- test/multiple.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/multiple.jl b/test/multiple.jl index f84dcd6..121ac16 100644 --- a/test/multiple.jl +++ b/test/multiple.jl @@ -28,7 +28,7 @@ end @testset "Combined Optimizations" begin - @syms A[1:3, 1:3] B[1:3, 1:2] C[1:3, 1:2] D[1:2, 1:2] E[1:2, 1:3] + @syms A[1:3, 1:3] B[1:3, 1:2] C[1:3, 1:3] D[1:2, 1:2] E[1:2, 1:3] P = A \ B expr = P + C * D From 1d2d1fee182e70d0043b73096f43b6b1302098ca Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Tue, 3 Feb 2026 16:43:50 +0530 Subject: [PATCH 20/33] Update test/multiple.jl --- test/multiple.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/multiple.jl b/test/multiple.jl index 121ac16..0d9ec7a 100644 --- a/test/multiple.jl +++ b/test/multiple.jl @@ -28,7 +28,7 @@ end @testset "Combined Optimizations" begin - @syms A[1:3, 1:3] B[1:3, 1:2] C[1:3, 1:3] D[1:2, 1:2] E[1:2, 1:3] + @syms A[1:3, 1:3] B[1:3, 1:2] C[1:3, 1:3] D[1:3, 1:2] E[1:2, 1:3] P = A \ B expr = P + C * D From bf06dbd018439645fd9ee880200c8b5c41f6e7fb Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Fri, 13 Feb 2026 11:24:20 +0000 Subject: [PATCH 21/33] chore: manage static ldiv --- ext/SCPLinearSolveExt/SCPLinearSolveExt.jl | 25 +++++++++++++++++++--- src/hvncat_static_opt.jl | 15 +++++-------- src/ldiv_opt.jl | 2 +- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl b/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl index fda1dea..6539152 100644 --- a/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl +++ b/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl @@ -5,17 +5,36 @@ using SymbolicUtils.Code using LinearSolve using LinearAlgebra import SymbolicCompilerPasses: ldiv_transformation, SymbolicCompilerPasses, get_factorization, get_from_cache, FACTORIZATION_CACHE +using StaticArrays -SymbolicCompilerPasses.LINEARSOLVE_LIB[] = true +__init__() = SymbolicCompilerPasses.LINEARSOLVE_LIB[] = true + +const LINSOLVEPROB_CACHE = Dict() + +function get_linear_prob(A::StaticArray, B::StaticArray) + prob = LinearSolve.LinearProblem(A, B) +end + +function get_linear_prob(A, B) + get!(LINSOLVEPROB_CACHE, A) do + prob = LinearSolve.LinearProblem(A, B) + init(prob) + end +end function linear_solve(A, B) - linsolve = get_factorization(A, B) - # linsolve = init(LinearSolve.LinearProblem(A, B)) + linsolve = get_linear_prob(A, B) linsolve.b = B sol = solve!(linsolve) return sol.u end +function linear_solve(A::StaticArray, B::StaticArray) + linsolve = get_linear_prob(A, B) + sol = solve(linsolve) + return sol.u +end + function get_factorization(A, B) get!(FACTORIZATION_CACHE, A) do prob = LinearSolve.LinearProblem(A, B) diff --git a/src/hvncat_static_opt.jl b/src/hvncat_static_opt.jl index 55bc8f6..e0d4f04 100644 --- a/src/hvncat_static_opt.jl +++ b/src/hvncat_static_opt.jl @@ -205,21 +205,16 @@ function transform_hvncat_to_static(expr::Code.Let, match_data::Vector{HvncatMat # Column vector: SVector{n}(elements...) n = dims[1] t = term(Core.apply_type, StaticArrays.SVector, n; type = Any) - static_ctor = Term{T}( - t, - elements; - type=symtype(lhs_var) - ) else # Matrix: SMatrix{m,n}(elements...) m, n = dims t = term(Core.apply_type, StaticArrays.SMatrix, m, n; type = Any) - static_ctor = Term{T}( - t, - elements; - type=symtype(lhs_var) - ) end + static_ctor = Term{T}( + t, + elements; + type=symtype(lhs_var) + ) new_assignment = Assignment(lhs_var, static_ctor) transformations[match.assignment_idx] = new_assignment diff --git a/src/ldiv_opt.jl b/src/ldiv_opt.jl index bb412e3..e713833 100644 --- a/src/ldiv_opt.jl +++ b/src/ldiv_opt.jl @@ -1,4 +1,4 @@ -const FACTORIZATION_CACHE = WeakKeyDict() +const FACTORIZATION_CACHE = Dict() struct LdivMatch{Ta, Tb, S <: Assignment, P <: AbstractString} <: AbstractMatched A::Ta From 75f161d95527ca68623bdc731675ccf1c05c148a Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Fri, 13 Feb 2026 17:36:21 +0530 Subject: [PATCH 22/33] Apply suggestions from code review Co-authored-by: Aayush Sabharwal --- ext/SCPLinearSolveExt/SCPLinearSolveExt.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl b/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl index 6539152..e3f7879 100644 --- a/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl +++ b/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl @@ -15,11 +15,11 @@ function get_linear_prob(A::StaticArray, B::StaticArray) prob = LinearSolve.LinearProblem(A, B) end -function get_linear_prob(A, B) +function get_linear_prob(A::TA, B::TB) where {TA, TB} get!(LINSOLVEPROB_CACHE, A) do prob = LinearSolve.LinearProblem(A, B) init(prob) - end + end::Base.promote_op(LinearSolve.LinearProblem, Tuple{TA, TB}) end function linear_solve(A, B) From 91acc9769aa820840f97ab06b82046f89dc0b4d9 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 16 Feb 2026 13:11:43 +0530 Subject: [PATCH 23/33] Update ext/SCPLinearSolveExt/SCPLinearSolveExt.jl Co-authored-by: Aayush Sabharwal --- ext/SCPLinearSolveExt/SCPLinearSolveExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl b/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl index e3f7879..95fcb49 100644 --- a/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl +++ b/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl @@ -19,7 +19,7 @@ function get_linear_prob(A::TA, B::TB) where {TA, TB} get!(LINSOLVEPROB_CACHE, A) do prob = LinearSolve.LinearProblem(A, B) init(prob) - end::Base.promote_op(LinearSolve.LinearProblem, Tuple{TA, TB}) + end::Base.promote_op(init, Tuple{Base.promote_op(LinearSolve.LinearProblem, Tuple{TA, TB})}) end function linear_solve(A, B) From ddd2efdeb8ff22afa869130e6b8a8cce1c0126fa Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 16 Feb 2026 15:28:39 +0000 Subject: [PATCH 24/33] test: simplify shapes --- test/multiple.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/multiple.jl b/test/multiple.jl index 0d9ec7a..2a9d05f 100644 --- a/test/multiple.jl +++ b/test/multiple.jl @@ -28,7 +28,7 @@ end @testset "Combined Optimizations" begin - @syms A[1:3, 1:3] B[1:3, 1:2] C[1:3, 1:3] D[1:3, 1:2] E[1:2, 1:3] + @syms A[1:3, 1:3] B[1:3, 1:3] C[1:3, 1:3] D[1:3, 1:2] E[1:3, 1:3] P = A \ B expr = P + C * D From 90ce954698f07e33ca9f862329f041165e9ad3a3 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 16 Feb 2026 15:30:14 +0000 Subject: [PATCH 25/33] build: add rotations to extras --- Project.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index e9c4590..433a51d 100644 --- a/Project.toml +++ b/Project.toml @@ -23,6 +23,7 @@ DataStructures = "0.19.3" LinearAlgebra = "1.11.0, 1.10" LinearSolve = "3.53.0" PreallocationTools = "0.4.34, 1" +Rotations = "1.7.1" StaticArrays = "1.9.15, 1" SymbolicUtils = "4.1.0" Symbolics = "7.2" @@ -33,6 +34,7 @@ Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Rotations = "6038ab10-8711-5258-84ad-4b1120ba62dc" [targets] -test = ["Pkg", "SafeTestsets", "Test", "Symbolics"] +test = ["Pkg", "SafeTestsets", "Test", "Symbolics", "Rotations"] From 13001c1953bad9d88e9d392d3898da3a00486552 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Tue, 17 Feb 2026 06:53:28 +0000 Subject: [PATCH 26/33] test: simplify shapes for testing multiple strats togeteher --- test/multiple.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/multiple.jl b/test/multiple.jl index 2a9d05f..8599ff5 100644 --- a/test/multiple.jl +++ b/test/multiple.jl @@ -28,7 +28,7 @@ end @testset "Combined Optimizations" begin - @syms A[1:3, 1:3] B[1:3, 1:3] C[1:3, 1:3] D[1:3, 1:2] E[1:3, 1:3] + @syms A[1:3, 1:3] B[1:3, 1:3] C[1:3, 1:3] D[1:3, 1:3] E[1:3, 1:3] P = A \ B expr = P + C * D From efbae928362eaa6fda83b23a49e7dcb0541ae891 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Tue, 17 Feb 2026 06:55:18 +0000 Subject: [PATCH 27/33] test: check if optimization is eexpected --- test/ortho_inv_opt.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/ortho_inv_opt.jl b/test/ortho_inv_opt.jl index 0955867..620215a 100644 --- a/test/ortho_inv_opt.jl +++ b/test/ortho_inv_opt.jl @@ -24,7 +24,7 @@ function has_ortho_opt(expr) false end -function check_ortho_opt(expr, A, B) +function check_ortho_opt(expr, A, B; expected_ortho = false) current = SU.Code.cse(expr) toexpr(current) @@ -33,7 +33,7 @@ function check_ortho_opt(expr, A, B) # return optimized # return toexpr(optimized) - @test has_ortho_opt(optimized) + @test has_ortho_opt(optimized) == expected_ortho current_fun = Func([A, B], [], current) optimized_fun = Func([A, B], [], optimized) @@ -55,7 +55,7 @@ function check_ortho_opt(expr, A, B) end -# @testset "Orthogonal Matrices: inv -> transpose" begin +@testset "Orthogonal Matrices: inv -> transpose" begin @syms A[1:3, 1:3] B[1:3, 1:3] C[1:3, 1:3] D[1:3, 1:3] E[1:3, 1:3] Ao = SU.setmetadata(A, SC.IsOrthogonal, true) @@ -71,4 +71,4 @@ end expr4 = inv(Ao * B) + B check_ortho_opt(expr4, A, B) -# end \ No newline at end of file +end \ No newline at end of file From a7f2d2a0368ee37f08d6d1753bb047e6effdd4bc Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Tue, 17 Feb 2026 07:02:55 +0000 Subject: [PATCH 28/33] test: set cases with no expected optimization --- test/ortho_inv_opt.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/ortho_inv_opt.jl b/test/ortho_inv_opt.jl index 620215a..1b96658 100644 --- a/test/ortho_inv_opt.jl +++ b/test/ortho_inv_opt.jl @@ -64,11 +64,11 @@ end check_ortho_opt(expr, Ao, B) expr2 = inv(A) * B - check_ortho_opt(expr2, A, B) + check_ortho_opt(expr2, A, B; expected_ortho = false) expr3 = inv(A) * B * inv(Ao) check_ortho_opt(expr3, A, B) expr4 = inv(Ao * B) + B - check_ortho_opt(expr4, A, B) + check_ortho_opt(expr4, A, B; expected_ortho = false) # Can't optimize inv(Ao * B) without more info end \ No newline at end of file From 60ddb96b3b73c0b4e3430532d583bdc8afebb0a8 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Tue, 17 Feb 2026 07:11:29 +0000 Subject: [PATCH 29/33] test: default checking ortho to true --- test/ortho_inv_opt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ortho_inv_opt.jl b/test/ortho_inv_opt.jl index 1b96658..9c32485 100644 --- a/test/ortho_inv_opt.jl +++ b/test/ortho_inv_opt.jl @@ -24,7 +24,7 @@ function has_ortho_opt(expr) false end -function check_ortho_opt(expr, A, B; expected_ortho = false) +function check_ortho_opt(expr, A, B; expected_ortho = true) current = SU.Code.cse(expr) toexpr(current) From 7e67eae034d9c7c4a99e3a162e7eb5344bf4b214 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Tue, 17 Feb 2026 07:33:46 +0000 Subject: [PATCH 30/33] chore: rm debug code --- src/ldiv_opt.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ldiv_opt.jl b/src/ldiv_opt.jl index dfc3977..7f571ad 100644 --- a/src/ldiv_opt.jl +++ b/src/ldiv_opt.jl @@ -27,7 +27,6 @@ function detect_ldiv_pattern(expr::Code.Let, state) all_arrays || return false A, B = args - @show validate_ldiv_shapes(A, B) validate_ldiv_shapes(A, B) end @@ -51,7 +50,6 @@ For A \\ B: - B must have n rows: (n, m) or (n,) """ function validate_ldiv_shapes(A, B) - return true A_shape = shape(A) B_shape = shape(B) From 6a85912ed5c6268564b47b76d829757518b47491 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Tue, 17 Feb 2026 09:22:56 +0000 Subject: [PATCH 31/33] test: handle rotation matrix appropriate --- test/multiple.jl | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/test/multiple.jl b/test/multiple.jl index 8599ff5..088f6f3 100644 --- a/test/multiple.jl +++ b/test/multiple.jl @@ -6,6 +6,8 @@ using LinearAlgebra using Symbolics using Test +using Rotations + function test_codegen(expr, rules, args...) current = SU.Code.cse(expr) optimized = SU.Code.apply_optimization_rules(current, SU.Code.CSEState(), rules) @@ -17,8 +19,13 @@ function test_codegen(expr, rules, args...) optimized_f = eval(toexpr(optimized_expr)) N = 3 - # test_args = collect(randn(N, N) for _ in 1:length(args)) - test_args = [rand(size(x)...) for x in args] + test_args = map(args) do arg + if getmetadata(arg, SC.IsOrthogonal, false) == true + RotXYZ((rand([0,1]) for x in 1:size(arg, 1))...) + else + rand(size(arg)...) + end + end current_res = @invokelatest current_f(test_args...) optimized_res = @invokelatest optimized_f(test_args...) @@ -44,5 +51,5 @@ end P = A \ B # expr3 = P + C * inv(Ro) expr3 = tril(P) + C * inv(Ro) - test_codegen(expr3, [SC.LDIV_RULE, SC.MATMUL_ADD_RULE, SC.ORTHO_INV_RULE], A, B, C, R) + test_codegen(expr3, [SC.LDIV_RULE, SC.MATMUL_ADD_RULE, SC.ORTHO_INV_RULE], A, B, C, Ro) end From 0552c65e02d75b7853aee8a5716e864f8418f149 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Tue, 17 Feb 2026 09:26:19 +0000 Subject: [PATCH 32/33] chore: rm IfElse red --- src/SymbolicCompilerPasses.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SymbolicCompilerPasses.jl b/src/SymbolicCompilerPasses.jl index 03e7666..2d56c5e 100644 --- a/src/SymbolicCompilerPasses.jl +++ b/src/SymbolicCompilerPasses.jl @@ -6,7 +6,7 @@ using SymbolicUtils import SymbolicUtils: symtype, vartype, Sym, BasicSymbolic, Term, iscall, operation, arguments, maketerm, Const, shape, isterm, unwrap, is_function_symbolic, is_called_function_symbolic, getname, Unknown, search_variables!, search_variables import SymbolicUtils.Code: Code, OptimizationRule, substitute_in_ir, apply_optimization_rules, AbstractMatched, - Assignment, CSEState, lhs, rhs, apply_substitution_map, IfElse, issym, isterm, toexpr, + Assignment, CSEState, lhs, rhs, apply_substitution_map, issym, isterm, toexpr, _is_array_of_symbolics, MakeArray, shape import SymbolicUtils: search_variables, search_variables! using StaticArrays From 34d5fad390ec11615c45b153aefc7b086e9c41cb Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Tue, 17 Feb 2026 09:30:18 +0000 Subject: [PATCH 33/33] chore: log only once --- ext/SCPLinearSolveExt/SCPLinearSolveExt.jl | 4 ++-- src/ldiv_opt.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl b/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl index 95fcb49..d5b3f85 100644 --- a/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl +++ b/ext/SCPLinearSolveExt/SCPLinearSolveExt.jl @@ -19,7 +19,7 @@ function get_linear_prob(A::TA, B::TB) where {TA, TB} get!(LINSOLVEPROB_CACHE, A) do prob = LinearSolve.LinearProblem(A, B) init(prob) - end::Base.promote_op(init, Tuple{Base.promote_op(LinearSolve.LinearProblem, Tuple{TA, TB})}) + end# ::Base.promote_op(init, Tuple{Base.promote_op(LinearSolve.LinearProblem, Tuple{TA, TB})}) end function linear_solve(A, B) @@ -45,7 +45,7 @@ end function ldiv_transformation(safe_matches, ::Val{true}) @info "Using LinearSolve.jl for in-place backsolve optimizations. - In order to opt-out of using LinearSolve, set SymbolicCompilerPasses.LINEARSOLVE_LIB[] = false." maxlog=Inf + In order to opt-out of using LinearSolve, set SymbolicCompilerPasses.LINEARSOLVE_LIB[] = false." maxlog=1 # Build transformation transformations = Dict{Int, Code.Assignment}() diff --git a/src/ldiv_opt.jl b/src/ldiv_opt.jl index 7f571ad..fc98683 100644 --- a/src/ldiv_opt.jl +++ b/src/ldiv_opt.jl @@ -161,7 +161,7 @@ ldiv_transformation(x, ::Nothing) = ldiv_transformation(x, Val(false)) function ldiv_transformation(safe_matches, ::Val{false}) @warn "Backsolve may be sped up by adding LinearSolve.jl. In order to enable this optimization, add LinearSolve.jl to your environment. - To opt-out of using LinearSolve, set SymbolicCompilerPasses.LINEARSOLVE_LIB[] = false." maxlog=Inf + To opt-out of using LinearSolve, set SymbolicCompilerPasses.LINEARSOLVE_LIB[] = false." maxlog=1 # Build transformation transformations = Dict{Int, Code.Assignment}()