Skip to main content

BoundML is a toolbox that helps with the development and evaluation of machine learning approach for the branch and bound algorithm.

Project description

What is boundml ?

BoundML is a toolbox to evaluate and compare branch and bound solvers. It allows to easily develop new machine learning based (or not) branching strategies for the Branch and Bound.

It comes with several submodules:

  • solvers: Contains all the class of type Solver. A Solver represent a MILP solver.
  • evaluation: Contains all the tools to evaluate and compare a list of Solver on a set of instances.
  • components: Contains all the definition of Component class that can be used to parametrize a ModularSolver. A Component can be simple observer called at a certain time in the solving process, or an active component of the solver depending on its subtype.
  • ml: Contains some ML tools to apply some wellknown techniques to learn branching strategies. In particular, it allows to collect a dataset and train a Graph Neural Network to imitate a branching strategy as in this paper.
  • instances: Contains a set of MILP instances generator

Installation

There is 2 way to install boundml: pip install boundml and pip install boundml[all]. The former does not require any specific setup but does not contain the classes that depend on a fork of the library ecole: ecole-fork. The latter contains everything but requires some additional installation steps in order to have ecole-fork and pyscipopt to share the same SCIP installation.

Full Installation

pip install boundml

You also need to install fmt in order to be able to use ecole-fork which is a dependency. It can be installed via conda: conda install fmt.

To test if everything works, the 2 following imports should work:

import boundml
import ecole

If import ecole failed, you can still use all the tools from boundml except for the classes that are wrapper around ecole.

How to ...

... Create my own branching strategy ?

In boundml, a branching strategy is simply a Component (in particular a BranchingComponent) that before each decision assigns a score to the candidates variables. Then, the associated Solver will branch on the candidate with the highest score.

For this example, we will implement a branching strategy where a candidate's score is its impact on the objective function: its objective's coefficient multiplied by its current LP solution.

The full example is available here.

import pyscipopt
from pyscipopt import Model

from boundml.components import ScoringBranchingStrategy


class MyBranchingStrategy(ScoringBranchingStrategy):
    def compute_scores(self, model: Model):
        """
        This method is called before each branching decision.
        It computes a score for each branching candidate
        """

        # List of branching candidates
        candidates, *_ = model.getLPBranchCands()

        # Compute the score for each candidate
        var: pyscipopt.Variable
        for i, var in enumerate(candidates):
            obj_coef = var.getObj()
            val = var.getLPSol()

            self.scores[i] = obj_coef * val

    def __str__(self):
        return "Custom"

... Test my branching strategy

Once a branching strategy is built as an Observer, it is easy to compare it with different solvers' configuration. For this example, we will compare 3 solvers. One that uses the default SCIP branching strategy relpscost, a second one that uses pscost as branching strategy, and the last one that use our custom strategy defined above.

Boundml provides easy tools to run the solvers on the same instances. In addition, it is easy to summarize the raw data by computing a report containing the metrics of interest (shifted geometric mean of a metric, number of wins, ...).

The full example is available here.

from boundml.evaluation import evaluate_solvers, SolverEvaluationResults
from boundml.solvers import DefaultScipSolver, ModularSolver
from boundml.instances import CombinatorialAuctionGenerator

scip_params = {
    "limits/time": 30
}

# List of solvers to evaluate
solvers = [
    DefaultScipSolver("relpscost", scip_params=scip_params),
    DefaultScipSolver("pscost", scip_params=scip_params),
    ModularSolver(MyBranchingStrategy(), scip_params=scip_params),
]

# Generator of instances on which to perform the evaluation
instances = CombinatorialAuctionGenerator(100, 500)

# Evaluate the solvers
# data is a SolverEvaluationResults. It can be pickled to be saved and analyzed latter
data = evaluate_solvers(
    solvers,
    instances,
    10,  # number of instances to solve
    ["nnodes", "time", "gap"],  # list of metrics of interes among ["nnodes", "time", "gap"]
    0,  # Number of cores to use in parallel. If 0, use all the available cores
)

# Compute a report from the raw data.
# The report aggregates different metrics for each solver.
report = data.compute_report(
    SolverEvaluationResults.sg_metric("nnodes", 10),  # SG mean of the number of nodes
    SolverEvaluationResults.sg_metric("time", 1),  # SG mean of the time spent
    SolverEvaluationResults.nwins("nnodes"),  # Number of time a solver has been the fastest
    SolverEvaluationResults.nsolved(),  # Number of time a solver solved an instance to optimality
    SolverEvaluationResults.auc_score("time"),  # AUC score with respect to time
)

# Display the report
# It is possible to get a latex table from it: report.to_latex()
print(report)

... Learn a branching strategy ?

boundml provides basic tools to train a Graph Convolutional Neural Network (GCNN) model to imitate any branching strategy designed as Observer.

The file gnn_pipeline shows how tu use this library to reproduce easily the work of Gasse et al.. It consists of training a GCNN to learn to imitate strong branching.

... Learn a branching strategy with my own model ?

For the moment, boundml only provides tools to train a GCNN to imitate a branching strategy. However, it is possible to design your own workflow to train a model, and use this model in an Observer to use it as a branching strategy.

DatasetGenerator can be useful to generate a dataset.

Limitations and future development

Here is a list of features that are not yet part of boundml but will be one day:

  • Implement Solver classes for different solvers (gurobi, highs, cplex)
  • For the moment, only BranchingComponent are really useful and called during the solving process. The idea is to also have specific Component for the different steps of the SCIP solver (node selection, heuristics, ...)
  • Remove all dependencies to ecole-fork

Feel free to contribute by creating pool requests with new features/fixes or by creating issues with your requirement that could improve boundml.

Troubleshooting and issue

If you encounter any unwanted behaviors or issues with boundml, do not hesitate to create an issue here.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

boundml-1.0.0.tar.gz (24.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

boundml-1.0.0-py3-none-any.whl (27.4 kB view details)

Uploaded Python 3

File details

Details for the file boundml-1.0.0.tar.gz.

File metadata

  • Download URL: boundml-1.0.0.tar.gz
  • Upload date:
  • Size: 24.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for boundml-1.0.0.tar.gz
Algorithm Hash digest
SHA256 ba80e992f9494933534c55fa16f28a8bdf0eaaccb6f2dc1d8f8bce5d5706635e
MD5 da04edbb5c5b543d12f5301848f7a286
BLAKE2b-256 a3fb3f93842152ed40d00bb5548b4cd59a3b416d3c8385a825bf052bec170c09

See more details on using hashes here.

File details

Details for the file boundml-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: boundml-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 27.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for boundml-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6c35776ffd3f73165bba25871a97c5f29fbdd2d328d4c76a379e75d7b84c963b
MD5 b70f8b888549ea826fef2509b4638c87
BLAKE2b-256 14b15ed81ba496968106839dbbe55150b2c88c8bb59fc6839f9ac67fcdcd2114

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page