From 76bf09d48f24a955962fb958592e7768381d356d Mon Sep 17 00:00:00 2001 From: contradict Date: Wed, 4 Sep 2024 14:48:15 -0700 Subject: [PATCH 01/30] Handle `BasicSymbolic` expressions in test The testing expression generator generates expressions of type `Symbolics.BasicSymbolic{Number}` when all the selected variables are of that type (generated by `@syms` instead of `@variables`). Add a method to wrap these expressions with a `Num` before checking for cancelation. --- test/semipoly.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/semipoly.jl b/test/semipoly.jl index 5a13113ec..ed9313cdb 100644 --- a/test/semipoly.jl +++ b/test/semipoly.jl @@ -426,6 +426,10 @@ end const components = [2, a, b, c, x, y, z, (1+x), (1+y)^2, z*y, z*x] +function verify(t::Symbolics.BasicSymbolic{Number}, d, wrt, nl) + verify(Num(t), d, wrt, nl) +end + function verify(t, d, wrt, nl) try iszero(t - (isempty(d) ? nl : sum(k*v for (k, v) in d) + nl)) From f285780bf1e63e07c5d4ff1250e8d66234510957 Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Fri, 6 Sep 2024 11:11:12 -0400 Subject: [PATCH 02/30] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index ddec70195..71f9b6375 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Symbolics" uuid = "0c5d862f-8b57-4792-8d23-62f2024744c7" authors = ["Shashi Gowda "] -version = "6.6.0" +version = "6.6.1" [deps] ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" From a5a56cc5c4d885bd9c7e4b0c206b611cf21d66ff Mon Sep 17 00:00:00 2001 From: n0rbed Date: Fri, 6 Sep 2024 12:41:11 +0300 Subject: [PATCH 03/30] simplified acos(0/1), asin(0/1) and anything + 0 --- src/solver/postprocess.jl | 41 +++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/solver/postprocess.jl b/src/solver/postprocess.jl index ff72fdf3f..afb87c263 100644 --- a/src/solver/postprocess.jl +++ b/src/solver/postprocess.jl @@ -1,4 +1,3 @@ - # Alex: make sure `Num`s are not processed here as they'd break it. _postprocess_root(x) = x @@ -32,12 +31,12 @@ function _postprocess_root(x::SymbolicUtils.BasicSymbolic) !iscall(x) && return x x = Symbolics.term(operation(x), map(_postprocess_root, arguments(x))...) + oper = operation(x) # sqrt(0), cbrt(0) => 0 # sqrt(1), cbrt(1) => 1 - if iscall(x) && - (operation(x) === sqrt || operation(x) === cbrt || operation(x) === ssqrt || - operation(x) === scbrt) + if (oper === sqrt || oper === cbrt || oper === ssqrt || + oper === scbrt) arg = arguments(x)[1] if isequal(arg, 0) || isequal(arg, 1) return arg @@ -45,17 +44,17 @@ function _postprocess_root(x::SymbolicUtils.BasicSymbolic) end # (X)^0 => 1 - if iscall(x) && operation(x) === (^) && isequal(arguments(x)[2], 0) + if oper === (^) && isequal(arguments(x)[2], 0) return 1 end # (X)^1 => X - if iscall(x) && operation(x) === (^) && isequal(arguments(x)[2], 1) + if oper === (^) && isequal(arguments(x)[2], 1) return arguments(x)[1] end # sqrt((N / D)^2 * M) => N / D * sqrt(M) - if iscall(x) && (operation(x) === sqrt || operation(x) === ssqrt) + if (oper === sqrt || oper === ssqrt) function squarefree_decomp(x::Integer) square, squarefree = big(1), big(1) for (p, d) in collect(Primes.factor(abs(x))) @@ -90,7 +89,7 @@ function _postprocess_root(x::SymbolicUtils.BasicSymbolic) end # (sqrt(N))^M => N^div(M, 2)*sqrt(N)^(mod(M, 2)) - if iscall(x) && operation(x) === (^) + if oper === (^) arg1, arg2 = arguments(x) if iscall(arg1) && (operation(arg1) === sqrt || operation(arg1) === ssqrt) if arg2 isa Integer @@ -105,6 +104,32 @@ function _postprocess_root(x::SymbolicUtils.BasicSymbolic) end end + arg = arguments(x)[1] + if oper === acos + if arg === 0 + return Symbolics.term(/, pi, 2) + elseif arg === 1 + return 0 + end + elseif oper === asin + if arg === 0 + return 0 + elseif arg === 1 + return Symbolics.term(/, pi, 2) + end + end + + if oper === (+) + args = arguments(x) + for arg in args + if isequal(arg, 0) + after_removing = setdiff(args, arg) + isone(length(after_removing)) && return after_removing[1] + return Symbolics.term(+, after_removing) + end + end + end + return x end From d072dae9c7975bb4395a5c3d783abb202ed29084 Mon Sep 17 00:00:00 2001 From: n0rbed Date: Sat, 7 Sep 2024 02:29:16 +0300 Subject: [PATCH 04/30] 2pi*N -> pi*N --- src/solver/ia_main.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/ia_main.jl b/src/solver/ia_main.jl index c1f998a4f..8f83ca02b 100644 --- a/src/solver/ia_main.jl +++ b/src/solver/ia_main.jl @@ -123,7 +123,7 @@ function isolate(lhs, var; warns=true, conditions=[]) new_var = (@variables $new_var)[1] rhs = map( sol -> term(rev_oper[oper], sol) + - term(*, Base.MathConstants.pi, 2 * new_var), + term(*, Base.MathConstants.pi, new_var), rhs) @info string(new_var) * " ϵ" * " Ζ" From 318034edbda5db98847cdfa7caebee64e24343d4 Mon Sep 17 00:00:00 2001 From: n0rbed Date: Sat, 7 Sep 2024 07:28:30 +0300 Subject: [PATCH 05/30] acos, asin simplification rules --- src/solver/attract.jl | 6 ++---- src/solver/postprocess.jl | 35 ++++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/solver/attract.jl b/src/solver/attract.jl index 027f85a99..6d03778e8 100644 --- a/src/solver/attract.jl +++ b/src/solver/attract.jl @@ -197,10 +197,8 @@ function attract_trig(lhs, var) r_trig = [@acrule(sin(~x::(contains_var))^2 + cos(~x::(contains_var))^2=>one(~x)) @acrule(sin(~x::(contains_var))^2 + -1=>-1 * cos(~x)^2) @acrule(cos(~x::(contains_var))^2 + -1=>-1 * sin(~x)^2) - @acrule(cos(~x::(contains_var))^2 + -1 * sin(~x::(contains_var))^2=>cos(2 * - ~x)) - @acrule(sin(~x::(contains_var))^2 + -1 * cos(~x::(contains_var))^2=>-cos(2 * - ~x)) + @acrule(cos(~x::(contains_var))^2 + -1 * sin(~x::(contains_var))^2=>cos(2*~x)) + @acrule(sin(~x::(contains_var))^2 + -1 * cos(~x::(contains_var))^2=>-cos(2*~x)) @acrule(cos(~x::(contains_var)) * sin(~x::(contains_var))=>sin(2 * ~x) / 2) @acrule(tan(~x::(contains_var))^2 + -1 * sec(~x::(contains_var))^2=>one(~x)) @acrule(-1 * tan(~x::(contains_var))^2 + sec(~x::(contains_var))^2=>one(~x)) diff --git a/src/solver/postprocess.jl b/src/solver/postprocess.jl index afb87c263..4c2f5249d 100644 --- a/src/solver/postprocess.jl +++ b/src/solver/postprocess.jl @@ -104,21 +104,38 @@ function _postprocess_root(x::SymbolicUtils.BasicSymbolic) end end - arg = arguments(x)[1] + isnegone(x) = isequal(-1, expand(x)) + ishalf(x) = isequal(1/2, expand(x)) + isneghalf(x) = isequal(-1/2, expand(x)) + symiszero(x) = isequal(0, expand(x)) + symisone(x) = isequal(1, expand(x)) + acos_rules = [(@rule acos(~x::symiszero) => Symbolics.term(/, pi, 2)), + (@rule acos(~x::symisone) => 0), + (@rule acos(~x::isnegone) => Symbolics.term(*, pi)), + (@rule acos(~x::ishalf) => Symbolics.term(/, pi, 3)), + (@rule acos(~x::isneghalf) => Symbolics.term(/, Symbolics.term(*,2,pi), 3)) + ] + + asin_rules = [(@rule asin(~x::symiszero) => 0), + (@rule asin(~x::symisone) => Symbolics.term(/, pi, 2)), + (@rule asin(~x::isnegone) => -Symbolics.term(/, pi, 2)), + (@rule asin(~x::ishalf) => Symbolics.term(/, pi, 6)), + (@rule asin(~x::isneghalf) => Symbolics.term(/, Symbolics.term(*,-1,pi), 6)) + ] + if oper === acos - if arg === 0 - return Symbolics.term(/, pi, 2) - elseif arg === 1 - return 0 + for r in acos_rules + after_r = r(x) + !isnothing(after_r) && return after_r end elseif oper === asin - if arg === 0 - return 0 - elseif arg === 1 - return Symbolics.term(/, pi, 2) + for r in asin_rules + after_r = r(x) + !isnothing(after_r) && return after_r end end + if oper === (+) args = arguments(x) for arg in args From 14e473e37554f8996446e6c61841c26efe6199ec Mon Sep 17 00:00:00 2001 From: n0rbed Date: Sat, 7 Sep 2024 08:07:42 +0300 Subject: [PATCH 06/30] added complex type --- src/solver/solve_helpers.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/solve_helpers.jl b/src/solver/solve_helpers.jl index f2420969d..7496f65f6 100644 --- a/src/solver/solve_helpers.jl +++ b/src/solver/solve_helpers.jl @@ -78,7 +78,7 @@ function check_expr_validity(expr) valid_type = false if type_expr <: Number || type_expr == Num || type_expr == SymbolicUtils.BasicSymbolic{Real} || - type_expr == Complex{Num} || type_expr == ComplexTerm{Real} + type_expr == Complex{Num} || type_expr == ComplexTerm{Real} || type_expr == SymbolicUtils.BasicSymbolic{Complex{Real}} valid_type = true end iscall(unwrap(expr)) && @assert !hasderiv(unwrap(expr)) "Differential equations are not currently supported" From e4474cc85b022e758a0296c3b680c692dc7e0287 Mon Sep 17 00:00:00 2001 From: n0rbed Date: Sun, 8 Sep 2024 03:44:29 +0300 Subject: [PATCH 07/30] alternative solution --- ext/SymbolicsGroebnerExt.jl | 4 ---- ext/SymbolicsNemoExt.jl | 6 ++++++ src/solver/postprocess.jl | 43 ++++++++++++++----------------------- 3 files changed, 22 insertions(+), 31 deletions(-) diff --git a/ext/SymbolicsGroebnerExt.jl b/ext/SymbolicsGroebnerExt.jl index ebf5174a5..66d069060 100644 --- a/ext/SymbolicsGroebnerExt.jl +++ b/ext/SymbolicsGroebnerExt.jl @@ -320,13 +320,9 @@ end # Helps with precompilation time PrecompileTools.@setup_workload begin @variables a b c x y z - equation1 = a*log(x)^b + c ~ 0 - equation_actually_polynomial = sin(x^2 +1)^2 + sin(x^2 + 1) + 3 simple_linear_equations = [x - y, y + 2z] equations_intersect_sphere_line = [x^2 + y^2 + z^2 - 9, x - 2y + 3, y - z] PrecompileTools.@compile_workload begin - symbolic_solve(equation1, x) - symbolic_solve(equation_actually_polynomial) symbolic_solve(simple_linear_equations, [x, y], warns=false) symbolic_solve(equations_intersect_sphere_line, [x, y, z], warns=false) end diff --git a/ext/SymbolicsNemoExt.jl b/ext/SymbolicsNemoExt.jl index 16fe2414e..9c9f31db1 100644 --- a/ext/SymbolicsNemoExt.jl +++ b/ext/SymbolicsNemoExt.jl @@ -61,7 +61,13 @@ end PrecompileTools.@setup_workload begin @variables a b c x y z expr_with_params = expand((x + b)*(x^2 + 2x + 1)*(x^2 - a)) + equation1 = a*log(x)^b + c ~ 0 + equation_polynomial = 9^x + 3^x + 2 + exp_eq = 5*2^(x+1) + 7^(x+3) PrecompileTools.@compile_workload begin + symbolic_solve(equation1, x) + symbolic_solve(equation_polynomial, x) + symbolic_solve(exp_eq) symbolic_solve(expr_with_params, x, dropmultiplicity=false) symbolic_solve(x^10 - a^10, x, dropmultiplicity=false) end diff --git a/src/solver/postprocess.jl b/src/solver/postprocess.jl index 4c2f5249d..2a0ce1c85 100644 --- a/src/solver/postprocess.jl +++ b/src/solver/postprocess.jl @@ -104,38 +104,27 @@ function _postprocess_root(x::SymbolicUtils.BasicSymbolic) end end - isnegone(x) = isequal(-1, expand(x)) - ishalf(x) = isequal(1/2, expand(x)) - isneghalf(x) = isequal(-1/2, expand(x)) - symiszero(x) = isequal(0, expand(x)) - symisone(x) = isequal(1, expand(x)) - acos_rules = [(@rule acos(~x::symiszero) => Symbolics.term(/, pi, 2)), - (@rule acos(~x::symisone) => 0), - (@rule acos(~x::isnegone) => Symbolics.term(*, pi)), - (@rule acos(~x::ishalf) => Symbolics.term(/, pi, 3)), - (@rule acos(~x::isneghalf) => Symbolics.term(/, Symbolics.term(*,2,pi), 3)) + opers = [acos, asin, atan] + exacts = [0, Symbolics.term(*, pi), Symbolics.term(/,pi,3), + Symbolics.term(/, pi, 2), + Symbolics.term(/, Symbolics.term(*, 2, pi), 3), + Symbolics.term(/, pi, 6), + Symbolics.term(/, Symbolics.term(*, 5, pi), 6), + Symbolics.term(/, pi, 4) ] - asin_rules = [(@rule asin(~x::symiszero) => 0), - (@rule asin(~x::symisone) => Symbolics.term(/, pi, 2)), - (@rule asin(~x::isnegone) => -Symbolics.term(/, pi, 2)), - (@rule asin(~x::ishalf) => Symbolics.term(/, pi, 6)), - (@rule asin(~x::isneghalf) => Symbolics.term(/, Symbolics.term(*,-1,pi), 6)) - ] - - if oper === acos - for r in acos_rules - after_r = r(x) - !isnothing(after_r) && return after_r - end - elseif oper === asin - for r in asin_rules - after_r = r(x) - !isnothing(after_r) && return after_r + if any(isequal(oper, o) for o in opers) && isempty(Symbolics.get_variables(x)) + val = eval(Symbolics.toexpr(x)) + for i in eachindex(exacts) + exact_val = eval(Symbolics.toexpr(exacts[i])) + if isapprox(exact_val, val, atol=1e-6) + return exacts[i] + elseif isapprox(-exact_val, val, atol=1e-6) + return -exacts[i] + end end end - if oper === (+) args = arguments(x) for arg in args From b9cd1f51461790d037a658277f325d73a96d076e Mon Sep 17 00:00:00 2001 From: n0rbed Date: Sun, 8 Sep 2024 09:11:37 +0300 Subject: [PATCH 08/30] function --- src/solver/postprocess.jl | 52 ++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/solver/postprocess.jl b/src/solver/postprocess.jl index 2a0ce1c85..6236573f9 100644 --- a/src/solver/postprocess.jl +++ b/src/solver/postprocess.jl @@ -104,26 +104,8 @@ function _postprocess_root(x::SymbolicUtils.BasicSymbolic) end end - opers = [acos, asin, atan] - exacts = [0, Symbolics.term(*, pi), Symbolics.term(/,pi,3), - Symbolics.term(/, pi, 2), - Symbolics.term(/, Symbolics.term(*, 2, pi), 3), - Symbolics.term(/, pi, 6), - Symbolics.term(/, Symbolics.term(*, 5, pi), 6), - Symbolics.term(/, pi, 4) - ] - - if any(isequal(oper, o) for o in opers) && isempty(Symbolics.get_variables(x)) - val = eval(Symbolics.toexpr(x)) - for i in eachindex(exacts) - exact_val = eval(Symbolics.toexpr(exacts[i])) - if isapprox(exact_val, val, atol=1e-6) - return exacts[i] - elseif isapprox(-exact_val, val, atol=1e-6) - return -exacts[i] - end - end - end + trig_simplified = check_trig_consts(x) + !isequal(trig_simplified, x) && return trig_simplified if oper === (+) args = arguments(x) @@ -153,3 +135,33 @@ function postprocess_root(x) end x # unreachable end + +function check_trig_consts(x) + !iscall(x) && return x + + oper = operation(x) + inv_opers = [asin, acos, atan] + inv_exacts = [0, Symbolics.term(*, pi), + Symbolics.term(/,pi,3), + Symbolics.term(/, pi, 2), + Symbolics.term(/, Symbolics.term(*, 2, pi), 3), + Symbolics.term(/, pi, 6), + Symbolics.term(/, Symbolics.term(*, 5, pi), 6), + Symbolics.term(/, pi, 4) + ] + + if any(isequal(oper, o) for o in inv_opers) && isempty(Symbolics.get_variables(x)) + val = eval(Symbolics.toexpr(x)) + for i in eachindex(inv_exacts) + exact_val = eval(Symbolics.toexpr(inv_exacts[i])) + if isapprox(exact_val, val, atol=1e-6) + return inv_exacts[i] + elseif isapprox(-exact_val, val, atol=1e-6) + return -inv_exacts[i] + end + end + end + + # add [sin, cos, tan] simplifications in the future? + return x +end From d352d8a5c82a2cb7dccace1cb517328c4c942cbd Mon Sep 17 00:00:00 2001 From: n0rbed Date: Mon, 9 Sep 2024 03:26:16 +0300 Subject: [PATCH 09/30] eval -> symbolic_to_float --- src/solver/postprocess.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solver/postprocess.jl b/src/solver/postprocess.jl index 6236573f9..741c36dc4 100644 --- a/src/solver/postprocess.jl +++ b/src/solver/postprocess.jl @@ -151,9 +151,9 @@ function check_trig_consts(x) ] if any(isequal(oper, o) for o in inv_opers) && isempty(Symbolics.get_variables(x)) - val = eval(Symbolics.toexpr(x)) + val = Symbolics.symbolic_to_float(x) for i in eachindex(inv_exacts) - exact_val = eval(Symbolics.toexpr(inv_exacts[i])) + exact_val = Symbolics.symbolic_to_float(inv_exacts[i]) if isapprox(exact_val, val, atol=1e-6) return inv_exacts[i] elseif isapprox(-exact_val, val, atol=1e-6) From f0ba7f7c3f6d5ac6c6375005e86a68a6ebfb4074 Mon Sep 17 00:00:00 2001 From: n0rbed Date: Thu, 12 Sep 2024 19:00:01 +0300 Subject: [PATCH 10/30] fixed_issue --- src/solver/main.jl | 22 ++++++++++++++++------ src/solver/preprocess.jl | 19 +++++++++++++------ test/solver.jl | 5 ++--- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/solver/main.jl b/src/solver/main.jl index e9d3f3aeb..e6671e1f5 100644 --- a/src/solver/main.jl +++ b/src/solver/main.jl @@ -195,7 +195,7 @@ function symbolic_solve(expr, x::T; dropmultiplicity = true, warns = true) where for e in expr for var in x if !check_poly_inunivar(e, var) - warns && @warn("This system can not be currently solved by solve.") + warns && @warn("This system can not be currently solved by `symbolic_solve`.") return nothing end end @@ -276,7 +276,7 @@ function solve_univar(expression, x; dropmultiplicity=true) end end - subs, filtered_expr = filter_poly(expression, x) + subs, filtered_expr, assumptions = filter_poly(expression, x, assum=true) coeffs, constant = polynomial_coeffs(filtered_expr, [x]) degree = sdegree(coeffs, x) @@ -296,18 +296,28 @@ function solve_univar(expression, x; dropmultiplicity=true) append!(arr_roots, og_arr_roots) end end - - return arr_roots end if length(factors) != 1 - for factor in factors_subbed - roots = solve_univar(factor, x, dropmultiplicity = dropmultiplicity) + for i in eachindex(factors_subbed) + if !any(isequal(x, var) for var in get_variables(factors[i])) + continue + end + roots = solve_univar(factors_subbed[i], x, dropmultiplicity = dropmultiplicity) append!(arr_roots, roots) end end + for i in reverse(eachindex(arr_roots)) + for j in eachindex(assumptions) + if isequal(substitute(assumptions[j], Dict(x=>arr_roots[i])), 0) + deleteat!(arr_roots, i) + end + end + end + if isequal(arr_roots, []) + @assert check_polynomial(expression) "This expression could not be solved by `symbolic_solve`." return [RootsOf(wrap(expression), wrap(x))] end diff --git a/src/solver/preprocess.jl b/src/solver/preprocess.jl index cd586edb3..2e0e238af 100644 --- a/src/solver/preprocess.jl +++ b/src/solver/preprocess.jl @@ -40,16 +40,19 @@ function clean_f(filtered_expr, var, subs) unwrapped_f = unwrap(filtered_expr) !iscall(unwrapped_f) && return filtered_expr oper = operation(unwrapped_f) + assumptions = [] if oper === (/) args = arguments(unwrapped_f) if any(isequal(var, x) for x in get_variables(args[2])) - return filtered_expr + filtered_expr = expand(args[1] * args[2]) + push!(assumptions, substitute(args[2], subs, fold=false)) + return filtered_expr, assumptions end filtered_expr = args[1] @info "Assuming $(substitute(args[2], subs, fold=false) != 0)" end - return filtered_expr + return filtered_expr, assumptions end """ @@ -238,15 +241,17 @@ julia> filter_poly((x+1)*term(log, 3), x) (Dict{Any, Any}(var"##247" => log(3)), var"##247"*(1 + x)) ``` """ -function filter_poly(og_expr, var) +function filter_poly(og_expr, var; assum=false) expr = deepcopy(og_expr) expr = unwrap(expr) vars = get_variables(expr) # handle edge cases if !isequal(vars, []) && isequal(vars[1], expr) + assum && return Dict{Any, Any}(), expr, [] return (Dict{Any, Any}(), expr) elseif isequal(vars, []) + assum && return filter_stuff(expr), [] return filter_stuff(expr) end @@ -256,14 +261,16 @@ function filter_poly(og_expr, var) # reassemble expr to avoid variables remembering original values issue and clean args = arguments(expr) oper = operation(expr) - new_expr = clean_f(term(oper, args...), var, subs) + new_expr, assumptions = clean_f(term(oper, args...), var, subs) + assum && return subs, new_expr, assumptions return subs, new_expr end -function filter_poly(og_expr) + +function filter_poly(og_expr; assum=false) new_var = gensym() new_var = (@variables $(new_var))[1] - return filter_poly(og_expr, new_var) + return filter_poly(og_expr, new_var; assum=assum) end diff --git a/test/solver.jl b/test/solver.jl index 7a39c8924..9eb2e8ec8 100644 --- a/test/solver.jl +++ b/test/solver.jl @@ -57,9 +57,8 @@ end @variables x y z a b c d e @testset "Invalid input" begin - @test_throws AssertionError Symbolics.get_roots(x, x^2) - @test_throws AssertionError Symbolics.get_roots(x^3 + sin(x), x) - @test_throws AssertionError Symbolics.get_roots(1/x, x) + @test_throws AssertionError symbolic_solve(x, x^2) + @test_throws AssertionError symbolic_solve(1/x, x) end @testset "Deg 1 univar" begin From 080d19f29b377e0a14a24ecb4b81f7b017ff80cc Mon Sep 17 00:00:00 2001 From: n0rbed Date: Thu, 12 Sep 2024 19:11:46 +0300 Subject: [PATCH 11/30] added test --- test/solver.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/solver.jl b/test/solver.jl index 9eb2e8ec8..58e5feb26 100644 --- a/test/solver.jl +++ b/test/solver.jl @@ -61,6 +61,12 @@ end @test_throws AssertionError symbolic_solve(1/x, x) end +@testset "Nice univar cases" begin + found_roots = symbolic_solve(1/x^2 ~ 1/y^2 - 2/x^3 * (x-y), x) + known_roots = Symbolics.unwrap.([y, -2y]) + @test isequal(found_roots, known_roots) +end + @testset "Deg 1 univar" begin @test isequal(symbolic_solve(x+1, x), [-1]) From bc014a0c3afc6e6b0c6d9eed246dc7a29451ffa0 Mon Sep 17 00:00:00 2001 From: n0rbed Date: Fri, 13 Sep 2024 12:32:25 +0300 Subject: [PATCH 12/30] fixed spelling --- src/solver/main.jl | 2 +- src/solver/preprocess.jl | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/solver/main.jl b/src/solver/main.jl index e6671e1f5..7254ea152 100644 --- a/src/solver/main.jl +++ b/src/solver/main.jl @@ -276,7 +276,7 @@ function solve_univar(expression, x; dropmultiplicity=true) end end - subs, filtered_expr, assumptions = filter_poly(expression, x, assum=true) + subs, filtered_expr, assumptions = filter_poly(expression, x, assumptions=true) coeffs, constant = polynomial_coeffs(filtered_expr, [x]) degree = sdegree(coeffs, x) diff --git a/src/solver/preprocess.jl b/src/solver/preprocess.jl index 2e0e238af..8b0dc5f81 100644 --- a/src/solver/preprocess.jl +++ b/src/solver/preprocess.jl @@ -241,17 +241,17 @@ julia> filter_poly((x+1)*term(log, 3), x) (Dict{Any, Any}(var"##247" => log(3)), var"##247"*(1 + x)) ``` """ -function filter_poly(og_expr, var; assum=false) +function filter_poly(og_expr, var; assumptions=false) expr = deepcopy(og_expr) expr = unwrap(expr) vars = get_variables(expr) # handle edge cases if !isequal(vars, []) && isequal(vars[1], expr) - assum && return Dict{Any, Any}(), expr, [] + assumptions && return Dict{Any, Any}(), expr, [] return (Dict{Any, Any}(), expr) elseif isequal(vars, []) - assum && return filter_stuff(expr), [] + assumptions && return filter_stuff(expr), [] return filter_stuff(expr) end @@ -261,16 +261,16 @@ function filter_poly(og_expr, var; assum=false) # reassemble expr to avoid variables remembering original values issue and clean args = arguments(expr) oper = operation(expr) - new_expr, assumptions = clean_f(term(oper, args...), var, subs) + new_expr, assum_array = clean_f(term(oper, args...), var, subs) - assum && return subs, new_expr, assumptions + assumptions && return subs, new_expr, assum_array return subs, new_expr end -function filter_poly(og_expr; assum=false) +function filter_poly(og_expr; assumptions=false) new_var = gensym() new_var = (@variables $(new_var))[1] - return filter_poly(og_expr, new_var; assum=assum) + return filter_poly(og_expr, new_var; assumptions=assumptions) end From 4a5b616d543aa3d24824196bfdf8e6581131c788 Mon Sep 17 00:00:00 2001 From: n0rbed Date: Fri, 13 Sep 2024 13:04:07 +0300 Subject: [PATCH 13/30] docs and const arr --- src/solver/postprocess.jl | 48 +++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/solver/postprocess.jl b/src/solver/postprocess.jl index 741c36dc4..4dce04fc6 100644 --- a/src/solver/postprocess.jl +++ b/src/solver/postprocess.jl @@ -104,8 +104,7 @@ function _postprocess_root(x::SymbolicUtils.BasicSymbolic) end end - trig_simplified = check_trig_consts(x) - !isequal(trig_simplified, x) && return trig_simplified + x = convert_consts(x) if oper === (+) args = arguments(x) @@ -136,28 +135,49 @@ function postprocess_root(x) x # unreachable end -function check_trig_consts(x) - !iscall(x) && return x - oper = operation(x) - inv_opers = [asin, acos, atan] - inv_exacts = [0, Symbolics.term(*, pi), +inv_exacts = [0, Symbolics.term(*, pi), Symbolics.term(/,pi,3), Symbolics.term(/, pi, 2), Symbolics.term(/, Symbolics.term(*, 2, pi), 3), Symbolics.term(/, pi, 6), Symbolics.term(/, Symbolics.term(*, 5, pi), 6), Symbolics.term(/, pi, 4) - ] +] +inv_evald = Symbolics.symbolic_to_float.(inv_exacts) + +const inv_pairs = collect(zip(inv_exacts, inv_evald)) +""" + function convert_consts(x) +This function takes BasicSymbolic terms as input (x) and attempts +to simplify these basic symbolic terms using known values. +Currently, this function only supports inverse trignometric functions. + +## Examples +```jldoctest +julia> Symbolics.convert_consts(Symbolics.term(acos, 0)) +π / 2 + +julia> Symbolics.convert_consts(Symbolics.term(atan, 0)) +0 + +julia> Symbolics.convert_consts(Symbolics.term(atan, 1)) +π / 4 +``` +""" +function convert_consts(x) + !iscall(x) && return x + + oper = operation(x) + inv_opers = [asin, acos, atan] if any(isequal(oper, o) for o in inv_opers) && isempty(Symbolics.get_variables(x)) val = Symbolics.symbolic_to_float(x) - for i in eachindex(inv_exacts) - exact_val = Symbolics.symbolic_to_float(inv_exacts[i]) - if isapprox(exact_val, val, atol=1e-6) - return inv_exacts[i] - elseif isapprox(-exact_val, val, atol=1e-6) - return -inv_exacts[i] + for (exact, evald) in inv_pairs + if isapprox(evald, val) + return exact + elseif isapprox(-evald, val) + return -exact end end end From eb664afd8207eba6952a270744e9716538aaab9e Mon Sep 17 00:00:00 2001 From: n0rbed Date: Fri, 13 Sep 2024 13:06:15 +0300 Subject: [PATCH 14/30] spelling mistake --- src/solver/postprocess.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/postprocess.jl b/src/solver/postprocess.jl index 4dce04fc6..4764690aa 100644 --- a/src/solver/postprocess.jl +++ b/src/solver/postprocess.jl @@ -151,7 +151,7 @@ const inv_pairs = collect(zip(inv_exacts, inv_evald)) function convert_consts(x) This function takes BasicSymbolic terms as input (x) and attempts to simplify these basic symbolic terms using known values. -Currently, this function only supports inverse trignometric functions. +Currently, this function only supports inverse trigonometric functions. ## Examples ```jldoctest From 8cb25a8c7cdd61460fc53cf714c2aa12788c62a3 Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Sat, 14 Sep 2024 16:24:52 +0200 Subject: [PATCH 15/30] Update .typos.toml --- .typos.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.typos.toml b/.typos.toml index 66edbcbaf..253ed3385 100644 --- a/.typos.toml +++ b/.typos.toml @@ -1,4 +1,5 @@ [default.extend-words] numer = "numer" Commun = "Commun" -nd = "nd" \ No newline at end of file +nd = "nd" +assum = "assum" From 86dc9567b9acceb6989a27b9f12f007f4a47cc99 Mon Sep 17 00:00:00 2001 From: Aayush Sabharwal Date: Fri, 13 Sep 2024 16:50:31 +0530 Subject: [PATCH 16/30] feat: add support for typed function symbolics --- src/variable.jl | 100 +++++++++++++++++++++++++++++++------ test/macro.jl | 123 ++++++++++++++++++++++++++++++++++++++++++++-- test/overloads.jl | 2 +- 3 files changed, 206 insertions(+), 19 deletions(-) diff --git a/src/variable.jl b/src/variable.jl index a8845171b..c73c423cb 100644 --- a/src/variable.jl +++ b/src/variable.jl @@ -101,6 +101,11 @@ function _parse_vars(macroname, type, x, transform=identity) # x = 1, [connect = flow; unit = u"m^3/s"] if Meta.isexpr(v, :(=)) v, val = v.args + # defaults with metadata for function variables + if Meta.isexpr(val, :block) + Base.remove_linenums!(val) + val = only(val.args) + end if Meta.isexpr(val, :tuple) && length(val.args) == 2 && isoption(val.args[2]) options = val.args[2].args val = val.args[1] @@ -124,7 +129,7 @@ function _parse_vars(macroname, type, x, transform=identity) isruntime, v = unwrap_runtime_var(v) iscall = Meta.isexpr(v, :call) isarray = Meta.isexpr(v, :ref) - if iscall && Meta.isexpr(v.args[1], :ref) + if iscall && Meta.isexpr(v.args[1], :ref) && !call_args_are_function(map(last∘unwrap_runtime_var, @view v.args[2:end])) @warn("The variable syntax $v is deprecated. Use $(Expr(:ref, Expr(:call, v.args[1].args[1], v.args[2]), v.args[1].args[2:end]...)) instead. The former creates an array of functions, while the latter creates an array valued function. The deprecated syntax will cause an error in the next major release of Symbolics. @@ -155,35 +160,54 @@ function _parse_vars(macroname, type, x, transform=identity) return ex end +call_args_are_function(_) = false +function call_args_are_function(call_args::AbstractArray) + !isempty(call_args) && (call_args[end] == :(..) || all(Base.Fix2(Meta.isexpr, :(::)), call_args)) +end + function construct_dep_array_vars(macroname, lhs, type, call_args, indices, val, prop, transform, isruntime) ndim = :($length(($(indices...),))) - vname = !isruntime ? Meta.quot(lhs) : lhs - if call_args[1] == :.. - ex = :($CallWithMetadata($Sym{$FnType{Tuple, Array{$type, $ndim}}}($vname))) + if call_args_are_function(call_args) + vname, fntype = function_name_and_type(lhs) + isruntime, vname = unwrap_runtime_var(vname) + if isruntime + _vname = vname + else + _vname = Meta.quot(vname) + end + argtypes = arg_types_from_call_args(call_args) + ex = :($CallWithMetadata($Sym{$FnType{$argtypes, Array{$type, $ndim}, $fntype}}($_vname))) else - ex = :($Sym{$FnType{Tuple, Array{$type, $ndim}}}($vname)(map($unwrap, ($(call_args...),))...)) + vname = lhs + if isruntime + _vname = vname + else + _vname = Meta.quot(vname) + end + ex = :($Sym{$FnType{Tuple, Array{$type, $ndim}, Nothing}}($_vname)(map($unwrap, ($(call_args...),))...)) end ex = :($setmetadata($ex, $ArrayShapeCtx, ($(indices...),))) if val !== nothing ex = :($setdefaultval($ex, $val)) end - ex = setprops_expr(ex, prop, macroname, Meta.quot(lhs)) + ex = setprops_expr(ex, prop, macroname, Meta.quot(vname)) #ex = :($scalarize_getindex($ex)) ex = :($wrap($ex)) ex = :($transform($ex)) if isruntime - lhs = gensym(lhs) + vname = gensym(vname) end - lhs, :($lhs = $ex) + vname, :($vname = $ex) end function construct_vars(macroname, v, type, call_args, val, prop, transform, isruntime) issym = v isa Symbol - isarray = isa(v, Expr) && v.head == :ref + isarray = Meta.isexpr(v, :ref) if isarray + # this can't be an array of functions, since that was handled by `construct_dep_array_vars` var_name = v.args[1] if Meta.isexpr(var_name, :(::)) var_name, type′ = var_name.args @@ -192,6 +216,15 @@ function construct_vars(macroname, v, type, call_args, val, prop, transform, isr isruntime, var_name = unwrap_runtime_var(var_name) indices = v.args[2:end] expr = _construct_array_vars(macroname, isruntime ? var_name : Meta.quot(var_name), type, call_args, val, prop, indices...) + elseif call_args_are_function(call_args) + var_name, fntype = function_name_and_type(v) + isruntime, var_name = unwrap_runtime_var(var_name) + if isruntime + vname = var_name + else + vname = Meta.quot(var_name) + end + expr = construct_var(macroname, fntype == Nothing ? vname : Expr(:(::), vname, fntype), type, call_args, val, prop) else var_name = v if Meta.isexpr(v, :(::)) @@ -253,13 +286,48 @@ function (f::CallWithMetadata)(args...) metadata(unwrap(f.f(map(unwrap, args)...)), metadata(f)) end +function arg_types_from_call_args(call_args) + if length(call_args) == 1 && only(call_args) == :.. + return Tuple + end + Ts = map(call_args) do arg + if arg == :.. + Vararg + elseif arg isa Expr && arg.head == :(::) + if length(arg.args) == 1 + arg.args[1] + elseif arg.args[1] == :.. + :(Vararg{$(arg.args[2])}) + else + arg.args[2] + end + else + error("Invalid call argument $arg") + end + end + return :(Tuple{$(Ts...)}) +end + +function function_name_and_type(var_name) + if var_name isa Expr && Meta.isexpr(var_name, :(::), 2) + var_name.args + else + var_name, Nothing + end +end + function construct_var(macroname, var_name, type, call_args, val, prop) expr = if call_args === nothing :($Sym{$type}($var_name)) - elseif !isempty(call_args) && call_args[end] == :.. - :($CallWithMetadata($Sym{$FnType{Tuple, $type}}($var_name))) + elseif call_args_are_function(call_args) + # function syntax is (x::TFunc)(.. or ::TArg1, ::TArg2)::TRet + # .. is Vararg + # (..)::ArgT is Vararg{ArgT} + var_name, fntype = function_name_and_type(var_name) + argtypes = arg_types_from_call_args(call_args) + :($CallWithMetadata($Sym{$FnType{$argtypes, $type, $fntype}}($var_name))) else - :($Sym{$FnType{NTuple{$(length(call_args)), Any}, $type}}($var_name)($(map(x->:($value($x)), call_args)...))) + :($Sym{$FnType{NTuple{$(length(call_args)), Any}, $type, Nothing}}($var_name)($(map(x->:($value($x)), call_args)...))) end if val !== nothing @@ -283,15 +351,17 @@ function _construct_array_vars(macroname, var_name, type, call_args, val, prop, expr = if call_args === nothing ex = :($Sym{Array{$type, $ndim}}($var_name)) :($setmetadata($ex, $ArrayShapeCtx, ($(indices...),))) - elseif !isempty(call_args) && call_args[end] == :.. + elseif call_args_are_function(call_args) need_scalarize = true - ex = :($Sym{Array{$FnType{Tuple, $type}, $ndim}}($var_name)) + var_name, fntype = function_name_and_type(var_name) + argtypes = arg_types_from_call_args(call_args) + ex = :($Sym{Array{$FnType{$argtypes, $type, $fntype}, $ndim}}($var_name)) ex = :($setmetadata($ex, $ArrayShapeCtx, ($(indices...),))) :($map($CallWithMetadata, $ex)) else # [(R -> R)(R) ....] need_scalarize = true - ex = :($Sym{Array{$FnType{Tuple, $type}, $ndim}}($var_name)) + ex = :($Sym{Array{$FnType{Tuple, $type, Nothing}, $ndim}}($var_name)) ex = :($setmetadata($ex, $ArrayShapeCtx, ($(indices...),))) :($map($CallWith(($(call_args...),)), $ex)) end diff --git a/test/macro.jl b/test/macro.jl index 20b96f00e..faae311e1 100644 --- a/test/macro.jl +++ b/test/macro.jl @@ -1,5 +1,5 @@ using Symbolics -import Symbolics: getsource, getdefaultval, wrap, unwrap, getname +import Symbolics: CallWithMetadata, getsource, getdefaultval, wrap, unwrap, getname import SymbolicUtils: Term, symtype, FnType, BasicSymbolic, promote_symtype using LinearAlgebra using Test @@ -221,12 +221,12 @@ let end @variables t y(t) -yy = Symbolics.variable(:y, T = Symbolics.FnType{Tuple{Any}, Real}) +yy = Symbolics.variable(:y, T = Symbolics.FnType{Tuple{Any}, Real, Nothing}) yyy = yy(t) @test isequal(yyy, y) @test yyy isa Num @test y isa Num -yy = Symbolics.variable(:y, T = Symbolics.FnType{Tuple, Real}) +yy = Symbolics.variable(:y, T = Symbolics.FnType{Tuple, Real, Nothing}) yyy = yy(t) @test !isequal(yyy, y) @variables y(..) @@ -238,3 +238,120 @@ spam(x) = 2x sym = spam([a, 2a]) @test sym isa Num @test unwrap(sym) isa BasicSymbolic{Real} + +fn_defaults = [print, min, max, identity, (+), (-), max, sum, vcat, (*)] + +struct VariableFoo end +Symbolics.option_to_metadata_type(::Val{:foo}) = VariableFoo + +function test_all_functions(fns) + f1, f2, f3, f4, f5, f6, f7, f8, f9, f10 = fns + @variables x y::Int z::Function w[1:3, 1:3] v[1:3, 1:3]::String + @test f1 isa CallWithMetadata{FnType{Tuple, Real, Nothing}} + @test all(x -> symtype(x) <: Real, [f1(), f1(1), f1(x), f1(x, y), f1(x, y, x+y)]) + @test f2 isa CallWithMetadata{FnType{Tuple{Any, Vararg}, Int, Nothing}} + @test all(x -> symtype(x) <: Int, [f2(1), f2(z), f2(x), f2(x, y), f2(x, y, x+y)]) + @test_throws ErrorException f2() + @test f3 isa CallWithMetadata{FnType{Tuple, Real, typeof(max)}} + @test all(x -> symtype(x) <: Real, [f3(), f3(1), f3(x), f3(x, y), f3(x, y, x+y)]) + @test f4 isa CallWithMetadata{FnType{Tuple{Int}, Real, Nothing}} + @test all(x -> symtype(x) <: Real, [f4(1), f4(y), f4(2y)]) + @test_throws ErrorException f4(x) + @test f5 isa CallWithMetadata{FnType{Tuple{Int, Vararg{Int}}, Real, Nothing}} + @test all(x -> symtype(x) <: Real, [f5(1), f5(y), f5(y, y), f5(2, 3)]) + @test_throws ErrorException f5(x) + @test f6 isa CallWithMetadata{FnType{Tuple{Int, Int}, Int, Nothing}} + @test all(x -> symtype(x) <: Int, [f6(1, 1), f6(y, y), f6(1, y), f6(y, 1)]) + @test_throws ErrorException f6() + @test_throws ErrorException f6(1) + @test_throws ErrorException f6(x, y) + @test_throws ErrorException f6(y) + @test f7 isa CallWithMetadata{FnType{Tuple{Int, Int}, Int, typeof(max)}} + # call behavior tested by f6 + @test f8 isa CallWithMetadata{FnType{Tuple{Function, Vararg}, Real, typeof(sum)}} + @test all(x -> symtype(x) <: Real, [f8(z), f8(z, x), f8(identity), f8(identity, x)]) + @test_throws ErrorException f8(x) + @test_throws ErrorException f8(1) + @test f9 isa CallWithMetadata{FnType{Tuple, Vector{Real}, Nothing}} + @test all(x -> symtype(unwrap(x)) <: Vector{Real} && size(x) == (3,), [f9(), f9(1), f9(x), f9(x + y), f9(z), f9(1, x)]) + @test f10 isa CallWithMetadata{FnType{Tuple{Matrix{<:Real}, Matrix{<:Real}}, Matrix{Real}, typeof(*)}} + @test all(x -> symtype(unwrap(x)) <: Matrix{Real} && size(x) == (3, 3), [f10(w, w), f10(w, ones(3, 3)), f10(ones(3, 3), ones(3, 3)), f10(w + w, w)]) + @test_throws ErrorException f10(w, v) +end + +function test_functions_defaults(fns) + for (fn, def) in zip(fns, fn_defaults) + @test Symbolics.getdefaultval(fn, nothing) == def + end +end + +function test_functions_metadata(fns) + for (i, fn) in enumerate(fns) + @test Symbolics.getmetadata(fn, VariableFoo, nothing) == i + end +end + +fns = @test_nowarn @variables begin + f1(..) + f2(::Any, ..)::Int + (f3::typeof(max))(..) + f4(::Int) + f5(::Int, (..)::Int) + f6(::Int, ::Int)::Int + (f7::typeof(max))(::Int, ::Int)::Int + (f8::typeof(sum))(::Function, ..) + f9(..)[1:3] + (f10::typeof(*))(::Matrix{<:Real}, ::Matrix{<:Real})[1:3, 1:3] + # f11[1:3](::Int)::Int +end + +test_all_functions(fns) + +fns = @test_nowarn @variables begin + f1(..) = fn_defaults[1] + f2(::Any, ..)::Int = fn_defaults[2] + (f3::typeof(max))(..) = fn_defaults[3] + f4(::Int) = fn_defaults[4] + f5(::Int, (..)::Int) = fn_defaults[5] + f6(::Int, ::Int)::Int = fn_defaults[6] + (f7::typeof(max))(::Int, ::Int)::Int = fn_defaults[7] + (f8::typeof(sum))(::Function, ..) = fn_defaults[8] + f9(..)[1:3] = fn_defaults[9] + (f10::typeof(*))(::Matrix{<:Real}, ::Matrix{<:Real})[1:3, 1:3] = fn_defaults[10] +end + +test_all_functions(fns) +test_functions_defaults(fns) + +fns = @variables begin + f1(..) = fn_defaults[1], [foo = 1] + f2(::Any, ..)::Int = fn_defaults[2], [foo = 2;] + (f3::typeof(max))(..) = fn_defaults[3], [foo = 3;] + f4(::Int) = fn_defaults[4], [foo = 4;] + f5(::Int, (..)::Int) = fn_defaults[5], [foo = 5;] + f6(::Int, ::Int)::Int = fn_defaults[6], [foo = 6;] + (f7::typeof(max))(::Int, ::Int)::Int = fn_defaults[7], [foo = 7;] + (f8::typeof(sum))(::Function, ..) = fn_defaults[8], [foo = 8;] + f9(..)[1:3] = fn_defaults[9], [foo = 9;] + (f10::typeof(*))(::Matrix{<:Real}, ::Matrix{<:Real})[1:3, 1:3] = fn_defaults[10], [foo = 10;] +end + +test_all_functions(fns) +test_functions_defaults(fns) +test_functions_metadata(fns) + +fns = @test_nowarn @variables begin + f1(..), [foo = 1,] + f2(::Any, ..)::Int, [foo = 2,] + (f3::typeof(max))(..), [foo = 3,] + f4(::Int), [foo = 4,] + f5(::Int, (..)::Int), [foo = 5,] + f6(::Int, ::Int)::Int, [foo = 6,] + (f7::typeof(max))(::Int, ::Int)::Int, [foo = 7,] + (f8::typeof(sum))(::Function, ..), [foo = 8,] + f9(..)[1:3], [foo = 9,] + (f10::typeof(*))(::Matrix{<:Real}, ::Matrix{<:Real})[1:3, 1:3], [foo = 10,] +end + +test_all_functions(fns) +test_functions_metadata(fns) diff --git a/test/overloads.jl b/test/overloads.jl index be893876e..bea817d85 100644 --- a/test/overloads.jl +++ b/test/overloads.jl @@ -12,7 +12,7 @@ vars = @variables t $a $b(t) $c(t)[1:3] @test c === :value_c @test isequal(vars[1], t) @test isequal(vars[2], Num(Sym{Real}(a))) -@test isequal(vars[3], Num(Sym{FnType{Tuple{Any},Real}}(b)(value(t)))) +@test isequal(vars[3], Num(Sym{FnType{Tuple{Any},Real,Nothing}}(b)(value(t)))) vars = @variables a,b,c,d,e,f,g,h,i @test isequal(vars, [a,b,c,d,e,f,g,h,i]) From 89a53a9fcfb200bd7bbb9047fc9b25faa7bb4405 Mon Sep 17 00:00:00 2001 From: Aayush Sabharwal Date: Fri, 13 Sep 2024 18:04:16 +0530 Subject: [PATCH 17/30] feat: add `CallWithParent` to keep track of callable variables --- src/variable.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/variable.jl b/src/variable.jl index c73c423cb..8abb3b3ee 100644 --- a/src/variable.jl +++ b/src/variable.jl @@ -282,8 +282,10 @@ function Base.show(io::IO, c::CallWithMetadata) print(io, "⋆") end +struct CallWithParent end + function (f::CallWithMetadata)(args...) - metadata(unwrap(f.f(map(unwrap, args)...)), metadata(f)) + setmetadata(metadata(unwrap(f.f(map(unwrap, args)...)), metadata(f)), CallWithParent, f) end function arg_types_from_call_args(call_args) From 8e1a3086702191fb9d2aeaa908881932933e161a Mon Sep 17 00:00:00 2001 From: Aayush Sabharwal Date: Fri, 13 Sep 2024 18:21:20 +0530 Subject: [PATCH 18/30] feat: support `Base.isequal` for `CallWithMetadata` --- src/variable.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/variable.jl b/src/variable.jl index 8abb3b3ee..40d6c5fb4 100644 --- a/src/variable.jl +++ b/src/variable.jl @@ -288,6 +288,8 @@ function (f::CallWithMetadata)(args...) setmetadata(metadata(unwrap(f.f(map(unwrap, args)...)), metadata(f)), CallWithParent, f) end +Base.isequal(a::CallWithMetadata, b::CallWithMetadata) = isequal(a.f, b.f) + function arg_types_from_call_args(call_args) if length(call_args) == 1 && only(call_args) == :.. return Tuple From 13f31e3076ded902761108e343ec2db4d2223453 Mon Sep 17 00:00:00 2001 From: Aayush Sabharwal Date: Tue, 17 Sep 2024 11:39:17 +0530 Subject: [PATCH 19/30] build: bump SymbolicUtils compat --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index b4829c368..9f7f78347 100644 --- a/Project.toml +++ b/Project.toml @@ -93,7 +93,7 @@ StaticArraysCore = "1.4" SymPy = "2.2" SymbolicIndexingInterface = "0.3.14" SymbolicLimits = "0.2.2" -SymbolicUtils = "2, 3" +SymbolicUtils = "3.7" TermInterface = "2" julia = "1.10" From ee99dea042ee965b0fcd5cc7a464b3e7d277bb23 Mon Sep 17 00:00:00 2001 From: Aayush Sabharwal Date: Wed, 18 Sep 2024 13:24:35 +0530 Subject: [PATCH 20/30] refactor: do not use `Nothing` as a sentinel value for `FnType` --- src/variable.jl | 18 +++++++++--------- test/macro.jl | 16 ++++++++-------- test/overloads.jl | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/variable.jl b/src/variable.jl index 40d6c5fb4..a85d8755c 100644 --- a/src/variable.jl +++ b/src/variable.jl @@ -176,7 +176,7 @@ function construct_dep_array_vars(macroname, lhs, type, call_args, indices, val, _vname = Meta.quot(vname) end argtypes = arg_types_from_call_args(call_args) - ex = :($CallWithMetadata($Sym{$FnType{$argtypes, Array{$type, $ndim}, $fntype}}($_vname))) + ex = :($CallWithMetadata($Sym{$FnType{$argtypes, Array{$type, $ndim}, $(fntype...)}}($_vname))) else vname = lhs if isruntime @@ -184,7 +184,7 @@ function construct_dep_array_vars(macroname, lhs, type, call_args, indices, val, else _vname = Meta.quot(vname) end - ex = :($Sym{$FnType{Tuple, Array{$type, $ndim}, Nothing}}($_vname)(map($unwrap, ($(call_args...),))...)) + ex = :($Sym{$FnType{Tuple, Array{$type, $ndim}}}($_vname)(map($unwrap, ($(call_args...),))...)) end ex = :($setmetadata($ex, $ArrayShapeCtx, ($(indices...),))) @@ -224,7 +224,7 @@ function construct_vars(macroname, v, type, call_args, val, prop, transform, isr else vname = Meta.quot(var_name) end - expr = construct_var(macroname, fntype == Nothing ? vname : Expr(:(::), vname, fntype), type, call_args, val, prop) + expr = construct_var(macroname, fntype == () ? vname : Expr(:(::), vname, fntype[1]), type, call_args, val, prop) else var_name = v if Meta.isexpr(v, :(::)) @@ -314,9 +314,9 @@ end function function_name_and_type(var_name) if var_name isa Expr && Meta.isexpr(var_name, :(::), 2) - var_name.args + var_name.args[1], (var_name.args[2],) else - var_name, Nothing + var_name, () end end @@ -329,9 +329,9 @@ function construct_var(macroname, var_name, type, call_args, val, prop) # (..)::ArgT is Vararg{ArgT} var_name, fntype = function_name_and_type(var_name) argtypes = arg_types_from_call_args(call_args) - :($CallWithMetadata($Sym{$FnType{$argtypes, $type, $fntype}}($var_name))) + :($CallWithMetadata($Sym{$FnType{$argtypes, $type, $(fntype...)}}($var_name))) else - :($Sym{$FnType{NTuple{$(length(call_args)), Any}, $type, Nothing}}($var_name)($(map(x->:($value($x)), call_args)...))) + :($Sym{$FnType{NTuple{$(length(call_args)), Any}, $type}}($var_name)($(map(x->:($value($x)), call_args)...))) end if val !== nothing @@ -359,13 +359,13 @@ function _construct_array_vars(macroname, var_name, type, call_args, val, prop, need_scalarize = true var_name, fntype = function_name_and_type(var_name) argtypes = arg_types_from_call_args(call_args) - ex = :($Sym{Array{$FnType{$argtypes, $type, $fntype}, $ndim}}($var_name)) + ex = :($Sym{Array{$FnType{$argtypes, $type, $(fntype...)}, $ndim}}($var_name)) ex = :($setmetadata($ex, $ArrayShapeCtx, ($(indices...),))) :($map($CallWithMetadata, $ex)) else # [(R -> R)(R) ....] need_scalarize = true - ex = :($Sym{Array{$FnType{Tuple, $type, Nothing}, $ndim}}($var_name)) + ex = :($Sym{Array{$FnType{Tuple, $type}, $ndim}}($var_name)) ex = :($setmetadata($ex, $ArrayShapeCtx, ($(indices...),))) :($map($CallWith(($(call_args...),)), $ex)) end diff --git a/test/macro.jl b/test/macro.jl index faae311e1..8624af78f 100644 --- a/test/macro.jl +++ b/test/macro.jl @@ -221,12 +221,12 @@ let end @variables t y(t) -yy = Symbolics.variable(:y, T = Symbolics.FnType{Tuple{Any}, Real, Nothing}) +yy = Symbolics.variable(:y, T = Symbolics.FnType{Tuple{Any}, Real}) yyy = yy(t) @test isequal(yyy, y) @test yyy isa Num @test y isa Num -yy = Symbolics.variable(:y, T = Symbolics.FnType{Tuple, Real, Nothing}) +yy = Symbolics.variable(:y, T = Symbolics.FnType{Tuple, Real}) yyy = yy(t) @test !isequal(yyy, y) @variables y(..) @@ -247,20 +247,20 @@ Symbolics.option_to_metadata_type(::Val{:foo}) = VariableFoo function test_all_functions(fns) f1, f2, f3, f4, f5, f6, f7, f8, f9, f10 = fns @variables x y::Int z::Function w[1:3, 1:3] v[1:3, 1:3]::String - @test f1 isa CallWithMetadata{FnType{Tuple, Real, Nothing}} + @test f1 isa CallWithMetadata{FnType{Tuple, Real}} @test all(x -> symtype(x) <: Real, [f1(), f1(1), f1(x), f1(x, y), f1(x, y, x+y)]) - @test f2 isa CallWithMetadata{FnType{Tuple{Any, Vararg}, Int, Nothing}} + @test f2 isa CallWithMetadata{FnType{Tuple{Any, Vararg}, Int}} @test all(x -> symtype(x) <: Int, [f2(1), f2(z), f2(x), f2(x, y), f2(x, y, x+y)]) @test_throws ErrorException f2() @test f3 isa CallWithMetadata{FnType{Tuple, Real, typeof(max)}} @test all(x -> symtype(x) <: Real, [f3(), f3(1), f3(x), f3(x, y), f3(x, y, x+y)]) - @test f4 isa CallWithMetadata{FnType{Tuple{Int}, Real, Nothing}} + @test f4 isa CallWithMetadata{FnType{Tuple{Int}, Real}} @test all(x -> symtype(x) <: Real, [f4(1), f4(y), f4(2y)]) @test_throws ErrorException f4(x) - @test f5 isa CallWithMetadata{FnType{Tuple{Int, Vararg{Int}}, Real, Nothing}} + @test f5 isa CallWithMetadata{FnType{Tuple{Int, Vararg{Int}}, Real}} @test all(x -> symtype(x) <: Real, [f5(1), f5(y), f5(y, y), f5(2, 3)]) @test_throws ErrorException f5(x) - @test f6 isa CallWithMetadata{FnType{Tuple{Int, Int}, Int, Nothing}} + @test f6 isa CallWithMetadata{FnType{Tuple{Int, Int}, Int}} @test all(x -> symtype(x) <: Int, [f6(1, 1), f6(y, y), f6(1, y), f6(y, 1)]) @test_throws ErrorException f6() @test_throws ErrorException f6(1) @@ -272,7 +272,7 @@ function test_all_functions(fns) @test all(x -> symtype(x) <: Real, [f8(z), f8(z, x), f8(identity), f8(identity, x)]) @test_throws ErrorException f8(x) @test_throws ErrorException f8(1) - @test f9 isa CallWithMetadata{FnType{Tuple, Vector{Real}, Nothing}} + @test f9 isa CallWithMetadata{FnType{Tuple, Vector{Real}}} @test all(x -> symtype(unwrap(x)) <: Vector{Real} && size(x) == (3,), [f9(), f9(1), f9(x), f9(x + y), f9(z), f9(1, x)]) @test f10 isa CallWithMetadata{FnType{Tuple{Matrix{<:Real}, Matrix{<:Real}}, Matrix{Real}, typeof(*)}} @test all(x -> symtype(unwrap(x)) <: Matrix{Real} && size(x) == (3, 3), [f10(w, w), f10(w, ones(3, 3)), f10(ones(3, 3), ones(3, 3)), f10(w + w, w)]) diff --git a/test/overloads.jl b/test/overloads.jl index bea817d85..be893876e 100644 --- a/test/overloads.jl +++ b/test/overloads.jl @@ -12,7 +12,7 @@ vars = @variables t $a $b(t) $c(t)[1:3] @test c === :value_c @test isequal(vars[1], t) @test isequal(vars[2], Num(Sym{Real}(a))) -@test isequal(vars[3], Num(Sym{FnType{Tuple{Any},Real,Nothing}}(b)(value(t)))) +@test isequal(vars[3], Num(Sym{FnType{Tuple{Any},Real}}(b)(value(t)))) vars = @variables a,b,c,d,e,f,g,h,i @test isequal(vars, [a,b,c,d,e,f,g,h,i]) From 79023776dc440ef17bc662e83c7148325bd52586 Mon Sep 17 00:00:00 2001 From: Aayush Sabharwal Date: Wed, 18 Sep 2024 13:24:46 +0530 Subject: [PATCH 21/30] feat: support interpolated names in callable symbolics --- src/variable.jl | 28 +++++++++++++++++++++------- test/macro.jl | 16 ++++++++++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/variable.jl b/src/variable.jl index a85d8755c..b5230f07b 100644 --- a/src/variable.jl +++ b/src/variable.jl @@ -169,11 +169,18 @@ function construct_dep_array_vars(macroname, lhs, type, call_args, indices, val, ndim = :($length(($(indices...),))) if call_args_are_function(call_args) vname, fntype = function_name_and_type(lhs) - isruntime, vname = unwrap_runtime_var(vname) + # name was already unwrapped before calling this function and is of the form $x if isruntime _vname = vname else - _vname = Meta.quot(vname) + # either no ::fnType or $x::fnType + vname, fntype = function_name_and_type(lhs) + isruntime, vname = unwrap_runtime_var(vname) + if isruntime + _vname = vname + else + _vname = Meta.quot(vname) + end end argtypes = arg_types_from_call_args(call_args) ex = :($CallWithMetadata($Sym{$FnType{$argtypes, Array{$type, $ndim}, $(fntype...)}}($_vname))) @@ -198,14 +205,14 @@ function construct_dep_array_vars(macroname, lhs, type, call_args, indices, val, ex = :($transform($ex)) if isruntime - vname = gensym(vname) + vname = gensym(Symbol(vname)) end vname, :($vname = $ex) end function construct_vars(macroname, v, type, call_args, val, prop, transform, isruntime) issym = v isa Symbol - isarray = Meta.isexpr(v, :ref) + isarray = !isruntime && Meta.isexpr(v, :ref) if isarray # this can't be an array of functions, since that was handled by `construct_dep_array_vars` var_name = v.args[1] @@ -218,11 +225,18 @@ function construct_vars(macroname, v, type, call_args, val, prop, transform, isr expr = _construct_array_vars(macroname, isruntime ? var_name : Meta.quot(var_name), type, call_args, val, prop, indices...) elseif call_args_are_function(call_args) var_name, fntype = function_name_and_type(v) - isruntime, var_name = unwrap_runtime_var(var_name) + # name was already unwrapped before calling this function and is of the form $x if isruntime vname = var_name else - vname = Meta.quot(var_name) + # either no ::fnType or $x::fnType + var_name, fntype = function_name_and_type(v) + isruntime, var_name = unwrap_runtime_var(var_name) + if isruntime + vname = var_name + else + vname = Meta.quot(var_name) + end end expr = construct_var(macroname, fntype == () ? vname : Expr(:(::), vname, fntype[1]), type, call_args, val, prop) else @@ -233,7 +247,7 @@ function construct_vars(macroname, v, type, call_args, val, prop, transform, isr end expr = construct_var(macroname, isruntime ? var_name : Meta.quot(var_name), type, call_args, val, prop) end - lhs = isruntime ? gensym(var_name) : var_name + lhs = isruntime ? gensym(Symbol(var_name)) : var_name rhs = :($transform($expr)) lhs, :($lhs = $rhs) end diff --git a/test/macro.jl b/test/macro.jl index 8624af78f..0dd82728b 100644 --- a/test/macro.jl +++ b/test/macro.jl @@ -240,6 +240,7 @@ sym = spam([a, 2a]) @test unwrap(sym) isa BasicSymbolic{Real} fn_defaults = [print, min, max, identity, (+), (-), max, sum, vcat, (*)] +fn_names = [Symbol(:f, i) for i in 1:10] struct VariableFoo end Symbolics.option_to_metadata_type(::Val{:foo}) = VariableFoo @@ -355,3 +356,18 @@ end test_all_functions(fns) test_functions_metadata(fns) + +fns = @test_nowarn @variables begin + $(fn_names[1])(..) + $(fn_names[2])(::Any, ..)::Int + ($(fn_names[3])::typeof(max))(..) + $(fn_names[4])(::Int) + $(fn_names[5])(::Int, (..)::Int) + $(fn_names[6])(::Int, ::Int)::Int + ($(fn_names[7])::typeof(max))(::Int, ::Int)::Int + ($(fn_names[8])::typeof(sum))(::Function, ..) + $(fn_names[9])(..)[1:3] + ($(fn_names[10])::typeof(*))(::Matrix{<:Real}, ::Matrix{<:Real})[1:3, 1:3] +end + +test_all_functions(fns) From ee77c8a09a4d19c2b3f2b736d9b36dab2cd084ba Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Wed, 18 Sep 2024 18:18:20 +0200 Subject: [PATCH 22/30] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 9f7f78347..bd45f7328 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Symbolics" uuid = "0c5d862f-8b57-4792-8d23-62f2024744c7" authors = ["Shashi Gowda "] -version = "6.11.0" +version = "6.12.0" [deps] ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" From 201596c6e0711ff87090141bbc98465d42a677a7 Mon Sep 17 00:00:00 2001 From: Aayush Sabharwal Date: Tue, 17 Sep 2024 13:04:38 +0530 Subject: [PATCH 23/30] feat: improve `diff2term` for array symbolics --- src/utils.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils.jl b/src/utils.jl index f2abd0cb7..2167bed06 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -131,8 +131,8 @@ function diff2term(O, O_metadata::Union{Dict, Nothing, Base.ImmutableDict}=nothi string(nameof(arguments(oldop)[1])) elseif oldop == getindex args = arguments(O) - opname = string(tosymbol(args[1]), "[", map(tosymbol, args[2:end])..., "]") - return Sym{symtype(O)}(Symbol(opname, d_separator, ds)) + opname = string(tosymbol(args[1])) + return metadata(Sym{symtype(args[1])}(Symbol(opname, d_separator, ds)), metadata(args[1]))[args[2:end]...] elseif oldop isa Function return nothing else From a291fe35670835c5dc07ffe50877f73a9c6a6025 Mon Sep 17 00:00:00 2001 From: Aayush Sabharwal Date: Fri, 20 Sep 2024 19:28:41 +0530 Subject: [PATCH 24/30] test: fix old `diff2term` in tests --- test/arrays.jl | 4 +++- test/diff.jl | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/arrays.jl b/test/arrays.jl index 79ec65d44..13fa73379 100644 --- a/test/arrays.jl +++ b/test/arrays.jl @@ -36,7 +36,9 @@ end @testset "getname" begin @variables t x(t)[1:4] v = Symbolics.lower_varname(unwrap(x[2]), unwrap(t), 2) - @test getname(v) == Symbol("x(t)[2]ˍtt") + @test operation(v) == getindex + @test arguments(v)[2] == 2 + @test getname(v) == getname(arguments(v)[1]) == Symbol("x(t)ˍtt") end @testset "getindex" begin diff --git a/test/diff.jl b/test/diff.jl index eb500cb9d..0431933b6 100644 --- a/test/diff.jl +++ b/test/diff.jl @@ -13,7 +13,7 @@ Dx = Differential(x) @test Symbol(D(D(uu))) === Symbol("uuˍtt(t)") @test Symbol(D(uuˍt)) === Symbol(D(D(uu))) -@test Symbol(D(v[2])) === Symbol("v(t)[2]ˍt") +@test Symbol(D(v[2])) === Symbol("getindex(var\"v(t)ˍt\", 2)") test_equal(a, b) = @test isequal(simplify(a), simplify(b)) From 193071569de122751fa441820784b148244b65d2 Mon Sep 17 00:00:00 2001 From: contradict Date: Mon, 23 Sep 2024 10:06:34 -0700 Subject: [PATCH 25/30] Add example of failing expression --- test/semipoly.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/semipoly.jl b/test/semipoly.jl index ed9313cdb..364f4c6c3 100644 --- a/test/semipoly.jl +++ b/test/semipoly.jl @@ -509,3 +509,7 @@ for i=1:20 trial() end end + +@testset "Extracted from fuzz testing" begin + @test verify(2.25(2.0 + 2c)*(c^2), Dict{Any, Any}(c^3 => 4.5, c^2 => 4.5), Num[c, y, z], 0) +end From 768044622231f50f6d4d645740fcad6380037987 Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Tue, 24 Sep 2024 05:32:55 -0400 Subject: [PATCH 26/30] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index bd45f7328..908cba4d3 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Symbolics" uuid = "0c5d862f-8b57-4792-8d23-62f2024744c7" authors = ["Shashi Gowda "] -version = "6.12.0" +version = "6.13.0" [deps] ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" From d5678df12ca452bf2e9ccbf33d7de2163664ac06 Mon Sep 17 00:00:00 2001 From: Mason Protter Date: Wed, 25 Sep 2024 16:34:52 +0200 Subject: [PATCH 27/30] Update Symbolics.jl --- src/Symbolics.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symbolics.jl b/src/Symbolics.jl index ea2b383dd..2b6a45912 100644 --- a/src/Symbolics.jl +++ b/src/Symbolics.jl @@ -92,6 +92,7 @@ export Inequality, ≲, ≳ include("inequality.jl") import Bijections, DynamicPolynomials +export tosymbol include("utils.jl") using ConstructionBase From 47fd17400a18e85df70a6eeafc196dfac51c9d0e Mon Sep 17 00:00:00 2001 From: Aayush Sabharwal Date: Fri, 27 Sep 2024 18:25:25 +0530 Subject: [PATCH 28/30] feat: improve `maketerm` for `ArrayOp` --- src/arrays.jl | 8 ++++++++ test/arrays.jl | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/arrays.jl b/src/arrays.jl index 6df9fbffb..388c79450 100644 --- a/src/arrays.jl +++ b/src/arrays.jl @@ -63,6 +63,14 @@ end ConstructionBase.constructorof(s::Type{<:ArrayOp{T}}) where {T} = ArrayOp{T} function SymbolicUtils.maketerm(::Type{<:ArrayOp}, f, args, m) + args = map(args) do arg + if iscall(arg) && operation(arg) == Ref && symbolic_type(only(arguments(arg))) == NotSymbolic() + return Ref(only(arguments(arg))) + else + return arg + end + end + t = f(args...) t isa Symbolic && !isnothing(m) ? metadata(t, m) : t diff --git a/test/arrays.jl b/test/arrays.jl index 13fa73379..27041d846 100644 --- a/test/arrays.jl +++ b/test/arrays.jl @@ -82,6 +82,8 @@ end @test isequal(T, Symbolics.maketerm(typeof(T), operation(T), arguments(T), nothing)) T2 = unwrap(3B) @test isequal(T2, Symbolics.maketerm(typeof(T), operation(T), [*, 3, unwrap(B)], nothing)) + T3 = unwrap(A .^ 2) + @test isequal(T3, Symbolics.maketerm(typeof(T3), operation(T3), arguments(T3), nothing)) end getdef(v) = getmetadata(v, Symbolics.VariableDefaultValue) From 2fca7f4ea05b7f8077d79f83be90441f8a520727 Mon Sep 17 00:00:00 2001 From: Aayush Sabharwal Date: Fri, 27 Sep 2024 18:25:43 +0530 Subject: [PATCH 29/30] fix: fix usage of deprecated property in `toexpr` of `ArrayOp` --- src/arrays.jl | 2 +- test/build_function.jl | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/arrays.jl b/src/arrays.jl index 388c79450..ac65fb616 100644 --- a/src/arrays.jl +++ b/src/arrays.jl @@ -976,7 +976,7 @@ end ### Codegen function SymbolicUtils.Code.toexpr(x::ArrayOp, st) - haskey(st.symbolify, x) && return st.symbolify[x] + haskey(st.rewrites, x) && return st.rewrites[x] if iscall(x.term) toexpr(x.term, st) diff --git a/test/build_function.jl b/test/build_function.jl index 18e0a574b..5e7266402 100644 --- a/test/build_function.jl +++ b/test/build_function.jl @@ -1,7 +1,7 @@ using Symbolics, SparseArrays, LinearAlgebra, Test using ReferenceTests using Symbolics: value -using SymbolicUtils.Code: DestructuredArgs, Func +using SymbolicUtils.Code: DestructuredArgs, Func, NameState @variables a b c1 c2 c3 d e g oop, iip = Symbolics.build_function([sqrt(a), sin(b)], [a, b], nanmath = true) @test all(isnan, eval(oop)([-1, Inf])) @@ -275,3 +275,9 @@ let #658 k = eval(build_function(a * X1 + X2, X1, X2, a)[2]) @test k(ones(3), ones(3), 1.5) == [2.5, 2.5, 2.5] end + +@testset "ArrayOp codegen" begin + @variables x[1:2] + T = value(x .^ 2) + @test_nowarn toexpr(T, NameState()) +end From b3ce057ac40112cd4ef997b983aee81faae85b1d Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Fri, 27 Sep 2024 12:32:58 -0400 Subject: [PATCH 30/30] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 908cba4d3..fcfe9ab1c 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Symbolics" uuid = "0c5d862f-8b57-4792-8d23-62f2024744c7" authors = ["Shashi Gowda "] -version = "6.13.0" +version = "6.13.1" [deps] ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"