File input/output of the model¶
You can load an LP or QPLIB file and create Model
from it, and vice versa, you can save Model
and output to an LP or QPLIB file.
This is useful for interfacing with other mathematical optimization solvers and for saving and reusing Model
.
LP file format¶
The format of LP files that the Amplify SDK can handle follows the Gurobi LP Format. The Amplify SDK supports the input and output of the following models.
Problems involving binary, integer, and real variables, as well as problems combining these variables
Problems consisting only of quadratic or less objective functions and constraints
Problems with objective functions and constraints expressible in LP format
Restrictions¶
Note the following restrictions about the input and output of LP files.
The following formats and sections are not supported for loading LP files.
Multi-Objective Case
Indicator Constraints
Lazy Constraints Section
User Cuts Section
SOS Section
PWLObj Section
General Constraints Section
Scenario Section
Semi-continuous variables are not supported for loading LP files.
Variables in the Amplify SDK with the following names are not output correctly.
Variable names containing the symbols
+, -, *, ^, :, /, [, ]
.Variable names beginning with the symbols
<, >, =, ,, (, )
in addition to the above
Constraint weights in the Amplify SDK are not described in the LP file.
QPLIB file format¶
The format of QPLIB files that the Amplify SDK can handle follows the QPLIB: a library of quadratic programming instances and its Supplementary material 1. The Amplify SDK supports the input and output of the following models.
Problems involving binary, integer, and real variables, as well as problems combining these variables
Problems consisting only of quadratic or less objective functions and constraints
Problems with objective functions and constraints expressible in QPLIB format
Restrictions¶
Note the following restrictions about the input and output of QPLIB files.
Variables and constraints in the Amplify SDK whose names contain newline characters (
\n, \v, \f, \r
) are not output correctly.Constraint weights in the Amplify SDK are not output to the QPLIB file.
The descriptions of the default values of variables are ignored for loading QPLIB files.
Output to LP/QPLIB file¶
To output a model created with the Amplify SDK to a file, pass Model
as the first argument and the file path as the second argument to save_lp()
or save_qplib()
for LP and QPLIB files, respectively.
from amplify import VariableGenerator, Model, one_hot, save_lp
gen = VariableGenerator()
q = gen.array("Binary", 4)
f = 2 * q[0] * q[1] + q[2] * q[3] + q[0] + q[1] + q[2] + q[3] - 1
c = one_hot(q[:3]) # q_0 + q_1 + q_2 == 1
model = Model(f, c)
save_lp(model, "model.lp")
Then, model.lp
is saved in the current directory.
model.lp
Minimize
1 q_0 + 1 q_1 + 1 q_2 + 1 q_3 + [ 4 q_0 * q_1 + 2 q_2 * q_3 ] / 2 - 1
Subject To
1 q_0 + 1 q_1 + 1 q_2 = 1
Bounds
q_0 free
q_1 free
q_2 free
q_3 free
Binaries
q_0 q_1 q_2 q_3
Generals
End
To save to a QPLIB file:
from amplify import save_qplib
save_qplib(model, "model.qplib")
Then, model.qplib
is saved in the current directory.
model.qplib
! -------------------
! problem information
! -------------------
# problem name
Amplify
# problem type
QBL
# problem sense
minimize
# number of variables
4
# number of constraints
1
! ------------------
! objective function
! ------------------
# quadratic terms
2
1 2 4
3 4 2
# linear terms
0
4
1 1
2 1
3 1
4 1
# constant
-1
! -----------
! constraints
! -----------
# linear terms
3
1 1 1
1 2 1
1 3 1
# infinity value
1.0e+20
# lower bounds
-2.0e+20
1
1 1
# upper bounds
2.0e+20
1
1 1
! ---------------
! starting points
! ---------------
# starting point for variables
0
0
# starting point for Lagrange multipliers
0
0
# starting point for dual variables
0
0
! -----------------------------
! variable and constraint names
! -----------------------------
# variable names
4
1 q_0
2 q_1
3 q_2
4 q_3
# constraint names
0
Note
LP and QPLIB files identify variables by their names. Therefore, when formulating in the Amplify SDK, make sure that the names of variables in the model are not duplicated.
Read from LP/QPLIB file¶
When the path to an LP/QPLIB files is given as an argument to load_lp()
or load_qplib()
, you will get a tuple of (Model
, VariableGenerator
) is returned.
They respectively represent the model described in the input file and the variable generator used to make the model.
For example, the model.lp
created above is loaded and solved as follows.
from amplify import load_lp
model, gen = load_lp("model.lp")
>>> print(model)
minimize:
2 q_0 q_1 + q_2 q_3 + q_0 + q_1 + q_2 + q_3 - 1
subject to:
q_0 + q_1 + q_2 == 1 (weight: 1)
The decision variables defined in the file can be found as follows.
>>> model.variables
[Variable({name: q_0, id: 0, type: Binary}), Variable({name: q_1, id: 1, type: Binary}),
Variable({name: q_2, id: 2, type: Binary}), Variable({name: q_3, id: 3, type: Binary})]
The loaded model can be solved by passing it to solve()
.
from amplify import solve, FixstarsClient
client = FixstarsClient()
client.token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
result = solve(model, client)
The mapping between the names and the values of the variables of the best solution is obtained as a dictionary as follows.
>>> {k.name: v for k,v in result.best.values.items()}
{'q_0': 0.0, 'q_1': 1.0, 'q_2': 0.0, 'q_3': 0.0}
Change the model after loading¶
You can change the objective and constraints of the loaded model from a file.
First, the variables contained in the model are converted into a list of Poly
, and then create polynomials from the variables contained in the model as follows.
from amplify import Poly
# Load model from file
model, gen = load_lp("model.lp")
# Convert variables in the model to a list of Poly
vars = [Poly(v) for v in model.variables]
# Change the model's objective function and add constraints
model += vars[1] * vars[2]
model += one_hot(sum(vars[1:]))
You can also add new variables to the model using the variable generators obtained from load_lp()
or load_qplib()
.
New variable names created here should not duplicate the those of variables in the existing model.
# Create a new integer variable `n` with the variable generator.
add_vars = gen.array("Integer", 2, bounds=(1, 4), name="n")
# Change the model's objective function
model += 2 * add_vars[0] - add_vars[1]
>>> print(model)
minimize:
2 q_0 q_1 + q_1 q_2 + q_2 q_3 + q_0 + q_1 + q_2 + q_3 + 2 n_0 - n_1 - 1
subject to:
q_0 + q_1 + q_2 == 1 (weight: 1),
q_1 + q_2 + q_3 == 1 (weight: 1)
Set constraint weights¶
Constraint weights are not described in the LP and QPLIB files. Therefore, you must set the weights for constraints after loading the model if you need. (See Constructing Constraints/Setting constraint weights)
Here, we output the model we have just changed to a file and then re-load and use it as an example.
# Output model to file
save_lp(model, "model.lp")
# Re-Load model from file
model, gen = load_lp("model.lp")
# Get the ConstraintList in the model.
constraints = model.constraints
>>> print(constraints)
[q_0 + q_1 + q_2 == 1 (weight: 1),
q_1 + q_2 + q_3 == 1 (weight: 1)]
>>> constraints *= 2
>>> print(constraints)
[q_0 + q_1 + q_2 == 1 (weight: 2),
q_1 + q_2 + q_3 == 1 (weight: 2)]
>>> constraints[0].weight = 5
>>> print(constraints)
[q_0 + q_1 + q_2 == 1 (weight: 5),
q_1 + q_2 + q_3 == 1 (weight: 2)]
Specify the algorithm for generating the penalty function¶
You can set PenaltyFormulation
as the second argument of load_lp()
and load_qplib()
.
This parameter represents the algorithm used to generate the penalty for inequality constraints. The default value is Default
. (See Constraints and Penalty Functions/Inequality constraints)
from amplify import VariableGenerator, Model, save_lp, load_lp, less_equal
gen = VariableGenerator()
q = gen.array("Binary", 3)
c = less_equal(q[0] + q[1] + q[2], 2)
model = Model(c)
save_lp(model, "model.lp")
>>> model, gen = load_lp("model.lp", "Default")
>>> print(model.constraints[0].penalty)
2 q_0 q_1 + 2 q_0 q_2 - 2 q_0 n_0 + 2 q_1 q_2 - 2 q_1 n_0 - 2 q_2 n_0 + n_0^2 + q_0 + q_1 + q_2
>>> model, gen = load_lp("model.lp", "LinearRelaxation")
>>> print(model.constraints[0].penalty)
0.5 q_0 + 0.5 q_1 + 0.5 q_2