2

I'm trying to use GEKKO to solve some kind of the shop stock balance problem - the main goal is to determine which arrival (x) of goods per day will provide sufficient stock (Inv) in the store, taking into account sales (s) and demand (d).

So, my objective function is:

Objective

With restrictions:

Constraints

See them in code below:

from gekko import GEKKO

m = GEKKO(remote=False)

n = 70  # Number of days, iterations
a = m.Param(144.846147/n)  # coefficient for balance valuation
b = m.Param(417.33)  # coefficient for deficit valuation
zero = m.Param(0.001)

receptions = [24, 31, 38, 45, 52, 59, 66]   # Days when arrival expected
sales_coef = m.Param([0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1,
                      0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
                      0, 1, 0, 0], integer=True)  # Sales
demand_coef = m.Param([0.218, 0.218, 0.218, 0.218, 0.218, 0.218, 0.218, 0.218, 0.218, 0.218, 0.218, 0.218, 0.218, 0.218,
                       0.218, 0.218, 0.218, 0.218, 0.218, 0.218, 0.218, 0.206, 0.206, 0.206, 0.206, 0.206, 0.206, 0.206,
                       0.206, 0.206, 0.206, 0.206, 0.206, 0.206, 0.206, 0.206, 0.251, 0.251, 0.251, 0.251, 0.251, 0.251,
                       0.251, 0.251, 0.251, 0.251, 0.251, 0.251, 0.251, 0.251, 0.251, 0.251, 0.21, 0.21, 0.21, 0.21,
                       0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21], integer=False)  # Demand

x = m.Array(m.MV, n, lb=0, integer=True)  # Arrival
y = m.Array(m.MV, n, lb=0, integer=True)  # Balance

# Restrictions
for i in range(n):
    if i + 1 in receptions:  # if arrival expected
        m.Equation(x[i] >= 0)
        x[i].STATUS = 1
    else:
        x[i].VALUE = 0  # In other days arrival fixed to 0
        x[i].STATUS = 0

    if i > 0:  # Restrictions for balance, except first day with initial value
        y[i] = m.Intermediate(m.max2(y[i - 1] - sales_coef[i - 1], zero) + x[i])
    else:
        y[i].VALUE = 5  # Initial balance
        y[i].STATUS = 0

m.Obj(a * m.sum(y) + b * m.sum([m.max2(demand_coef[i] - y[i], zero) for i in range(n)]))

m.options.SOLVER = 1
m.options.IMODE = 5
m.options.MAX_ITER = 1000

m.solve(disp=True)

print([(i + 1, yi) for i, yi in enumerate(y)])

I'm using APOPT (v1.0) and, as you can see, variables with integer=True are used for balancies and arrivals. But when I look at the values of balancies y[i] in output, I can see, that for some days (when the deficit is expected), optimizer somehow selected float values for integer variable, for example:

(24, [1.0]), (25, [0.2059999]), (26, [0.2059999])

I expected, that type of variable will be taken into account when manipulating with variable. So, how is it possible? Have I miss some variables parameters, model options?

1 Answer 1

1

There is an option in APOPT that gives a tolerance for what is considered an integer value. It is the amount that a candidate solution variable can deviate from an integer solution and still be considered an integer and has a default value of 1.0e-2.

minlp_integer_tol 1.0e-2

This means that it can deviate up to 0.01 away from an integer value and still be considered an integer. You can adjust this and other solver options in Gekko as shown in the documentation.

m.solver_options = ['minlp_integer_tol 1.0e-2',\
                    'minlp_gap_tol 1.0e-2',\
                    'minlp_maximum_iterations 10000',\
                    'minlp_max_iter_with_int_sol 500']

If you set minlp_integer_tol 0 it may increase the solution time but will give you exact integer solutions.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for reply! I already read about this solver option and used it in one of versions, but problem seems to be in another place. Here: y[i] = m.Intermediate(m.max2(y[i - 1] - sales_coef[i - 1], zero) + x[i]) I assigned to integer MV intermediate expression and after that it is not an integer, right?
Try using max3 (Binary switch form) instead of max2 (MPCC form) if you are getting non-optimal results. Your expression for y[i] should still be integer because all of the terms are also integer and there is no division, only addition and subtraction.
y[i] also used in objective function, where its value is compared to demand: [m.max2(demand_coef[i] - y[i], zero) for i in range(n)] And demand can be (and in this example always is) a float. So optimizer seems to take it into account and set some of y[i] = demand value

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.