Simpy Simulation for Job Shop Problem, using parralel ressources - python

I'm trying to programm and simulate a the job shop problem with the simpy modul (https://simpy.readthedocs.io/en/latest/index.html). At the end I want to optimize the problem with reinforcement learning. However, my problem is when I try to simulate the created sequence (not yet generated by the agent) simpy uses a time for all resources (machines). I had thought about passing the individual operations with a while loop to the timeout event of simpy and then simulate. However, it does not work. Can someone help me? Here is my code so far.
15 15
6 94 12 66 4 10 7 53 3 26 2 15 10 65 11 82 8 10 14 27 9 93 13 92 5 96 0 70 1 83
4 74 5 31 7 88 14 51 13 57 8 78 11 8 9 7 6 91 10 79 0 18 3 51 12 18 1 99 2 33
1 4 8 82 9 40 12 86 6 50 11 54 13 21 5 6 0 54 2 68 7 82 10 20 4 39 3 35 14 68
5 73 2 23 9 30 6 30 10 53 0 94 13 58 4 93 7 32 14 91 11 30 8 56 12 27 1 92 3 9
7 78 8 23 6 21 10 60 4 36 9 29 2 95 14 99 12 79 5 76 1 93 13 42 11 52 0 42 3 96
5 29 3 61 12 88 13 70 11 16 4 31 14 65 7 83 2 78 1 26 10 50 0 87 9 62 6 14 8 30
12 18 3 75 7 20 8 4 14 91 6 68 1 19 11 54 4 85 5 73 2 43 10 24 0 37 13 87 9 66
11 32 5 52 0 9 7 49 12 61 13 35 14 99 1 62 2 6 8 62 4 7 3 80 9 3 6 57 10 7
10 85 11 30 6 96 14 91 0 13 1 87 2 82 5 83 12 78 4 56 8 85 7 8 9 66 13 88 3 15
6 5 11 59 9 30 2 60 8 41 0 17 13 66 3 89 10 78 7 88 1 69 12 45 14 82 4 6 5 13
4 90 7 27 13 1 0 8 5 91 12 80 6 89 8 49 14 32 10 28 3 90 1 93 11 6 9 35 2 73
2 47 14 43 0 75 12 8 6 51 10 3 7 84 5 34 8 28 9 60 13 69 1 45 3 67 11 58 4 87
5 65 8 62 10 97 2 20 3 31 6 33 9 33 0 77 13 50 4 80 1 48 11 90 12 75 7 96 14 44
8 28 14 21 4 51 13 75 5 17 6 89 9 59 1 56 12 63 7 18 11 17 10 30 3 16 2 7 0 35
10 57 8 16 12 42 6 34 4 37 1 26 13 68 14 73 11 5 0 8 7 12 3 87 2 83 9 20 5 97
import gym
import simpy
from simpy.events import AnyOf, AllOf, Event
import random
import numpy as np
class JobShop_RL(gym.Env):
def __init__(self):
# Reading the Dataset for the JSP
with open("taillard.txt", "r") as self.data:
self.read_data = self.data.readline()
self.line = self.read_data.split()
# Getting number of Jobs and Machines
self.jobs = int(self.line[0])
self.machines = int(self.line[1])
self.all_jobs = np.zeros((self.jobs, self.machines), dtype=(int, 2))
# Filling Matrix with (jobs/number) = (machine/time)
self.line = self.data.readline()
job = 0
self.max_time = 0 # Max time
self.sum_time = 0 # Sum of the whole time
self.jobs_duration = np.zeros(self.machines, dtype=int) # Sum of time for each job
i = 0
j = 0
while job < self.jobs:
self.line = self.line.split()
while i <= ((self.jobs + self.machines) - 1):
self.all_jobs[job][j] = int(self.line[i]), int(self.line[i + 1])
self.jobs_duration[job] += int(self.line[i + 1])
self.max_time = max(self.max_time, int(self.line[i + 1]))
self.sum_time += int(self.line[i + 1])
j += 1
i += 2
self.line = self.data.readline()
job += 1
i = 0
j = 0
# possible legal actions + the same number for no op for each machine
# e. g. 15x15 JSSP = 15 legal moves and also 15 no op
self.action_space = gym.spaces.Discrete(self.machines+self.machines)
# observation space
self.observation_space = gym.spaces.Box
# jobs_done = last stage, storing all jobs which are done
self.jobs_done = []
# last jobs = represents jobs the last jobs ( = nb of machines) which are done
#self.last_jobs = np.zeros(self.jobs, dtype=(int, 2))
# last jobs = represents jobs the last jobs ( = nb of machines) which are done
self.possible_actions = np.zeros(self.jobs, dtype=(int, 2))
i = 0
while i < self.machines:
self.possible_actions[i] = self.all_jobs[i][0]
i += 1
#
self.counting = np.zeros(self.machines)
# final order of the job shop problem
self.final_order = np.zeros_like(self.all_jobs)
self.simpy_env = simpy.Environment()
# Store the simpy resources (machines) in the list
self.machines_sy = []
i = 0
while i <= self.machines:
self.machines_sy.append(simpy.Resource(self.simpy_env, capacity=1))
i += 1
def get_operation_index(self, action):
index_machine = action // self.jobs
index_operation = action % self.jobs
#print("INDEX", index_operation, index_machine, self.all_jobs[index_operation][index_machine])
# Returns the Indizes of the action, [Machine][Operation]
return index_operation, index_machine
def get_machine(self, action):
nb_machine = self.all_jobs[self.get_operation_index(action)]
return nb_machine[0]
def machine_process(self, simpy_env, action):
#Request and timeout the action for each incoming action (if machine is busy its going in the queue)
machine = self.get_machine(action)
print("ACTION IN MACHINE PROCESS", action)
#operation = self.possible_actions[action]
#operation = self.final_order[machine][int(self.counting[action])]
#print("OPERATION", operation)
i = 0
j = 0
while i < self.machines:
while j < self.jobs:
operation = self.final_order[i][j]
with self.machines_sy[operation[0]].request() as req:
yield req
print("Machine ", i, " proceed Operation ", self.final_order[i][j], " at ", simpy_env.now)
self.jobs_done.append(self.final_order[machine][int(self.counting[action])])
yield simpy_env.timeout(operation[1]) # Operation[1] defines the processing time
print("Machine ", i, " released Operation ",
self.final_order[i][j], " at ", simpy_env.now)
j += 1
if j == 15:
i += 1
j = 0
def is_done(self):
# Returns True if len(jobs_done) is the same as the sum of operations which need to be done
# ### Die Anzahl an no ops muss beachtet werden
if len(self.jobs_done) == self.all_jobs.shape[1]*self.all_jobs.shape[0]:
return True
else:
return False
def take_action(self, action):
nb_machine = self.possible_actions[action]
nb_machine = nb_machine[0]
self.simpy_env.process(env.machine_process(env.simpy_env, action))
machine = self.get_machine(action)
# Filling Final Order
tmp = np.count_nonzero(self.final_order[nb_machine]) // 2
self.final_order[nb_machine][tmp] = self.possible_actions[action]
# Update possible actions
self.possible_action(action)
def possible_action(self, action):
self.counting[action] += 1
self.possible_actions[action] = self.all_jobs[action][int(self.counting[action])]
def step(self, action):
reward = 0
operation = self.get_operation_index(action)
if action <= self.machines:
print("##STEP## NORMALE ACTION", action, self.possible_actions[action])
self.take_action(action)
reward = 10
elif self.machines < action <= self.action_space.n:
print("NOOP", action)
reward = -3
#Check if done
done = self.is_done()
#Info is unused
info = {}
return reward, done, info
def reset(self):
pass
def render(self, mode='human'):
pass
if __name__ == "__main__":
env = JobShop_RL()
print(env.possible_actions)
env.step(0)
print("****## NEXT ##***")
env.step(1)
print("****## NEXT ##***")
env.step(2)
print("****## NEXT ##***")
env.simpy_env.run(1000)

