0

I'm working on an optimization problem and working through converting a hard coded, inflexible solution into a functional, flexible one. I'm struggling on how to use multiple dictionaries in a function of a PuLP optimization problem. My best guess would be to possible use nested for loops, but can't wrap my head around how to do this. Below is what my current hard coded solution looks like.

import pulp

part_numbers = {"Part A", "Part B"}
employees = {"Employee A", "Employee B", "Employee C", "Employee D", "Employee E", "Employee F", "Employee G", "Employee H"}
efficiency = {85, .75, .5, .75, .59, .40, .87, .37, .65, .85, .85, .5, .4, .8, .3, .92}
exptime = {20, 10}

model += ((
    (pulp.lpSum(
        ( (exptime[0] * qty_produced[part_numbers[0], employees[0]])/ efficiency[0])
        + ((exptime[0] * qty_produced[part_numbers[0], employees[1]])/ efficiency[1])
        + ((exptime[0] * qty_produced[part_numbers[0], employees[2]])/ efficiency[2])
        + ((exptime[0] * qty_produced[part_numbers[0], employees[3]]) / efficiency[3])
        + ((exptime[0] * qty_produced[part_numbers[0], employees[4]]) / efficiency[4])
        + ((exptime[0] * qty_produced[part_numbers[0], employees[5]]) / efficiency[5])
        + ((exptime[0] * qty_produced[part_numbers[0], employees[6]]) / efficiency[6])
        + ((exptime[0] * qty_produced[part_numbers[0], employees[7]]) / efficiency[7])
        + ((exptime[1] * qty_produced[part_numbers[1], employees[0]])/ efficiency[8])
        + ((exptime[1] * qty_produced[part_numbers[1], employees[1]])/ efficiency[9])
        + ((exptime[1] * qty_produced[part_numbers[1], employees[2]])/ efficiency[10])
        + ((exptime[1] * qty_produced[part_numbers[1], employees[3]]) / efficiency[11])
        + ((exptime[1] * qty_produced[part_numbers[1], employees[4]]) / efficiency[12])
        + ((exptime[1] * qty_produced[part_numbers[1], employees[5]]) / efficiency[13])
        + ((exptime[1] * qty_produced[part_numbers[1], employees[6]]) / efficiency[14])
        + ((exptime[1] * qty_produced[part_numbers[1], employees[7]]) / efficiency[15])
    ))/(len(part_numbers)*(len(employees)))))

model += ((exptime[0] * qty_produced[part_numbers[0], employees[0]])/efficiency[0]) + ((exptime[1] * qty_produced[part_numbers[1], employees[0]])/efficiency[8]) <= 530
model += ((exptime[0] * qty_produced[part_numbers[0], employees[1]])/efficiency[1]) + ((exptime[1] * qty_produced[part_numbers[1], employees[1]])/efficiency[9]) <= 530
model += ((exptime[0] * qty_produced[part_numbers[0], employees[2]])/efficiency[2]) + ((exptime[1] * qty_produced[part_numbers[1], employees[2]])/efficiency[10]) <= 530
model += ((exptime[0] * qty_produced[part_numbers[0], employees[3]])/efficiency[3]) + ((exptime[1] * qty_produced[part_numbers[1], employees[3]])/efficiency[11]) <= 530
model += ((exptime[0] * qty_produced[part_numbers[0], employees[4]])/efficiency[4]) + ((exptime[1] * qty_produced[part_numbers[1], employees[4]])/efficiency[12]) <= 530
model += ((exptime[0] * qty_produced[part_numbers[0], employees[5]])/efficiency[5]) + ((exptime[1] * qty_produced[part_numbers[1], employees[5]])/efficiency[13]) <= 530
model += ((exptime[0] * qty_produced[part_numbers[0], employees[6]])/efficiency[6]) + ((exptime[1] * qty_produced[part_numbers[1], employees[6]])/efficiency[14]) <= 530
model += ((exptime[0] * qty_produced[part_numbers[0], employees[7]])/efficiency[7]) + ((exptime[1] * qty_produced[part_numbers[1], employees[7]])/efficiency[15]) <= 530

model.solve()
pulp.LpStatus[model.status]
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
Bajunes
  • 5
  • 2
  • You're specific question has been asked before (https://stackoverflow.com/questions/38987/how-do-i-merge-two-dictionaries-in-a-single-expression-taking-union-of-dictiona). It looks like you just want to improve this code though. https://softwareengineering.stackexchange.com might be able to help for that. – c z Jun 01 '21 at 11:59

1 Answers1

0

Please note that the iterables you provided are not dictionaries but sets. dictionaries come in keys and values, while sets are just accounts for unique values. Not sure about the logic for your calculation for the last part, but i hope this gives you a head start to seeing how you can loop through the nest. Another consideration to put in mind is if you have sets that have same lengths, you should consider using enumerate so you can reduce the nests of your loops

#step 1: #handles the intial calculaion for the values to be applied for the pulp.lpSum

def func(part, empl, eff,exptime):
    val= 0
    for indx, time in enumerate(exptime): # assumes you have the same data length
        for prt in part:
            for employee in empl:
                for efficiency in eff:
                    val += (time *qty_produced[prt],employee)/efficiency
    return val /(len(part)* len(empl))



#step2: 



def model_func(func,part, empl, eff,exptime ):
    len_emp = len(employees)//2
    len_part= len(part)//2
    len_eff = len(efficiency)//2
    len_exp = len(exptime)//2

    model = 0
    func_result = func(part, empl, eff,exptime)
    model+= (pulp.lpSum(func_result))
    
    for xp1, xp2 in zip(part_numbers[:len_part], part_numbers[len_exp:]):
    
        for empl1, emp2 in zip(employees[:len_emp],employees[len_emp:]):
        
            for  eff1, eff2 in zip(efficiency[:len_eff], efficiency[len_eff:]):
            
                for exp1,exp2 in zip(exptime[:len_exp], exptime[len_exp:]):
                
                    model += #(exp1 * qty_produced[xp1] ,empl1/eff1 ) + (exp2 * qty_produced[xp2],empl2/eff2 ) as an example
                
                   
    return model

# call your function
   
model_func(func,part_numbers,employees,efficiency,exptime) # should return your model output
Ade_1
  • 1,480
  • 1
  • 6
  • 17
  • Thanks for the response and help here. Unfortunately not all sets will be the same length, as the amount of employees will change. In regards to the calculation for the last part, I'm constructing a constraint that keeps the total time for that employee under 530. My thoughts to get the efficiencies for each part for each employee would be to just add the val*len(employee) as an offset. – Bajunes Jun 01 '21 at 12:48
  • can the length of employees and efficiency be split into equak half? – Ade_1 Jun 01 '21 at 13:00
  • I don't see why not, as long as everything can be tied together correctly. Eventually, the number of parts, actual part no, and quantities need will be user input. Everything else will be pulled from SQL. – Bajunes Jun 01 '21 at 14:29
  • okay, just updated. i think you are better off using a list, so you can see i converted it to a list. the loop does the iteration, so you should be able to use the unpacked results to get the values or calculations you need. i think this should answer your question about how to iterate through. – Ade_1 Jun 01 '21 at 15:26