Python or Rust : Performance Comparison in Optimization Model Environment

Share this post
Priya Senthil
April 28, 2025
7 mins

With the wide array of programming languages available today, developers can often feel overwhelmed when deciding which one to use for a given project. While many languages share common principles, they also differ significantly in functionality, performance, and ecosystem. Python is one of the most widely adopted languages, valued for its readability, ease of use, and the strength of its community and libraries. Rust, being a compiled language, offering significant benefits in terms of speed and memory safety—albeit with a steeper learning curve.

Selecting a language is typically influenced by a developer's familiarity, but the complexity of the problem at hand can often drive a need to look beyond the usual tools. In industrial environments—ranging from manufacturing to logistics—addressing daily challenges such as production planning and demand forecasting requires efficient algorithms and reliable execution. One popular mathematical approach to model such scenarios is Mixed Integer Programming(MIP), which involves solving optimization problems with both integer and continuous variables.

MIP problems are computationally intensive due to their combinatorial nature. As the number of integer variables and constraints grows, so does the complexity of the solution space—especially in time-sensitive or real-time applications.

This blog walks through our experience building a parallel MIP solver, beginning with Python for prototyping and later incorporating Rust. This shift illustrates how combining the strengths of different languages can unlock performance gains, and why stepping outside the comfort zone of familiar tools can be worth while when developing enterprise-grade applications.

A brief background of our Parallel Branch & Bound

The core method typically used to solve MIPs (Mixed Integer Programs) is an algorithm called Branch and Bound (B&B). Many commercial and open-source solvers use the Branch and Bound algorithm to systematically explore all possible solutions to the MIP by branching, bounding on the ones that are integer feasible and pruning (eliminating) the unwanted branches. But the implementations of B&B provided by these solvers are not typically flexible or adaptable for controlled experimentations or custom use-cases.

Therefore, we developed our very own lightweight, flexible MIP solver with our bespoke parallel B&B tree structure and management approach that could be modified, tested, and evaluated in isolation.

Fig. 1 shows the schematic of the Hub-multi worker parallel B&B architecture. Learn more about our parallel architecture in our next blog.

Rust: The Right Fit for our Parallel BnB

Harnessing Rust’s Safety and Speed: A Strategic Choice for Scalable Parallel Branch and Bound Algorithms

Our MVP (Minimal Viable Product) was initially built in Python mainly for its suitability to agile and rapid development and its extensive machine learning libraries. Python’s flexibility allowed us to prototype and test ML-based variable selection strategies quickly, leveraging existing libraries such as Scikit-learn to validate our approach. Read more about our ML based Branching Variable Selection here. .

However, as our focus shifted toward parallel development and the need for a highly efficient and scalable system, we transitioned to Rust for the following main reasons:

Performance

  • Rust is blazingly fast as it is a statically compiled language and therefore doesn’t impose any interpreter overload at the runtime. This was the primary criteria for our parallel B&B algorithm as it would be beneficial to prune the feasible region quicker.

Memory Safety

  • Thanks to the ownership model, borrow checker and lifetimes in Rust, the data races and locking issues that are common in the multithreaded environments are no longer a threat. As our parallel B&B architecture involves concurrent updates on the Primal bounds by multiple workers the entire application needs to be thread safe which is guaranteed by Rust.

Consistent updates in parallel architecture using CRDT

  • Rust offers rRich Native libraries to support the CRDT (Conflict-free Replicated Data Types) which forms the foundation for our concurrent and distributed parallel B&B architecture. It helps to update the bounds (Primal and dual) across multiple workers independently and later merged without conflicts. This ensures a Global bound value across the distributed system.

·

Performance Comparison of Rust vs Python in Optimization environment

Two phased development approach of our MVP provided an alternate implementation to benchmark and compare our advanced Rust-based system against, ensuring that the improvements in scalability and efficiency were both measurable and meaningful.

Our two-phased approach—from a Python MVP to a Rust implementation—reflects agile principles, balancing rapid prototyping with a transition to a robust, high-performance solution. While our goal wasn't a detailed performance benchmark, comparing the Python and Rust versions of our Branch-and-Bound framework highlighted practical reasons for the switch. Python was ideal for quickly testing ML strategies and building an MVP, but as our needs grew to include parallelism, scalability, and efficient resource handling, Rust proved better suited for production-grade development.

Key Configuration Parameters for Comparison

We ran the tests on both Python and Rust versions of our Parallel B&B MIP solver with the following configuration settings:

  • 1 % target gap
  • Max runtime set to 3600 seconds
  • The nodes were evaluated in the same order by assigning same starting node to each solver.
  • Alternating search strategies between best bound and depth first for every 100 node evaluations
  • The floating-point precision between both solver implementations was similar and thereby introducing a similar tolerance for treating floating point values in LP relaxations was maintained.

For testing purpose, we chose 10 problems of varying difficulty levels which are part of the publicly listed collection set of MIPLIB 2017.

The following table summarises the results in a nutshell

Performance Comparison of Rust Vs Python
Gap between bb and Solution

In the above graph we can observe that the Rust solver has found better or same feasible solutions for every instance, and improved bounds r in 8/10 instances. In the remaining two benchmarks, the Rust solver was terminated as a gap of 1% was reached.

Number of Nodes Explored per second

The speed of the rust implementation was almost 6-7 times faster than that of Python’s. The average MIP gap of the solutions found by the Rust solver is 2.5 times smaller than the Python implementation and further validates our decision to proceed with Rust as our preferred stack for our parallel B&B solver implementation.

Percentage Difference from the optimal solution

As we can observe in the above graph for one of the instances (mik-250-20-75-4), Python failed to find any feasible solution whereas Rust managed to find a solution with 7.8% gap, demonstrating that the improved performance can help to solve harder MIPs.

We compared the performance of our bespoke Branch-and-Bound solver in both Python and Rust. While Python enabled rapid prototyping and ML strategy testing, it struggled with runtime and memory efficiency on larger instances. In contrast, the Rust version—leveraging low-level control and concurrency—achieved 6–7× faster execution with significantly lower memory usage. Though not a comprehensive benchmark, these results clearly demonstrated Rust’s suitability for scalable, high-performance, parallel computation. This performance gain, along with Rust’s safe concurrency model, validated our shift to Rust for production while retaining the Python prototype for ongoing ML experimentation.

Share this post
learn
MIP
optimization models
Priya Senthil
April 28, 2025
7 mins