Adding a priority value to tasks in a Flexible Job Shop Problem

1,014 views
Skip to first unread message

Ema Ilic

unread,
Mar 10, 2022, 11:53:49 AM3/10/22
to or-tools-discuss
Hi! I don't have any experience using or-tools so I would really appreciate some help. 
I'm currently working on this Flexible Job shop Problem for orders in the restaurant. Namely, every order has a preparation and cooking time, and there are 2 preparation stations and 2 cooking stations.  All orders must be prepared before being cooked, though they don't need to be cooked immediately after being prepared. The objective is to come up with a sequence of the orders per each of the machines so that the makespan (total time elapsed from the beginnig of the preparation of the first order to the end of preparation of the last order) is minimized.
Namely, I successfully implemented the solution thanks to the flexible job shop example by or-tools.  Here is the plot just to make you understand the solution clearer.
The last constraint I would need to implement is the constraint for kids: if the order is for a kid, prioritize it.
Ideally, we would have this decimal number alpha which takes on values between 0 and 1 depending on how much importance we want to give to a kid's order. If the value is 1, kid's orders are gonna get cooked first and non-kids orders are gonna get cooked last.If the value is 0, it is irrelevant who is making the order.
Any idea on how to implement this? Should it be a constraint or something else? 
Kindest thanks in advance!

Find the code below:
 
import collections
import random
from ortools.sat.python import cp_model

attrs = {0: {"kid": True, "prep": 5, "cook": 20},
         1: {"kid": False, "prep": 15, "cook": 15},
         2: {"kid": True, "prep": 20, "cook": 25},
         3: {"kid": True, "prep": 5, "cook": 55},
         4: {"kid": True, "prep": 40, "cook": 45},
         5: {"kid": False, "prep": 45, "cook": 35},
         6: {"kid": False, "prep": 50, "cook": 55},
         7: {"kid": False, "prep": 5, "cook": 10},
         8: {"kid": True, "prep": 10, "cook": 10},
         9: {"kid": True, "prep": 55, "cook": 30},
         10: {"kid": False, "prep": 25, "cook": 20},
         11: {"kid": True, "prep": 30, "cook": 40},
         12: {"kid": False, "prep": 15, "cook": 5},
         13: {"kid": True, "prep": 35, "cook": 15}}

def getJobs(attrs):
    jobs=list()
    for key, value in attrs.items():
        jobs.append([[(value['prep'],0),(value['prep'],1)],[(value['cook'],2),(value['cook'],3)],value['kid']])
    return jobs

jobs_list=getJobs(attrs)

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

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

    def on_solution_callback(self):
        """Called at each new solution."""
        print('Solution %i, time = %f s, objective = %i' %
              (self.__solution_count, self.WallTime(), self.ObjectiveValue()))
        self.__solution_count += 1


