pythonoptimizationor-toolsnonlinear-optimization

Limit the coefficient valule on google OR-Tools


I Have a problem very similar to the The Stigler diet

I have replicated the results with my data in the below code:

data = [
['f1', 10, 15, 17, 10],
['f2', 2, 11, 12, 14],
['f3', 5, 17, 16, 13],
['f4', 8, 12, 8, 16]
]

nutrients = [
    ["protein",15.5],
    ["carbohydrates",12.3]]

TM = 10
nutrients = [
    ["protein",15.5*TM],
    ["carbohydrates",12.3*TM]]

food = [[]] * len(data)

# Objective: minimize the sum of (price-normalized) foods.
objective = solver.Objective()
for i in range(0, len(data)):
    food[i] = solver.NumVar(0.0, solver.infinity(), data[i][0])
    objective.SetCoefficient(food[i], 4)
objective.SetMinimization()

# Create the constraints, one per nutrient.

constraints = [0] * len(nutrients)
for i in range(0, len(nutrients)):
    constraints[i] = solver.Constraint(nutrients[i][1], solver.infinity())
    for j in range(0, len(data)):
        constraints[i].SetCoefficient(food[j], data[j][i+3])


status = solver.Solve()

if status == solver.OPTIMAL:
    # Display the amounts (in dollars) to purchase of each food.
    price = 0
    num_nutrients = len(data[i]) - 3
    nutrients = [0] * (len(data[i]) - 3)
    for i in range(0, len(data)):
        price += food[i].solution_value()

        for nutrient in range(0, num_nutrients):
            nutrients[nutrient] += data[i][nutrient+3] * food[i].solution_value()

        if food[i].solution_value() > 0:
            print ("%s = %f" % (data[i][0], food[i].solution_value()))

    print ('Optimal  price: $%.2f' % (price))
else:  # No optimal solution was found.
    if status == solver.FEASIBLE:
        print ('A potentially suboptimal solution was found.')
    else:
        print ('The solver could not solve the problem.')

Which returns this result:

f1 = 0.770492 f3 = 8.868852 Optimal  price: $9.64

Which is fine, except that I have and upperbound for each type of food: E.G:

f1 = 4
f2 = 6
f3 = 5
f4 =2

How can I add this part to the constrains?


Solution

  • You will have to set them to the decision variables (which in this case seem to be how much of which food item to eat) and add an upper bound for each food item that describes its range.

    So in this case:

    upper_bounds = [4, 6, 5, 2]
    # Objective: minimize the sum of (price-normalized) foods.
    objective = solver.Objective()
    for i in range(0, len(data)):
        food[i] = solver.NumVar(0.0, upper_bounds[i], data[i][0])
        objective.SetCoefficient(food[i], 4)
    objective.SetMinimization()
    

    Note that solver.NumVar takes 3 arguments, first the lower bound, second the upper bound and last its name. Hope this helps.