Skip to content

Commit

Permalink
Merge branch 'master' into rs/highs
Browse files Browse the repository at this point in the history
  • Loading branch information
tuliotoffolo committed Feb 17, 2024
2 parents 6bce768 + 2c4d42c commit fcb37be
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 51 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Some of the main features of MIP are:
different solvers are handled by Python-MIP and you write only one
solver independent code;

* written in modern [typed](https://docs.python.org/3/library/typing.html) Python 3 (requires Python 3.6 or newer).
* written in modern [typed](https://docs.python.org/3/library/typing.html) Python 3 (requires Python 3.8 or newer).

## Examples

Expand All @@ -63,7 +63,7 @@ Questions, suggestions and feature request can be posted at [Discussions](https:

## Build status

[![Github Actions Status](https://github.com/coin-or/python-mip/workflows/CI/badge.svg?branch=master)](https://github.com/coin-or/python-mip/actions)
[![CI](https://github.com/coin-or/python-mip/actions/workflows/github-ci.yml/badge.svg)](https://github.com/coin-or/python-mip/actions/workflows/github-ci.yml)
[![Current version](https://badge.fury.io/gh/coin-or%2Fpython-mip.svg)](https://github.com/coin-or/python-mip/releases)
[![Current total of lines](https://tokei.rs/b1/github/coin-or/python-mip?category=lines)](https://github.com/coin-or/python-mip)
[![License](https://img.shields.io/badge/license-EPL-blue.svg)](https://github.com/coin-or/python-mip/blob/master/LICENSE)
Expand Down
59 changes: 20 additions & 39 deletions examples/plant_location.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,6 @@

import sys

# Workaround for issues with python not being installed as a framework on mac
# by using a different backend.
if sys.platform == "darwin": # OS X
import matplotlib as mpl
mpl.use('Agg')
del mpl

import matplotlib.pyplot as plt
from math import sqrt, log
from itertools import product
from mip import Model, xsum, minimize, OptimizationStatus
Expand All @@ -36,28 +28,26 @@
C = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# position of clients
pc = {1: (94, 10), 2: (57, 26), 3: (74, 44), 4: (27, 51), 5: (78, 30), 6: (23, 30),
7: (20, 72), 8: (3, 27), 9: (5, 39), 10: (51, 1)}
pc = {
1: (94, 10),
2: (57, 26),
3: (74, 44),
4: (27, 51),
5: (78, 30),
6: (23, 30),
7: (20, 72),
8: (3, 27),
9: (5, 39),
10: (51, 1),
}

# demands
d = {1: 302, 2: 273, 3: 275, 4: 266, 5: 287, 6: 296, 7: 297, 8: 310, 9: 302, 10: 309}

# plotting possible plant locations
for i, p in pf.items():
plt.scatter((p[0]), (p[1]), marker="^", color="purple", s=50)
plt.text((p[0]), (p[1]), "$f_%d$" % i)

# plotting location of clients
for i, p in pc.items():
plt.scatter((p[0]), (p[1]), marker="o", color="black", s=15)
plt.text((p[0]), (p[1]), "$c_{%d}$" % i)

plt.text((20), (78), "Region 1")
plt.text((70), (78), "Region 2")
plt.plot((50, 50), (0, 80))

dist = {(f, c): round(sqrt((pf[f][0] - pc[c][0]) ** 2 + (pf[f][1] - pc[c][1]) ** 2), 1)
for (f, c) in product(F, C) }
dist = {
(f, c): round(sqrt((pf[f][0] - pc[c][0]) ** 2 + (pf[f][1] - pc[c][1]) ** 2), 1)
for (f, c) in product(F, C)
}

m = Model()

Expand All @@ -82,7 +72,7 @@
D = 6 # nr. of discretization points, increase for more precision
v = [c[f] * (v / (D - 1)) for v in range(D)] # points
# non-linear function values for points in v
vn = [0 if k == 0 else 1520 * log(v[k]) for k in range(D)]
vn = [0 if k == 0 else 1520 * log(v[k]) for k in range(D)]
# w variables
w = [m.add_var() for v in range(D)]
m += xsum(w) == 1 # convexification
Expand All @@ -98,30 +88,21 @@

# objective function
m.objective = minimize(
xsum(dist[i, j] * x[i, j] for (i, j) in product(F, C)) + xsum(y[i] for i in F) )
xsum(dist[i, j] * x[i, j] for (i, j) in product(F, C)) + xsum(y[i] for i in F)
)

m.optimize()

plt.savefig("location.pdf")

if m.num_solutions:
print("Solution with cost {} found.".format(m.objective_value))
print("Facilities capacities: {} ".format([z[f].x for f in F]))
print("Facilities cost: {}".format([y[f].x for f in F]))

# plotting allocations
for (i, j) in [(i, j) for (i, j) in product(F, C) if x[(i, j)].x >= 1e-6]:
plt.plot(
(pf[i][0], pc[j][0]), (pf[i][1], pc[j][1]), linestyle="--", color="darkgray"
)

plt.savefig("location-sol.pdf")

# sanity checks
opt = 99733.94905406
if m.status == OptimizationStatus.OPTIMAL:
assert abs(m.objective_value - opt) <= 0.01
elif m.status == OptimizationStatus.FEASIBLE:
assert m.objective_value >= opt - 0.01
else:
assert m.status not in [OptimizationStatus.INFEASIBLE, OptimizationStatus.UNBOUNDED]
assert m.status not in [OptimizationStatus.INFEASIBLE, OptimizationStatus.UNBOUNDED]
14 changes: 10 additions & 4 deletions mip/cbc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import Dict, List, Tuple, Optional, Union
from sys import platform, maxsize
from os.path import dirname, isfile, exists
from platform import machine as platform_machine
import os
import multiprocessing as multip
import numbers
Expand Down Expand Up @@ -97,7 +98,9 @@
elif platform.lower().startswith("darwin") or platform.lower().startswith(
"macos"
):
if os_is_64_bit:
if platform_machine().lower().startswith("arm64"):
libfile = os.path.join(pathlib, "cbc-c-darwin-arm64.dylib")
elif os_is_64_bit:
libfile = os.path.join(pathlib, "cbc-c-darwin-x86-64.dylib")
if not libfile:
raise NotImplementedError("You operating system/platform is not supported")
Expand Down Expand Up @@ -1405,20 +1408,23 @@ def var_get_column(self, var: "Var") -> Column:

def add_constr(self, lin_expr: LinExpr, name: str = ""):
# collecting linear expression data
numnz = len(lin_expr.expr)

# In case of empty linear expression add dummy row
# by setting first index of row explicitly with 0
numnz = len(lin_expr.expr) or 1

if numnz > self.iidx_space:
self.iidx_space = max(numnz, self.iidx_space * 2)
self.iidx = ffi.new("int[%d]" % self.iidx_space)
self.dvec = ffi.new("double[%d]" % self.iidx_space)

# cind = self.iidx
self.iidx = [var.idx for var in lin_expr.expr.keys()]
self.iidx = [var.idx for var in lin_expr.expr.keys()] or [0]

# cind = ffi.new("int[]", [var.idx for var in lin_expr.expr.keys()])
# cval = ffi.new("double[]", [coef for coef in lin_expr.expr.values()])
# cval = self.dvec
self.dvec = [coef for coef in lin_expr.expr.values()]
self.dvec = [coef for coef in lin_expr.expr.values()] or [0]

# constraint sense and rhs
sense = lin_expr.sense.encode("utf-8")
Expand Down
5 changes: 5 additions & 0 deletions mip/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ class OptimizationStatus(Enum):
CUTOFF = 7
"""No feasible solution exists for the current cutoff"""

INF_OR_UNBD = 8
"""Special state for gurobi solver. In some cases gurobi could not
determine if the problem is infeasible or unbounded due to application
of dual reductions (when active) during presolve."""

OTHER = 10000


Expand Down
9 changes: 8 additions & 1 deletion mip/gurobi.py
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,14 @@ def callback(
if status == 3: # INFEASIBLE
return OptimizationStatus.INFEASIBLE
if status == 4: # INF_OR_UNBD
return OptimizationStatus.UNBOUNDED
# Special case by gurobi, where an additional run has to be made
# to determine infeasibility or unbounded problem
# For this run dual reductions must be disabled
# See gurobi support article online - How do I resolve the error "Model is infeasible or unbounded"?
# self.set_int_param("DualReductions", 0)
# GRBoptimize(self._model)
# return OptimizationStatus.INFEASIBLE if self.get_int_attr("Status") == 3 else OptimizationStatus.UNBOUNDED
return OptimizationStatus.INF_OR_UNBD
if status == 5: # UNBOUNDED
return OptimizationStatus.UNBOUNDED
if status == 6: # CUTOFF
Expand Down
Binary file added mip/libraries/cbc-c-darwin-arm64.dylib
Binary file not shown.
6 changes: 1 addition & 5 deletions mip/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,11 +338,7 @@ def add_constr(
raise mip.InvalidLinExpr(
"A boolean (true/false) cannot be used as a constraint."
)
# TODO: some tests use empty linear constraints, which ideally should not happen
# if len(lin_expr) == 0:
# raise mip.InvalidLinExpr(
# "An empty linear expression cannot be used as a constraint."
# )

return self.constrs.add(lin_expr, name, priority)

def add_lazy_constr(self: "Model", expr: "mip.LinExpr"):
Expand Down
85 changes: 85 additions & 0 deletions scripts/buildCBCMacARM.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
export MACOSX_DEPLOYMENT_TARGET="10.9"
export CFLAGS="-fPIC -Ofast -DNDEBUG -ffast-math -mmacosx-version-min=10.9"
export CXXFLAGS="-fPIC -Og -DNDEBUG -ffast-math -std=c++11 -stdlib=libc++ -mmacosx-version-min=10.9"
export F77FLAGS="-fPIC -Ofast -DNDEBUG -ffast-math"
export LDFLAGS="-fPIC -Ofast -DNDEBUG -ffast-math"

DIR=`pwd`
OUTDIR="/opt/cbc/bin"
export PKG_CONFIG_PATH="${OUTDIR}/lib/pkgconfig/:${PKG_CONFIG_PATH}"

echo
echo "Making and installing Glpk"
cd ${DIR}/ThirdParty-Glpk
./configure --prefix=${OUTDIR}/ --enable-static --disable-shared
git pull
make
make install

echo
echo "Making and installing Lapack"
cd ${DIR}/ThirdParty-Lapack
./configure --prefix=${OUTDIR}/ --enable-static --disable-shared
git pull
make
make install

echo
echo "Making and installing Blas"
cd ${DIR}/ThirdParty-Blas
./configure --prefix=${OUTDIR}/ --enable-static --disable-shared
git pull
make
make install

echo
echo "Making and installing CoinUtils"
cd ${DIR}/CoinUtils
./configure --prefix=${OUTDIR}/ --enable-static --disable-shared
git pull
make
make install

echo
echo "Making and installing Osi"
cd ${DIR}/Osi
./configure --prefix=${OUTDIR}/ --enable-static --disable-shared
git pull
make
make install

echo
echo "Making and installing Clp"
cd ${DIR}/Clp
./configure --prefix=${OUTDIR}/ --enable-static --disable-shared
git pull
make
make install

echo
echo "Making and installing Cgl"
cd ${DIR}/Cgl
./configure --prefix=${OUTDIR}/ --enable-static --disable-shared
git pull
make
make install

echo
echo "Making and installing Cbc"
cd ${DIR}/Cbc
./configure --prefix=${OUTDIR}/ --enable-cbc-parallel --enable-static --disable-shared
git pull
make
make install

echo
echo "Compiling dynamic library"
cd ${DIR}
clang++ -shared -Ofast -fPIC -o cbc-c-darwin-arm64.dylib \
-I${OUTDIR}/include/coin-or/ -I${OUTDIR}/include/coin-or/glpk -I${OUTDIR}/include/coin \
-L${OUTDIR}/lib \
./Cbc/src/Cbc_C_Interface.cpp \
-lCbc -lCgl -lClp -lCoinUtils -lOsi -lOsiCbc -lOsiClp -lOsiGlpk \
-lcoinblas -lcoinglpk -lcoinlapack \
-lbz2 -lz -llapack ${CXXFLAGS} -stdlib=libc++ -lreadline
echo "Done!"

0 comments on commit fcb37be

Please sign in to comment.