Related

How to display two different return values from if/elif in Python?

I'm reading a csv file and appending the data into a list and later using another function, I'm calculating these numbers and try to return two values using if/elif statements. To display the result I have created a procedure called displayData(numbers) and here I'm struggling to show the calculated values from previous function called seyrogus(numbers) against the original csv values.
Currently, it's showing all only "4" as result. Where I'm doing wrong?
My code so far
def getData():
numbers = []
file = open("numbers.csv","r")
for line in file:
data = line.strip()
numbers.append(int(data.strip()))
return numbers
def seyrogus(numbers):
for counter in range(len(numbers)):
if numbers[counter] % 2 != 0:
return (int(numbers[counter] * 3) + 1)
elif numbers[counter] % 2 == 0:
return (int(numbers[counter] / 2))
def displayData(numbers):
print("Original Numbers \t Converted Numbers")
for counter in range(len(numbers)):
print(f"{numbers[counter]} \t \t \t {seyrogus(numbers)}")
def main():
numbers = getData()
displayData(numbers)
main()
output
Original Numbers Converted Numbers
1 4
2 4
3 4
4 4
5 4
6 4
7 4
8 4
9 4
10 4
11 4
12 4
13 4
14 4
15 4
16 4
17 4
18 4
19 4
20 4
21 4
22 4
23 4
24 4
25 4
26 4
27 4
28 4
29 4
30 4
31 4
32 4
33 4
34 4
35 4
36 4
37 4
38 4
39 4
40 4
41 4
42 4
43 4
44 4
45 4
46 4
47 4
48 4
49 4
50 4
51 4
52 4
53 4
54 4
55 4
56 4
57 4
58 4
59 4
60 4
61 4
62 4
63 4
64 4
65 4
66 4
67 4
68 4
69 4
70 4
71 4
72 4
73 4
74 4
75 4
76 4
77 4
78 4
79 4
80 4
81 4
82 4
83 4
84 4
85 4
86 4
87 4
88 4
89 4
90 4
91 4
92 4
93 4
94 4
95 4
96 4
97 4
98 4
99 4
100 4
csv file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
Your seyrogus function needs to return a list rather than returning a single value. The reason you're only getting 4 as the result is that every time you call it, it iterates over numbers from the beginning and then returns the first converted value rather than iterating over the entire list.
Both getData and seyrogus can be implemented very simply as list comprehensions. You then need to iterate over both numbers and seyrogus(numbers) in parallel in displayData; an easy way of doing that is the zip function.
def getData():
with open("numbers.csv") as file:
return [int(line.strip()) for line in file]
def seyrogus(numbers):
return [n * 3 + 1 if n % 2 else n // 2 for n in numbers]
def displayData(numbers):
print("Original Numbers \t Converted Numbers")
for original, converted in zip(numbers, seyrogus(numbers)):
print(f"{original} \t \t \t {converted}")
def main():
displayData(getData())
main()
prints:
Original Numbers Converted Numbers
1 4
2 1
3 10
4 2
5 16
6 3
7 22
8 4
9 28
10 5
11 34
etc.

Create bi-weekly and monthly labels with week numbers in pandas

I have a dataframe with profit values, IDs, and week values. It looks a little like this
ID
Week
Profit
A
1
2
A
2
2
A
3
0
A
4
0
I want to create two new columns called "Bi-Weekly" and "Monthly", so week 1 would be label 2, week 2 would also be label 2, but week 3 would be labeled 4, and week 4 would be labeled 4, and they would all be labeled month 1, so I could groupby weekly, bi-weekly, or monthly profit as needed. Right now I've created two functions which work, but the weeks are going to go up to a year (52 weeks) so I was wondering if there's a more efficient way. My bi-weekly function below.
def biweek(prof_calc):
if (prof_calc['week']==2):
return 2
elif (prof_calc['week']==3):
return 2
elif (prof_calc['week']==4):
return 4
elif (prof_calc['week']==5):
return 4
elif (prof_calc['week']==6):
return 6
elif (prof_calc['week']==7):
return 6
elif (prof_calc['week']==8):
return 8
elif (prof_calc['week']==9):
return 8
elif (prof_calc['week']==10):
return 10
elif (prof_calc['week']==11):
return 10
prof_calc['BiWeek'] = prof_calc.apply(biweek, axis=1)
IIUC, you could try:
df["Biweekly"] = (df["Week"]-1)//2+1
df["Monthly"] = (df["Week"]-1)//4+1
>>> df
ID Week Profit Biweekly Monthly
0 A 1 42 1 1
1 A 2 69 1 1
2 A 3 53 2 1
3 A 4 63 2 1
4 A 5 56 3 2
5 A 6 57 3 2
6 A 7 86 4 2
7 A 8 23 4 2
8 A 9 35 5 3
9 A 10 10 5 3
10 A 11 25 6 3
11 A 12 21 6 3
12 A 13 39 7 4
13 A 14 82 7 4
14 A 15 76 8 4
15 A 16 20 8 4
16 A 17 97 9 5
17 A 18 67 9 5
18 A 19 21 10 5
19 A 20 22 10 5
20 A 21 88 11 6
21 A 22 67 11 6
22 A 23 33 12 6
23 A 24 38 12 6
24 A 25 8 13 7
25 A 26 67 13 7
26 A 27 16 14 7
27 A 28 49 14 7
28 A 29 3 15 8
29 A 30 17 15 8
30 A 31 79 16 8
31 A 32 19 16 8
32 A 33 21 17 9
33 A 34 9 17 9
34 A 35 56 18 9
35 A 36 83 18 9
36 A 37 1 19 10
37 A 38 53 19 10
38 A 39 66 20 10
39 A 40 55 20 10
40 A 41 85 21 11
41 A 42 90 21 11
42 A 43 34 22 11
43 A 44 3 22 11
44 A 45 9 23 12
45 A 46 28 23 12
46 A 47 58 24 12
47 A 48 14 24 12
48 A 49 42 25 13
49 A 50 69 25 13
50 A 51 76 26 13
51 A 52 49 26 13

Print numbers serially in columns

I am struggling in one of the Pattern matching problems in Python
When input = 3, below is the expected output (input value is the number of columns it should print)
Expected output:
1
2 6
3 7 9
4 8
5
I am somehow moving in a wrong direction, hence would need some help in it.
This is the code I have tried so far:
def display():
n = 5
i = 1
# Outer loop for how many lines we want to print
while(i<=n):
k = i
j = 1
# Inner loop for printing natural number
while(j <= i):
print (k,end=" ")
# Logic to print natural value column-wise
k = k + n - j
j = j + 1
print("\r")
i = i + 1
#Driver code
display()
But it is giving me output as this:
1
2 6
3 7 10
4 8 11 13
5 9 12 14 15
Anybody who can help me with this?
n=10
for i in range(1,2*n):
k=i
for j in range(2*n-i if i>n else i):
print(k,end=' ')
k = k + 2*n - 2*j - 2
print()
Result
1
2 20
3 21 37
4 22 38 52
5 23 39 53 65
6 24 40 54 66 76
7 25 41 55 67 77 85
8 26 42 56 68 78 86 92
9 27 43 57 69 79 87 93 97
10 28 44 58 70 80 88 94 98 100
11 29 45 59 71 81 89 95 99
12 30 46 60 72 82 90 96
13 31 47 61 73 83 91
14 32 48 62 74 84
15 33 49 63 75
16 34 50 64
17 35 51
18 36
19
>
Here's a way, I started from scratch and not for code, much more easy for me
def build(nb_cols):
values = list(range(1, nb_cols ** 2 + 1))
res = []
for idx in range(nb_cols):
row_values, values = values[-(idx * 2 + 1):], values[:-(idx * 2 + 1)]
res.append([' '] * (nb_cols - idx - 1) + row_values + [' '] * (nb_cols - idx - 1))
for r in zip(*reversed(res)):
print(" ".join(map(str, r)))
Here's a recursive solution:
def col_counter(start, end):
yield start
if start < end:
yield from col_counter(start+1, end)
yield start
def row_generator(start, col, N, i=1):
if i < col:
start = start + 2*(N - i)
yield start
yield from row_generator(start, col, N, i+1)
def display(N):
for i, col_num in enumerate(col_counter(1, N), 1):
print(i, *row_generator(i, col_num, N))
Output:
>>> display(3)
1
2 6
3 7 9
4 8
5
>>> display(4)
1
2 8
3 9 13
4 10 14 16
5 11 15
6 12
7
>>> display(10)
1
2 20
3 21 37
4 22 38 52
5 23 39 53 65
6 24 40 54 66 76
7 25 41 55 67 77 85
8 26 42 56 68 78 86 92
9 27 43 57 69 79 87 93 97
10 28 44 58 70 80 88 94 98 100
11 29 45 59 71 81 89 95 99
12 30 46 60 72 82 90 96
13 31 47 61 73 83 91
14 32 48 62 74 84
15 33 49 63 75
16 34 50 64
17 35 51
18 36
19
Here is the solution using simple loops
def display(n):
nrow = 2*n -1 #Number of rows
i = 1
noofcols = 1 #Number of columns in each row
t = 1
while (i <= nrow):
print(i,end=' ')
if i <= n:
noofcols = i
else:
noofcols = 2*n - i
m =i
if t < noofcols:
for x in range(1,noofcols):
m = nrow + m -(2*x-1)
print(m, end=' ')
i = i+1
print()

Python times tables code with recursion

I have to make a times table code using recursive functions. I have to ask the user for a number and print out the times tables from 1 to 12. And I have to use recursive functions and it is not allowed to use for loops or while loops and all variables besides the user input have to be defined inside the functions. I am having trouble defining the number that the user provided number needs to be multiplied with. E.X. 2 x 1 2 x 2 2 x 3.
def times_tables(num):
def multiply(x):
product = x * num
if x < 12:
print (str(multiply(x + 1)))
user = input("Enter a number: ")
times_tables(user)
If I define x in the times_tables function then every time the function runs it will get set back to whatever I set it to the first time. Thanks for your help.
You are not modifying x, x is passed by value, this mean it is copied.
If you want to keep the exit conditon outside the recursion you need a way to write X directly from the recursion, which probably would involve a global (bad practices so avoid).
You need to have the exit condition inside multiply, because that will be your recursion, in that case your X will increase and you will do the check on the proper incremented value. Or change the function all together as ruggfrancesco suggested
def times_tables(n, t=1):
if t == 13:
return
print(str(n) + " x " + str(t) + " = " + str(n*t))
times_tables(n, t+1)
times_tables(int(input("Enter number: ")))
Enter number: 3
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
3 x 4 = 12
3 x 5 = 15
3 x 6 = 18
3 x 7 = 21
3 x 8 = 24
3 x 9 = 27
3 x 10 = 30
3 x 11 = 33
3 x 12 = 36
When I (Image) Google "times table", I get a very different result from what the other answers produce. Below is my recursive solution in two dimensions:
def times_table(limit):
number_format = "{{:{}}}".format(len(str(limit ** 2)))
def times_table_recursive(number, increment):
minimum = max(increment, 1)
if number <= minimum * limit:
print(number_format.format(number if number > 0 else 'x'), end=' ')
times_table_recursive(number + minimum, increment)
elif increment < limit:
print()
increment += 1
print(number_format.format(increment), end=' ')
times_table_recursive(increment, increment)
else:
print()
times_table_recursive(0, 0)
times_table(12)
OUTPUT
> python3 test.py
x 1 2 3 4 5 6 7 8 9 10 11 12
1 1 2 3 4 5 6 7 8 9 10 11 12
2 2 4 6 8 10 12 14 16 18 20 22 24
3 3 6 9 12 15 18 21 24 27 30 33 36
4 4 8 12 16 20 24 28 32 36 40 44 48
5 5 10 15 20 25 30 35 40 45 50 55 60
6 6 12 18 24 30 36 42 48 54 60 66 72
7 7 14 21 28 35 42 49 56 63 70 77 84
8 8 16 24 32 40 48 56 64 72 80 88 96
9 9 18 27 36 45 54 63 72 81 90 99 108
10 10 20 30 40 50 60 70 80 90 100 110 120
11 11 22 33 44 55 66 77 88 99 110 121 132
12 12 24 36 48 60 72 84 96 108 120 132 144
>
Only goes up to times_table(30) without expanding Python's recursion depth limit.
def fun (no,i=1):
if i==10:
print (no*i)
else:
print (no*fun(i+1)
no=int (input ("Enter a no="))
fun (no)

Python-Loops, nested loop [duplicate]

I am trying to teach myself python using interactivepython.org. I have come across a problem that I can not figure out. I have the slope and the spacing correct. I need it to print one less number every time. Could anybody help a newbie out?...
My Code:
for j in range(11):
for i in range(j):
print(str(i), end=" ")
print()
print("")
Output:
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4
0 1 2 3 4 5
0 1 2 3 4 5 6
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 8 9
Desired Output:
10
11 12
13 14 15
16 17 18 19
20 21 22 23 24
25 26 27 28 29 30
31 32 33 34 35 36 37
38 39 40 41 42 43 44 45
46 47 48 49 50 51 52 53 54
The exercise is about nesting for loops...I know there are other ways to do this.
This should do it:
start = 10
width = 9
for i in range(1, width+1):
for _ in range(i):
print (start, end=" ")
start += 1
print('\n')
Output:
10
11 12
13 14 15
16 17 18 19
20 21 22 23 24
25 26 27 28 29 30
31 32 33 34 35 36 37
38 39 40 41 42 43 44 45
46 47 48 49 50 51 52 53 54
Well this one again for you Brandon Shockley :)
code:
x = 9
lines = 10
for i in range(lines):
for j in range(i):
x+=1
print x,
print ''
output:
10
11 12
13 14 15
16 17 18 19
20 21 22 23 24
25 26 27 28 29 30
31 32 33 34 35 36 37
38 39 40 41 42 43 44 45
46 47 48 49 50 51 52 53 5
Hope This helps :)
You can do it like this
current, levels = 10, 9
for i in range(levels):
for j in range(i + 1):
print(current, end = " ")
current += 1
print("\n")
Output
10
11 12
13 14 15
16 17 18 19
20 21 22 23 24
25 26 27 28 29 30
31 32 33 34 35 36 37
38 39 40 41 42 43 44 45
46 47 48 49 50 51 52 53 54
>>> lst = list(range(54,9, -1))
>>> for j in range(11):
... for i in range(j):
... if len(lst):
... print(lst.pop(), end=" ")
... print(" ")
inc = 10
for j in range(10):
for i in range(j):
print(inc, end=" ")
inc += 1
print()
print("")
Is anything wrong with this?
Single loop, in Python 2.x (can't remove the space after each print)
c = 1
j = 0
for i in range(10, 55):
print str(i) + ',',
j += 1
if j == c:
print
c += 1
j = 0
Using join
start = 10
for i in range(1, 10):
print(' '.join(map(str, range(start, start + i))))
start += i
A pointlessly compact version using join and some maths:
print('\n'.join(' '.join(map(str,
range(10 + i * (i+1) / 2, 10 + (i+1) * (i+2) / 2))) for i in range(9)))
And confusingly, this also works (in python 2):
j = 9
for i in range(10):
for j in range(j + 1, j + i + 1):
print j,
print

Categories

Resources