google / or-tools

Google's Operations Research tools:
https://developers.google.com/optimization/
Apache License 2.0
11.19k stars 2.12k forks source link

Solution unable to converge for Assignment with Task Sizes #1578

Closed KungFuPandey closed 5 years ago

KungFuPandey commented 5 years ago

Hi,

I tried to elaborate on the Assignment with Task Sizes by adding a multi-dimensional "size" and "total_size_max" .

The solution seems to decide to allocate everything to 1 worker only despite the fact that others are available. The result when run allocates everything to worker(machine 18).

Sample output :

Machine 18 is assigned to produce Component 0 with minimum Cycle_Time = 10000000 Machine 18 is assigned to produce Component 1 with minimum Cycle_Time = 10000000 Machine 18 is assigned to produce Component 2 with minimum Cycle_Time = 10000000 Machine 18 is assigned to produce Component 3 with minimum Cycle_Time = 10000000 Machine 18 is assigned to produce Component 4 with minimum Cycle_Time = 10000000 Machine 18 is assigned to produce Component 5 with minimum Cycle_Time = 10000000

Attaching the code as a txt file here as it doesnt supports a py extension.

test6.txt

I took this from the sample example and tweaked input data according to need. Can you help resolve ?

lperron commented 5 years ago

If you print total_size_max, it looks very suspicious to me.

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

Le ven. 13 sept. 2019 à 21:53, KungFuPandey notifications@github.com a écrit :

Hi,

I tried to elaborate on the Assignment with Task Sizes by adding a multi-dimensional "size" and "total_size_max" .

The solution seems to decide to allocate everything to 1 worker only despite the fact that others are available. The result when run allocates everything to worker(machine 18).

Attaching the code as a txt file here as it doesnt supports a py extension.

test6.txt https://github.com/google/or-tools/files/3611596/test6.txt

I took this from the sample example and tweaked input data according to need. Can you help resolve ?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/google/or-tools/issues/1578?email_source=notifications&email_token=ACUPL3KL4I6FQJQ2JF43T2LQJPVUFA5CNFSM4IWTP6Z2YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4HLKCVBA, or mute the thread https://github.com/notifications/unsubscribe-auth/ACUPL3PKFZIZ5VWLSYVPLETQJPVUFANCNFSM4IWTP6ZQ .

KungFuPandey commented 5 years ago

Total_size_max is now a multi-dim array to meet the need of variable sized constraint for each machine(worker). I have just divided each "cost" by the max value so that i get a worker(machine) level max limit.

Below is the output of the same : array([[324173, 0, 0, ..., 0, 0, 0], [ 0, 0, 0, ..., 0, 0, 0], [ 0, 0, 0, ..., 0, 0, 0], ..., [ 0, 120153, 0, ..., 0, 0, 0], [ 0, 306538, 0, ..., 0, 0, 0], [ 0, 382508, 0, ..., 0, 0, 0]])

lperron commented 5 years ago

Mostly 0, that does not leave much flexibility in the assignment. Laurent Perron | Operations Research | lperron@google.com | (33) 1 42 68 53 00

Le ven. 13 sept. 2019 à 22:22, KungFuPandey notifications@github.com a écrit :

Total_size_max is now a multi-dim array to meet the need of variable sized constraint for each machine(worker). I have just divided each "cost" by the max value so that i get a worker(machine) level max limit.

Below is the output of the same : array([[324173, 0, 0, ..., 0, 0, 0], [ 0, 0, 0, ..., 0, 0, 0], [ 0, 0, 0, ..., 0, 0, 0], ..., [ 0, 120153, 0, ..., 0, 0, 0], [ 0, 306538, 0, ..., 0, 0, 0], [ 0, 382508, 0, ..., 0, 0, 0]])

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/google/or-tools/issues/1578?email_source=notifications&email_token=ACUPL3JYQ5H2XV22K55JCGLQJPZARA5CNFSM4IWTP6Z2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD6WDBGQ#issuecomment-531378330, or mute the thread https://github.com/notifications/unsubscribe-auth/ACUPL3PYT4JTR42XJYR5ZZLQJPZARANCNFSM4IWTP6ZQ .

KungFuPandey commented 5 years ago

i understand, but then there are possibilities where the solution should be able to allocate it correctly.

The similar code here works (having no 1s ofcourse helped it) for lesser data-set but doesnt works for larger (and sparse) dataset. IM_test6 - Copy.txt

lperron commented 5 years ago

I have no reason not to believe this is optimal.

And the solver checks all solutions, so the model must be wrong.

Please check the model carefully. Laurent Perron | Operations Research | lperron@google.com | (33) 1 42 68 53 00

