Wikunia / ConstraintSolver.jl

ConstraintSolver in Julia: Blog posts ->
https://opensourc.es/blog/constraint-solver-1
MIT License
136 stars 14 forks source link

Question: Correct way to do use value of an integer variable for indexing #164

Open metanoid opened 4 years ago

metanoid commented 4 years ago

I have p products, and for each product I have a possibility of l price levels. For each such product and price level, I have the expected quantity sold, in a DataFrame called vals. I want to add a constraint that the total quantity sold must be greater than a constant.

If I used a binary programming approach, I would multiply each product's potential quantity by the binary decision variable. But I'm trying to solve this using an integer decision variable to represent the price level, and I realise I don't know how to use the value of a given variable as a lookup.

What I tried:

using JuMP
using ConstraintSolver
using DataFrames
const CS = ConstraintSolver # just to abbreviate

m = Model(CS.Optimizer)

num_products = 10
num_price_levels = 5

# make some fake data 
vals = DataFrame(ProductID = Int[], PriceLevel = Int[], Quantity = Float32[], ProfitMargin = Float32[], Profit = Float32[])
for prod in 1:num_products
    for pl in 1:num_price_levels
        q = 4 - pl/10 + rand()/10
        pm = 0.12 + pl/20 - (pl/20)^2 + rand()/10
        p = q*pm
        push!(vals, (prod, pl, q, pm, p))
    end
end

# one variable per product, the value of which is the index of the optimal price level
@variable(m, 1 <= price_level[p = 1:num_products] <= num_price_levels, Int)
# an expression per product which gives the quantity sold at the current price level
@expression(m, quantity[p = 1:num_products], sum(vals.Quantity[vals.ProductID .== p .& vals.PriceLevel .== price_level[p]]))     # TODO not working, figure out how to index by the value of a variable, if possible
@expression(m, profit[p = 1:num_products], sum(vals.Profit[vals.ProductID .== p .& vals.PriceLevel .== price_level[p]])) # TODO not working

# add a constraint that we must sell a minimum of quantity N overall
N = 100
@constraint(m, min_volume, 
    sum(quantity[p] for p in 1:num_products) >= N)

@objective(m, Max, sum(profit[p] for p in 1:num_products))

print(m)
optimize!(m)

However, this does not work. Is this sort of "indexing by the value of a variable" even possible? If so, what would a good design for such a thing look like?

Wikunia commented 4 years ago

Thanks for opening the issue. The short version: This is currently not possible. There is currently no way to index an array by the value of a variable in JuMP. The package JuCP.jl will eventually make it possible I think/hope and then I need to implement it here ;) Sorry that the ConstraintSolver is currently quite limited :/

metanoid commented 4 years ago

Is there a recommended workaround way of doing what I'm trying to do above, but without indexing by the value of the variable?

If not, I'm relatively confident I can do the above as a binary programming problem, I just wanted to use ConstraintSolver to be fancy, so no stress.

Wikunia commented 4 years ago

I would write it as a binary problem as well. At least currently I can't think of a workaround. Nevertheless thanks for having another try at my solver :smile:

Wikunia commented 3 years ago

I'm getting closer with this one as you seem to only need it for constant arrays. (#213) The problem here is also that you do some boolean logic inside the indexing which I don't have an idea for how to accomplish that kind of magic yet :smile: