0

I have a very simple program in C++ with Or-tools cp-sat solver that is taking quite long to solve. on average I am getting anywhere between 500-950 randomization per second.

Here is the code

#include <absl/log/initialize.h>
#include <stdlib.h>

#include "ortools/base/logging.h"
#include "ortools/sat/cp_model.h"
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/cp_model_solver.h"
#include "ortools/util/sorted_interval_list.h"

void SimpleSatProgram() {
  const operations_research::Domain domain(0, 100);
  operations_research::sat::CpSolverResponse response;

  operations_research::sat::CpModelBuilder cp_model;
  operations_research::sat::IntVar a = cp_model.NewIntVar(domain);
  operations_research::sat::IntVar b = cp_model.NewIntVar(domain);
  operations_research::sat::IntVar c = cp_model.NewIntVar(domain);
  cp_model.AddEquality(a + b + c, 200);

  for (int x=0; x < 10000; x++) {
    response = operations_research::sat::Solve(cp_model.Build());

    if (response.status() == operations_research::sat::CpSolverStatus::OPTIMAL ||
        response.status() == operations_research::sat::CpSolverStatus::FEASIBLE) {
      // for (auto i : all)
      //   std::cout << std::setfill('0') << std::setw(2)
      //             << SolutionIntegerValue(response, i) << " ";
      // std::cout << "\n";
    } else {
      LOG(INFO) << "No solution found.";
    }
  }
}

int main() {
  // absl::InitializeLog();
  SimpleSatProgram();
  return EXIT_SUCCESS;
}

I have a proprietary tool that is giving close well above 120k randomizations per second in the same setup.

Is there something I can do to optimize or follow any best practices in coding to get the best performance?

Laurent Perron
  • 8,594
  • 1
  • 8
  • 22
Krishna
  • 924
  • 1
  • 7
  • 28
  • First thing coming to my mind: Set compiler option `-O3` – optimise best for speed. Documentation for GCC is [here](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html), clang has the same options, MSVC similar ones (I think `/O3`, but you need to verify yourself...). – Aconcagua May 04 '23 at 06:49
  • It's a proprietary tool – do you still have access to its code? It might internally not do the same as you do nor use the same libraries. – Aconcagua May 04 '23 at 06:55
  • I am actually using -O3 aleady – Krishna May 04 '23 at 07:05
  • I tested the proprietary tool along with this code on same machine. Its not in C++ – Krishna May 04 '23 at 07:06
  • Well, how can you tell what your proprietary tool internally does? Maybe using entirely different libraries? Or does it rely on the *same* SO- (linux)/DLL- (windows) files? And even if the latter *is* so, how can you tell if exactly the same algorithms are used? You'd need to de-compile the proprietary tool to know... – Aconcagua May 04 '23 at 08:34
  • One thing that looks suspicious: You build the model again and again in the loop – is this intentionally, i.e. do you want to include building time in your measurement? If so, then fine, if *not*, then build *before* entering the loop, store the result in a variable and use that one inside. – Aconcagua May 04 '23 at 08:39
  • I do want to include the build time too, but the Build* functions in or-tools are just returning an internal impl_ pointer/reference, so I don't think that is causing the issue. – Krishna May 04 '23 at 10:11
  • My idea is not to compare the or-tools with the proprietary tool, but <1k randomizations per second seems too slow for such a simple constraint problem. I want to know if I am missing something – Krishna May 04 '23 at 10:13
  • What do you mean by *'randomisation'* anyway – I do not see any call to `rand` or using C++ `random` facility anywhere, so where's the 'random' part? Do you mean *'iterations'* instead? Apart from, truth is that I do not know the or-tools, so I cannot tell what these do *internally*. Your code indeed is pretty small, but that doesn't mean that there's not much work done hidden away in or-tools libraries. Then again: Did you compile these on your own, and if so, have you added `-O3` flag for these as well? – Aconcagua May 04 '23 at 10:22
  • Yes, I have used -O3, sorry for the confusion around randomization. I mean iterations, I have some peripheral code (that I removed in this example to simplify) that adds randomization, which results in the program returning different solutions in each iteration. – Krishna May 04 '23 at 13:08

1 Answers1

2

You can try to add

SatParameters params;
params.set_num_workers(1);
params.set_cp_model_presolve(false);

And replace Solve() by Solvewithparameters().

Note that cp-sat is tuned to solve meaningful non trivial models.

Laurent Perron
  • 8,594
  • 1
  • 8
  • 22
  • Awesome, what black magic is this, it suddenly increased the speed from 350-1200 iterations to 2865-16949 iterations per second, anywhere between 8x-14x. How can I understand this, what changed with these parameters? – Krishna May 04 '23 at 13:19
  • My requirement is to get a random solution for a set of constraints and get done with it, most likely the setup changes after each solution so I need to redo it all over again. Looks like it is in my best interest to understand internals of or-tools, what is the best place to start? – Krishna May 04 '23 at 13:23
  • 1
    By default, the solver presolves the model, and uses all cores. This is inefficient for small models. – Laurent Perron May 04 '23 at 14:02