def flexible_jobshop():
    """Solve a small flexible jobshop problem."""
    # Data part.
    jobs = jobs_list

    num_jobs = len(jobs)
    all_jobs = range(num_jobs)

    num_machines = 4
    all_machines = range(num_machines)

    # Model the flexible jobshop problem.
    model = cp_model.CpModel()
   
    #total time of all the tasks at hand
    horizon = 0
    for job in jobs:
        for task in job:
            if isinstance(task, list):
                horizon+=task[0][0]
    print('Horizon = %i' % horizon)
   

    # Global storage of variables.
    intervals_per_resources = collections.defaultdict(list)
    starts = {}  # indexed by (job_id, task_id).
    presences = {}  # indexed by (job_id, task_id, alt_id).
    job_ends = []

    # Scan the jobs and create the relevant variables and intervals.
    for job_id in all_jobs:
        job = jobs[job_id]
        num_tasks = 2
        previous_end = None
        for task_id in range(num_tasks):
            task = job[task_id]

            min_duration = task[0][0]
            max_duration = task[0][0]
            #in our case min and max duration are the same
            #because both stations are equally fast.
         
            num_alternatives = len(task)
            all_alternatives = range(2)
           
            # Create main interval for the task.
            suffix_name = '_job%i_task%i' % (job_id, task_id)
            start = model.NewIntVar(0, horizon, 'start' + suffix_name)
            duration = model.NewIntVar(min_duration, max_duration,
                                        'duration' + suffix_name)
            #this interval is a workaround becuase the model
            #expects the times on the two alternative machines
            #to be distinct.
           
            end = model.NewIntVar(0, horizon, 'end' + suffix_name)
            interval = model.NewIntervalVar(start, duration, end,
                                            'interval' + suffix_name)
            priority=model.NewConstant(jobs[job_id][2])
            # Store the start for the solution.
            starts[(job_id, task_id)] = start

            # Add precedence with previous task in the same job,
            # i.e. make sure the preparation(0)
            # happens before cooking (1).
            if previous_end is not None:
                model.Add(start >= previous_end)
            previous_end = end
            #if there is a kid..
            # if job_id!=0:
            #     model.Add(start >= starts[(job_id-1, task_id)]).OnlyEnforceIf(job_id[2]==True)
           
           

            #Create alternative intervals.
         
            if num_alternatives > 1:
                l_presences = []
                for alt_id in all_alternatives:
                    alt_suffix = '_j%i_t%i_a%i' % (job_id, task_id, alt_id)
                    l_presence = model.NewBoolVar('presence' + alt_suffix)
                    l_start = model.NewIntVar(0, horizon, 'start' + alt_suffix)
                    l_duration = task[alt_id][0]
                    l_end = model.NewIntVar(0, horizon, 'end' + alt_suffix)
                    l_interval = model.NewOptionalIntervalVar(
                        l_start, l_duration, l_end, l_presence,
                        'interval' + alt_suffix)
                    l_presences.append(l_presence)

                    # Link the master variables with the local ones.
                    model.Add(start == l_start).OnlyEnforceIf(l_presence)
                    model.Add(duration == l_duration).OnlyEnforceIf(l_presence)
                    model.Add(end == l_end).OnlyEnforceIf(l_presence)

                    # Add the local interval to the right machine.
                    intervals_per_resources[task[alt_id][1]].append(l_interval)

                    # Store the presences for the solution.
                    presences[(job_id, task_id, alt_id)] = l_presence

                # Select exactly one presence variable.
                # This adds a bounded linear expression to the model,
                # which is a bool in this case, and returns
                # an instance of a constraint class.
                model.Add(sum(l_presences) == 1)
               
            else:
                intervals_per_resources[task[0][1]].append(interval)
                presences[(job_id, task_id, 0)] = model.NewConstant(1)

        job_ends.append(previous_end)
   
    # Create machines constraints.
    for machine_id in all_machines:
        intervals = intervals_per_resources[machine_id]
        if len(intervals) > 1:
            model.AddNoOverlap(intervals)

    # make Makespan objective
    makespan = model.NewIntVar(0, horizon, 'makespan')
    model.AddMaxEquality(makespan, job_ends)
    model.Minimize(makespan)

    # Solve model.
    solver = cp_model.CpSolver()
    solution_printer = SolutionPrinter()
    status = solver.Solve(model, solution_printer)
   
    # using this for easier plotting later
    number_of_colors = len(jobs)
    color = ["#"+''.join([random.choice('0123456789ABCDEF') for j in range(6)])
             for i in range(number_of_colors)]

   

    
    for machine_id in all_machines:
        if machine_id in [0,1]:
            print('Preparation station', machine_id)
        else:
            print('Cooking station', machine_id-2)
        for job_id in all_jobs:
            for task_id in range(2):
                start_value = solver.Value(starts[(job_id, task_id)])
                machine = -1
                duration = -1
                selected = -1
                for alt_id in range(2): #len(jobs[job_id][task_id]
                    if solver.Value(presences[(job_id, task_id, alt_id)]):
                        duration = jobs[job_id][task_id][alt_id][0]
                        machine = jobs[job_id][task_id][alt_id][1]
                        selected = alt_id
                if machine_id==machine:
                    print('  Job_%i Task_%i starts at %i (duration %i)' %
                    (job_id, task_id, start_value, duration))
                    
               


flexible_jobshop()

Figure 2022-03-10 164359.png

Laurent Perron

unread,
Mar 10, 2022, 5:07:04 PM3/10/22
to or-tools-discuss
change the objective to V * makespan  + Wi * end of job1, where Wi and V are integer constants.
You want to balance the makespan objective with the priorities, and you want higher Wi for kids meals.
Laurent Perron | Operations Research | lpe...@google.com | (33) 1 42 68 53 00



--
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/750f52e9-afd7-47ed-aab6-84cf662a49a9n%40googlegroups.com.

Ema Ilic

