Note, you can also see a list of code and modeling examples, across a range of programming languages on our code examples, modeling examples pages, or you can learn more about MIP solvers.
The problems most commonly solved by the Gurobi Parallel Mixed Integer Programming solver are of the form:
Objective: | minimize cT x |
Constraints: | A x = b (linear constraints) |
l ≤ x ≤ u (bound constraints) | |
some or all xj must take integer values (integrality constraints) |
The integrality constraints allow MIP models to capture the discrete nature of some decisions. For example, a variable whose values are restricted to 0 or 1, called a binary variable, can be used to decide whether or not some action is taken, such as building a warehouse or purchasing a new machine.
The Gurobi MIP solver can also solve models with a quadratic objective and/or quadratic constraints:
Objective: | minimize xT Q x + qT x |
Constraints: | A x = b (linear constraints) |
l ≤ x ≤ u (bound constraints) | |
xT Qi x + qiT x ≤ bi (quadratic constraints) | |
some or all x must take integer values (integrality constraints) |
MIP models with a quadratic objective but without quadratic constraints are called Mixed Integer Quadratic Programming (MIQP) problems. MIP models with quadratic constraints are called Mixed Integer Quadratically Constrained Programming (MIQCP) problems. Models without any quadratic features are often referred to as Mixed Integer Linear Programming (MILP) problems.
What follows is a description of the algorithm used by Gurobi to solve MILP models. The extension to MIQP and MIQCP is mostly straightforward, but we won’t describe them here.
Mixed Integer Linear Programming problems are generally solved using a linear-programming based branch-and-bound algorithm.
Basic LP-based branch-and-bound can be described as follows. We begin with the original MIP. Not knowing how to solve this problem directly, we remove all of the integrality restrictions. The resulting LP is called the linear-programming relaxation of the original MIP. We can then solve this LP. If the result happens to satisfy all of the integrality restrictions, even though these were not explicitly imposed, then we have been quite lucky. This solution is an optimal solution of the original MIP, and we can stop. If not, as is usually the case, then the normal procedure is to pick some variable that is restricted to be integer, but whose value in the LP relaxation is fractional. For the sake of argument, suppose that this variable is x and its value in the LP relaxation is 5.7. We can then exclude this value by, in turn, imposing the restrictions x ≤ 5.0 and x ≥ 6.0.
If the original MIP is denoted P0, then we might denote these two new MIPs by P1, where x ≤ 5.0 is imposed, and P2, where x ≥ 6.0 is imposed. The variable x is then called a branching variable, and we are said to have branched on x, producing the two sub-MIPs P1 and P2. It should be clear that if we can compute optimal solutions for each of P1 and P2, then we can take the better of these two solutions and it will be optimal to the original problem, P0. In this way we have replaced P0 by two simpler (or at least more-restricted) MIPs. We now apply the same idea to these two MIPs, solving the corresponding LP relaxations and, if necessary, selecting branching variables. In so doing we generate what is called a search tree. The MIPs generated by the search procedure are called the nodes of the tree, with P0 designated as the root node. The leaves of the tree are all the nodes from which we have not yet branched. In general, if we reach a point at which we can solve or otherwise dispose of all leaf nodes, then we will have solved the original MIP.
To complete our description of (LP-based) branch-and-bound we need to describe the additional logic that is applied in processing the nodes of the search tree. Let us assume that our goal is to minimize the objective, and suppose that we have just solved the LP relaxation of some node in the search tree. If it happens that all of the integrality restrictions in the original MIP are satisfied in the solution at this node, then we know we have found a feasible solution to the original MIP. There are two important steps that we then take. First, we designate this node as fathomed. It is not necessary to branch on this node; it is a permanent leaf of the search tree. Second, we analyze the information provided by the feasible solution we have just found, as follows. Let us denote the best integer solution found at any point in the search as the incumbent. At the start of the search, we have no incumbent. If the integer feasible solution that we have just found has a better objective function value than the current incumbent (or if we have no incumbent), then we record this solution as the new incumbent, along with its objective function value. Otherwise, no incumbent update is necessary and we simply proceed with the search.
There are two other possibilities that can lead to a node being fathomed. First, it can happen that the branch that led to the current node added a restriction that made the LP relaxation infeasible. Obviously if this node contains no feasible solution to the LP relaxation, then it contains no integer feasible solution. The second possibility is that an optimal relaxation solution is found, but its objective value is bigger than that of the current incumbent. Clearly this node cannot yield a better integral solution and again can be fathomed.
There are two additional important values we need to introduce to complete our description of branch-and-bound. First observe that, once we have an incumbent, the objective value for this incumbent, assuming the original MIP is a minimization problem, is a valid upper bound on the optimal solution of the given MIP. That is, we know that we will never have to accept an integer solution of value higher than this value. Somewhat less obvious is that, at any time during the branch-and-bound search we also have a valid lower bound, sometimes call the best bound. This bound is obtained by taking the minimum of the optimal objective values of all of the current leaf nodes. Finally, the difference between the current upper and lower bounds is known as the gap. When the gap is zero we have demonstrated optimality.
The field of mixed integer programming has witnessed remarkable improvements in recent years in the capabilities of MIP algorithms. Four of the biggest contributors have been presolve, cutting planes, heuristics, and parallelism. We now give high-level overviews of these four components.
Presolve refers to a collection of problem reductions that are typically applied in advance of the start of the branch-and-bound procedure. These reductions are intended to reduce the size of the problem and to tighten its formulation.
A simple example of a size-reducing transformation is the following. Suppose a given problem contains the following constraints:
x1 + x2 + x3 ≥ 15
x1 ≤ 7
x2 ≤ 3
x3 ≤ 5
Clearly the only way that all of these constraints can be satisfied is if x1 = 7, x2 = 3, and x3 =5. In this case we can substitute out these variables, completely removing them from the formulation along with the above four constraints. The list of such possible reductions, of which this is only one, is quite extensive and can have an enormous effect on the overall size of the problem.
The above reduction is what we would call an LP-presolve reduction, since its validity does not depend on integrality restrictions. An example of an MIP-specific reduction is the following. Suppose that x1 and x2 are non-negative integer variables and that our formulation includes a constraint of the following form:
2 x1 + 2 x2 ≤ 1.
Dividing both sides of this constraint by 2 yields:
x1 + x2 ≤ ½.
Since x1 and x2 are both required to be integral, this inequality clearly implies that x1 + x2 ≤ 0, and so by non-negativity that x1 = x2 = 0. Hence both of these variables and this constraint can be removed from the formulation. Note also that this reduction is different in character from the first in the sense that we have actually reduced the set of feasible solutions to the LP relaxation, even though the set of integer feasible solutions has remained the same. This kind of tightening can be critical to the solution of an integer program, and is one of the reasons that MIP presolve is an important tool in the solution on MIPs, much more so than LP presolve in the solution of linear programs.
Let us now consider the idea of cuttings planes. We should say at the outset that the theory of cutting planes is deep and extensive. It is also generally accepted to be the single most important contributor to the computational advances that have been made in integer programming over the last several years. The idea of cutting planes is that they tighten the formulation by removing undesirable fractional solutions, as in the case of MIP presolve, but that they do this during the solution process and without the undesirable side-effect of creating additional sub-problems (unlike branching).
Here is one simple example of a cutting plane. Suppose our formulation includes the following constraint:
6 x1 + 5 x2 + 7 x3 + 4 x4 + 5 x5 ≤ 15,
where x1 through x5 are restricted to be binary. Suppose in addition that we have just solved an LP relaxation and that these variables take the following values in this LP relaxation: x1 = 0, x2 = 1, x3 = x4 = x5 = 3/4. This undesirable solution can be excluded with the following observation: since 7 + 4 + 5 = 16 > 15, it is not possible that x3 = x4 = x5 = 1, and hence that the following new inequality is a valid addition to the given MIP: x3 + x4 + x5 ≤ 2. Since 3/4 + 3/4 + 3/4 = 9/4 > 2, the new inequality cuts off the current solution. This inequality is an example of a so-called knapsack cover.
The reader may ask at this point why we have not simply added this new constraint, or cut, at the start. There are several reasons. One is that there are generally an enormous number of such additional constraints. It would be too expensive to find them all, and likely impossible to add them all to the model. A second reason is that adding constraints makes the LP relaxations progressively harder to solve. We only want to add these constraints if we know they will help. Judiciously adding such constraints can have an enormously beneficial effect on the solution process.
Our next topic in this discussion is heuristics. We introduced the concept of the incumbent in our introduction to branch-and-bound. Having good incumbents, and finding them as quickly as possible, can be extremely valuable in the MIP search for a number of reasons. First, it may not be possible to solve a problem to provable optimality. For example, the underlying MIP may just be too difficult, or there may be some user imposed restriction on the amount of time that we can allow our MIP algorithm run. In either case, we want to have the best possible feasible solution at termination. Having good feasible solutions also helps the search process prior to termination. The better the objective value of the incumbent, the more likely it is that the value of an LP relaxation will exceed it (in a minimization problem) and hence lead to a node being fathomed.
As the above remarks are meant to suggest, it has turned out to be extremely valuable to do a little extra work at some of the nodes of the search tree to see if a good integer feasible solution can be extracted, even though integrality has not yet resulted due to the branching. For example, it may be that many of the integer variables, while not integral, have values that are quite close to integral. We could then consider rounding some of these variables to their nearby values, fixing them to these values, solving the resulting LP relaxation, and repeating this procedure several times in the hopes that all integer variables will fall into line. If they do, and if the resulting feasible has a better objective value than the current incumbent, we can replace that incumbent and proceed. Gurobi includes multiple such heuristics of many different flavors.
As noted at the beginning of this discussion, the Gurobi MIP solver runs in parallel. The main source of parallelism is the fact that different nodes in the MIP tree search can be processed independently. As is probably apparent, however, the root node presents limited parallelism opportunities. Thus, models that explore large search trees can exploit cores quite effectively, while those that spend the majority of their runtime at the root node are more constrained in their ability to utilize multiple cores.
In addition to the techniques discussed above, a modern MIP solver will include a long list of additional techniques. A few examples include sophisticated branch variable selection techniques, node presolve, symmetry detection, and disjoint subtree detection. The goal in most cases is to limit the size of the branch-and-bound tree that must be explored.
The behaviors of most of the strategies and techniques described here can be adjusted using Gurobi parameters. While some models can benefit from parameter tuning, our goal in designing and building the Gurobi Optimizer has been to make the default settings work as well as possible across a broad range of models. You generally shouldn’t need to worry about the details of how the different techniques work, or about how the associated parameters should be adjusted.
GUROBI NEWSLETTER
Latest news and releases
Choose the evaluation license that fits you best, and start working with our Expert Team for technical guidance and support.
Request free trial hours, so you can see how quickly and easily a model can be solved on the cloud.
Cookie | Duration | Description |
---|---|---|
_biz_flagsA | 1 year | A Cloudflare cookie set to record users’ settings as well as for authentication and analytics. |
_biz_pendingA | 1 year | A Cloudflare cookie set to record users’ settings as well as for authentication and analytics. |
_biz_sid | 30 minutes | This cookie is set by Bizible, to store the user's session id. |
ARRAffinity | session | ARRAffinity cookie is set by Azure app service, and allows the service to choose the right instance established by a user to deliver subsequent requests made by that user. |
ARRAffinitySameSite | session | This cookie is set by Windows Azure cloud, and is used for load balancing to make sure the visitor page requests are routed to the same server in any browsing session. |
BIGipServersj02web-nginx-app_https | session | NGINX cookie |
cookielawinfo-checkbox-advertisement | 1 year | Set by the GDPR Cookie Consent plugin, this cookie is used to record the user consent for the cookies in the "Advertisement" category . |
cookielawinfo-checkbox-analytics | 11 months | This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics". |
cookielawinfo-checkbox-functional | 11 months | The cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional". |
cookielawinfo-checkbox-necessary | 11 months | This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary". |
cookielawinfo-checkbox-others | 11 months | This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other. |
cookielawinfo-checkbox-performance | 11 months | This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance". |
CookieLawInfoConsent | 1 year | Records the default button state of the corresponding category & the status of CCPA. It works only in coordination with the primary cookie. |
elementor | never | This cookie is used by the website's WordPress theme. It allows the website owner to implement or change the website's content in real-time. |
JSESSIONID | session | New Relic uses this cookie to store a session identifier so that New Relic can monitor session counts for an application. |
viewed_cookie_policy | 11 months | The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data. |
Cookie | Duration | Description |
---|---|---|
__cf_bm | 30 minutes | This cookie, set by Cloudflare, is used to support Cloudflare Bot Management. |
_biz_nA | 1 year | Bizible sets this cookie to remember users’ settings as well as for authentication and analytics. |
_biz_uid | 1 year | This cookie is set by Bizible, to store user id on the current domain. |
_hjAbsoluteSessionInProgress | 30 minutes | Hotjar sets this cookie to detect a user's first pageview session, which is a True/False flag set by the cookie. |
_mkto_trk | 2 years | This cookie is set by Marketo. This allows a website to track visitor behavior on the sites on which the cookie is installed and to link a visitor to the recipient of an email marketing campaign, to measure campaign effectiveness. Tracking is performed anonymously until a user self-identifies by submitting a form. |
bcookie | 1 year | LinkedIn sets this cookie from LinkedIn share buttons and ad tags to recognize browser ID. |
bscookie | 1 year | LinkedIn sets this cookie to store performed actions on the website. |
doc_langsBB | 1 year | Documentation system cookie |
doc_version | 1 year | Documentation system cookie |
lang | session | LinkedIn sets this cookie to remember a user's language setting. |
lidc | 1 day | LinkedIn sets the lidc cookie to facilitate data center selection. |
UserMatchHistory | 1 month | LinkedIn sets this cookie for LinkedIn Ads ID syncing. |
whova_client_id | 10 years | Event agenda system cookie |
Cookie | Duration | Description |
---|---|---|
_gat_UA-5909815-1 | 1 minute | A variation of the _gat cookie set by Google Analytics and Google Tag Manager to allow website owners to track visitor behaviour and measure site performance. The pattern element in the name contains the unique identity number of the account or website it relates to. |
Cookie | Duration | Description |
---|---|---|
_an_uid | 7 days | 6Sense Cookie |
_BUID | 1 year | This cookie, set by Bizible, is a universal user id to identify the same user across multiple clients’ domains. |
_ga | 2 years | The _ga cookie, installed by Google Analytics, calculates visitor, session and campaign data and also keeps track of site usage for the site's analytics report. The cookie stores information anonymously and assigns a randomly generated number to recognize unique visitors. |
_ga_* | 1 year 1 month 4 days | Google Analytics sets this cookie to store and count page views. |
_gat_UA-* | 1 minute | Google Analytics sets this cookie for user behaviour tracking. |
_gcl_au | 3 months | Provided by Google Tag Manager to experiment advertisement efficiency of websites using their services. |
_gd_session | 4 hours | This cookie is used for collecting information on users visit to the website. It collects data such as total number of visits, average time spent on the website and the pages loaded. |
_gd_visitor | 2 years | This cookie is used for collecting information on the users visit such as number of visits, average time spent on the website and the pages loaded for displaying targeted ads. |
_gid | 1 day | Installed by Google Analytics, _gid cookie stores information on how visitors use a website, while also creating an analytics report of the website's performance. Some of the data that are collected include the number of visitors, their source, and the pages they visit anonymously. |
_hjFirstSeen | 30 minutes | Hotjar sets this cookie to identify a new user’s first session. It stores the true/false value, indicating whether it was the first time Hotjar saw this user. |
_hjIncludedInSessionSample_* | 2 minutes | Hotjar cookie that is set to determine if a user is included in the data sampling defined by a site's daily session limit. |
_hjRecordingEnabled | never | Hotjar sets this cookie when a Recording starts and is read when the recording module is initialized, to see if the user is already in a recording in a particular session. |
_hjRecordingLastActivity | never | Hotjar sets this cookie when a user recording starts and when data is sent through the WebSocket. |
_hjSession_* | 30 minutes | Hotjar cookie that is set when a user first lands on a page with the Hotjar script. It is used to persist the Hotjar User ID, unique to that site on the browser. This ensures that behavior in subsequent visits to the same site will be attributed to the same user ID. |
_hjSessionUser_* | 1 year | Hotjar cookie that is set when a user first lands on a page with the Hotjar script. It is used to persist the Hotjar User ID, unique to that site on the browser. This ensures that behavior in subsequent visits to the same site will be attributed to the same user ID. |
_hjTLDTest | session | To determine the most generic cookie path that has to be used instead of the page hostname, Hotjar sets the _hjTLDTest cookie to store different URL substring alternatives until it fails. |
6suuid | 2 years | 6Sense Cookie |
AnalyticsSyncHistory | 1 month | LinkedIn cookie |
BE_CLA3 | 1 year 1 month 4 days | BrightEdge sets this cookie to enable data aggregation, analysis and report creation to assess marketing effectiveness and provide solutions for SEO, SEM and website performance. |
CONSENT | 2 years | YouTube sets this cookie via embedded youtube-videos and registers anonymous statistical data. |
dj | 10 years | DemandJump cookie |
djaimid.a28e | 2 years | DemandJump cookiean |
djaimses.a28e | 30 minutes | DemandJump cookie |
li_gc | 5 months 27 days | LinkedIn Cookie |
ln_or | 1 day | LinkedIn Cookie |
vuid | 2 years | Vimeo installs this cookie to collect tracking information by setting a unique ID to embed videos to the website. |
Cookie | Duration | Description |
---|---|---|
__adroll | 1 year 1 month | This cookie is set by AdRoll to identify users across visits and devices. It is used by real-time bidding for advertisers to display relevant advertisements. |
__adroll_fpc | 1 year | AdRoll sets this cookie to target users with advertisements based on their browsing behaviour. |
__adroll_shared | 1 year 1 month | Adroll sets this cookie to collect information on users across different websites for relevant advertising. |
__ar_v4 | 1 year | This cookie is set under the domain DoubleClick, to place ads that point to the website in Google search results and to track conversion rates for these ads. |
_fbp | 3 months | This cookie is set by Facebook to display advertisements when either on Facebook or on a digital platform powered by Facebook advertising, after visiting the website. |
_te_ | session | Adroll cookie |
fr | 3 months | Facebook sets this cookie to show relevant advertisements to users by tracking user behaviour across the web, on sites that have Facebook pixel or Facebook social plugin. |
IDE | 1 year 24 days | Google DoubleClick IDE cookies are used to store information about how the user uses the website to present them with relevant ads and according to the user profile. |
li_sugr | 3 months | LinkedIn sets this cookie to collect user behaviour data to optimise the website and make advertisements on the website more relevant. |
test_cookie | 15 minutes | The test_cookie is set by doubleclick.net and is used to determine if the user's browser supports cookies. |
VISITOR_INFO1_LIVE | 5 months 27 days | A cookie set by YouTube to measure bandwidth that determines whether the user gets the new or old player interface. |
YSC | session | YSC cookie is set by Youtube and is used to track the views of embedded videos on Youtube pages. |
yt-remote-connected-devices | never | YouTube sets this cookie to store the video preferences of the user using embedded YouTube video. |
yt-remote-device-id | never | YouTube sets this cookie to store the video preferences of the user using embedded YouTube video. |
yt.innertube::nextId | never | This cookie, set by YouTube, registers a unique ID to store data on what videos from YouTube the user has seen. |
yt.innertube::requests | never | This cookie, set by YouTube, registers a unique ID to store data on what videos from YouTube the user has seen. |