Can't take a gradient using Symbolic vector

I’m running into some trouble when taking a gradient of a symbolic function using a symbolic vector.

using Symbolics

@variables x[1:2]

xₒ = [1;1]

f = (x[1] + 2*x[2])^3

f_fun = build_function(f, x)

vals = eval(f_fun)

vals(xₒ)

df = Symbolics.gradient(f, x)

This code works just fine up until I try to use Symbolics.gradient. At this point, I get this error:

ERROR: MethodError: no method matching similar(::Type{Vector{Num}}, ::Tuple{UnitRange{Int64}})

Does anyone have any experience with why this might be happening and how to fix it? Any help would be greatly appreciated.

EDIT:

So I tried this:

df = Symbolics.gradient(f,[x[1],x[2]])

which worked just fine. However, when I run isequal(x, [x[1],x[2]]), it returns true. So now I’m extra confused. Any advice on why one way works and the other doesn’t would be great!

What version of Symbolics are you using?

julia> using Symbolics

julia> xₒ = [1;1]
2-element Vector{Int64}:
 1
 1

julia> @variables x[1:2]
1-element Vector{Symbolics.Arr{Num, 1}}:
 x[1:2]

julia> xₒ = [1;1]
2-element Vector{Int64}:
 1
 1

julia> f = (x[1] + 2*x[2])^3
(x[1] + 2x[2])^3

julia> f_fun = build_function(f, x)
:(function (x,)
      #= /home/russel/.julia/packages/SymbolicUtils/ssQsQ/src/code.jl:373 =#
      #= /home/russel/.julia/packages/SymbolicUtils/ssQsQ/src/code.jl:374 =#
      #= /home/russel/.julia/packages/SymbolicUtils/ssQsQ/src/code.jl:375 =#
      (^)((+)((getindex)(x, 1), (*)(2, (getindex)(x, 2))), 3)
  end)

julia> vals = eval(f_fun)
#7 (generic function with 1 method)

julia> vals(xₒ)
27

julia> df = Symbolics.gradient(f, x)
2-element OffsetArray(::Vector{Num}, 1:2) with eltype Num with indices 1:2:
 3((x[1] + 2x[2])^2)
 6((x[1] + 2x[2])^2)

(MTK) pkg> st
Project MTK v0.1.0
Status `~/Desktop/Julia/MTK/Project.toml`
  [b0b7db55] ComponentArrays v0.15.5
  [82cc6244] DataInterpolations v4.5.0
  [0c46a032] DifferentialEquations v7.11.0
  [961ee093] ModelingToolkit v8.73.1
  [16a59e39] ModelingToolkitStandardLibrary v2.3.4
  [8913a72c] NonlinearSolve v2.8.2
  [1dea7af3] OrdinaryDiffEq v6.59.3
  [d96e819e] Parameters v0.12.3
  [91a5bcdd] Plots v1.39.0
  [731186ca] RecursiveArrayTools v2.38.10
  [0c5d862f] Symbolics v5.10.0

I have the same version that you have. Interesting that it is working for you. Do you think that another package that you have installed could be making it work for you in some weird way?

Works in a temporary environment with just Symbolics as well. How about Julia versions?

(jl_BnaUHa) pkg> st
Status `/tmp/jl_BnaUHa/Project.toml`
  [0c5d862f] Symbolics v5.10.0

julia> versioninfo()
Julia Version 1.9.4
Commit 8e5136fa297 (2023-11-14 08:46 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 8 × Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, skylake)
  Threads: 1 on 8 virtual cores
Environment:
  JULIA_REVISE_INCLUDE = 1

I am reproducing the same issue as @Cade_Armstrong and I am currently running Julia 1.9.4 and Symbolics 5.10.0. My platform is on Mac OS X 13.5.1 and the hardware is a M2 MacBook Pro.

Error replicated also.

julia> df = Symbolics.gradient(f, x[1:2])
2-element Vector{Num}:
 0
 0

works but it gets a wrong answer.

julia> Symbolics.gradient(f, [x[1],x[2]])
2-element Vector{Num}:
 3((x[1] + 2x[2])^2)
 6((x[1] + 2x[2])^2)

