Formulation¶
- class formulation_bench.formulation.Formulation(path, problem)[source]¶
A MILP formulation for an optimization problem.
- Parameters:
- path
strorpathlib.Path Path to the directory containing this formulation. See Formulation Directory for the expected directory structure.
- problem
Problem The parent optimization problem this formulation belongs to.
- path
- Attributes:
- path
pathlib.Path Resolved absolute path to the formulation directory.
- problem
Problem The parent optimization problem this formulation belongs to.
- validbool
Whether this formulation is a faithful reformulation of the parent problem.
- parameters
dict[str,Parameter] The parametrization of this formulation. Note this may differ from the parent problem’s parameters which define the general problem data.
- definitions
dict[str,Definition] Optional named derived quantities computed from parameters before variables are declared. Useful for defining sets, constants, etc… that are referenced in multiple places in the formulation.
- assumptions
list[Assumption] Assumptions on the problem parameters.
- variables
dict[str,Variable] Decision variables, keyed by name.
- constraints
list[Constraint] Constraints on the decision variables.
- objective
Objective Objective function.
- imports
list[str] gen_solve_py()generates a Python script with an implementation of this formulation in Gurobi. By default, the import block includesjson,gurobipy, andargpase. If the formulation requires additional imports (e.g.,import networkx as nx), they are included here.- lean_formulation_path
pathlib.Path Path to a Lean file (
Formulation.lean) containing a formal specification of this formulation. See MILP Formulation for details on how a MILP formulation is represented in Lean.- metadata
dict[str,Any] Free-form metadata about the formulation. Typically includes a
sourcefield with details about the origin of the formulation and anotesfield with additional commentary.
- path
Examples
Load formulation
aof p12 | Traveling Salesman Problem (TSP):>>> from formulation_bench import Dataset >>> ds = Dataset("dataset") >>> f = ds.problems[12].formulations["a"] >>> f.problem.name 'Traveling Salesman Problem (TSP)'
Check if the formulation is valid:
>>> f.valid True
Get the formulation’s parameters and assumptions:
>>> f.parameters {'n': Parameter(...), 'c': Parameter(...)} >>> f.assumptions [Assumption(description='There must be at least two cities ...)]
Get the first constraint of the formulation:
>>> f.constraints[0] Constraint(description='Each city has exactly one outgoing arc ...)
Get the formulation’s objective function:
>>> f.objective Objective(description='Minimize the total travel cost ...)
Get the path to the Lean specification of this formulation:
>>> f.lean_formulation_path PosixPath('.../dataset/problems/p12/formulations/a/Formulation.lean')
- gen_solve_py()[source]¶
Generate a Python script with a Gurobi implementation of this formulation.
The script is generated from the
gurobipycode snippets in thecodeattribute of every formulation component (parameters, definitions, assumptions, variables, constraints, and objective). Additionalimportsare also included at the top of the script.The resulting script expects
--paramsand--solutioncommand-line arguments for paths to the input parameters and output solution, respectively.Examples
Generate the solve script for p12 | Traveling Salesman Problem (TSP):
>>> from formulation_bench import Dataset >>> ds = Dataset("dataset") >>> f = ds.problems[12].formulations["a"] # MTZ formulation of TSP >>> script = f.gen_solve_py() >>> print(script) import json import gurobipy as gp from gurobipy import GRB import argparse ... if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("params", help="Path to parameters.json") parser.add_argument("solution", help="Path to write solution.json") ...
- render_markdown(include_implicit=True)[source]¶
Render this formulation in Markdown.
The output is produced by rendering the following Jinja template. The
assumptionsandconstraintspassed to this template are filtered according toinclude_implicitflag.# {{ problem_name }} ## Problem Description {{ problem_description }} ## Formulation ### Parameters {% for name, p in parameters.items() %} - **{{ name }}** (type: {{ p.type.value }}, shape: `{{ p.shape }}`): {{ p.description }} {% endfor %} {% if assumptions %} ### Assumptions {% for a in assumptions %} - {{ a.description }} $${{ a.formulation }}$$ {% endfor %} {% endif %} {% if definitions %} ### Definitions {% for name, d in definitions.items() %} - **{{ name }}**: {{ d.description }} $${{ d.formulation }}$$ {% endfor %} {% endif %} ### Variables {% for name, v in variables.items() %} - **{{ name }}** (type: {{ v.type.value }}, shape: `{{ v.shape }}`): {{ v.description }} {% endfor %} ### Constraints {% for c in constraints %} - {{ c.description }} $${{ c.formulation }}$$ {% endfor %} ### Objective {{ objective.description }} $${{ objective.formulation }}$$
- Parameters:
- Returns:
- markdown
str The rendered Markdown string.
- markdown
Examples
Render a formulation of p12 | Traveling Salesman Problem (TSP) without implicit constraints:
>>> from formulation_bench import Dataset >>> ds = Dataset("dataset") >>> f = ds.problems[12].formulations["a"] # MTZ formulation of TSP >>> md = f.render_markdown(include_implicit=False) >>> print(md) # Traveling Salesman Problem (TSP) ## Problem Description The Traveling Salesman Problem (TSP) aims to find the shortest cycle in a graph that visits every node exactly once. ... ## Formulation ### Parameters - **n** (type: integer, shape: `[]`): Number of cities - **c** (type: continuous, shape: `['n', 'n']`): Travel cost from city i to city j ... ### Variables - **x** (type: binary, shape: `['n', 'n']`): 1 if the tour goes directly from city i to city j, 0 otherwise - **u** (type: continuous, shape: `['n']`): MTZ position of city i in the tour ### Constraints - Each city has exactly one outgoing arc in the tour. $$\sum_{j \in V,\, j \neq i} x_{ij} = 1 \quad \forall i \in V$$ - Each city has exactly one incoming arc in the tour. $$\sum_{i \in V,\, i \neq j} x_{ij} = 1 \quad \forall j \in V$$ - MTZ subtour elimination constraint. $$u_i - u_j + n \cdot x_{ij} \leq n - 1 \quad \forall i, j \in V \setminus \{0\},\; i \neq j$$ - Depot position is fixed to 1 to anchor the tour ordering. $$u_0 = 1$$ - Lower bound on MTZ position: each non-depot city's position is at least 2. $$u_i \geq 2 \quad \forall i \in V \setminus \{0\}$$ - Upper bound on MTZ position: each non-depot city's position is at most n. $$u_i \leq n \quad \forall i \in V \setminus \{0\}$$ ### Objective Minimize the total travel cost of the Hamiltonian cycle. $$\min \sum_{i \in V} \sum_{j \in V,\, j \neq i} c_{ij} \cdot x_{ij}$$
- run_gen_params(input_path=None, output_path=None)[source]¶
Run this formulation’s
gen_params.pyscript.Each formulation includes a
gen_params.pyscript that transforms problem-level instance data into the specific parameter values used by the formulation. Note the solver script generated bygen_solve_py()expects these formulation-specific parameters.- Parameters:
- input_path
strorpathlib.Path, optional Path to a
data.jsonfile containing the problem instance data. Defaults to the parent problem’sdata.json.- output_path
strorpathlib.Path, optional Path to write the generated parameters. Defaults to
parameters.jsonin this formulation’s directory.
- input_path
Examples
Run the parameter generation script for formulation
bof p1 | Amusement Park Ticket Machines:>>> import json >>> from formulation_bench import Dataset >>> ds = Dataset("dataset") >>> f = ds.problems[1].formulations["b"] >>> # Inspect the raw problem instance data >>> data = json.load(open(f.problem.path / "data.json", "r")) >>> data["CashMachineProcessingRate"] 20 >>> # Run the parameter generation script and inspect >>> f.run_gen_params() >>> params = json.load(open(f.path / "parameters.json", "r")) >>> params["A"] # The variable name for "CashMachineProcessingRate" 20
- with_constraint(constraint)[source]¶
Return a new
Formulationwith one extra constraint appended.The original formulation is not modified. Useful for creating formulations from cutting planes or fixing variable values.
- Parameters:
- constraint
Constraint The constraint to be added to the formulation.
- constraint
- Returns:
- formulation
Formulation A new formulation with the added constraint.
- formulation
Examples
Add a cutting plane to the MTZ TSP formulation of p12 | Traveling Salesman Problem (TSP) that prevents two-city subtours:
>>> from formulation_bench import Dataset >>> ds = Dataset("dataset") >>> f = ds.problems[12].formulations["a"] # MTZ formulation of TSP >>> c = Constraint( ... description="No 2-city subtours", ... formulation=r"x_{1,2} + x_{2,1} \leq 1", ... explicit=False, ... code={"gurobipy": "model.addConstr(x[1,2] + x[2,1] <= 1)"} ... ) >>> new_f = f.with_constraint(c) >>> new_f.constraints[-1] Constraint(description='No 2-city subtours', ...)