Le ven. 13 sept. 2019 à 22:34, KungFuPandey notifications@github.com a écrit :

i understand, but then there are possibilities where the solution should be able to allocate it correctly.

The similar code here works (having no 1s ofcourse helped it) for lesser data-set but doesnt works for larger (and sparse) dataset.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/google/or-tools/issues/1578?email_source=notifications&email_token=ACUPL3OXN5Q2NIBCXJT4HM3QJP2MBA5CNFSM4IWTP6Z2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD6WD5GY#issuecomment-531381915, or mute the thread https://github.com/notifications/unsubscribe-auth/ACUPL3PIV4TTUSYQTBC6N3LQJP2MBANCNFSM4IWTP6ZQ .

KungFuPandey commented 5 years ago

alright, the reason why there are many 0s there is because i had to add in a large number(10000000) in COST where a machine cannot make a component.

is there a way to work-around this?

lperron commented 5 years ago

Make it a -1, and when you create the boolvar, if it is -1, create a constant var with value 0.

Bonus point, do not create it, and filter all you sums checking that the cost is not -1.

Le ven. 13 sept. 2019 à 22:46, KungFuPandey notifications@github.com a écrit :

alright, the reason why there are many 0s there is because i had to add in a large number(10000000) in COST where a machine cannot make a component.

is there a way to work-around this?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/google/or-tools/issues/1578?email_source=notifications&email_token=ACUPL3OUBMFPIHOFHBJ4JALQJP3ZHA5CNFSM4IWTP6Z2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD6WEYII#issuecomment-531385377, or mute the thread https://github.com/notifications/unsubscribe-auth/ACUPL3OSG5GWVWA7VVP5KTDQJP3ZHANCNFSM4IWTP6ZQ .

KungFuPandey commented 5 years ago

thanks, your approach sounds great!

so I will be replacing the entries with -1 in cost and how would the check to ignore -1s be used in the below code ?

model.Minimize(sum([np.dot(x_row, cost_row) for (x_row, cost_row) in zip(x, costlist)])) `

sorry i'm totally new (but eager to learn) to or-tools if this is a simple ask.

lperron commented 5 years ago

This is not a or-tools question but a numpy one, and I never use numpy.

Sorry.

Le ven. 13 sept. 2019 à 23:02, KungFuPandey notifications@github.com a écrit :

thanks, your approach sounds great!

so I will be replacing the entries with -1 in cost and how would the check to ignore -1s be used in the below code ?

model.Minimize(sum([np.dot(x_row, cost_row) for (x_row, cost_row) in zip(x, costlist)])) `

sorry i'm totally new (but eager to learn) to or-tools if this is a simple ask.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/google/or-tools/issues/1578?email_source=notifications&email_token=ACUPL3NSVIC2GUOXDIF63WTQJP5V3A5CNFSM4IWTP6Z2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD6WF4LQ#issuecomment-531389998, or mute the thread https://github.com/notifications/unsubscribe-auth/ACUPL3NZEFMEZH3UB3GT55LQJP5V3ANCNFSM4IWTP6ZQ .

lperron commented 5 years ago

Here is my interpretation of the problem

-- coding: utf-8 --

""" Created on Sat Sep 14 00:52:54 2019

@author: 320048504 """

from future import print_function

from ortools.sat.python import cp_model import time import numpy as np

def main(): model = cp_model.CpModel()

