Cplex是IBM出的一款科学计算软件,从IBM官网可以下到最新版。最近惊奇的发现python竟然能直接安装使用cplex了!
安装方法如下:
pip install cplex
pip install docplex
这个版本是限制变量数量的,如果要使用无限制版,请购买正版cplex或申请学术版,然后将python/cplex文件夹整体复制到anaconda的site-package下。
用一个简单案例尝试一下:
max x 1 + 2 x 2 + 3 x 3 + x 4 \max x_1+2x_2+3x_3+x_4 maxx1+2x2+3x3+x4
s.t. − x 1 + x 2 + x 3 + 10 x 4 ≤ 20 -x_1+x_2+x_3+10x_4\le20 −x1+x2+x3+10x4≤20
x 1 − 3 x 2 + x 3 ≤ 30 x_1-3x_2+x_3\le30 x1−3x2+x3≤30
x 2 − 3.5 x 4 = 0 x_2-3.5x_4=0 x2−3.5x4=0
x 1 ≤ 40 x_1\le40 x1≤40
2 ≤ x 4 ≤ 3 2\le x_4\le3 2≤x4≤3, x 4 ∈ Z x_4\in Z x4∈Z
x 1 , x 2 , x 3 ≥ 0 x_1,x_2,x_3\ge0 x1,x2,x3≥0
import cplex
from cplex.exceptions import CplexError
my_obj = [1.0, 2.0, 3.0, 1.0]
my_ub = [40.0, cplex.infinity, cplex.infinity, 3.0]
my_lb = [0.0, 0.0, 0.0, 2.0]
my_ctype = "CCCI"
my_colnames = ["x1", "x2", "x3", "x4"]
my_rhs = [20.0, 30.0, 0.0]
my_rownames = ["r1", "r2", "r3"]
my_sense = "LLE"
def populatebyrow(prob):
prob.objective.set_sense(prob.objective.sense.maximize)
prob.variables.add(obj=my_obj, lb=my_lb, ub=my_ub, types=my_ctype,
names=my_colnames)
rows = [[my_colnames, [-1.0, 1.0, 1.0, 10.0]],
[my_colnames, [1.0, -3.0, 1.0, 0.0]],
[my_colnames, [0.0, 1.0, -3.5, 0.0]]]
prob.linear_constraints.add(lin_expr=rows, senses=my_sense,rhs=my_rhs, names=my_rownames)
try:
my_prob = cplex.Cplex()
handle = populatebyrow(my_prob)
my_prob.solve()
except CplexError as exc:
print(exc)
print("Solution status = ", my_prob.solution.status[my_prob.solution.get_status()])
print("Solution value = ", my_prob.solution.get_objective_value())
x = my_prob.solution.get_values()
print('x: ',x)
代码中:
my_ctype中,C表示连续变量,I表示整数型变量
my_sense,G表示大于等于,E表示等于,L表示小于等于
不过由于只用能矩阵和向量形式表示,因此对于某些复杂的模型,写起来还是比较麻烦的。
docplex(Decision Optimization CPLEX® Modeling for Python)是一个基于python的建模语言库,这里是官方文档。
关键语句包括:
下面是一个简单的例子:
# first import the Model class from docplex.mp
from docplex.mp.model import Model
# create one model instance, with a name
m = Model(name='telephone_production')
# by default, all variables in Docplex have a lower bound of 0 and infinite upper bound
desk = m.continuous_var(name='desk')
cell = m.continuous_var(name='cell')
# constraint #1: desk production is greater than 100
m.add_constraint(desk >= 100)
# constraint #2: cell production is greater than 100
m.add_constraint(cell >= 100)
# constraint #3: assembly time limit
ct_assembly = m.add_constraint( 0.2 * desk + 0.4 * cell <= 400)
# constraint #4: paiting time limit
ct_painting = m.add_constraint( 0.5 * desk + 0.4 * cell <= 490)
m.maximize(12 * desk + 20 * cell)
s = m.solve()
m.print_information()
m.print_solution()
进阶技巧包括:
使用字典、元祖等进行定义,比如:
costs = {(1,3): 2, (1,5):4, (2,4):5, (2,5):3}
source = range(1, 3)
tm.minimize(tm.sum(x[i,j]*costs.get((i,j), 0)))
x = {(i,j): tm.continuous_var(name='x_{0}_{1}'.format(i,j)) for i in source for j in target}
使用列表推导式,比如:
x = {(i,j): tm.continuous_var(name='x_{0}_{1}'.format(i,j)) for i in source for j in target}
tm.minimize(tm.sum(x[i,j]*costs.get((i,j), 0) for i in source for j in target))
使用KPI,在report中查看。
下面是一个稍复杂的例子:
from collections import namedtuple
from docplex.mp.model import Model
from docplex.util.environment import get_environment
# ----------------------------------------------------------------------------
# Initialize the problem data
# ----------------------------------------------------------------------------
FOODS = [
("Roasted Chicken", 0.84, 0, 10),
("Spaghetti W/ Sauce", 0.78, 0, 10),
("Tomato,Red,Ripe,Raw", 0.27, 0, 10),
("Apple,Raw,W/Skin", .24, 0, 10),
("Grapes", 0.32, 0, 10),
("Chocolate Chip Cookies", 0.03, 0, 10),
("Lowfat Milk", 0.23, 0, 10),
("Raisin Brn", 0.34, 0, 10),
("Hotdog", 0.31, 0, 10)
]
NUTRIENTS = [
("Calories", 2000, 2500),
("Calcium", 800, 1600),
("Iron", 10, 30),
("Vit_A", 5000, 50000),
("Dietary_Fiber", 25, 100),
("Carbohydrates", 0, 300),
("Protein", 50, 100)
]
FOOD_NUTRIENTS = [
("Roasted Chicken", 277.4, 21.9, 1.8, 77.4, 0, 0, 42.2),
("Spaghetti W/ Sauce", 358.2, 80.2, 2.3, 3055.2, 11.6, 58.3, 8.2),
("Tomato,Red,Ripe,Raw", 25.8, 6.2, 0.6, 766.3, 1.4, 5.7, 1),
("Apple,Raw,W/Skin", 81.4, 9.7, 0.2, 73.1, 3.7, 21, 0.3),
("Grapes", 15.1, 3.4, 0.1, 24, 0.2, 4.1, 0.2),
("Chocolate Chip Cookies", 78.1, 6.2, 0.4, 101.8, 0, 9.3, 0.9),
("Lowfat Milk", 121.2, 296.7, 0.1, 500.2, 0, 11.7, 8.1),
("Raisin Brn", 115.1, 12.9, 16.8, 1250.2, 4, 27.9, 4),
("Hotdog", 242.1, 23.5, 2.3, 0, 0, 18, 10.4)
]
Food = namedtuple("Food", ["name", "unit_cost", "qmin", "qmax"])
Nutrient = namedtuple("Nutrient", ["name", "qmin", "qmax"])
# ----------------------------------------------------------------------------
# Build the model
# ----------------------------------------------------------------------------
def build_diet_model(**kwargs):
# Create tuples with named fields for foods and nutrients
foods = [Food(*f) for f in FOODS]
nutrients = [Nutrient(*row) for row in NUTRIENTS]
food_nutrients = {(fn[0], nutrients[n].name):
fn[1 + n] for fn in FOOD_NUTRIENTS for n in range(len(NUTRIENTS))}
# Model
mdl = Model(name='diet', **kwargs)
# Decision variables, limited to be >= Food.qmin and <= Food.qmax
qty = mdl.continuous_var_dict(foods, lb=lambda f: f.qmin, ub=lambda f: f.qmax, name=lambda f: "q_%s" % f.name)
# Limit range of nutrients, and mark them as KPIs
for n in nutrients:
amount = mdl.sum(qty[f] * food_nutrients[f.name, n.name] for f in foods)
mdl.add_range(n.qmin, amount, n.qmax)
mdl.add_kpi(amount, publish_name="Total %s" % n.name)
# Minimize cost
mdl.minimize(mdl.sum(qty[f] * f.unit_cost for f in foods))
return mdl
# ----------------------------------------------------------------------------
# Solve the model and display the result
# ----------------------------------------------------------------------------
if __name__ == '__main__':
mdl = build_diet_model()
mdl.print_information()
mdl.export_as_lp()
if mdl.solve():
mdl.float_precision = 3
print("* model solved as function:")
mdl.print_solution()
mdl.report_kpis()
# Save the CPLEX solution as "solution.json" program output
with get_environment().get_output_stream("solution.json") as fp:
mdl.solution.export(fp, "json")
else:
print("* model has no solution")
输出为:
Model: diet
- number of variables: 9
- binary=0, integer=0, continuous=9
- number of constraints: 7
- linear=7
- parameters: defaults
* model solved as function:
objective: 2.690
"q_Spaghetti W/ Sauce"=2.155
"q_Chocolate Chip Cookies"=10.000
"q_Lowfat Milk"=1.831
"q_Hotdog"=0.930
* KPI: Total Calories = 2000.000
* KPI: Total Calcium = 800.000
* KPI: Total Iron = 11.278
* KPI: Total Vit_A = 8518.433
* KPI: Total Dietary_Fiber = 25.000
* KPI: Total Carbohydrates = 256.806
* KPI: Total Protein = 51.174