How do you apply ceil/round function inside JuMP constraints, or can you force constraints to evaluate to Ints?

Hi, I have this simple model that tries to maximize theoretical demand for a product given some SKU level inventory constraints and a probability distribution for SKU demand. In the first constraint I’d like to compare the output of a multiplication of my variable d multiplied by the given probability distribution p for a SKU to the inventory constraint for that SKU. However, I’d like to apply either a ceil or round function to the multiplication since we can’t have partial units. I’ve set this up as an integer problem, but I don’t know how I can either specify integer constraints, or apply a type coercion/ceil/round function inside of the constraint. Sample code:

using JuMP, GLPK

p = [ .1, .15, .2, .25, .2, .1 ]
inventory = [ 10.0, 13.0, 22.0, 25.0, 20.0, 10.0 ];

m = Model(with_optimizer(GLPK.Optimizer))

@variable(m, d >= 0, Int)
@objective(m, Max, d/sum(inventory))

for i = 1:length(p)
    @constraint(m, ceil(d * p[i]) <= inventory[i])
end

Error:

MethodError: no method matching ceil(::GenericAffExpr{Float64,VariableRef})
Closest candidates are:
  ceil(!Matched::Type{BigInt}, !Matched::BigFloat) at mpfr.jl:314
  ceil(!Matched::Missing) at missing.jl:112
  ceil(!Matched::Missing, !Matched::Integer) at missing.jl:112
  ...

Is there a better way to ensure that the output of d * p[i] gets coerced into an integer value?
Thanks!

I was able to reformulate this in a way that I don’t think need the function applied anymore:

This now models each SKU’s demand as an integer and then checks that against the required SKU distribution.

skus = [1,2,3,4,5,6]
n_skus = length(skus)

sku_probabilities = [ .1, .15, .2, .25, .2, .1 ]
total_demand = 10000
inventory_distribution = [ .1, .13, .22, .25, .2, .1 ]
inventory = [ total_demand * p for p in inventory_distribution ]

m = Model(with_optimizer(GLPK.Optimizer))

@variable(m, sku_demand[1:n_skus] >= 0, Int)

# we maximize inventory utilization:
@objective(m, Max, sum(sku_demand)/sum(inventory))

for i = 1:length(skus)
    # make sure demand <= inventory
    @constraint(m, sku_demand[i] <= inventory[i] )
    # make sure demand is distributed as required
    @constraint(m, sku_demand[i] <= sum(sku_demand) * sku_probabilities[i] )
end

m

Another way is to add an auxiliary variable and force that to be integer.

p = 0.3
model = Model()
@variable(model, d >= 0, Int)
@variable(model, aux, Int)
@constraint(model, d * p == aux)
2 Likes

Oh that’s handy, thanks!
So, you’d still also have the original constraint then, but the aux constraint forces d * p[i] to evaulate to an int?

@constraint(m, d * p[i]  <= inventory[i])

Yes, exactly.