Can't register a function to JuMP

Hello, here is a reduced version of my actual code which replicates my problem.

using JuMP
using Ipopt;
a0 = rand(81);
b = 10
c = 11
d = zeros(b,c)
function calculation_2(a)
    for i in 1:b
        for j in 1:c
            d[i,j] = i*j 
        end
    end
    return sum(d)
end
lower_boundary = zeros(81) .+ 0.1
upper_boundary = ones(81);
model = Model(Ipopt.Optimizer)
@variable(model, lower_boundary[i] <= a[i in 1:81] <= upper_boundary[i])
set_start_value.(a, a0)
register(model, :calculation_2, length(a0), calculation_2, autodiff=true)
@objective(model, Min, calculation_2(a))

Here is my error:

Unable to register the function :calculation_2.

Common reasons for this include:

 * The function takes `f(x::Vector)` as input, instead of the splatted
   `f(x...)`.
 * The function assumes `Float64` will be passed as input, it must work for any
   generic `Real` type.
 * The function allocates temporary storage using `zeros(3)` or similar. This
   defaults to `Float64`, so use `zeros(T, 3)` instead.

As examples, instead of:
```julia
my_function(x::Vector) = sum(x.^2)
```
use:
```julia
my_function(x::T...) where {T<:Real} = sum(x[i]^2 for i in 1:length(x))
```

Instead of:
```julia
function my_function(x::Float64...)
    y = zeros(length(x))
    for i in 1:length(x)
        y[i] = x[i]^2
    end
    return sum(y)
end
```
use:
```julia
function my_function(x::T...) where {T<:Real}
    y = zeros(T, length(x))
    for i in 1:length(x)
        y[i] = x[i]^2
    end
    return sum(y)
end
```

Review the stacktrace below for more information, but it can often be hard to
understand why and where your function is failing. You can also debug this
outside of JuMP as follows:
```julia
import ForwardDiff

# If the input dimension is 1
x = 1.0
my_function(a) = a^2
ForwardDiff.derivative(my_function, x)

# If the input dimension is more than 1
x = [1.0, 2.0]
my_function(a, b) = a^2 + b^2
ForwardDiff.gradient(x -> my_function(x...), x)
```


Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:35
 [2] _validate_register_assumptions(f::typeof(calculation_2), name::Symbol, dimension::Int64)
   @ MathOptInterface.Nonlinear ~/.julia/packages/MathOptInterface/8f6oN/src/Nonlinear/operators.jl:267
 [3] (MathOptInterface.Nonlinear._MultivariateOperator{81})(op::Symbol, f::Function)
   @ MathOptInterface.Nonlinear ~/.julia/packages/MathOptInterface/8f6oN/src/Nonlinear/operators.jl:297
 [4] register_operator(registry::MathOptInterface.Nonlinear.OperatorRegistry, op::Symbol, nargs::Int64, f::Function)
   @ MathOptInterface.Nonlinear ~/.julia/packages/MathOptInterface/8f6oN/src/Nonlinear/operators.jl:350
 [5] register_operator
   @ ~/.julia/packages/MathOptInterface/8f6oN/src/Nonlinear/model.jl:217 [inlined]
 [6] register(model::Model, op::Symbol, dimension::Int64, f::Function; autodiff::Bool)
   @ JuMP ~/.julia/packages/JuMP/pQApG/src/nlp.jl:708
 [7] top-level scope
   @ In[58]:4

So you’ve managed to hit the first and third points mentioned in the error message:

  • Your function takes a vector instead of splatting
  • Your function uses the preallocated d array, which is a Matrix{Float64}.

Your function also doesn’t use a at all.

Try following the suggestions in the error message, and if they don’t help, provide a reproducible example of your model that actually uses a.

To get started, you might do something like

using JuMP
using Ipopt

function calculation_2(a::T...) where {T}
    b, c = 10, 11
    d = zeros(T, b, c)
    for i in 1:b, j in 1:c
        d[i, j] = a[i] * a[j]
    end
    return sum(d)
end
a0 = rand(81);
model = Model(Ipopt.Optimizer)
@variable(model, 0.1 <= a[i=1:81] <= 1, start = a0[i])
register(model, :calculation_2, 81, calculation_2; autodiff=true)
@NLobjective(model, Min, calculation_2(a...))