# Using Custom Structs for Nonlinear Optimization

**URL:** https://discourse.julialang.org/t/using-custom-structs-for-nonlinear-optimization/75755
**Category:** Optimization (Mathematical)
**Created:** [February 3, 2022, 8:40pm UTC](https://discourse.julialang.org/t/using-custom-structs-for-nonlinear-optimization/75755 "2022-02-03T20:40:36Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![danny.s](https://avatars.discourse-cdn.com/v4/letter/d/41988e/32.png) [@danny.s](https://discourse.julialang.org/u/danny.s)
#### Post date: [February 3, 2022, 8:40pm UTC](https://discourse.julialang.org/t/using-custom-structs-for-nonlinear-optimization/75755/1 "2022-02-03T20:40:36Z")

</div>

Hi, I’m new to JuMP and I’m trying to wrap my head around why what I’m doing is incorrect. A much simplified MWE is below:

```julia
using JuMP, Ipopt

M,N = 3,5
struct myPoly
    vec
end
function (f::myPoly)(x)
    ret = 0.
    for v in f.vec
        ret = x*ret + v
    end
    ret
end

function myPolyEval(f::myPoly, x)
    ret = 0.
    for v in f.vec
        ret = x*ret + v
    end
    ret
end

##

bas = myPoly.([collect(1:j) for j in 1:N])
samp = range(0,1,length=M)
model = Model(Ipopt.Optimizer)
@variable(model, x[1:N])
@NLexpression(model, callStruct[i=1:M,j=1:N], bas[j](samp[i])) # 1
# LoadError: MethodError: no method matching _is_sum(::Expr)

register(model, :myPolyEval, 2, myPolyEval; autodiff=true)
@NLexpression(model, mpe[i=1:M,j=1:N], myPolyEval(bas[j],samp[i]))
# LoadError: Unexpected object myPoly([1]) (of type myPoly in nonlinear expression.

@NLobjective(model, Min, sum( (x[j]*myPolyEval(bas[j],samp[i]))^2 for j in 1:N, i in 1:M) )
# LoadError: Unexpected object myPoly([1]) (of type myPoly in nonlinear expression.

```

Obviously, I see the trouble that one might run into with callable structs, but I would anticipate the others to work and can’t see why they wouldn’t. For reference, I anticipate `bas` representing an arbitrary basis (not necessarily polynomials, but I found this while using the [Polynomials.jl](https://juliamath.github.io/Polynomials.jl/stable/) package), and I’d like this to work in generality (with a more complicated constraint in mind)

---

<div class="post-metadata">

### Author: ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)
#### Post date: [February 3, 2022, 10:35pm UTC](https://discourse.julialang.org/t/using-custom-structs-for-nonlinear-optimization/75755/2 "2022-02-03T22:35:55Z")

</div>

Hopefully this helps:

```julia
using JuMP, Ipopt
M, N = 3, 5

struct myPoly
    vec::Vector{Int}
end

function (f::myPoly)(x)
    ret = 0.0
    for v in f.vec
        ret = x * ret + v
    end
    return ret
end

bas = [myPoly(collect(1:j)) for j in 1:N]
samp = range(0, 1; length=M)
model = Model(Ipopt.Optimizer)
@variable(model, x[1:N])

# Option 1: if you are only using linear or quadratic terms:
@objective(
    model,
    Min,
    sum((bas[j](samp[i]) * x[j])^2 for j in 1:N, i in 1:M),
)

# Option 2: if you are using higher-order terms:
coefficients = [bas[j](samp[i]) for j in 1:N, i in 1:M]
@NLobjective(
    model,
    Min,
    sum((coefficients[j, i] * x[j])^2 for j in 1:N, i in 1:M),
)

```

Why? `@NL...` macros don’t like function calls like `bas[j](...)` because we  
need to construct and expression graph based only on the syntax (we don’t get to  
see the _value_ of `bas[j]` until _after_ we have constructed the expression  
graph). As a work-around, store all the coefficients in a matrix (or other data  
structure that doesn’t involve function calls) and index into the data structure.

`@objective` (and `@constraint`) doesn’t have this problem because it works with the _values_ of things, rather than on the syntax. It’s also one reason why the `@NL` macros are “different” to the rest of JuMP.