is more like it.

Wow, that’s quite a diversity of results! Can someone who gets the exception post a full backtrace?

julia> df = Symbolics.gradient(f, x)
ERROR: MethodError: no method matching similar(::Type{Vector{Num}}, ::Tuple{UnitRange{Int64}})

Closest candidates are:
  similar(::VSCodeServer.JuliaInterpreter.Compiled, ::Any)
   @ VSCodeServer ~/.vscode-oss/extensions/julialang.language-julia-1.60.2-universal/scripts/packages/JuliaInterpreter/src/types.jl:7
  similar(::Type{A}, ::Type{T}, ::StaticArraysCore.Size{S}) where {A<:Array, T, S}
   @ StaticArrays ~/.julia/packages/StaticArrays/yXGNL/src/abstractarray.jl:136
  similar(::Type{A}, ::StaticArraysCore.Size{S}) where {A<:AbstractArray, S}
   @ StaticArrays ~/.julia/packages/StaticArrays/yXGNL/src/abstractarray.jl:124
  ...

Stacktrace:
 [1] _array_for(::Type{Num}, ::Base.HasShape{1}, axs::Tuple{UnitRange{Int64}})
   @ Base ./array.jl:662
 [2] _array_for(::Type{Num}, itr::Symbolics.Arr{Num, 1}, isz::Base.HasShape{1})
   @ Base ./array.jl:665
 [3] gradient(O::Num, vars::Symbolics.Arr{Num, 1}; simplify::Bool)
   @ Symbolics ~/.julia/packages/Symbolics/gBKZv/src/diff.jl:435
 [4] gradient(O::Num, vars::Symbolics.Arr{Num, 1})
   @ Symbolics ~/.julia/packages/Symbolics/gBKZv/src/diff.jl:434
 [5] top-level scope
   @ REPL[12]:1

(@v1.11) pkg> st
Status `~/.julia/environments/v1.11/Project.toml`
  [233ec0c9] AMRVW v1.2.1
  [9b6a8646] AllocCheck v0.1.0
  [6e4b80f9] BenchmarkTools v1.3.2
  [bcf9a6e7] BugReporting v0.3.4
  [31c24e10] Distributions v0.25.103
  [7c1d4256] DynamicPolynomials v0.5.3 `~/tmp/jl/DynamicPolynomials.jl`
  [af72fe11] FindMinimaxPolynomial v0.4.0 `~/src/gitlab.com/nsajko/FindMinimaxPolynomial`
  [c91e804a] Gadfly v1.4.0
  [c3a54625] JET v0.8.20
  [b8f27783] MathOptInterface v1.22.0
  [102ac46a] MultivariatePolynomials v0.5.3 `~/tmp/jl/MultivariatePolynomials.jl`
  [d8a4904e] MutableArithmetics v1.3.3 `~/tmp/jl/MutableArithmetics.jl`
  [cae6f51d] OptimalSortingNetworks v1.0.0 `~/src/gitlab.com/nsajko/OptimalSortingNetworks`
  [e4faabce] PProf v3.1.0
  [14b8a8f1] PkgTemplates v0.7.46
  [f27b6e38] Polynomials v4.0.6
  [0c5d862f] Symbolics v5.10.0
  [6dd1b50a] Tulip v0.9.5
  [ce3070e3] TupleShuffling v1.0.0 `~/src/gitlab.com/nsajko/TupleShuffling`
  [4fd249ec] TupleSorting v1.0.0 `~/src/gitlab.com/nsajko/TupleSorting`
  [afbbf031] TypedPolynomials v0.4.1
  [99140e25] UnsafeAssume v1.0.1 `~/src/gitlab.com/nsajko/UnsafeAssume`

The code hasn’t been changed in two years, so I guess this is a Symbolics.Arr bug?

Yep, it looks like its a bug that was reported at the beginning of October. Here’s the link:

In the bug report, the author gives a pretty simple work around.

using Symbolics

@variables x[1:2]

f = (x[1] + 2*x[2])^3

y = [x...]

df = Symbolics.gradient(f, y)

seems to work fine.