unread,
Mar 11, 2022, 12:19:46 PM3/11/22
to or-tools-discuss
Hi Laurent! Thanks a lot for your feedback.
What exactly would V be? model.NewConstant taking on whatever value I assign it (e.g. 0 if I want adult's meals to be completely unprioritized?)? And Wi I guess would be a model.NewConstant taking on value e.g. 1000 if a meal is a Kid's meal and 0 if its an adult's meal? 
This is what  I did, I'm just not sure how to define that the NewConstant takes a different value depending on whether the meal is kid's or not. I'm also not sure if I should define V*makespan+Wi*job_ends as a separate equation with model.LinearExpression or if I should just leave it like this in the  model.Minimize(V*makespan+Wi*job_ends)? With what I've done now, I'm getting the following error: 'TypeError: Not an number: makespan'
I'm attaching here the modifications I've done:

.
.
.
# Create machines constraints.
    for machine_id in all_machines:
        intervals = intervals_per_resources[machine_id]
        if len(intervals) > 1:
            model.AddNoOverlap(intervals)
    V=model.NewConstant(0)
    Wi=model.NewConstant(100000)


    # make Makespan objective
    makespan = model.NewIntVar(0, horizon, 'makespan')
    model.AddMaxEquality(makespan, job_ends)
    model.Minimize(V*makespan+Wi*job_ends)

    # Solve model.
    solver = cp_model.CpSolver()
    solution_printer = SolutionPrinter()
    status = solver.Solve(model, solution_printer)
.
.
.
Any idea as to why am I getting this error and how to make sure Wi gets a different value depending on whether the order is for kids? 
Thanks a lot and eagerly looking forward to your answer!

Ema

Laurent Perron

unread,
Mar 11, 2022, 12:31:39 PM3/11/22
to or-tools-discuss
V is an integer constant.

Imagine makespan is critical, you have 50 tasks, take V = 50, Wkid= 1, Wadult=0

Ema Ilic

unread,
Mar 11, 2022, 12:57:25 PM3/11/22
to or-tools-discuss
Hi Laurent!
Thanks for clearing up. So far, this is what I did:
# Scan the jobs and create the relevant variables and intervals.
    for job_id in all_jobs:
        job = jobs[job_id]
        num_tasks = 2
        previous_end = None
        for task_id in range(num_tasks):
            task = job[task_id]

            min_duration = task[0][0]
            max_duration = task[0][0]
            #in our case min and max duration are the same
            #because both stations are equally fast.
         
            num_alternatives = len(task)
            all_alternatives = range(2)
           
            # kid?
            if jobs[job_id][2]==True:
                Wi=model.NewConstant(1)
            else:
                Wi=model.NewConstant(0)

.
.
.

# make Makespan objective
    makespan = model.NewIntVar(0, horizon, 'makespan')
    model.AddMaxEquality(makespan, job_ends)
    model.Minimize(num_jobs*makespan+Wi*job_ends)

Any idea as to why do I keep on receiving this error and how can I fix it?   'TypeError: Not an number: [end_job0_task1(0..735), end_job1_task1(0..735), end_job2_task1(0..735), end_job3_task1(0..735), end_job4_task1(0..735), end_job5_task1(0..735), end_job6_task1(0..735), end_job7_task1(0..735), end_job8_task1(0..735), end_job9_task1(0..735), end_job10_task1(0..735), end_job11_task1(0..735), end_job12_task1(0..735), end_job13_task1(0..735)]'
What did I do wrong in the modifications I intriduced to the code? Was there some other change I was meant to introduce to the code? 

Thanks a lot, really.
Ema
                

Laurent Perron

unread,
Mar 11, 2022, 1:07:27 PM3/11/22
to or-tools-discuss
no.

model.Minimize(num_jobs * makespan + sum(jobs_ends[i] * weights[j] for j in range(num_jobs))

where weights[j] = 0 or 1 depending on the job type.

Laurent Perron | Operations Research | lpe...@google.com | (33) 1 42 68 53 00


Ema Ilic

unread,
Mar 11, 2022, 1:37:57 PM3/11/22
to or-tools-discuss
Hi Laurent! 
Thank you for your kind and prompt reply, and most importantly for your patience. I really appreciate your help here.
So here is what I did: I implemented the weights list and assigned it a NewConstant being 0 or 1 depending on whether there is a kid or not. Then I applied the function as you advised (changing i for j in num_job[i] because I assumed it was a mistake, please correct me if I'm wrong). It gave me the following error: TypeError: Not an number: 1. I think might be because job_ends is a list of the format: end_job0_task1(0..735), end_job1_task1(0..735), end_job2_task1(0..735), end_job3_task1(0..735).
Then  I tried using the l_end instead of job_ends in the model.Minimize(num_jobs * makespan + sum(l_end[i] * weights[j] for j in range(num_jobs))  because for what I understood it is meant to be the list of job ending times. This gave me the following error: TypeError: 'IntVar' object is not subscriptable.

 # Scan the jobs and create the relevant variables and intervals.
    for job_id in all_jobs:
        job = jobs[job_id]
        num_tasks = 2
        previous_end = None
        for task_id in range(num_tasks):
            task = job[task_id]

            min_duration = task[0][0]
            max_duration = task[0][0]
            #in our case min and max duration are the same
            #because both stations are equally fast.
         
            num_alternatives = len(task)
            all_alternatives = range(2)
           
            # kid?
           
            if jobs[job_id][2]==True:
                Wi=model.NewConstant(1)
            else:
                Wi=model.NewConstant(0)
            weights.append(Wi)

               
           
            # Create main interval for the task.
            suffix_name = '_job%i_task%i' % (job_id, task_id)
            start = model.NewIntVar(0, horizon, 'start' + suffix_name)
            duration = model.NewIntVar(min_duration, max_duration,
                                        'duration' + suffix_name)
            #this interval is a workaround becuase the model
            #expects the times on the two alternative machines
            #to be distinct.
           
            end = model.NewIntVar(0, horizon, 'end' + suffix_name)
            interval = model.NewIntervalVar(start, duration, end,
                                            'interval' + suffix_name)
            #priority=model.NewConstant(jobs[job_id][2])
    model.Minimize(num_jobs * makespan + sum(job_ends[j] * weights[j] for j in range(num_jobs))) 
    (or alternatively model.Minimize(num_jobs * makespan + sum(l_end[j] * weights[j] for j in range(num_jobs)))  )

Do you have any clue on what I did wrong?
Infinite thanks for your patience, once again,

Laurent Perron

unread,
Mar 11, 2022, 3:41:28 PM3/11/22
to or-tools-discuss
What is weights[0] ? Which type? 
It has to be a python int. 

Message has been deleted
Message has been deleted

Ema Ilic

unread,
Mar 12, 2022, 8:44:58 AM3/12/22
to or-tools-discuss
Hi Laurent (and everyone else that might be interested),
I changed the Wi from the <class 'ortools.sat.python.cp_model.IntVar'> to a python intger and that fixed my problem.
I limited the number of solutions to 15 and that fixed the infinite search for an optimal solution (the numbers were going past 40 and the algorithm was loading for a long time). The solution status is no longer OPTIMAL, it's feasible, and I'm satisfied with that.
However, when I actually ordered and printed the results per machine, it  looks like the kid's meals are not really being prioritized. 
I tried playing around with wi values, namely setting it between 1 and 10000 for kids and setting values -1 and 0 for no kids and it didn't appear to have an impact on the final sequence of orders. It always looks as if it was happening independently of whether it's a kids order or not. Im leaving you the script here in case you're curious and would really like to hear your opinion about this. I'm also leaving you the output

import collections
import plotly.express as px
import plotly.figure_factory as ff
from plotly.offline import plot
import pandas as pd
from matplotlib.patches import Patch
import matplotlib.pyplot as plt
import numpy as np
import random
from datetime import datetime

from ortools.sat.python import cp_model

attrs = {0: {"kid": True, "prep": 5, "cook": 20},
         1: {"kid": False, "prep": 15, "cook": 15},
         2: {"kid": True, "prep": 20, "cook": 25},
         3: {"kid": True, "prep": 5, "cook": 55},
         4: {"kid": True, "prep": 40, "cook": 45},
         5: {"kid": False, "prep": 45, "cook": 35},
         6: {"kid": False, "prep": 50, "cook": 55},
         7: {"kid": False, "prep": 5, "cook": 10},
         8: {"kid": True, "prep": 10, "cook": 10},
         9: {"kid": True, "prep": 55, "cook": 30},
         10: {"kid": False, "prep": 25, "cook": 20},
         11: {"kid": True, "prep": 30, "cook": 40},
         12: {"kid": False, "prep": 15, "cook": 5},
         13: {"kid": True, "prep": 35, "cook": 15}}

def getJobs(attrs):
    jobs=list()
    for key, value in attrs.items():
        jobs.append([[(value['prep'],0),(value['prep'],1)],[(value['cook'],2),(value['cook'],3)],value['kid']])
    return jobs

jobs_list=getJobs(attrs)
print(jobs_list[:3])

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

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

    def on_solution_callback(self):
        """Called at each new solution."""
        print('Solution %i, time = %f s, objective = %i' %
              (self.__solution_count, self.WallTime(), self.ObjectiveValue()))
        self.__solution_count += 1
        if self.__solution_count >= 5:
            print('Stop search after %i solutions' % 15)
            self.StopSearch()



def flexible_jobshop():
    """Solve a small flexible jobshop problem."""
    # Data part.
    jobs = jobs_list

    num_jobs = len(jobs)
    all_jobs = range(num_jobs)

    num_machines = 4
    all_machines = range(num_machines)

    # Model the flexible jobshop problem.
    model = cp_model.CpModel()
   
    #total time of all the tasks at hand
    horizon = 0
    for job in jobs:
        for task in job:
            if isinstance(task, list):
                horizon+=task[0][0]
    print('Horizon = %i' % horizon)
   

    # Global storage of variables.
    intervals_per_resources = collections.defaultdict(list)
    starts = {}  # indexed by (job_id, task_id).
    presences = {}  # indexed by (job_id, task_id, alt_id).
    job_ends = []
    weights=list()


    # Scan the jobs and create the relevant variables and intervals.
    for job_id in all_jobs:
        job = jobs[job_id]
        num_tasks = 2
        previous_end = None
        for task_id in range(num_tasks):
            task = job[task_id]

            min_duration = task[0][0]
            max_duration = task[0][0]
            #in our case min and max duration are the same
            #because both stations are equally fast.
         
            num_alternatives = len(task)
            all_alternatives = range(2)
           
            # kid?
           
            if jobs[job_id][2]==True:
            
                Wi=1000
     
            else:
                Wi=0

         
            weights.append(Wi)
           
               
           
            # Create main interval for the task.
            suffix_name = '_job%i_task%i' % (job_id, task_id)
            start = model.NewIntVar(0, horizon, 'start' + suffix_name)
            duration = model.NewIntVar(min_duration, max_duration,
                                        'duration' + suffix_name)
            #this interval is a workaround becuase the model
            #expects the times on the two alternative machines
            #to be distinct.
           
            end = model.NewIntVar(0, horizon, 'end' + suffix_name)
            interval = model.NewIntervalVar(start, duration, end,
                                            'interval' + suffix_name)
            #priority=model.NewConstant(jobs[job_id][2])
            # Store the start for the solution.
            starts[(job_id, task_id)] = start

            # Add precedence with previous task in the same job,
            # i.e. make sure the preparation(0)
            # happens before cooking (1).
            if previous_end is not None:
                model.Add(start >= previous_end)
            previous_end = end
           
           

    model.Minimize(num_jobs* makespan + sum(job_ends[j] * weights[j] for j in range(num_jobs)))

   
    # Solve model.
    solver = cp_model.CpSolver()
    solution_printer = SolutionPrinter()
    status = solver.Solve(model, solution_printer)
   
    # using this for easier plotting later
    number_of_colors = len(jobs)
    color = ["#"+''.join([random.choice('0123456789ABCDEF') for j in range(6)])
             for i in range(number_of_colors)]

   

    plot_list=[]

    for machine_id in all_machines:
        if machine_id in [0,1]:
            print('Preparation station', machine_id)
        else:
            print('Cooking station', machine_id-2)
        for job_id in all_jobs:
            for task_id in range(2):
                start_value = solver.Value(starts[(job_id, task_id)])
                machine = -1
                duration = -1
                selected = -1
                for alt_id in range(2): #len(jobs[job_id][task_id]
                    if solver.Value(presences[(job_id, task_id, alt_id)]):
                        duration = jobs[job_id][task_id][alt_id][0]
                        machine = jobs[job_id][task_id][alt_id][1]
                        selected = alt_id
                        kid=jobs[job_id][2]
                if machine_id==machine:
                    #print('  Job_%i Task_%i starts at %i (duration %i), kid=%r' %
                    #(job_id, task_id, start_value, duration,kid))
                    plot_list.append(dict(Machine=machine, Job=job_id, Start=start_value, Finish=start_value+duration, Duration=duration, Color=color[job_id], Kid=kid))  
   
  
    #print sequences per machine ordered chronologically:
    prep1=list()
    prep2=list()
    cook1=list()
    cook2=list()

    for dic in plot_list:
        if dic['Machine']==0:
            prep1.append((dic['Job'] ,dic['Finish'], dic['Kid'])) #job_id, start, kid
        if dic['Machine']==1:
             prep2.append((dic['Job'] ,dic['Finish'], dic['Kid'])) #job_id, start, kid
        if dic['Machine']==2:
             cook1.append((dic['Job'] ,dic['Finish'], dic['Kid'])) #job_id, start, kid
        if dic['Machine']==3:
            cook2.append((dic['Job'] ,dic['Finish'], dic['Kid'])) #job_id, start, kid
    ordered_sequences=[prep1,prep2,cook1,cook2]
    for x in ordered_sequences:
        x.sort(key = lambda x: x[1])
        if x==prep1:
            print('Preparation station 1: ')
        if x==prep2:
            print('Preparation station 2: ')
        if x==cook1:
            print('Cooking station 1: ')
        if x==cook2:
             print('Cooking station 2: ')
        for element in x:
            print('\t Job {} finishing at time {} with a kid=={}'.format(element[0],element[1], element[2]))
               
           


    plt.show()
               

    print('Solve status: %s' % solver.StatusName(status))
    print('Optimal objective value: %i' % solver.ObjectiveValue())
    print('Statistics')
    print('  - conflicts : %i' % solver.NumConflicts())
    print('  - branches  : %i' % solver.NumBranches())
    print('  - wall time : %f s' % solver.WallTime())


flexible_jobshop()

Thanks a lot for your help Laurent!
Ema

Fastest_Food_Kids_output.html

Laurent Perron

unread,
Mar 12, 2022, 1:00:11 PM3/12/22
to or-tools-discuss
I changed the solve part:

# Solve model.
solver = cp_model.CpSolver()
solver.parameters.log_search_progress = True
solver.parameters.num_search_workers = 16
# solution_printer = SolutionPrinter()
status = solver.Solve(model)

It solves to optimality in 1.2s on my laptop.

CpSolverResponse summary:

status: OPTIMAL

objective: 618290

best_bound: 618290

booleans: 727

conflicts: 4245

branches: 13121

propagations: 474494

integer_propagations: 690694

restarts: 468

lp_iterations: 0

walltime: 1.20134

usertime: 1.20134

deterministic_time: 1.27085

gap_integral: 5.2009


Laurent Perron | Operations Research | lpe...@google.com | (33) 1 42 68 53 00


Ema Ilic

unread,
Mar 13, 2022, 5:20:40 PM3/13/22
to or-tools-discuss
Hi Laurent! Thanks for your response.
Namely, I just implemented the changes to the solver part as you proposed.
Indeed, I do manage to reach an optimal solution, though after quite a while. however, when I print the output, I can tell that the kid's orders are definitely not the first ones to be cooked, on neither machine. The order of the orders appears to be quite random. Which values of Wi (weight) are you using? I tried both with 10000 and 0, 10000 and 1, and 1 and 0. 
I introduced the exact same changes to the code as you just advised, no more and no less with respect to the previous code I sent.
Looking forward to hearing from you,
Ema

fastest_food_kids_output2.html

alireza...@gmail.com

unread,
Feb 21, 2023, 12:16:01 PM2/21/23
to or-tools-discuss
Hi Laurent, 
I have a question on CpSolverResponse 
My model is sometimes sensitive to the input data (which is expected) 
in some cases it takes 5 minutes to run and sometimes (althought there are less number of variabkles) it takes much more (20 minutes) 

Is there any way I can improve the model based on the CpSolverResponse? What can we understand from them ? 
Screenshot 2023-02-21 at 17.10.12.png Screenshot 2023-02-21 at 17.12.33.png
Screenshot 2023-02-21 at 17.15.11.png

These are from two different models. 
Thanks in advance 
Alireza



Laurent Perron

unread,
Feb 21, 2023, 12:46:52 PM2/21/23
to or-tools-discuss
Use multiple workers. 

Reply all
Reply to author
Forward
0 new messages