Search code examples
pythonplotlyor-toolsgantt-chartcp-sat

How to plot intermediate solutions of or-tools with plotly


Lately, I've been struggling a lot with plotly, it seemed like I tamed it to match my needs until this problem came up. I'm solving a Job Shop problem with the or-tools solver and use plotly to create an interactive gantt-chart. Everything worked out quite well, but there's still one thing, which would make it perfect. I don't want to simply plot the final result of this mathematical problem, but also the intermediate steps, meaning all the solution the solver finds before it finds the optimal solution. Or-Tools provides on their website code for a solution printer, which met my requirements: it prints the intermediate solutions found. The only problem I'm facing is: I can't plot the intermediate solutions with plotly.

Below you can see the code provided by Or-Tools, I modified it for my problem and it works just fine. It prints the intermediate solutions. As soon as the solver found the optimal solution it continues to my plotly function and plots a gantt-chart. I tried to put the plot function in the on_soltuion_callback function of the class VarArraySolutionPrinter. What happens, it plots the very first solution found and stops the execution of the code. Is there a way in plotly I can plot all solution my solver finds on its way to optimality?

This is the code from or-tools: Source: https://developers.google.com/optimization/cp/cp_solver

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from ortools.sat.python import cp_model


class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):
    """Print intermediate solutions."""

    def __init__(self, variables):
        cp_model.CpSolverSolutionCallback.__init__(self)
        self.__variables = variables
        self.__solution_count = 0

    def on_solution_callback(self):
        self.__solution_count += 1
        for v in self.__variables:
            print('%s=%i' % (v, self.Value(v)), end=' ')
        print()

    def solution_count(self):
        return self.__solution_count


def SearchForAllSolutionsSampleSat():
    """Showcases calling the solver to search for all solutions."""
    # Creates the model.
    model = cp_model.CpModel()

    # Creates the variables.
    num_vals = 3
    x = model.NewIntVar(0, num_vals - 1, 'x')
    y = model.NewIntVar(0, num_vals - 1, 'y')
    z = model.NewIntVar(0, num_vals - 1, 'z')

    # Create the constraints.
    model.Add(x != y)

    # Create a solver and solve.
    solver = cp_model.CpSolver()
    solution_printer = VarArraySolutionPrinter([x, y, z])
    status = solver.SearchForAllSolutions(model, solution_printer)

    print('Status = %s' % solver.StatusName(status))
    print('Number of solutions found: %i' %solution_printer.solution_count())


SearchForAllSolutionsSampleSat()

Solution

  • I finally figured it out. I simply deepcopied my object and plotted the deepcopied version of my object.