>= 0; # 製品1の生産量
var x >= 0; # 製品2の生産量
var y 40 * x + 30 * y;
maximize Profit: + 2 * y <= 20; # 資源1の制約
subject to Constraint1: x 3 * x + y <= 30; # 資源2の制約 subject to Constraint2:
Overwriting production.mod
AMPLをPythonから呼び出して使うためには amplpy パッケージを使う。AMPLはモデルファイル(.mod)とデータファイル(.dat)とコマンドファイル(.run)から構成される。
マジックコマンド writefile の後にファイル名を入れてモデルファイルを出力しておく。
AMPLクラスのインスタンスを作り、readメソッドでモデルファイルを読み込む。
モデルインスタンス m
に対するメソッドを用いてソルバー指定、最適化や結果を得ることができる。
from amplpy import AMPL, Environment, tools
env = Environment("/Users/mikiokubo/Documents/ampl/")
ampl = AMPL(env)
# Google Colab.の場合
# from amplpy import ampl_notebook
# m = ampl_notebook(
# modules=["highs","gurobi","cbc","scip","coin","gecode"], #coin includes ipopt, couenne, bonmin
# license_uuid=None)
ampl.read('production.mod')
ampl.option["solver"] = "highs"
ampl.solve()
print("Profit=", ampl.get_value("Profit"))
print("x=", ampl.get_value("x"))
print("y=", ampl.get_value("y"))
HiGHS 1.10.0: optimal solution; objective 500
2 simplex iterations
0 barrier iterations
Profit= 500
x= 8
y= 6
AMPLの1つの特徴としてモデルとデータの分離があげられる。以下は AMPLコマンドで普通に書いた例を示す。
reset;
# モデルファイル (example.mod)
model;
param a;
param b;
param c;
var x >= 0;
var y >= 0;
maximize Profit: a * x + b * y;
subject to Constraint1: x + y <= c;
# データファイル (example.dat)
data;
param a := 3;
param b := 2;
param c := 5;
# AMPLコマンド
#model example.mod;
#data example.dat;
option solver highs;
solve;
display Profit, x, y;
HiGHS 1.10.0: optimal solution; objective 15
0 simplex iterations
0 barrier iterations
Profit = 15
x = 5
y = 0
amplpyを使うと、データをPythonで入力することができる。これによって、Pythonのデータ分析とAMPLの融合が可能になる。
param a;
param b;
param c;
var x >= 0;
var y >= 0;
maximize Profit: a * x + b * y;
subject to Constraint1: x + y <= c;
Overwriting example.mod
m = AMPL(env)
m.read('example.mod')
m.param["a"] = 3
m.param["b"] = 2
m.param["c"] = 5
m.option["solver"] = "highs"
m.solve()
print("Profit=", m.get_value("Profit"))
print("x=", m.get_value("x"))
print("y=", m.get_value("y"))
HiGHS 1.10.0: optimal solution; objective 15
0 simplex iterations
0 barrier iterations
Profit= 15
x= 5
y= 0
多次元ナップサック問題を用いて、データをPythonのコマンドで入力する方法を示す。
# 多制約ナップサック問題のAMPLモデル
set ITEMS; # アイテムの集合
set RESOURCES; # リソースの集合
param value{i in ITEMS} >= 0; # 各アイテムの価値
param weight{r in RESOURCES, i in ITEMS} >= 0; # 各アイテムの各リソース消費量
param capacity{r in RESOURCES} >= 0; # 各リソースの容量
var select{i in ITEMS} binary; # アイテム選択変数
maximize TotalValue: sum{i in ITEMS} value[i] * select[i];
subject to ResourceCapacity{r in RESOURCES}:
sum{i in ITEMS} weight[r,i] * select[i] <= capacity[r];
Overwriting mkp.mod
import random
random.seed(1)
m = AMPL(env)
m.read('mkp.mod')
m.set['ITEMS'] = [1,2,3]
m.set['RESOURCES'] = ["A","B"]
m.param["value"] ={i:random.randint(1,10) for i in [1,2,3]}
m.param["weight"] ={(r,i):random.randint(5,30) for r in ["A","B"] for i in [1,2,3]}
m.param["capacity"] = {r:50 for r in ["A","B"]}
m.option["solver"] = "highs"
m.solve()
print("TotalValue=", m.get_value("TotalValue"))
m.display("select")
m.var["select"].to_dict() #変数を辞書に変換
HiGHS 1.10.0: optimal solution; objective 13
0 simplex iterations
0 branching nodes
TotalValue= 13
select [*] :=
1 1
2 1
3 0
;
{1: 1, 2: 1, 3: 0}
栄養問題を例として、pandasのデータフレームからデータを生成する方法を示す。
# 栄養問題のAMPLモデル
set FOODS; # 食品の集合
set NUTRIENTS; # 栄養素の集合
param cost{f in FOODS} >= 0; # 各食品の単価
param amount{n in NUTRIENTS, f in FOODS} >= 0; # 各食品に含まれる栄養素の量
param min_req{n in NUTRIENTS} >= 0; # 各栄養素の最小必要量
param max_req{n in NUTRIENTS} >= 0; # 各栄養素の最大許容量
var buy{f in FOODS} >= 0; # 各食品の購入量
minimize TotalCost: sum{f in FOODS} cost[f] * buy[f];
subject to MinNutrient{n in NUTRIENTS}:
sum{f in FOODS} amount[n,f] * buy[f] >= min_req[n];
subject to MaxNutrient{n in NUTRIENTS}:
sum{f in FOODS} amount[n,f] * buy[f] <= max_req[n];
Overwriting diet.mod
import pandas as pd
import numpy as np
food_df = pd.DataFrame(
[
("BEEF", 3.59),
("CHK", 2.59),
("FISH", 2.29),
("HAM", 2.89),
("MCH", 1.89),
("MTL", 1.99),
("SPG", 1.99),
("TUR", 2.49),
],
columns=["FOODS", "cost"],
).set_index("FOODS")
# Create a pandas.DataFrame with data for n_min, n_max
nutr_df = pd.DataFrame(
[
("A", 700, 20000),
("C", 700, 20000),
("B1", 700, 20000),
("B2", 700, 20000),
("NA", 0, 50000),
("CAL", 16000, 24000),
],
columns=["NUTRIENTS", "min_req", "max_req"],
).set_index("NUTRIENTS")
amt_df = pd.DataFrame(
np.matrix(
[
[60, 8, 8, 40, 15, 70, 25, 60],
[20, 0, 10, 40, 35, 30, 50, 20],
[10, 20, 15, 35, 15, 15, 25, 15],
[15, 20, 10, 10, 15, 15, 15, 10],
[928, 2180, 945, 278, 1182, 896, 1329, 1397],
[295, 770, 440, 430, 315, 400, 379, 450],
]
),
columns=food_df.index.tolist(),
index=nutr_df.index.tolist(),
)
amt_df
BEEF | CHK | FISH | HAM | MCH | MTL | SPG | TUR | |
---|---|---|---|---|---|---|---|---|
A | 60 | 8 | 8 | 40 | 15 | 70 | 25 | 60 |
C | 20 | 0 | 10 | 40 | 35 | 30 | 50 | 20 |
B1 | 10 | 20 | 15 | 35 | 15 | 15 | 25 | 15 |
B2 | 15 | 20 | 10 | 10 | 15 | 15 | 15 | 10 |
NA | 928 | 2180 | 945 | 278 | 1182 | 896 | 1329 | 1397 |
CAL | 295 | 770 | 440 | 430 | 315 | 400 | 379 | 450 |
m = AMPL(env)
m.read('diet.mod')
m.set_data(food_df, "FOODS")
m.set_data(nutr_df, "NUTRIENTS")
m.get_parameter("amount").set_values(amt_df)
m.option["solver"] = "highs"
m.solve()
print("TotalCost=", m.get_value("TotalCost"))
m.display("buy")
HiGHS 1.10.0: optimal solution; objective 90.0041958
2 simplex iterations
0 barrier iterations
TotalCost= 90.00419580419579
buy [*] :=
BEEF 0
CHK 0
FISH 0
HAM 0
MCH 28.6247
MTL 18.042
SPG 0
TUR 0
;