Try to solve the man-machine chart with Python

An attempt to solve a common MM chart problem with python instead of manually.

Theme "State the minimum cycle time and process allocation to workers in the circular process" image.png

--The number of processes and the time required for each process are given in a list.
This time, there are 8 processes, and the time required for each process is [6, 3, 3, 10, 6, 8, 4, 5]. ――The time it takes to move a worker is 1, skip one next to each other 2, 2, otherwise 3 --The number of workers is also variable. This time, there are three.

condition


process_time_lst = [6, 3, 3, 10, 6, 8, 4, 5]
move_cost_lst = [1, 2, 3]
num_of_workers = 3

What I want to know is, "Which process should bears, rabbits, and pigs take charge of?" image.png

First, make a dictionary of process names and their man-hours.

image


# Input:
[6, 3, 3, 10, 6, 8, 4, 5]
# Output:
{'process0':6, 'process1':3, ... , 'process7':5}

code


def generate_process_lst(process_time_lst):
    lst = ['process'+str(val) for val in range(len(process_time_lst))]
    return lst

process_lst = generate_process_lst(process_time_lst)
process_time_dict = {process:cost for process, cost in zip(process_lst, process_time_lst)}

Next, we will perform preprocessing for calculation. Insert move, which means move to the next process, between all processes.

image


# Input
['process0', 'process1', ... , 'process7']
# Output
['process0', 'move', 'process1', 'move', ... , 'move', 'process7']

code


def generate_process_and_move_lst(process_lst):
    len_lst = len(process_lst) - 1
    process_and_move_lst = process_lst.copy()
    for i in range(len_lst):
        process_and_move_lst.insert(len_lst - i, 'move')
    return process_and_move_lst

process_and_move_lst = generate_process_and_move_lst(process_lst)

Next, create an index list where the list process_and_move_lst is separated.

image


# Input
['process0', 'move', 'process1', 'move', ... , 'move', 'process7']
# Output
[(0, 1, 2), (0, 1, 3), ... , (11, 13, 14), (12, 13, 14)]

code


import itertools

def generate_combi_lst(process_and_move_lst, num_of_workers):
    len_lst = len(process_and_move_lst)
    idx_lst = [x for x in range(len_lst)]
    combi_lst = list(itertools.combinations(idx_lst, num_of_workers))
    return combi_lst

combi_lst = generate_combi_lst(process_and_move_lst, num_of_workers)

Using the index list to be carved, a combination of process lists to be assigned to each worker is generated.

image


# Input
['process0', 'move', 'process1', 'move', ... , 'move', 'process7']
[(0, 1, 2), (0, 1, 3), ... , (11, 13, 14), (12, 13, 14)]
# Output(image)* It is a part of the actual output list because it is difficult to understand what you are doing.
worker0 : ['move', 'process1', 'move']
worker1 : ['process2', 'move', 'process3', 'move', 'process4', 'move', 'process5', 'move', 'process6', 'move']
worker2 : ['process7', 'move', 'process0']

code


def generate_process_group_lst(process_and_move_lst, combi_lst):
    process_group_lst = []
    for combi in combi_lst:
        if combi[0] != 0:
            tmplst = [process_and_move_lst[0:combi[0]]]
        else:
            tmplst = []
        for idx, val in enumerate(combi):
            start = val
            if idx == len(combi) - 1:
                end = len(process_and_move_lst)
            else:
                end = combi[idx + 1]
            tmplst.append(process_and_move_lst[start:end])
        
        if combi[0] != 0:
            tmplst[-1].append('move')
            tmplst[-1] = tmplst[-1] + tmplst[0]
            tmplst = tmplst[1:]
        process_group_lst.append(tmplst)
    return process_group_lst

process_group_lst = generate_process_group_lst(process_and_move_lst, combi_lst)

We will calculate the required man-hours for each worker.

image


# Input(image)* It's hard to understand what you're doing(Abbreviation
worker0 : ['move', 'process1', 'move']
worker1 : ['process2', 'move', 'process3', 'move', 'process4', 'move', 'process5', 'move', 'process6', 'move']
worker2 : ['process7', 'move', 'process0']

# Output(image)
[7, 39, 13] # move:1, process1:3, move:1, return_cost:2 → total 7

code


def calc_return_cost(process_set, process_time_dict, move_cost_lst):
    tmplst = [val for val in process_set if val in process_time_dict.keys()]
    if len(tmplst) == 0:
        return_cost = move_cost_lst[0]
    elif len(tmplst) == 1:
        if len(process_set) == 2:
            return_cost = move_cost_lst[0]
        else:
            return_cost = move_cost_lst[1]
    else:
        start_num = int(tmplst[0][-1])
        end_num = int(tmplst[-1][-1])
        if process_set[0] == 'move':
            start_num -= 1
        if process_set[-1] == 'move':
            end_num += 1
        tmp = abs(start_num - end_num)
        distance = min( tmp,  (len(process_time_dict.keys()) - tmp) )
        if distance == 1:
            return_cost = move_cost_lst[0]
        elif distance == 2:
            return_cost = move_cost_lst[1]
        else:
            return_cost = move_cost_lst[2]
    return return_cost

