# Registering an array of functions and using them in constraints and objectives

(Julia beginner)
Still thinking about Nonlinear Programming with JuMP with some generality.
(@NLconstraint with a sum, array and scalar variables)
There are many NLP JuMP examples available but all more or less similar to the Rosenbrok problem in the sense that they involve a few explicit functions for objective and constraints.

My intuition for my own problem (pyro chemistry) is that I might need to create many nonlinear functions and that I would use as part of an array of functions or a dictionary of functions.
Therefore when registering some new function(s) with some symbol(s) like here:

`JuMP.register(model, :hJuMP, 1, hjulia; autodiff=true)`

there is the problem that I will probably never be able to use literally the `hJuMP` symbol created in this statement. Instead, my likely use of `hJuMP` would be as one element from a list of such function:

``````funlist = [..., ..., hJuMP, ..., ...]

@NLconstraint(model, funlist[idx](T, xs...) ==  h0)
``````

This kind of statement does not work and return for example this error:

``````LoadError: MethodError: no method matching _is_sum(::Expr)
``````

I tried several variant of the idea without success.

Would there be a way to use JuMP/Julia as above?
Or should I think otherwise?

Michel

This may help:

``````using JuMP, Ipopt

function main(functions)
model = Model(Ipopt.Optimizer)
@variable(model, x)
for (i, f) in enumerate(functions)
f_sym = Symbol("f_\$(i)")
register(model, f_sym, 1, f; autodiff = true)
end
return model
end

main([
x -> x^2,
x -> sin(x)^2,
])
``````

I should add it as an example to the documentation. The current section on this is a little bare: Nonlinear Modeling · JuMP

1 Like

Thanks odow, it could help indeed …

How would you modify the last line of this snippet to involve a sum() on these two functions ?

``````
model = Model(Ipopt.Optimizer)
f_sym = [:f_1, :f_2]
f_fun = [x -> x^2, x -> sin(x)^2]
@variable(model, x)
for (s, f) in zip(f_sym,f_fun)
register(model, s, 1, f; autodiff = true)
end
#@NLconstraint(model, f_1(x) + f_2(x) <= 1.0 )
add_NL_constraint(model, :(\$(f_sym)(\$x) + \$(f_sym)(\$x) <= 1.0) )

``````

As a beginner, I get already confused when trying to adjust this (very) naïve attempt:

``````add_NL_constraint(model, :( sum( \$(f_sym[i])(\$x) for i in 1:2) <= 1.0) )
``````

or this variant:

``````add_NL_constraint(model, :( sum( ((\$f)(\$x)) for f in f_sym) <= 1.0) )
``````

Could you also suggest some readings on metaprogramming that deal with this kind of yoga with expressions? Explaining the mechanics of it a bit more in detail than what I found already.

Thanks!

1 Like

You need to build the expression manually:

``````expr = Expr(:call, :+)
for f in f_sym
push!(expr.args, :(\$(f)(\$x))
end
``````

Here are the Julia docs: Metaprogramming · The Julia Language

It’s often helpful to write the expression you want to achieve, then `dump` it to see the internal structure:

``````julia> expr = :(f_1(x) + f_2(x) <= 1)
:(f_1(x) + f_2(x) <= 1)

julia> dump(expr)
Expr
args: Array{Any}((3,))
1: Symbol <=
2: Expr
args: Array{Any}((3,))
1: Symbol +
2: Expr