start = time.time()
cost = [[
    7.995722268, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7.995722268,

-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7.995722268, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7.995722268, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.764712938, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.64179678, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.764712938, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], [ -1, -1, -1, -1, -1, -1, 26.10110138, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26.10110138, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], [ -1, -1, -1, -1, -1, -1, 24.79202174, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27.72432227, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29.63946277, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29.4907994, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24.79202174, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27.72432227, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29.63946277, -1, -1, -1 ], [ -1, -1, -1, 6.271052178, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.271052178, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.271052178, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.271052178, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.271052178, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.271052178, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.271052178, -1, -1, -1, -1, -1, -1 ], [ 8.213437897, -1, 4.372568825, -1, -1, -1, -1, -1, -1, -1, -1, 8.213437897, -1, 4.372568825, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.372568825, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.372568825, -1, -1, -1, -1, -1, -1, -1, 8.213437897, -1, 4.372568825, -1, -1, -1, -1, -1, -1, -1, -1, 8.213437897, -1, 4.372568825, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.372568825, -1, -1, -1, -1, -1, -1, -1 ], [ -1, -1, -1, 6.282863934, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.282863934, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.282863934, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.282863934, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.282863934, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.282863934, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.282863934, -1, -1, -1, -1, -1, -1 ], [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15.49746661, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14.36944353, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14.95278777, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13.33333333, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13.33333333, -1, -1, -1, -1 ], [ -1, -1, -1, 6.194286893, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.194286893, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.194286893, -1, 14.56521739, -1, -1, -1, -1, -1, -1, -1, 6.194286893, -1, 17.57157641, -1, -1, -1, -1, -1, -1, -1, 6.194286893, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.194286893, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.194286893, -1, 14.56521739, -1, -1, -1, -1 ], [ 8.076237035, -1, 4.400797794, -1, -1, -1, -1, -1, -1, -1, -1, 8.076237035, -1, 4.400797794, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.400797794, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.400797794, -1, -1, -1, -1, -1, -1, -1, 8.076237035, -1, 4.400797794, -1, -1, -1, -1, -1, -1, -1, -1, 8.076237035, -1, 4.400797794, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.400797794, -1, -1, -1, -1, -1, -1, -1 ], [ 8.019304639, -1, 4.496583613, -1, -1, -1, -1, -1, -1, -1, -1, 8.019304639, -1, 4.496583613, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.496583613, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.496583613, -1, -1, -1, -1, -1, -1, -1, 8.019304639, -1, 4.496583613, -1, -1, -1, -1, -1, -1, -1, -1, 8.019304639, -1, 4.496583613, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.496583613, -1, -1, -1, -1, -1, -1, -1 ], [ -1, -1, -1, -1, 3.778990587, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3.778990587, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3.778990587, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3.778990587, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3.778990587, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3.778990587, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3.778990587, -1, -1, -1, -1, -1 ], [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11.51228733, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], [ -1, -1, 4.492667454, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.492667454, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.492667454, -1, -1, -1, -1, -1, -1, -1, 11.06301248, -1, 4.492667454, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.492667454, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.492667454, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4.492667454, -1, -1, -1, -1, -1, -1, -1 ], [ -1, -1, -1, -1, -1, -1, -1, -1, 5.512785364, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5.512785364, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5.512785364, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5.512785364, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5.512785364, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5.512785364, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5.512785364, -1 ], [ -1, -1, -1, -1, -1, -1, -1, 1.780837358, -1, 1.780837358, 1.780837358, -1, -1, -1, -1, -1, -1, -1, 1.780837358, -1, 1.780837358, -1, -1, -1, -1, -1, -1, -1, 1.780837358, -1, 1.780837358, -1, -1, -1, -1, -1, -1, -1, 1.780837358, -1, 1.780837358, -1, -1, -1, -1, -1, -1, -1, 1.780837358, -1, 1.780837358, 1.780837358, -1, -1, -1, -1, -1, -1, -1, 1.780837358, -1, 1.780837358, -1, -1, -1, -1, -1, -1, -1, 1.780837358, -1, 1.780837358 ], [ -1, -1, -1, -1, -1, 7.755011055, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7.755011055, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7.755011055, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7.755011055, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], [ -1, -1, -1, -1, -1, -1, 25.45422456, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29.69460764, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32.00169225, -1, -1, -1, -1, -1, -1, -1, -1, -1, 25.45422456, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29.69460764, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], [ -1, -1, -1, -1, -1, -1, 28.19319991, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27.13193117, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26.59704717, -1, -1, -1, -1, -1, -1, -1, -1, -1, 28.19319991, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27.13193117, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], [ -1, 21.5723175, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21.5723175, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21.5723175, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21.5723175, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21.5723175, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21.5723175, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21.5723175, -1, -1, -1, -1, -1, -1, -1, -1 ], [ -1, 8.455696203, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8.455696203, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8.455696203, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8.455696203, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8.455696203, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8.455696203, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8.455696203, -1, -1, -1, -1, -1, -1, -1, -1 ], [ -1, 6.776314217, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.776314217, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.776314217, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.776314217, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.776314217, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.776314217, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6.776314217, -1, -1, -1, -1, -1, -1, -1, -1 ]]

int_cost = [[int(round(x)) for x in line] for line in cost]

# demand for each component
demand = [
    28, 28, 28, 28, 28, 28, 28, 28, 28, 56, 28, 30, 30, 30, 30, 30, 30,

30, 30, 30, 60, 176, 176, 176, 176, 176, 176, 176, 176, 176, 352, 194, 194, 194, 194, 194, 194, 194, 194, 194, 388, 56, 56, 56, 56, 56, 56, 56, 56, 56, 112, 56, 149, 149, 149, 149, 149, 149, 149, 149, 149, 298, 911, 911, 911, 911, 911, 911, 911, 911, 911, 1822 ]

