mobook / MO-book

Hands-On Optimization with Python
MIT License
153 stars 40 forks source link

"Cutting Stock" section errors out in multiple places #75

Open IndyHouseGuy opened 8 months ago

IndyHouseGuy commented 8 months ago

If you take the code on this section:

https://mobook.github.io/MO-book/notebooks/05/06-cutting-stock.html

And place it in Google Colab, it works up to "Cutting Stock Problem: Bilinear reformulation" and then most of the sections error out after that. Any advice? 8 of the code sections in total error out for a variety of reasons.

My best guess is it's related to the version of the solver.

If you want to see the errors, you can see my notebook here:

https://github.com/IndyHouseGuy/Pyomo/blob/main/06_cutting_stock_NO_EDITS_NO_MODIFICATIONS.ipynb

That said, the first block to error out is:

def bilinear_cut_stock(stocks, finish, Np=len(finish)):
    m = pyo.ConcreteModel()

    m.S = pyo.Set(initialize=list(stocks.keys()))
    m.F = pyo.Set(initialize=list(finish.keys()))
    m.P = pyo.RangeSet(0, Np - 1)

    # sum of all finished parts
    f_total_demand = max([finish[f]["demand"] for f in m.F])

    # define a with bounded values
    def a_bounds(m, f, p):
        return (0, max([int(stocks[s]["length"] / finish[f]["length"]) for s in m.S]))

    m.a = pyo.Var(m.F, m.P, domain=pyo.NonNegativeIntegers, bounds=a_bounds)
    m.b = pyo.Var(m.S, m.P, domain=pyo.Binary)
    m.x = pyo.Var(m.P, domain=pyo.NonNegativeIntegers, bounds=(0, f_total_demand))

    # minimize cost
    @m.Objective(sense=pyo.minimize)
    def cost(m):
        c = {s: stocks[s]["cost"] for s in m.S}
        return sum(c[s] * m.b[s, p] * m.x[p] for s in m.S for p in m.P)

    # assign one stock to each pattern
    @m.Constraint(m.P)
    def assign_each_stock_to_pattern(m, p):
        return sum(m.b[s, p] for s in m.S) == 1

    # pattern feasibility
    @m.Constraint(m.P)
    def feasible_pattern(m, p):
        return sum(m.a[f, p] * finish[f]["length"] for f in m.F) <= sum(
            m.b[s, p] * stocks[s]["length"] for s in m.S
        )

    # demand constraints
    @m.Constraint(m.F)
    def demand(m, f):
        return sum(m.a[f, p] * m.x[p] for p in m.P) >= finish[f]["demand"]

    # order the patterns to reduce symmetries
    @m.Constraint(m.P)
    def order(m, p):
        if p == 0:
            return pyo.Constraint.Skip
        return m.x[p] >= m.x[p - 1]

    # upper bound on sum of all patterns
    @m.Constraint()
    def max_patterns(m):
        return sum(m.x[p] for p in m.P) <= f_total_demand

    MINLO_SOLVER.solve(m)

    cost = m.cost()
    x = [m.x[p]() for p in m.P]
    patterns = []
    for p in m.P:
        a = {f: round(m.a[f, p]()) for f in m.F}
        patterns.append({"stock": [s for s in m.S if m.b[s, p]() > 0][0], "cuts": a})

    return patterns, x, cost

patterns, x, cost = bilinear_cut_stock(stocks, finish, 2)
plot_nonzero_patterns(stocks, finish, patterns, x, cost)

which gets this error:

ERROR:pyomo.opt:Solver (asl) returned non-zero return code (-6)
ERROR:pyomo.opt:Solver log:
Couenne 0.5.8 -- an Open-Source solver for Mixed Integer Nonlinear Optimization
Mailing list: [couenne@list.coin-or.org](mailto:couenne@list.coin-or.org)
Instructions: http://www.coin-or.org/Couenne
munmap_chunk(): invalid pointer
couenne: 
---------------------------------------------------------------------------
ApplicationError                          Traceback (most recent call last)
[<ipython-input-12-36f29ff97f2b>](https://localhost:8080/#) in <cell line: 66>()
     64 
     65 
---> 66 patterns, x, cost = bilinear_cut_stock(stocks, finish, 2)
     67 plot_nonzero_patterns(stocks, finish, patterns, x, cost)

1 frames
[/usr/local/lib/python3.10/dist-packages/pyomo/opt/base/solvers.py](https://localhost:8080/#) in solve(self, *args, **kwds)
    625                 elif hasattr(_status, 'log') and _status.log:
    626                     logger.error("Solver log:\n" + str(_status.log))
--> 627                 raise ApplicationError("Solver (%s) did not exit normally" % self.name)
    628             solve_completion_time = time.time()
    629             if self._report_timing:

ApplicationError: Solver (asl) did not exit normally

I must empasize that multiple of the other sections error out as well.