Given a mixed-integer optimization problem (MIP) (or more accurately, mixed binary problem), solve this problem through branch-and-bound process.
We will first replace all the binary variables with continuous variables, and relax the integral constraint on the binary variables z ∈ {0, 1} with continuous constraints 0 ≤ z ≤ 1. In the subsequent steps, at each node of the tree, we will fix some binary variables to either 0 or 1, and solve the rest of the variables. Notice that we will create a new set of variables in the branch-and-bound process, since we need to replace the binary variables with continuous variables.
#include <drake/solvers/branch_and_bound.h>
Classes | |
struct | Options |
Configuration settings for the MixedIntegerBranchAndBound constructor. More... | |
Public Types | |
enum | VariableSelectionMethod { kUserDefined, kLeastAmbivalent, kMostAmbivalent } |
Different methods to pick a branching variable. More... | |
enum | NodeSelectionMethod { kUserDefined, kDepthFirst, kMinLowerBound } |
Different methods to pick a branching node. More... | |
using | NodeSelectFun = std::function< MixedIntegerBranchAndBoundNode *(const MixedIntegerBranchAndBound &)> |
The function signature for the user defined method to pick a branching node or a branching variable. More... | |
using | VariableSelectFun = std::function< const symbolic::Variable *(const MixedIntegerBranchAndBoundNode &)> |
using | NodeCallbackFun = std::function< void(const MixedIntegerBranchAndBoundNode &, MixedIntegerBranchAndBound *bnb)> |
The function signature for user defined node callback function. More... | |
Public Member Functions | |
MixedIntegerBranchAndBound (const MathematicalProgram &prog, const SolverId &solver_id, Options options=Options{}) | |
Construct a branch-and-bound tree from a mixed-integer optimization program. More... | |
SolutionResult | Solve () |
Solve the mixed-integer problem (MIP) through a branch and bound process. More... | |
double | GetOptimalCost () const |
Get the optimal cost. More... | |
double | GetSubOptimalCost (int nth_suboptimal_cost) const |
Get the n'th sub-optimal cost. More... | |
double | GetSolution (const symbolic::Variable &mip_var, int nth_best_solution=0) const |
Get the n'th best integral solution for a variable. More... | |
template<typename Derived > | |
std::enable_if_t< std::is_same_v< typename Derived::Scalar, symbolic::Variable >, MatrixLikewise< double, Derived > > | GetSolution (const Eigen::MatrixBase< Derived > &mip_vars, int nth_best_solution=0) const |
Get the n'th best integral solution for some variables. More... | |
const symbolic::Variable & | GetNewVariable (const symbolic::Variable &old_variable) const |
Given an old variable in the original mixed-integer program, return the corresponding new variable in the branch-and-bound process. More... | |
template<typename Derived > | |
std::enable_if_t< is_eigen_scalar_same< Derived, symbolic::Variable >::value, MatrixLikewise< symbolic::Variable, Derived > > | GetNewVariables (const Eigen::MatrixBase< Derived > &old_variables) const |
Given a matrix of old variables in the original mixed-integer program, return a matrix of corresponding new variables in the branch-and-bound process. More... | |
void | SetNodeSelectionMethod (NodeSelectionMethod node_selection_method) |
The user can choose the method to pick a node for branching. More... | |
void | SetUserDefinedNodeSelectionFunction (NodeSelectFun fun) |
Set the user-defined method to pick the branching node. More... | |
void | SetVariableSelectionMethod (VariableSelectionMethod variable_selection_method) |
The user can choose the method to pick a variable for branching in each node. More... | |
void | SetUserDefinedVariableSelectionFunction (VariableSelectFun fun) |
Set the user-defined method to pick the branching variable. More... | |
void | SetSearchIntegralSolutionByRounding (bool flag) |
Set the flag to true if the user wants to search an integral solution in each node, after the optimization problem in that node is solved. More... | |
void | SetUserDefinedNodeCallbackFunction (NodeCallbackFun fun) |
The user can set a defined callback function in each node. More... | |
bool | IsLeafNodeFathomed (const MixedIntegerBranchAndBoundNode &leaf_node) const |
If a leaf node is fathomed, then there is no need to branch on this node any more. More... | |
const MixedIntegerBranchAndBoundNode * | root () const |
Getter for the root node. More... | |
double | best_upper_bound () const |
Getter for the best upper bound. More... | |
double | best_lower_bound () const |
Getter for the best lower bound. More... | |
const std::multimap< double, Eigen::VectorXd > & | solutions () const |
Getter for the solutions. More... | |
void | set_absolute_gap_tol (double tol) |
Setter for the absolute gap tolerance. More... | |
double | absolute_gap_tol () const |
Getter for the absolute gap tolerance. More... | |
void | set_relative_gap_tol (double tol) |
Setter for the relative gap tolerance. More... | |
double | relative_gap_tol () const |
Geeter for the relative gap tolerance. More... | |
Friends | |
class | MixedIntegerBranchAndBoundTester |
using NodeCallbackFun = std::function<void( const MixedIntegerBranchAndBoundNode&, MixedIntegerBranchAndBound* bnb)> |
The function signature for user defined node callback function.
using NodeSelectFun = std::function<MixedIntegerBranchAndBoundNode*( const MixedIntegerBranchAndBound&)> |
The function signature for the user defined method to pick a branching node or a branching variable.
using VariableSelectFun = std::function<const symbolic::Variable*( const MixedIntegerBranchAndBoundNode&)> |
|
strong |
|
strong |
|
explicit |
Construct a branch-and-bound tree from a mixed-integer optimization program.
prog | A mixed-integer optimization program. |
solver_id | The ID of the solver for the optimization. |
double absolute_gap_tol | ( | ) | const |
Getter for the absolute gap tolerance.
double best_lower_bound | ( | ) | const |
Getter for the best lower bound.
double best_upper_bound | ( | ) | const |
Getter for the best upper bound.
const symbolic::Variable& GetNewVariable | ( | const symbolic::Variable & | old_variable | ) | const |
Given an old variable in the original mixed-integer program, return the corresponding new variable in the branch-and-bound process.
old_variable | A variable in the original mixed-integer program. |
new_variable | The corresponding variable in the branch-and-bound procedure. |
std::exception | if the pre-condition fails. |
std::enable_if_t< is_eigen_scalar_same<Derived, symbolic::Variable>::value, MatrixLikewise<symbolic::Variable, Derived> > GetNewVariables | ( | const Eigen::MatrixBase< Derived > & | old_variables | ) | const |
Given a matrix of old variables in the original mixed-integer program, return a matrix of corresponding new variables in the branch-and-bound process.
old_variables | Variables in the original mixed-integer program. |
new_variables | The corresponding variables in the branch-and-bound procedure. |
double GetOptimalCost | ( | ) | const |
Get the optimal cost.
double GetSolution | ( | const symbolic::Variable & | mip_var, |
int | nth_best_solution = 0 |
||
) | const |
Get the n'th best integral solution for a variable.
The best solutions are sorted in the ascending order based on their costs. Each solution is found in a separate node in the branch-and-bound tree, so the values of the binary variables are different in each solution.
mip_var | A variable in the original MIP. |
nth_best_solution. | The index of the best integral solution. |
mip_var
is a variable in the original MIP. nth_best_solution
is between 0 and solutions().size(). std::exception | if the preconditions are not satisfied. |
std::enable_if_t< std::is_same_v<typename Derived::Scalar, symbolic::Variable>, MatrixLikewise<double, Derived> > GetSolution | ( | const Eigen::MatrixBase< Derived > & | mip_vars, |
int | nth_best_solution = 0 |
||
) | const |
Get the n'th best integral solution for some variables.
The best solutions are sorted in the ascending order based on their costs. Each solution is found in a separate node in the branch-and-bound tree, so
mip_vars | Variables in the original MIP. |
nth_best_solution. | The index of the best integral solution. |
mip_vars
are variables in the original MIP. nth_best_solution
is between 0 and solutions().size(). std::exception | if the preconditions are not satisfied. |
Get the n'th sub-optimal cost.
The costs are sorted in the ascending order. The sub-optimal costs do not include the optimal cost.
nth_suboptimal_cost | The n'th sub-optimal cost. |
nth_suboptimal_cost
is between 0 and solutions().size() - 1. std::exception | if the precondition is not satisfied. |
bool IsLeafNodeFathomed | ( | const MixedIntegerBranchAndBoundNode & | leaf_node | ) | const |
If a leaf node is fathomed, then there is no need to branch on this node any more.
A leaf node is fathomed is any of the following conditions are satisfied:
leaf_node | A leaf node to check if it is fathomed. |
std::exception | if the precondition is not satisfied. |
double relative_gap_tol | ( | ) | const |
Geeter for the relative gap tolerance.
const MixedIntegerBranchAndBoundNode* root | ( | ) | const |
Getter for the root node.
Note that this is aliased for the lifetime of this object.
void set_absolute_gap_tol | ( | double | tol | ) |
Setter for the absolute gap tolerance.
The branch-and-bound will terminate if its difference between its best upper bound and best lower bound is below this gap tolerance.
void set_relative_gap_tol | ( | double | tol | ) |
Setter for the relative gap tolerance.
The branch-and-bound will terminate if (best_upper_bound() - best_lower_bound()) / abs(best_lower_bound()) is smaller than this tolerance.
void SetNodeSelectionMethod | ( | NodeSelectionMethod | node_selection_method | ) |
The user can choose the method to pick a node for branching.
We provide options such as "depth first" or "min lower bound".
node_selection_method | The option to pick a node. If the option is NodeSelectionMethod::kUserDefined, then the user should also provide the method to pick a node through SetUserDefinedNodeSelectionFunction. |
void SetSearchIntegralSolutionByRounding | ( | bool | flag | ) |
Set the flag to true if the user wants to search an integral solution in each node, after the optimization problem in that node is solved.
The program can search for an integral solution based on the solution to the optimization program in the node, by rounding the binary variables to the nearest integer value, and solve for the continuous variables. If a solution is obtained in this new program, then this solution is an integral solution to the mixed-integer program.
void SetUserDefinedNodeCallbackFunction | ( | NodeCallbackFun | fun | ) |
The user can set a defined callback function in each node.
This function is called after the optimization is solved in each node.
void SetUserDefinedNodeSelectionFunction | ( | NodeSelectFun | fun | ) |
Set the user-defined method to pick the branching node.
This method is used if the user calls SetNodeSelectionMethod(NodeSelectionMethod::kUserDefined).
For example, if the user has defined a function LeftMostNode that would return the left-most unfathomed node in the tree, then the user could do
A more detailed example can be found in solvers/test/branch_and_bound_test.cc in TestSetUserDefinedNodeSelectionFunction.
std::exception | if the node is not a leaf node, or it is fathomed. |
void SetUserDefinedVariableSelectionFunction | ( | VariableSelectFun | fun | ) |
Set the user-defined method to pick the branching variable.
This method is used if the user calls SetVariableSelectionMethod(VariableSelectionMethod::kUserDefined).
For example, if the user has defined a function FirstVariable, that would return the first un-fixed binary variable in this branch as
The user can then set the branch-and-bound to use this function to select the branching variable as
void SetVariableSelectionMethod | ( | VariableSelectionMethod | variable_selection_method | ) |
The user can choose the method to pick a variable for branching in each node.
We provide options such as "most ambivalent" or "least ambivalent".
variable_selection_method | The option to pick a variable. If the option is VariableSelectionMethod::kUserDefined, then the user should also provide the method to pick a variable through SetUserDefinedVariableSelectionFunction(...). |
const std::multimap<double, Eigen::VectorXd>& solutions | ( | ) | const |
Getter for the solutions.
Returns a list of solutions, together with the costs evaluated at the solutions. The solutions are sorted in the ascending order based on the cost.
SolutionResult Solve | ( | ) |
Solve the mixed-integer problem (MIP) through a branch and bound process.
solution_result | If solution_result=SolutionResult::kSolutionFound, then the best solutions are stored inside solutions(). The user can access the value of each variable(s) through GetSolution(...). If solution_result=SolutionResult::kInfeasibleConstraints, then the mixed-integer problem is primal infeasible. If solution_result=SolutionResult::kUnbounded, then the mixed-integer problem is primal unbounded. |
|
friend |