I mean if there is a function whose input arguments are allowed to degenerate from a matrix to a vector or from a vector to a scalar. I try to give an example and sincerely ask the experienced practitioners what is the most recommended solution:
using JuMP, HiGHS
function fun(a, b, c)
model = Model(HiGHS.Optimizer)
@variable(model, x[eachindex(a)])
@variable(model, y[eachindex(b)])
@variable(model, z[eachindex(c)])
@constraint(model, a' * x + b' * y + c' * z >= 0)
optimize!(model)
return value.(x) <= rand(size(a)...), value.(y) <= rand(size(b)...), value.(z) <= rand(size(c)...)
end
fun([1, 2], [3, 4], [5, 6]) # (true, true, true)
fun(1, [3, 4], [5, 6]) # ERROR: Addition between an array and a JuMP scalar is not supported: instead of `x + y`, do `x .+ y` for element-wise addition.
OK, it doesn’t matter to write the constraint in a broadcast form instead of the more accurate vector form:
function fun(a, b, c)
model = Model(HiGHS.Optimizer)
@variable(model, x[eachindex(a)])
@variable(model, y[eachindex(b)])
@variable(model, z[eachindex(c)])
@constraint(model, a' * x .+ b' * y .+ c' * z >= 0)
optimize!(model)
return value.(x) <= rand(size(a)...), value.(y) <= rand(size(b)...), value.(z) <= rand(size(c)...)
end
fun([1, 2], [3, 4], [5, 6]) # (true, true, true)
fun(1, [3, 4], [5, 6]) # ERROR: MethodError: no method matching isless(::Vector{Float64}, ::Float64)
But now it brings an error similar to the [0] == 0
fault.
Then, what should I do now? Should I use some means to turn variable x
into a scalar when it has only one element,
function fun(a, b, c)
model = Model(HiGHS.Optimizer)
x = reduce(vcat, @variable(model, x[eachindex(a)]))
y = reduce(vcat, @variable(model, y[eachindex(b)]))
z = reduce(vcat, @variable(model, z[eachindex(c)]))
@constraint(model, a' * x .+ b' * y .+ c' * z >= 0)
optimize!(model)
return value.(x) <= rand(size(a)...), value.(y) <= rand(size(b)...), value.(z) <= rand(size(b)...)
end
fun([1, 2], [3, 4], [5, 6]) # (true, true, true)
fun(1, [3, 4], [5, 6]) # (true, true, true)
or should I use multiple dispatch (where size
has to be replaced by length
)?
function fun(a, b, c)
model = Model(HiGHS.Optimizer)
@variable(model, x[eachindex(a)])
@variable(model, y[eachindex(b)])
@variable(model, z[eachindex(c)])
@constraint(model, a' * x .+ b' * y .+ c' * z >= 0)
optimize!(model)
return value.(x) <= rand(length(a)), value.(y) <= rand(length(b)), value.(z) <= rand(length(c)) # `size` has to be replaced by `length`
end
fun(a::Number, b, c) = fun([a], b, c)
fun(a, b::Number, c) = fun(a, [b], c)
fun(a, b, c::Number) = fun(a, b, [c])
fun([1, 2], [3, 4], [5, 6]) # (true, true, true)
fun(1, [3, 4], [5, 6]) # (true, true, true)
How about the function has many input arguments: fun(a, b, c, d, e, f)
? And how about the function’s input arguments are matrices by default (do I have to write methods for each argument in case that it is a vector and a scalar)?