You need something like:
using JuMP, Symbolics, Ipopt
to_jump_expr(c::Any, ::Dict{Symbol}) = c
to_jump_expr(x::Symbol, map::Dict{Symbol}) = JuMP.index(map[x])
to_jump_expr(f::Function, ::Dict{Symbol}) = Symbol(f)
function to_jump_expr(expr::Expr, map::Dict{Symbol})
if Meta.isexpr(expr, :call, 3) && expr.args[1] == getindex
return JuMP.index(getindex(map[expr.args[2]], expr.args[3]))
end
for i in 1:length(expr.args)
expr.args[i] = to_jump_expr(expr.args[i], map)
end
return expr
end
foo(x, y) = sqrt(sin(x) + cos(y))
Symbolics.@variables X[1:2]
sym_expr = Symbolics.toexpr(foo(X[1], X[2]))
model = Model()
@variable(model, x[1:2])
jump_expr = to_jump_expr(sym_expr, Dict(:X => x))
add_nonlinear_constraint(model, :($jump_expr <= 0))
In general, I don’t like the macro approaches. Just walk the expression and modify it as needed.