Are there any hidden differences in OR-Tools' default parameters for a MIP model in Python vs C++?

97 views
Skip to first unread message

Guillermo Gutierrez

unread,
Jul 5, 2023, 1:44:17 PM7/5/23
to or-tools-discuss

StackOverflow cross-post here.

As a disclaimer -- I am very aware that OR-Tools' Python code are just wrappers around their C++ source code. I'm just getting an odd discrepancy between a model setup in Python and one setup in C++ and am wracking my brain to figure out what I've messed up (because its most likely me not implementing something correctly or missing a "hidden-to-me" difference between the two).

Setup Context

OS

  • Pop!OS 22.04 (basically Ubuntu)
  • x86_64

Python Environment

  • Python 3.10.5
  • ortools 9.6.2534

C++ Environment

  • CMake 3.26.4
  • gcc 11.3.0
  • or-tools FetchContent'd from stable Git branch
Problem Context

I've got two scripts, one in Python and the other in C++, that are setup to do (what I believe) is the same thing: read in an MPS file and solve the contained MIP using the SCIP solver.

The MPS file being fed into both scripts is the same, so I would have expected them to produce similar results. I might have even expected the C++ program to run faster than its Python counterpart. But what I'm seeing is that the Python script finished in ~20 seconds or so, while the C++ script errors out during the solve process after 5+ minutes.

The C++ error produced was (effectively): ERROR: (node 1) unresolved numerical troubles in LP 2 cannot be dealt with, which is mentioned in this question.

Upon inspecting the logs from both solvers, I see they are both coming to the same primal / dual bounds. But whereas the Python script reaches those bounds and exits with an Optimal solution, the C++ script continues to iterate until error-ing out with the above issue.

I'm wondering if it could be related to the way I've read in the MPS file and loaded it into a model? The process for each is laid out below:

Python

  • use ortools.linear_solver.python.model_builder.ModelBuilderand ModelSolver
  • instantiate objects model = ModelBuilder() and solver = ModelSolver("SCIP")
  • model.import_from_mps_file to read MPS
  • solver.solve(model) to optimize MIP

C++

  • #include <ortools/lp_data/mps_reader.h> and #include <ortools/linear_solver/linear_solver.h>
  • instantiate solver `solver = MPSolver::CreateSolver("SCIP")
  • read MPS file to proto model_proto = glop::MpsFileToMPModelProto(mps_file)
  • load model from proto solver->LoadModelFromProto(*model_proto, ...)
  • solver->Solve()

So, in Python, I'm using the ModelHelpers and in C++ I'm interfacing directly with the MPSolver class. Perhaps this is where the difference lies?

Any thoughts / suggestions as to why I'm seeing this difference would be much appreciated!

Laurent Perron

unread,
Jul 5, 2023, 1:57:38 PM7/5/23
to or-tools-discuss
They use different set of solver parameters, in particular tolerances and gaps. 

--
You received this message because you are subscribed to the Google Groups "or-tools-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to or-tools-discu...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/or-tools-discuss/2441da69-c885-48bf-9983-acc5ead1dd3en%40googlegroups.com.

Guillermo Gutierrez

unread,
Jul 5, 2023, 2:01:21 PM7/5/23
to or-tools-discuss
Ah, lovely -- that would account for it, assuming that C++'s tolerances are more strict than Python's.

Thanks!

Laurent Perron

unread,
Jul 5, 2023, 2:02:45 PM7/5/23
to or-tools-discuss
Yes, it forces 1e-7 I believe, while model_builder uses the default from scip.

Guillermo Gutierrez

unread,
Jul 5, 2023, 3:36:08 PM7/5/23
to or-tools-discuss
Is there an accessible location to see what parameters the model_builder sets? Digging around in GitHub hasn't quite revealed them yet, so I've just been looking at the SCIP parameters documentation and trying to relate it to the MPSolverParameters that are configurable.

Adjusting the primal and dual tolerances to the SCIP defaults do remove the error I was getting (so thats good), but the solve still takes 10x+ the time in C++, which is very strange to me.

Laurent Perron

unread,
Jul 5, 2023, 3:43:49 PM7/5/23
to or-tools-discuss

Guillermo Gutierrez

unread,
Jul 5, 2023, 3:46:33 PM7/5/23
to or-tools-discuss
Ah -- perfect! Thanks again~

Guillermo Gutierrez

unread,
Jul 5, 2023, 5:48:26 PM7/5/23
to or-tools-discuss
Are there any other obvious reasons the two models might differ in solve-time?

I believe I've succeeded in setting those SCIP parameters such that they match with the defaults, but the solve time hasn't adjusted much at all. Perhaps I'm just incorrectly setting the parameters.

Guillermo Gutierrez

unread,
Jul 6, 2023, 7:55:37 AM7/6/23
to or-tools-discuss
So I've gone ahead and re-did my C++ approach to use the ModelBuilderHelper / ModelSolverHelper wrappers to try and match everything that the Python version is doing under the hood.

And, to my dismay, the C++ version STILL takes ~10 minutes to solve! Auditing the logs of both versions, it appears they are coming to the exact same solution -- all the way down to the number of solving nodes lining up and everything.

I've got not idea how / why this is possible.

Laurent Perron

unread,
Jul 6, 2023, 8:00:49 AM7/6/23
to or-tools...@googlegroups.com
Most likely, you are compiling the C++ in debug mode.
Laurent Perron | Operations Research | lpe...@google.com | (33) 1 42 68 53 00



Guillermo Gutierrez

unread,
Jul 6, 2023, 8:50:22 AM7/6/23
to or-tools-discuss
Ah! Yes, that was in fact the problem!

Thanks for sticking with me there lol much appreciated!

Mizux Seiha

unread,
Jul 6, 2023, 9:25:01 AM7/6/23
to or-tools-discuss
May we know which command did you use to build the C++ ?

It should have been Release by default if using CMake...
https://github.com/google/or-tools/blob/a855ded443dbb94698f2baa2b004568e834ddb8a/CMakeLists.txt#L39-L55

Guillermo Gutierrez

unread,
Jul 6, 2023, 9:36:31 AM7/6/23
to or-tools-discuss

Sure thing -- I'm using the JetBrains CLion IDE and their standard CMake plugin. It appears that the plugin's default is to make a Debug configuration (it does explicitly say "Debug" in its title, I just didn't notice), so it explicitly passes in the flag -CMAKE_BUILD_TYPE=Debug when it executes the cmake command.

Once I went to add a new CMake configuration in the plugin, it automatically made the new one a Release configuration and changed the CMAKE_BUILD_TYPE flag to Release without me needing to do anything.

So it would appear that this issue was just a CLion trying-to-be-helpful issue, in the end haha perhaps there is a way in OR-Tools CMakeLists.txt to alert the user when this flag is explicitly set in the cmake command? Not sure if that would be possible / even within the scope of OR-Tools' responsibility (it really is just a user error).
Reply all
Reply to author
Forward
0 new messages