def calc_cycleTime(process_group_lst, process_time_dict, move_cost_lst):
    ct_lst = []
    for process_group in process_group_lst:
        ct_tmp_lst = []
        for process_set in process_group:
            ct = 0
            ct += process_set.count('move') * move_cost_lst[0]
            ct += sum([process_time_dict[val] for val in process_set if val in process_time_dict.keys()])
            ct += calc_return_cost(process_set, process_time_dict, move_cost_lst)
            ct_tmp_lst.append(ct)
        ct_lst.append(ct_tmp_lst)
    return ct_lst

ct_lst = calc_cycleTime(process_group_lst, process_time_dict, move_cost_lst)

Calculate the cycle time for each process allocation combination for each worker.

image


# Input
[[8, 2, 47], [8, 5, 44], ... ,[6, 2, 49], [6, 2, 49]]
# Output
[47, 44, ..., 49, 49]

code


max_ct_lst = [max(lst) for lst in ct_lst]

Calculate which combination has the shortest cycle time and Get the index where the combination exists.

image


# Input
[47, 44, ..., 49, 49]
# Output
[58, 211]

code


min_ct = min(max_ct_lst)
min_ct_idx_lst = [idx for idx, val in enumerate(max_ct_lst) if val == min_ct]

Finally, the display of the minimum cycle time and The process allocation to the workers who achieve it is displayed.

image


# Output
minimumCT:21s
condition:
Worker0:['process0', 'move', 'process1', 'move', 'process2', 'move'], time=18s
Worker1:['process3', 'move', 'process4', 'move'], time=20s
Worker2:['process5', 'move', 'process6', 'move', 'process7'], time=21s
condition:
Worker0:['process1', 'move', 'process2', 'move', 'process3'], time=20s
Worker1:['move', 'process4', 'move', 'process5', 'move'], time=20s
Worker2:['process6', 'move', 'process7', 'move', 'process0', 'move'], time=21s

code


print(f'minimumCT:{min_ct}s')
for idx in min_ct_idx_lst:
    print('condition:')
    for worker, process in enumerate(process_group_lst[idx]):
        print(f'Worker{worker}:{process}, time={ct_lst[idx][worker]}s')

When all the codes are connected, it becomes as follows.

code


import itertools

def generate_process_lst(process_time_lst):
    lst = ['process'+str(val) for val in range(len(process_time_lst))]
    return lst

def generate_process_and_move_lst(process_lst):
    len_lst = len(process_lst) - 1
    process_and_move_lst = process_lst.copy()
    for i in range(len_lst):
        process_and_move_lst.insert(len_lst - i, 'move')
    return process_and_move_lst

def generate_combi_lst(process_and_move_lst, num_of_workers):
    len_lst = len(process_and_move_lst)
    idx_lst = [x for x in range(len_lst)]
    combi_lst = list(itertools.combinations(idx_lst, num_of_workers))
    return combi_lst

def generate_process_group_lst(process_and_move_lst, combi_lst):
    process_group_lst = []
    for combi in combi_lst:
        if combi[0] != 0:
            tmplst = [process_and_move_lst[0:combi[0]]]
        else:
            tmplst = []
        for idx, val in enumerate(combi):
            start = val
            if idx == len(combi) - 1:
                end = len(process_and_move_lst)
            else:
                end = combi[idx + 1]
            tmplst.append(process_and_move_lst[start:end])
        
        if combi[0] != 0:
            tmplst[-1].append('move')
            tmplst[-1] = tmplst[-1] + tmplst[0]
            tmplst = tmplst[1:]
        process_group_lst.append(tmplst)
    return process_group_lst

def calc_return_cost(process_set, process_time_dict, move_cost_lst):
    tmplst = [val for val in process_set if val in process_time_dict.keys()]
    if len(tmplst) == 0:
        return_cost = move_cost_lst[0]
    elif len(tmplst) == 1:
        if len(process_set) == 2:
            return_cost = move_cost_lst[0]
        else:
            return_cost = move_cost_lst[1]
    else:
        start_num = int(tmplst[0][-1])
        end_num = int(tmplst[-1][-1])
        if process_set[0] == 'move':
            start_num -= 1
        if process_set[-1] == 'move':
            end_num += 1
        tmp = abs(start_num - end_num)
        distance = min( tmp,  (len(process_time_dict.keys()) - tmp) )
        if distance == 1:
            return_cost = move_cost_lst[0]
        elif distance == 2:
            return_cost = move_cost_lst[1]
        else:
            return_cost = move_cost_lst[2]
    return return_cost