# total available hours
available_hrs = 2592000

num_workers = len(int_cost)
num_tasks = len(int_cost[1])
print('num_workers =', num_workers, ', num_tasks =', num_tasks)

# Variables
x = [[
    0 if int_cost[i][j] == -1 else model.NewIntVar(
        0, demand[j], 'x[%i,%i]' % (i, j)) for j in range(num_tasks)
] for i in range(num_workers)]

# Constraints

# For each component, demand is met.
for j in range(num_tasks):
    model.Add(
        sum(x[i][j] for i in range(num_workers)
            if int_cost[i][j] >= 0) == demand[j])

# Total worked hours for each machine is at most available_hrs.
for i in range(num_workers):
    model.Add(
        sum(x[i][j] * int_cost[i][j]
            for j in range(num_tasks)) <= available_hrs)

# Objective: minimize worked hours.
model.Minimize(
    sum(x[i][j] * int_cost[i][j] for i in range(num_workers)
        for j in range(num_tasks) if int_cost[i][j] != -1))

# Solve.
solver = cp_model.CpSolver()
solver.parameters.log_search_progress = True
solver.parameters.num_search_workers = 8
status = solver.Solve(model)

# Print solution.
if status == cp_model.OPTIMAL:
    print('Minimum cost = %i' % solver.ObjectiveValue())
    print()

    for i in range(num_workers):

        for j in range(num_tasks):
            qty = 0 if cost[i][j] == -1 else solver.Value(x[i][j])
            if qty > 0:
                print('Machine ', i, ' is assigned to produce', qty,
                      'of Component ', j, ' with minimum Cycle_Time = ',
                      cost[i][j])
    print()
    end = time.time()
    print("Time = ", round(end - start, 4), "seconds")

if name == 'main': main()

You need to meet demand, spreading each component onto different machines, while staying below max_available_hours, and minimizing total working time

It produces the following output in 64 ms on my laptop. I hope the model is correct.

num_workers = 25 , num_tasks = 72

Parameters: log_search_progress: true num_search_workers: 8

Optimization model '':

Variables: 152 (152 in objective)

kLinear1: 42

kLinear2: 4

kLinear3: 19

kLinearN: 32

*** starting model expansion at 0.00s

*** starting model presolve at 0.00s

Optimization model '':

Variables: 112 (32 in objective)

kLinear3: 18

kLinearN: 14

*** starting Search at 0.00s with 8 workers and strategies: [ auto, lp_br, pseudo_cost, no_lp, max_lp, core, helper, rnd_lns_auto, var_lns_auto, cst_lns_auto, rins/rens_lns_auto ]

Bound 0.00s best:inf next:[104223,155538] no_lp

1 0.00s best:128243 next:[104223,128242] no_lp num_bool:87

2 0.00s best:126699 next:[104223,126698] core num_bool:73

Bound 0.01s best:126699 next:[104321,126698] core

Bound 0.01s best:126699 next:[125839,126698] core

Bound 0.01s best:126699 next:[125923,126698] pseudo_cost

3 0.01s best:126528 next:[125923,126527] core num_bool:96

4 0.01s best:125923 next:[125923,125922] core num_bool:104

Done 0.01s core

CpSolverResponse:

status: OPTIMAL

objective: 125923

best_bound: 125923

booleans: 1

conflicts: 0

branches: 1

propagations: 0

integer_propagations: 138

walltime: 0.011411

usertime: 0.011412

deterministic_time: 0.000137944

primal_integral: 0

Minimum cost = 125923

Machine 1 is assigned to produce 176 of Component 21 with minimum Cycle_Time = 6.764712938

Machine 1 is assigned to produce 194 of Component 31 with minimum Cycle_Time = 6.64179678

Machine 1 is assigned to produce 911 of Component 62 with minimum Cycle_Time = 6.764712938

Machine 3 is assigned to produce 176 of Component 27 with minimum Cycle_Time = 29.63946277

Machine 3 is assigned to produce 911 of Component 68 with minimum Cycle_Time = 29.63946277

Machine 8 is assigned to produce 194 of Component 36 with minimum Cycle_Time = 14.36944353

Machine 10 is assigned to produce 176 of Component 26 with minimum Cycle_Time = 13.33333333

Machine 10 is assigned to produce 911 of Component 67 with minimum Cycle_Time = 13.33333333

Machine 11 is assigned to produce 28 of Component 3 with minimum Cycle_Time = 6.194286893

Machine 11 is assigned to produce 30 of Component 14 with minimum Cycle_Time = 6.194286893

