-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b8095f1
Showing
13 changed files
with
696 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
import numpy as np | ||
|
||
def c_range(llim, ulim): | ||
""" | ||
c_range es por correct range, llim es por lower limit, ulim es por upper limit. | ||
Esta functión toma un range que empieza en llim y devuelve un range que empieza en llim - 1. | ||
""" | ||
|
||
return range(llim - 1, ulim) | ||
|
||
def PT(T): | ||
""" | ||
P es por ponderación, PT es por Ponderación de Todos los trabajos en todas las máquinas. | ||
Esta función devuelve la ponderación de las tres partes de un número triangular difuso | ||
""" | ||
|
||
I = range(len(T)) | ||
|
||
if (np.array(T).ndim == 3): | ||
P = [[(T[i][u][0] + 2*T[i][u][1] + T[i][u][2])/4 for u in range(len(T[0]))] for i in I] | ||
elif (np.array(T).ndim == 2): | ||
P = [(T[i][0] + 2*T[i][1] + T[i][2])/4 for i in I] | ||
elif (np.array(T).ndim == 1): | ||
P = (T[0] + 2*T[1] + T[2])/4 | ||
return P | ||
|
||
def ct(pi, i, ex = []): | ||
""" | ||
pi es una secuencia de trabajos. | ||
i es uno de los trabajos. | ||
ex es una lista de trabajos excluidos cuya posición no es cambiada por i | ||
Esta función devuelve una lista de secuencias, poniendo i en cada puesto de la secuencia de trabajos. ct es por cambiar trabajos. | ||
""" | ||
pi2 = pi.copy() | ||
pis = [] | ||
|
||
if i not in pi2: pi2.append(i) | ||
for j in range(len(pi2)): | ||
if j not in ex: | ||
pi2[pi2.index(i)], pi2[j] = pi2[j], pi2[pi2.index(i)] | ||
pis.append(pi2.copy()) | ||
return pis | ||
|
||
def st(pi, i, ex = []): | ||
""" | ||
pi es una secuencia de trabajos. | ||
i es uno de los trabajos. | ||
ex es una lista de trabajos excluidos cuya posición no es cambiada por i | ||
Esta función devuelve una lista de secuencias, intercambiando i por cada uno de los otros trabajos de la secuencia. st es por swap trabajos (porque esta función es creada por necesidad de la función swap del algoritmo MNIG). | ||
""" | ||
pi2 = pi.copy() | ||
pis = [] | ||
if i not in pi2: pi2.append(i) | ||
|
||
for j in range(len(pi2)): | ||
if j not in ex: | ||
k = pi2.index(i) | ||
pi2[k], pi2[j] = pi2[j], pi2[k] | ||
pis.append(pi2.copy()) | ||
pi2[k], pi2[j] = pi2[j], pi2[k] | ||
return pis | ||
|
||
def makespan(pi, Tn, U_s, Pn, debug = False): | ||
""" | ||
pi es una secuencia de trabajos. | ||
Tn son los tiempos de producción en orden de secuencia natural, 1, 2 ,3, ... | ||
U_s es el conjunto de máquinas o unidades de la etapa s. | ||
Pn es la ponderación de los números triangulares en orden de secuencia natural, 1, 2, 3, ... | ||
Esta función calcula el makespan de una secuencia en el modelo FMMSP | ||
""" | ||
|
||
# L es la cantidad total de etapas del sistema de producción. | ||
L = len(U_s) | ||
|
||
# I es el conjunto de trabajos. | ||
I = range(len(pi)) | ||
|
||
T = [Tn[pi[i] - 1] for i in I] | ||
P = [Pn[pi[i] - 1] for i in I] | ||
|
||
# S es el conjunto de etapas. | ||
S = range(L) | ||
|
||
# EsC es por Early start Comparación, esta variable guarda los tiempos ponderados (para hacer comparaciones entre tiempos diferentes) más tempranos en que un trabajo puede iniciar en cada máquina dada u | ||
UT = np.sum([len(U_s[s]) for s in c_range(1, L)]) | ||
U = range(UT) | ||
|
||
Ts = [[(0, 0, 0) for s in S] for i in I] | ||
Tf = [[(0, 0, 0) for s in S] for i in I] | ||
UI = [[(0, 0, 0) for s in S] for i in I] | ||
TfU = [[(0, 0, 0) for u in U] for i in I] | ||
|
||
for s in S: | ||
if (debug == True): print() | ||
for i in I: | ||
if s == 0 and i == 0: | ||
v = np.argmin([PT(np.add(TfU[i][u], T[i][u])) for u in U_s[s]]) + U_s[s][0] | ||
|
||
Ts[i][s] = (0, 0, 0) | ||
Tf[i][s] = np.add(Ts[i][s], T[i][v]) | ||
for j in I: TfU[j][v] = Tf[i][s] | ||
if s == 0 and i > 0: | ||
v = np.argmin([PT(np.add(TfU[i][u], T[i][u])) for u in U_s[s]]) + U_s[s][0] | ||
|
||
Ts[i][s] = TfU[i][v] | ||
Tf[i][s] = np.add(Ts[i][s], T[i][v]) | ||
for j in I: TfU[j][v] = Tf[i][s] | ||
if s > 0 and i == 0: | ||
for u in U_s[s]: | ||
if (PT(Tf[i][s - 1]) > PT(TfU[i][u])): | ||
TfU[i][u] = Tf[i][s - 1] | ||
v = np.argmin([PT(np.add(TfU[i][u], T[i][u])) for u in U_s[s]]) + U_s[s][0] | ||
|
||
Ts[i][s] = Tf[i][s - 1] | ||
Tf[i][s] = np.add(Ts[i][s], T[i][v]) | ||
for j in I: TfU[j][v] = Tf[i][s] | ||
if s > 0 and i > 0: | ||
for u in U_s[s]: | ||
if (PT(Tf[i][s - 1]) > PT(TfU[i][u])): | ||
TfU[i][u] = Tf[i][s - 1] | ||
v = np.argmin([PT(np.add(TfU[i][u], T[i][u])) for u in U_s[s]]) + U_s[s][0] | ||
|
||
if (PT(Tf[i][s - 1]) > PT(TfU[i][v])): | ||
Ts[i][s] = Tf[i][s - 1] | ||
else: | ||
Ts[i][s] = TfU[i][v] | ||
|
||
Tf[i][s] = np.add(Ts[i][s], T[i][v]) | ||
for j in I: TfU[j][v] = Tf[i][s] | ||
if (debug == True): | ||
piO = "%2d" % (pi[i]) | ||
TsO = "(%2d, %2d, %2d)" % (Ts[i][s][0], Ts[i][s][1], Ts[i][s][2]) | ||
TfO = "(%2d, %2d, %2d)" % (Tf[i][s][0], Tf[i][s][1], Tf[i][s][2]) | ||
print("pi[i]:", piO, " s:", s + 1, " u:", v + 1, " Ts:", TsO, " Tf:", TfO) | ||
|
||
n = np.argmax(PT([[Tf[i][L - 1]] for i in I])) | ||
|
||
return Tf[n][L - 1] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright © 2021 Polirecyliente | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# Multi-Neighborhood Iterated Greedy (MNIG) algorithm, to solve the Fuzzy Multiproduct Multistage Scheduling Problem (FMMSP) | ||
|
||
This is the MNIG algorithm written in Python to solve the FMMSP. The | ||
MNIG algorithm is implemented here as defined by the article: | ||
https://www.sciencedirect.com/science/article/abs/pii/S0950705120300344 | ||
|
||
The FMMSP model is defined in | ||
https://www.sciencedirect.com/science/article/abs/pii/S0925231220302563 | ||
|
||
This implementation is at least as good as the DBSA-LS algorithm to | ||
solve the FMMSP (as is confirmed using the only available public | ||
instance of the FMMSP, which is the one that comes by default inside | ||
this program). | ||
|
||
# Usage | ||
|
||
`python3 MNIG_to_FMMSP 5 1.1 4` | ||
|
||
This example command makes the algorithm run 250 iterations (which comes | ||
from 10\*5^2^). | ||
|
||
The meanings of the arguments are taken from the MNIG algorithm, they | ||
are N, T~0~, and d, respectively. | ||
|
||
# Installation | ||
|
||
Download the release and execute it as described in the Usage (so you | ||
need to have the `python3` interpreter installed already). | ||
|
||
# Details about the code | ||
|
||
The comments and the doc-strings are written in Spanish, because this | ||
project was originally created in Spanish. | ||
|
||
An optional `--debug` flag can be passed to the program, to print each | ||
iteration with its sequence, the makespan of the sequence, and a few | ||
other info. At the end of the iterations, a table is printed with the | ||
starting times and the finish times of each job in the sequence, among | ||
other info. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
from algorithms import DNEH_SMR, destruction_reconstruction, local_search | ||
from API.functions import PT, c_range, makespan | ||
|
||
import numpy as np | ||
import random | ||
import math | ||
|
||
# Soluciones probadas: | ||
# Makespan: (36, 44, 52) | ||
# Secuencias: | ||
# [7, 8, 6, 10, 1, 9, 5, 4, 2, 3] | ||
# [7, 8, 6, 10, 5, 9, 1, 4, 2, 3] | ||
# [6, 1, 9, 7, 8, 10, 4, 5, 2, 3] | ||
# [1, 6, 9, 10, 7, 8, 5, 4, 2, 3] | ||
# [6, 5, 10, 1, 9, 7, 8, 4, 2, 3] | ||
# [6, 10, 1, 8, 9, 4, 5, 7, 2, 3] | ||
# [6, 5, 7, 10, 8, 1, 4, 9, 2, 3] | ||
# [9, 7, 1, 6, 8, 10, 4, 5, 2, 3] | ||
# [5, 8, 7, 6, 10, 4, 1, 9, 2, 3] | ||
# [7, 1, 6, 10, 5, 9, 8, 4, 2, 3] | ||
|
||
# Datos de la instancia de prueba | ||
Tn = [ | ||
[(10, 12, 13), (11, 12, 14), (9, 10, 12), (6, 7, 9), (8, 9, 10)], | ||
[(7, 8, 10), (8, 9, 10), (5, 6, 8), (4, 5, 6), (4, 5, 6)], | ||
[(10, 11, 12), (9, 10, 12), (2, 3, 4), (5, 6, 8), (5, 6, 7)], | ||
[(8, 9, 10), (6, 7, 8), (7, 8, 9), (4, 5, 6), (5, 6, 8)], | ||
[(6, 7, 8), (8, 9, 10), (4, 5, 6), (6, 7, 8), (6, 7, 9)], | ||
[(4, 5, 6), (2, 3, 4), (15, 16, 19), (13, 14, 15), (15, 16, 20)], | ||
[(11, 13, 15), (1, 2, 3), (11, 13, 14), (10, 11, 13), (9, 10, 12)], | ||
[(10, 11, 12), (18, 19, 23), (5, 6, 7), (6, 7, 9), (7, 8, 10)], | ||
[(5, 6, 8), (4, 5, 6), (14, 15, 16), (19, 21, 25), (10, 12, 13)], | ||
[(15, 17, 20), (12, 14, 15), (16, 17, 20), (17, 18, 21), (18, 19, 21)] | ||
] | ||
# Tn tiene la estructura [ trabajo1, trabajo2, trabajoN ], a su vez cada trabajo tiene la forma [ máquina1, máquina2, máquinaM ], y cada máquina tiene la forma (tiempo_pesimista, tiempo_promedio, tiempo_optimista). | ||
|
||
# U_s es el conjunto de máquinas o unidades de la etapa s. | ||
U_s = [[0, 1], [2, 3, 4]] | ||
|
||
# L es el total de etapas | ||
L = len(U_s) | ||
|
||
# Pn es la ponderación de los números triangulares. | ||
Pn = PT(Tn) | ||
|
||
# Parametros para las iteraciones, introducidos como argumentos a este programa | ||
|
||
import argparse | ||
parser1 = argparse.ArgumentParser() | ||
|
||
parser1.add_argument("N", type = int) | ||
parser1.add_argument("T_0", type = float) | ||
parser1.add_argument("d", type = int) | ||
parser1.add_argument("--debug", action = "store_true") | ||
|
||
args1 = parser1.parse_args() | ||
|
||
N = args1.N | ||
T_0 = args1.T_0 | ||
d = args1.d | ||
debug = args1.debug | ||
|
||
# N es un parámetro para el número de iteraciones | ||
# N = 5 | ||
|
||
# T_0 es un parámetro para crear variación en el algoritmo, diferente de cero | ||
# T_0 = 1.1 | ||
|
||
# d es un parámetro para la cantidad de trabajos a colocar en pi_d para el algoritmo destruction_reconstruction | ||
# d = 4 | ||
|
||
|
||
# Paso 1 | ||
|
||
pi_re3, Ta = DNEH_SMR(Tn, U_s, Pn) | ||
|
||
|
||
# Paso 2 | ||
|
||
pi_result = pi_re3.copy() | ||
pi_temp = pi_re3.copy() | ||
iter1 = 1 | ||
|
||
|
||
# Paso 3 | ||
|
||
UT = np.sum([len(U_s[s]) for s in c_range(1, L)]) | ||
TT = T_0*(np.sum(Ta))/(10 * N * L) | ||
|
||
while (iter1 <= N**2 * L * UT): | ||
iter1 += 1 | ||
|
||
|
||
# Paso 4 | ||
|
||
pi_temp = local_search(pi_temp, Tn, U_s, Pn) | ||
|
||
|
||
# Paso 5 | ||
|
||
if (PT(makespan(pi_temp, Tn, U_s, Pn)) < PT(makespan(pi_re3, Tn, U_s, Pn))): | ||
|
||
|
||
# Paso 6 | ||
|
||
pi_re3 = pi_temp.copy() | ||
|
||
|
||
# Paso 7 | ||
|
||
if (PT(makespan(pi_temp, Tn, U_s, Pn)) < PT(makespan(pi_result, Tn, U_s, Pn))): | ||
|
||
|
||
# Paso 8 | ||
|
||
pi_result = pi_temp.copy() | ||
|
||
|
||
# Paso 9 | ||
|
||
else: | ||
|
||
|
||
# Paso 10 | ||
|
||
if ( random.random() < math.exp(-(PT(makespan(pi_temp, Tn, U_s, Pn)) - PT(makespan(pi_re3, Tn, U_s, Pn)))/TT) ): | ||
|
||
|
||
# Paso 11 | ||
|
||
pi_re3 = pi_temp.copy() | ||
|
||
|
||
# Paso 12 | ||
|
||
pi_temp = destruction_reconstruction(pi_temp, d, Tn, U_s, Pn) | ||
|
||
if (debug == True): | ||
mk = makespan(pi_re3, Tn, U_s, Pn) | ||
iter1O = "%4d" % (iter1 - 1) | ||
print("Iter:", iter1O, " Secuencia:", pi_re3, " Makespan:", mk, " P:", PT(mk)) | ||
|
||
|
||
# Paso 13 | ||
|
||
print("\n", pi_result, makespan(pi_result, Tn, U_s, Pn, debug)) |
Oops, something went wrong.