def calc_cycleTime(process_group_lst, process_time_dict, move_cost_lst):
    ct_lst = []
    for process_group in process_group_lst:
        ct_tmp_lst = []
        for process_set in process_group:
            ct = 0
            ct += process_set.count('move') * move_cost_lst[0]
            ct += sum([process_time_dict[val] for val in process_set if val in process_time_dict.keys()])
            ct += calc_return_cost(process_set, process_time_dict, move_cost_lst)
            ct_tmp_lst.append(ct)
        ct_lst.append(ct_tmp_lst)
    return ct_lst

process_time_lst = [6, 3, 3, 10, 6, 8, 4, 5]
move_cost_lst = [1, 2, 3]
num_of_workers = 3

process_lst = generate_process_lst(process_time_lst)
process_time_dict = {process:cost for process, cost in zip(process_lst, process_time_lst)}
process_and_move_lst = generate_process_and_move_lst(process_lst)
combi_lst = generate_combi_lst(process_and_move_lst, num_of_workers)
process_group_lst = generate_process_group_lst(process_and_move_lst, combi_lst)
ct_lst = calc_cycleTime(process_group_lst, process_time_dict, move_cost_lst)
max_ct_lst = [max(lst) for lst in ct_lst]
min_ct = min(max_ct_lst)
min_ct_idx_lst = [idx for idx, val in enumerate(max_ct_lst) if val == min_ct]

print(f'minimumCT:{min_ct}s')
for idx in min_ct_idx_lst:
    print('condition:')
    for worker, process in enumerate(process_group_lst[idx]):
        print(f'Worker{worker}:{process}, time={ct_lst[idx][worker]}s')

So far, I tried to solve the man-machine chart using python.

Recommended Posts

Try to solve the man-machine chart with Python
Try to solve the programming challenge book with python3
Try to solve the internship assignment problem with Python
Try to solve the shortest path with Python + NetworkX + social data
Try to solve the fizzbuzz problem with Keras
Try to solve the Python class inheritance problem
I tried to solve the soma cube with python
I tried to solve the problem with Python Vol.1
Try to solve the traveling salesman problem with a genetic algorithm (Python code)
Try to operate Facebook with Python
I wanted to solve the Panasonic Programming Contest 2020 with Python
Try to automate the operation of network devices with Python
Try to decipher the garbled attachment file name with Python
Try to reproduce color film with Python
Try logging in to qiita with Python
I wanted to solve ABC160 with Python
Python amateurs try to summarize the list ①
I wanted to solve ABC172 with Python
The road to compiling to Python 3 with Thrift
Try to solve the N Queens problem with SA of PyQUBO
I wanted to solve the ABC164 A ~ D problem with Python
Put Cabocha 0.68 on Windows and try to analyze the dependency with Python
Solve AtCoder 167 with python
I wanted to solve NOMURA Contest 2020 with Python
The 16th offline real-time how to write reference problem to solve with Python
Try to draw a life curve with python
Specify the Python executable to use with virtualenv
Try to image the elevation data of the Geographical Survey Institute with Python
How to try the friends-of-friends algorithm with pyfof
Say hello to the world with Python with IntelliJ
Try to make a "cryptanalysis" cipher with Python
Try to solve the traveling salesman problem with a genetic algorithm (Theory)
Solve Sudoku with Python
Try to automatically generate Python documents with Sphinx
The easiest way to use OpenCV with python
Introduction to Python with Atom (on the way)
I want to solve APG4b with Python (Chapter 2)
Try to make a dihedral group with Python
The 19th offline real-time how to write reference problem to solve with Python
Try to solve a set problem of high school math with Python
Solve POJ 2386 with python
[Cloudian # 5] Try to list the objects stored in the bucket with Python (boto3)
Try to detect fish with python + OpenCV2.4 (unfinished)
Try to solve the traveling salesman problem with a genetic algorithm (execution result)
Try to use up the Raspberry Pi 2's 4-core CPU with Parallel Python
[First API] Try to get Qiita articles with Python
[Python] Try to read the cool answer to the FizzBuzz problem
[Introduction to Python] How to iterate with the range function?
[Cloudian # 8] Try setting the bucket versioning with Python (boto3)
Try translating with Python while maintaining the PDF layout
Try to solve the problems / problems of "Matrix Programmer" (Chapter 1)
Try to visualize the room with Raspberry Pi, part 1
Try touching the micro: bit with VS Code + Python
The first algorithm to learn with Python: FizzBuzz problem
I tried to touch the CSV file with Python
[Python] How to specify the download location with youtube-dl
Try to operate DB with Python and visualize with d3
Convert the image in .zip to PDF with Python
I want to inherit to the back with python dataclass
Try to get the contents of Word with Golang
[Neo4J] ④ Try to handle the graph structure with Cypher