Machine 11 is assigned to produce 176 of Component 24 with minimum Cycle_Time = 6.194286893

Machine 11 is assigned to produce 194 of Component 34 with minimum Cycle_Time = 6.194286893

Machine 11 is assigned to produce 56 of Component 44 with minimum Cycle_Time = 6.194286893

Machine 11 is assigned to produce 149 of Component 55 with minimum Cycle_Time = 6.194286893

Machine 11 is assigned to produce 911 of Component 65 with minimum Cycle_Time = 6.194286893

Machine 13 is assigned to produce 28 of Component 0 with minimum Cycle_Time = 8.019304639

Machine 13 is assigned to produce 30 of Component 11 with minimum Cycle_Time = 8.019304639

Machine 13 is assigned to produce 56 of Component 41 with minimum Cycle_Time = 8.019304639

Machine 13 is assigned to produce 149 of Component 52 with minimum Cycle_Time = 8.019304639

Machine 14 is assigned to produce 28 of Component 4 with minimum Cycle_Time = 3.778990587

Machine 14 is assigned to produce 30 of Component 15 with minimum Cycle_Time = 3.778990587

Machine 14 is assigned to produce 176 of Component 25 with minimum Cycle_Time = 3.778990587

Machine 14 is assigned to produce 194 of Component 35 with minimum Cycle_Time = 3.778990587

Machine 14 is assigned to produce 56 of Component 45 with minimum Cycle_Time = 3.778990587

Machine 14 is assigned to produce 149 of Component 56 with minimum Cycle_Time = 3.778990587

Machine 14 is assigned to produce 911 of Component 66 with minimum Cycle_Time = 3.778990587

Machine 16 is assigned to produce 28 of Component 2 with minimum Cycle_Time = 4.492667454

Machine 16 is assigned to produce 30 of Component 13 with minimum Cycle_Time = 4.492667454

Machine 16 is assigned to produce 176 of Component 23 with minimum Cycle_Time = 4.492667454

Machine 16 is assigned to produce 194 of Component 33 with minimum Cycle_Time = 4.492667454

Machine 16 is assigned to produce 56 of Component 43 with minimum Cycle_Time = 4.492667454

Machine 16 is assigned to produce 149 of Component 54 with minimum Cycle_Time = 4.492667454

Machine 16 is assigned to produce 911 of Component 64 with minimum Cycle_Time = 4.492667454

Machine 17 is assigned to produce 28 of Component 8 with minimum Cycle_Time = 5.512785364

Machine 17 is assigned to produce 30 of Component 19 with minimum Cycle_Time = 5.512785364

Machine 17 is assigned to produce 176 of Component 29 with minimum Cycle_Time = 5.512785364

Machine 17 is assigned to produce 194 of Component 39 with minimum Cycle_Time = 5.512785364

Machine 17 is assigned to produce 56 of Component 49 with minimum Cycle_Time = 5.512785364

Machine 17 is assigned to produce 149 of Component 60 with minimum Cycle_Time = 5.512785364

Machine 17 is assigned to produce 911 of Component 70 with minimum Cycle_Time = 5.512785364

Machine 18 is assigned to produce 28 of Component 7 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 56 of Component 9 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 28 of Component 10 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 30 of Component 18 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 60 of Component 20 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 176 of Component 28 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 352 of Component 30 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 194 of Component 38 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 388 of Component 40 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 56 of Component 48 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 112 of Component 50 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 56 of Component 51 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 149 of Component 59 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 298 of Component 61 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 911 of Component 69 with minimum Cycle_Time = 1.780837358

Machine 18 is assigned to produce 1822 of Component 71 with minimum Cycle_Time = 1.780837358

Machine 19 is assigned to produce 28 of Component 5 with minimum Cycle_Time = 7.755011055

Machine 19 is assigned to produce 30 of Component 16 with minimum Cycle_Time = 7.755011055

Machine 19 is assigned to produce 56 of Component 46 with minimum Cycle_Time = 7.755011055

Machine 19 is assigned to produce 149 of Component 57 with minimum Cycle_Time = 7.755011055

Machine 20 is assigned to produce 28 of Component 6 with minimum Cycle_Time = 25.45422456

Machine 20 is assigned to produce 56 of Component 47 with minimum Cycle_Time = 25.45422456

Machine 21 is assigned to produce 30 of Component 17 with minimum Cycle_Time = 27.13193117

Machine 21 is assigned to produce 194 of Component 37 with minimum Cycle_Time = 26.59704717

Machine 21 is assigned to produce 149 of Component 58 with minimum Cycle_Time = 27.13193117

Machine 24 is assigned to produce 28 of Component 1 with minimum Cycle_Time = 6.776314217

Machine 24 is assigned to produce 30 of Component 12 with minimum Cycle_Time = 6.776314217

Machine 24 is assigned to produce 176 of Component 22 with minimum Cycle_Time = 6.776314217

Machine 24 is assigned to produce 194 of Component 32 with minimum Cycle_Time = 6.776314217

Machine 24 is assigned to produce 56 of Component 42 with minimum Cycle_Time = 6.776314217

Machine 24 is assigned to produce 149 of Component 53 with minimum Cycle_Time = 6.776314217

Machine 24 is assigned to produce 911 of Component 63 with minimum Cycle_Time = 6.776314217

Time = 0.0643 seconds

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

Le ven. 13 sept. 2019 à 23:04, Laurent Perron lperron@google.com a écrit :

This is not a or-tools question but a numpy one, and I never use numpy.

Sorry.

Le ven. 13 sept. 2019 à 23:02, KungFuPandey notifications@github.com a écrit :

thanks, your approach sounds great!

so I will be replacing the entries with -1 in cost and how would the check to ignore -1s be used in the below code ?

model.Minimize(sum([np.dot(x_row, cost_row) for (x_row, cost_row) in zip(x, costlist)])) `

sorry i'm totally new (but eager to learn) to or-tools if this is a simple ask.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/google/or-tools/issues/1578?email_source=notifications&email_token=ACUPL3NSVIC2GUOXDIF63WTQJP5V3A5CNFSM4IWTP6Z2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD6WF4LQ#issuecomment-531389998, or mute the thread https://github.com/notifications/unsubscribe-auth/ACUPL3NZEFMEZH3UB3GT55LQJP5V3ANCNFSM4IWTP6ZQ .

KungFuPandey commented 5 years ago

Hi Laurent,

Thanks for the comprehensive detailing on the above, this really helps!

I wanted to know how/where do you get the details of the optimization (as mentioned in above comment where variables , riles and cpsolver details are mentioned). The information from OR output stack may help me to better understand how it optimized to a solution.

How did you reach to a conclusion of choosing 8 num_search_workers only ?

also - this one is near perfect(if not perfect already) - to take care of the scenario when the demand > availability on the BEST machine , but could be met if divided to other possible 2ndbest/3rd best.. machines. I just tried this and it works absolutely perfect. This really helps!

KungFuPandey commented 5 years ago

I see there is a minor bug in this approach , if the demand for a component is increased to a large value (lets say 324000) , and the cycle_time to produce that component is just over an integer rounded value (lets say 8.0193 ), then the total hours to make it will exceed (2598253 hrs) over the available hours (2592000). it is because we are rounding off the cost from 8.019 to 8 in order to get the optimization done.

how can we address this issue ? An example to show this is below :

# -*- coding: utf-8 -*-
from __future__ import print_function

from ortools.sat.python import cp_model
import time
import numpy as np
import pandas as pd

class fetch_data: 
    def __init__(self):
        # set COST
        self.cost = [[-1,7.995722268,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
            [6.764712938,-1,6.64179678,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
            [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,26.10110138,-1,-1,-1],
            [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,29.63946277,27.72432227,24.79202174,29.4907994,-1,-1],
            [-1,-1,-1,-1,-1,6.271052178,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
            [-1,8.213437897,-1,-1,4.372568825,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
            [-1,-1,-1,-1,-1,6.282863934,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
            [-1,-1,-1,-1,-1,-1,-1,-1,-1,15.49746661,-1,-1,-1,-1,-1,-1],
            [-1,-1,-1,-1,-1,-1,-1,-1,-1,14.36944353,-1,-1,-1,-1,-1,-1],
            [-1,-1,-1,-1,-1,-1,-1,-1,-1,14.95278777,-1,-1,-1,-1,-1,-1],
            [-1,-1,-1,-1,-1,-1,-1,13.33333333,-1,-1,-1,-1,-1,-1,-1,-1],
            [-1,-1,-1,-1,-1,6.194286893,-1,14.56521739,-1,17.57157641,-1,-1,-1,-1,-1,-1],
            [-1,8.076237035,-1,-1,4.400797794,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
            [-1,8.019304639,-1,-1,4.496583613,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
            [-1,-1,-1,-1,-1,-1,3.778990587,-1,-1,-1,-1,-1,-1,-1,-1,-1],
            [-1,-1,11.51228733,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
            [-1,-1,11.06301248,-1,4.492667454,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
            [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,5.512785364,-1],
            [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1.780837358],
            [-1,-1,-1,-1,-1,-1,-1,-1,7.755011055,-1,-1,-1,-1,-1,-1,-1],
            [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,29.69460764,25.45422456,32.00169225,-1,-1],
            [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,27.13193117,28.19319991,26.59704717,-1,-1],
            [-1,-1,-1,21.5723175,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
            [-1,-1,-1,8.455696203,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
            [-1,-1,-1,6.776314217,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
           ]

        # set DEMAND
        #self.demand = [1087,500000,194,1544,1544,1544,1544,1087,263,194,1087,179,84,194,1544,3088] #263 for component-1   
        self.demand = [ ("a",1087), ("b",500000),   ("c",194),  ("d",1544), ("e",1544), ("f",1544), ("g",1544), ("h",1087), ("i",263),  ("j",194),  ("k",1087), ("l",179),  ("m",84),   ("n",194),  ("o",1544), ("p",3088)]

        # set AVAILABLE HOURS
        #self.available_hrs = [2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000]
        self.available_hrs = [ ('IMM01',2592000) , ('IMM02',2592000) , ('IMM08',2592000) , ('IMM09',2592000)  , ('21',2592000) ,  ('31',2592000) , ('32',2592000) , ('34',2592000) , ('35',2592000)  , ('38',2592000) , ('40',2592000) , ('42',2592000)  , ('43',2592000) , ('44',2592000)  , ('45',2592000) , ('46',2592000) , ('47',2592000) , ('49',2592000) , ('56',2592000) , ('58',2592000) , ('L06',2592000) , ('L07',2592000) , ('L12',2592000) , ('L18',2592000) , ('L33',2592000) ]

def get_data():
    return fetch_data()

def IM_solution(c, d, a):
    model = cp_model.CpModel()

    start = time.time()

#    cost = [[-1,7.995722268,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
#            [6.764712938,-1,6.64179678,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
#            [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,26.10110138,-1,-1,-1],
#            [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,29.63946277,27.72432227,24.79202174,29.4907994,-1,-1],
#            [-1,-1,-1,-1,-1,6.271052178,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
#            [-1,8.213437897,-1,-1,4.372568825,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
#            [-1,-1,-1,-1,-1,6.282863934,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
#            [-1,-1,-1,-1,-1,-1,-1,-1,-1,15.49746661,-1,-1,-1,-1,-1,-1],
#            [-1,-1,-1,-1,-1,-1,-1,-1,-1,14.36944353,-1,-1,-1,-1,-1,-1],
#            [-1,-1,-1,-1,-1,-1,-1,-1,-1,14.95278777,-1,-1,-1,-1,-1,-1],
#            [-1,-1,-1,-1,-1,-1,-1,13.33333333,-1,-1,-1,-1,-1,-1,-1,-1],
#            [-1,-1,-1,-1,-1,6.194286893,-1,14.56521739,-1,17.57157641,-1,-1,-1,-1,-1,-1],
#            [-1,8.076237035,-1,-1,4.400797794,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
#            [-1,8.019304639,-1,-1,4.496583613,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
#            [-1,-1,-1,-1,-1,-1,3.778990587,-1,-1,-1,-1,-1,-1,-1,-1,-1],
#            [-1,-1,11.51228733,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
#            [-1,-1,11.06301248,-1,4.492667454,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
#            [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,5.512785364,-1],
#            [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1.780837358],
#            [-1,-1,-1,-1,-1,-1,-1,-1,7.755011055,-1,-1,-1,-1,-1,-1,-1],
#            [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,29.69460764,25.45422456,32.00169225,-1,-1],
#            [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,27.13193117,28.19319991,26.59704717,-1,-1],
#            [-1,-1,-1,21.5723175,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
#            [-1,-1,-1,8.455696203,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
#            [-1,-1,-1,6.776314217,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
#           ]

    cost = c
    int_cost = [[int(round(x)) for x in line] for line in cost]

    # demand for each component
    #demand = [1087,500000,194,1544,1544,1544,1544,1087,263,194,1087,179,84,194,1544,3088] #263 for component-1
    demand = d

    # total available hours
    #available_hrs = [2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000,2592000]
    available_hrs = a

    num_workers = len(int_cost)
    num_tasks = len(int_cost[1])
    print('num_workers =', num_workers, ', num_tasks =', num_tasks)

    # Variables
    x = [[
        0 if int_cost[i][j] == -1 else model.NewIntVar(
            0, demand[j], 'x[%i,%i]' % (i, j)) for j in range(num_tasks)
    ] for i in range(num_workers)]

    # Constraints

    # For each component, demand is met.
    for j in range(num_tasks):
        model.Add(
            sum(x[i][j] for i in range(num_workers)
                if int_cost[i][j] >= 0) == demand[j])

    # Total worked hours for each machine is at most available_hrs.
    for i in range(num_workers):
        model.Add(
            sum(x[i][j] * int_cost[i][j]
                for j in range(num_tasks)) < available_hrs[i])

    # Objective: minimize worked hours.
    model.Minimize(
        sum(x[i][j] * int_cost[i][j] for i in range(num_workers)
            for j in range(num_tasks) if int_cost[i][j] != -1))

    # Solve.
    solver = cp_model.CpSolver()
    solver.parameters.log_search_progress = True
    solver.parameters.num_search_workers = 8
    status = solver.Solve(model)

    # Print solution.
    if status == cp_model.OPTIMAL:
        print('Minimum cost = %i' % solver.ObjectiveValue())
        print()
        lst_res = []
        for i in range(num_workers):

            for j in range(num_tasks):
                qty = 0 if cost[i][j] == -1 else solver.Value(x[i][j])
                if qty > 0:
                    print('Machine ', i, ' is assigned to produce', qty,
                          'of Component ', j, ' with minimum Cycle_Time = ',
                          cost[i][j])
                    # add each row to a list
                    lst = [i,j,cost[i][j],qty]
                    #append each list to final list
                    lst_res.append(lst)
        print()
        end = time.time()
        print("Time = ", round(end - start, 4), "seconds")

    df_res = pd.DataFrame(data = lst_res , columns = ['Machine#', 'Component#' , 'Cycle_Time' , 'Demand_met']) 
    #print(df_res)
    return df_res

if __name__ == '__main__':
    data = get_data()
    # get Cost
    c = data.cost
    # get demand
    d1 = data.demand
    d1_dict = dict(d1)
    d = list(d1_dict.values())
    df_d = pd.DataFrame( data=d1 , columns = ['Component' , 'Demand'] )
    df_d.reset_index(inplace = True)
    df_d = df_d.rename(columns = {"index": "Component#"})
    # get available hours
    a1 = data.available_hrs
    a1_dict = dict(a1)
    a = list(a1_dict.values())
    df_a = pd.DataFrame( data=a1 , columns = ['Machine' , 'Available_hours'] )
    df_a.reset_index(inplace = True)
    df_a = df_a.rename(columns = {"index": "Machine#"})
    #print("COST :")
    #print(c)
    #print("DEMAND :")
    #print(d)
    #print("AVAILABLE HOURS :")
    #print(a)

    # Call IM optimization solution 
    df_IMres = IM_solution(c,d,a)
    #print(df_IMres)

    #combine result with demand and avaiable hrs to calculate metrics
    df_merged1 = pd.merge(df_IMres, df_d, how = 'left', on =['Component#'])
    df_merged1 = pd.merge(df_merged1, df_a, how = 'left', on =['Machine#'])
    df_merged1['Max_comp_possible'] = df_merged1.apply(lambda row: (row.Available_hours / row.Cycle_Time ), axis = 1) 
    df_merged1['%Demand_met'] = df_merged1.apply(lambda row: (row.Demand_met / row.Demand ), axis = 1) 
    df_merged1['Used_hours'] =  df_merged1.apply(lambda row: (row.Cycle_Time * row.Demand_met ), axis = 1) 
    df_merged1['%Utilization'] =  df_merged1.apply(lambda row: (row.Used_hours / row.Available_hours ), axis = 1) 
    #df_merge1.to_csv('temp1.csv')
    print(df_merged1)
lperron commented 5 years ago

You need to be conservative when rounding the time. So ceil instead of round() I would think. Laurent Perron | Operations Research | lperron@google.com | (33) 1 42 68 53 00

Le ven. 20 sept. 2019 à 10:13, KungFuPandey notifications@github.com a écrit :

I see there is a minor bug in this approach , if the demand for a component is increased to a large value (lets say 324000) , and the cycle_time to produce that component is just over an integer rounded value (lets say 8.0193 ), then the total hours to make it will exceed (2598253 hrs) over the available hours (2592000). it is because we are rounding off the cost from 8.019 to 8 in order to get the optimization done.

how can we address this issue ?

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub https://github.com/google/or-tools/issues/1578?email_source=notifications&email_token=ACUPL3NTTIFRX5LA2KD7PFDQKSA37A5CNFSM4IWTP6Z2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD7F6KLA#issuecomment-533456172, or mute the thread https://github.com/notifications/unsubscribe-auth/ACUPL3OQNBZ6KZKRNNVVJK3QKSA37ANCNFSM4IWTP6ZQ .