From b8de690cb6b700e566c6caba55ad4a3fe4e2dd4c Mon Sep 17 00:00:00 2001 From: codeMGL Date: Fri, 8 May 2026 20:14:49 +0200 Subject: [PATCH 1/8] Matriz Recompensas v1 --- .gitignore | 4 + ControlModule.py | 223 +++++++++++++++++++++++++++++++++++++++++++---- main.py | 13 +-- 3 files changed, 219 insertions(+), 21 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b2d0b1f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ControlModule.cpython-312.pyc +__pycache__/ControlModule.cpython-312.pyc +__pycache__/ControlModule.cpython-312.pyc +__pycache__/Reactor.cpython-312.pyc diff --git a/ControlModule.py b/ControlModule.py index ebe085c..2ef535a 100644 --- a/ControlModule.py +++ b/ControlModule.py @@ -8,37 +8,227 @@ def __init__(self): """Dummy constructor to use the Python Class as a namespace""" pass - @staticmethod # Hace que la función no necesite un argumento + @staticmethod def generate_P(probs) -> np.ndarray: """Function that generates the probabilities (transition) matrix""" ### TO BE COMPLETED BY THE STUDENTS ### # 3x3 o 3x3x3 o 100x100x3 - matriz_P = np.zeros((3, 10, 10), dtype=np.float64) + matrix_P = np.zeros((3, 10, 10), dtype=np.float64) # cambiar a 100x100 + probs_decrease = probs[0] probs_maintain = probs[1] - print(probs_maintain) + probs_increase = probs[2] + + # ---------------- DECREASE ---------------- + for i in range(10): + for j in range(10): + if i == j: + matrix_P[0][i][j] = probs_decrease[2] + elif i - 1 == j: + matrix_P[0][i][j] = probs_decrease[1] + elif i - 2 == j: + matrix_P[0][i][j] = probs_decrease[0] + # ---------------- MAINTAIN ---------------- for i in range(10): for j in range(10): if i == j: - matriz_P[1][i][j] = probs_maintain[1] + matrix_P[1][i][j] = probs_maintain[1] elif i + 1 == j: - matriz_P[1][i][j] = probs_maintain[2] - elif i-1 == j: - matriz_P[1][i][j] = probs_maintain[0] - + matrix_P[1][i][j] = probs_maintain[2] + elif i - 1 == j: + matrix_P[1][i][j] = probs_maintain[0] + # ---------------- INCREASE ---------------- + for i in range(10): + for j in range(10): + if i == j: + matrix_P[2][i][j] = probs_increase[0] + elif i + 1 == j: + matrix_P[2][i][j] = probs_increase[1] + elif i + 2 == j: + matrix_P[2][i][j] = probs_increase[2] - print("Probabilidades:\n", matriz_P.shape) - print(matriz_P) - return matriz_P - ... + print("Probabilidades:\n") + print(matrix_P) + return matrix_P @staticmethod - def generate_R() -> np.ndarray: + def generate_R(estado_actual, demand, n_states: np.int32 = 100) -> np.ndarray: """Function that generates the rewards (costs) matrix""" - ### TO BE COMPLETED BY THE STUDENTS ### - ... + demand = np.floor(demand[0] * 100) + # demand = 2 + """ + Coste_inicial = abs(estado_actual - demand) + matriz_calculo_costes = np.zeros((3, 3)) + + print(matriz_calculo_costes) # debería printearse una matriz 3x3 llena de ceros + + # Se mantiene constanteeeeeee + matriz_cambios_estado = np.array([[-2, -1, 0], [-1, 0, 1], [0, 1, 2]]) # 3 x 3 + matriz_P = np.zeros((3, 100, 100), dtype=np.float64) # cambiar a 100x100 + # Calculas la matriz que guarda los costes a partir de cada cambio de estado a partir de las posibles acciones + for estado_inicial in range(3): + for state in range(100): + for j in range(3): + coste_final_asociado = matriz_cambios_estado[estado_inicial][ + j + ] # 10 x 3 + + next_state = state + coste_final_asociado + next_state = np.clip(next_state, 0, 100 - 1) + matriz_calculo_costes[estado_inicial][j] = coste_final_asociado + matriz_P[estado_inicial][state][next_state] = 1 + print(matriz_P) + + # -------------------------------Territorio de Angel------------------- + # for i in range(3): + # for j in range(3): + # coste_accion_asociado = matriz_cambios_estado[i][j]# 10 x 3 + # next_state = state + coste_final_asociado + # matriz_calculo_costes[i][j] = coste_final_asociado + # print (matriz_P) + + print(matriz_calculo_costes) + """ + + ######################################################################## + matrix_R = np.zeros((3, 10, 10)) + # cambiar a 100x100 + # quitar DEBUGGING + # son recompensas, poner costes negativos + + # Se calcula la matriz de distancias entre el estado actual s y el estado futuro s' + # Aunque no se pueden alcanzar algunos estados (ej, pasar de s a s + 40), + # como en la matriz de probabilidades esa probabilidad es nula, el coste es indiferente + # Entonces, calculamos la distancia entre 'estado_inicial' y 'estado_final' y la duplicamos + # si la acción elegida se aleja del objetivo 'demand' + + # ---------------- DECREASE ---------------- + for estado_inicial in range(10): + for estado_final in range(10): + + delta_t = demand - estado_final + + # Comprobamos si la acción nos aleja del estado final (demanda) + # Si la distancia hasta la demanda es mayor en el estado actual vs. en el estado final, + # nos hemos alejado. Hay que multiplicar x2 la distancia + if delta_t > 0: + # print( + # "Nos alejamos (decrease)", + # estado_inicial, + # estado_final, + # "d_t", + # delta_t, + # ) + delta_t = -abs(delta_t * 2) + else: + delta_t = abs(delta_t) # Para DEBUGING + + # Rellenamos la matriz para estado_final x estado_inicial + matrix_R[0][estado_final][estado_inicial] = delta_t + + # ---------------- MAINTAIN ---------------- + for estado_inicial in range(10): + for estado_final in range(10): + + delta_t = demand - estado_final + + # Comprobamos si la acción nos aleja del estado final (demanda) + # Si la distancia hasta la demanda es mayor en el estado actual vs. en el estado final, + # nos hemos alejado. Hay que multiplicar x2 la distancia + if delta_t != 0: + # print( + # "Nos alejamos (maintain)", + # estado_inicial, + # estado_final, + # "d_t", + # delta_t, + # ) + delta_t = -abs(delta_t * 2) + else: + delta_t = abs(delta_t) # Para DEBUGING + + matrix_R[1][estado_final][estado_inicial] = delta_t + + # ---------------- INCREASE ---------------- + for estado_inicial in range(10): + for estado_final in range(10): + + delta_t = demand - estado_final + + # Comprobamos si la acción nos aleja del estado final (demanda) + # Si la distancia hasta la demanda es mayor en el estado actual vs. en el estado final, + # nos hemos alejado. Hay que multiplicar x2 la distancia + if delta_t < 0: + # print( + # "Nos alejamos (increase)", + # estado_inicial, + # estado_final, + # "d_t", + # delta_t, + # ) + delta_t = -abs(delta_t * 2) + else: + delta_t = abs(delta_t) # Para DEBUGING + + matrix_R[2][estado_final][estado_inicial] = delta_t + + print() + print("DEMANDA ACTUAL: ", demand) + print(matrix_R) + + # Creamos unos tests + print() + for estado_inicial in range(1, 3): + for estado_final in range(estado_inicial - 1, estado_inicial + 2): + coste0 = matrix_R[0][estado_final][estado_inicial] + coste1 = matrix_R[1][estado_final][estado_inicial] + coste2 = matrix_R[2][estado_final][estado_inicial] + print( + f"ACCIÓN: decrease. Para ir desde {estado_inicial} hasta {estado_final} --> Coste: {coste0}" + ) + print( + f"ACCIÓN: maintain. Para ir desde {estado_inicial} hasta {estado_final} --> Coste: {coste1}" + ) + print( + f"ACCIÓN: increase. Para ir desde {estado_inicial} hasta {estado_final} --> Coste: {coste2}" + ) + """ + [[[ *4. *4. *4. *4. *4. *4. *4. *4. *4. *4.] + [ *2. *2. *2. *2. *2. *2. *2. *2. *2. *2.] + [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] + [ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] + [ 2. 2. 2. 2. 2. 2. 2. 2. 2. 2.] + [ 3. 3. 3. 3. 3. 3. 3. 3. 3. 3.] + [ 4. 4. 4. 4. 4. 4. 4. 4. 4. 4.] + [ 5. 5. 5. 5. 5. 5. 5. 5. 5. 5.] + [ 6. 6. 6. 6. 6. 6. 6. 6. 6. 6.] + [ 7. 7. 7. 7. 7. 7. 7. 7. 7. 7.]] + + [[ *4. *4. *4. *4. *4. *4. *4. *4. *4. *4.] + [ *2. *2. *2. *2. *2. *2. *2. *2. *2. *2.] + [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] + [ *2. *2. *2. *2. *2. *2. *2. *2. *2. *2.] + [ *4. *4. *4. *4. *4. *4. *4. *4. *4. *4.] + [ *6. *6. *6. *6. *6. *6. *6. *6. *6. *6.] + [ *8. *8. *8. *8. *8. *8. *8. *8. *8. *8.] + [*10. *10. *10. *10. *10. *10. *10. *10. *10. *10.] + [*12. *12. *12. *12. *12. *12. *12. *12. *12. *12.] + [*14. *14. *14. *14. *14. *14. *14. *14. *14. *14.]] + + [[ 2. 2. 2. 2. 2. 2. 2. 2. 2. 2.] + [ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] + [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] + [ *2. *2. *2. *2. *2. *2. *2. *2. *2. *2.] + [ *4. *4. *4. *4. *4. *4. *4. *4. *4. *4.] + [ *6. *6. *6. *6. *6. *6. *6. *6. *6. *6.] + [ *8. *8. *8. *8. *8. *8. *8. *8. *8. *8.] + [*10. *10. *10. *10. *10. *10. *10. *10. *10. *10.] + [*12. *12. *12. *12. *12. *12. *12. *12. *12. *12.] + [*14. *14. *14. *14. *14. *14. *14. *14. *14. *14.]]] + """ + return matrix_R @staticmethod def control_iteration() -> np.int32: @@ -60,3 +250,6 @@ def control_loop( ### DUMMY BEHAVIOUR TO PREVENT CRASHING (MUST BE DELETED AFTER THE FULL IMPLEMENTATION) ### return np.zeros_like(a=demand, dtype=np.float64) ### ### + + +#:) diff --git a/main.py b/main.py index 94ed703..46481dc 100644 --- a/main.py +++ b/main.py @@ -52,19 +52,20 @@ def main() -> None: probs = np.array([reactor.probabilities['decrease'], reactor.probabilities['maintain'], reactor.probabilities['increase']], dtype=np.float64) - + matriz_P = ControlModule.generate_P(probs) - + # Make a radar-plot with the reactor probabilities - plot_reactor_as_radar(probs=probs) - + # plot_reactor_as_radar(probs=probs) + # Generate a random power demand demand = generate_demand(n_samples=512) + matriz_R = ControlModule.generate_R(0, [0.02]) + # Define the number of MDP's states, actions and the discount factor (gamma) n_states = 100 n_actions = 3 - # Get the response time-series (answer to the demand time-series) response = ControlModule.control_loop(demand=demand, @@ -72,7 +73,7 @@ def main() -> None: n_states=n_states, n_actions=n_actions, gamma=gamma) - + # Plot the original power demand plot_demand(demand=demand) From d2e84fe3efa8a396d5d69b1301452954299118cc Mon Sep 17 00:00:00 2001 From: codeMGL Date: Fri, 8 May 2026 20:29:01 +0200 Subject: [PATCH 2/8] Cambio de variable para matrix_P --- .gitignore | 5 +-- ControlModule.py | 86 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 61 insertions(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index b2d0b1f..c18dd8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1 @@ -__pycache__/ControlModule.cpython-312.pyc -__pycache__/ControlModule.cpython-312.pyc -__pycache__/ControlModule.cpython-312.pyc -__pycache__/Reactor.cpython-312.pyc +__pycache__/ diff --git a/ControlModule.py b/ControlModule.py index 2ef535a..9979471 100644 --- a/ControlModule.py +++ b/ControlModule.py @@ -18,39 +18,73 @@ def generate_P(probs) -> np.ndarray: probs_decrease = probs[0] probs_maintain = probs[1] probs_increase = probs[2] - # ---------------- DECREASE ---------------- - for i in range(10): - for j in range(10): - if i == j: - matrix_P[0][i][j] = probs_decrease[2] - elif i - 1 == j: - matrix_P[0][i][j] = probs_decrease[1] - elif i - 2 == j: - matrix_P[0][i][j] = probs_decrease[0] + for estado_inicial in range(10): + for estado_final in range(10): + if estado_inicial == estado_final: + matrix_P[0][estado_inicial][estado_final] = probs_decrease[2] + elif estado_inicial - 1 == estado_final: + matrix_P[0][estado_inicial][estado_final] = probs_decrease[1] + elif estado_inicial - 2 == estado_final: + matrix_P[0][estado_inicial][estado_final] = probs_decrease[0] # ---------------- MAINTAIN ---------------- - for i in range(10): - for j in range(10): - if i == j: - matrix_P[1][i][j] = probs_maintain[1] - elif i + 1 == j: - matrix_P[1][i][j] = probs_maintain[2] - elif i - 1 == j: - matrix_P[1][i][j] = probs_maintain[0] + for estado_inicial in range(10): + for estado_final in range(10): + if estado_inicial == estado_final: + matrix_P[1][estado_inicial][estado_final] = probs_maintain[1] + elif estado_inicial + 1 == estado_final: + matrix_P[1][estado_inicial][estado_final] = probs_maintain[2] + elif estado_inicial - 1 == estado_final: + matrix_P[1][estado_inicial][estado_final] = probs_maintain[0] # ---------------- INCREASE ---------------- - for i in range(10): - for j in range(10): - if i == j: - matrix_P[2][i][j] = probs_increase[0] - elif i + 1 == j: - matrix_P[2][i][j] = probs_increase[1] - elif i + 2 == j: - matrix_P[2][i][j] = probs_increase[2] + for estado_inicial in range(10): + for estado_final in range(10): + if estado_inicial == estado_final: + matrix_P[2][estado_inicial][estado_final] = probs_increase[0] + elif estado_inicial + 1 == estado_final: + matrix_P[2][estado_inicial][estado_final] = probs_increase[1] + elif estado_inicial + 2 == estado_final: + matrix_P[2][estado_inicial][estado_final] = probs_increase[2] print("Probabilidades:\n") print(matrix_P) + """ + [[[0.8 0. 0. 0. 0. 0. 0. 0. 0. 0. ] + [0.025 0.8 0. 0. 0. 0. 0. 0. 0. 0. ] + [0.175 0.025 0.8 0. 0. 0. 0. 0. 0. 0. ] + [0. 0.175 0.025 0.8 0. 0. 0. 0. 0. 0. ] + [0. 0. 0.175 0.025 0.8 0. 0. 0. 0. 0. ] + [0. 0. 0. 0.175 0.025 0.8 0. 0. 0. 0. ] + [0. 0. 0. 0. 0.175 0.025 0.8 0. 0. 0. ] + [0. 0. 0. 0. 0. 0.175 0.025 0.8 0. 0. ] + [0. 0. 0. 0. 0. 0. 0.175 0.025 0.8 0. ] + [0. 0. 0. 0. 0. 0. 0. 0.175 0.025 0.8 ]] + + [[0.6 0.35 0. 0. 0. 0. 0. 0. 0. 0. ] + [0.05 0.6 0.35 0. 0. 0. 0. 0. 0. 0. ] + [0. 0.05 0.6 0.35 0. 0. 0. 0. 0. 0. ] + [0. 0. 0.05 0.6 0.35 0. 0. 0. 0. 0. ] + [0. 0. 0. 0.05 0.6 0.35 0. 0. 0. 0. ] + [0. 0. 0. 0. 0.05 0.6 0.35 0. 0. 0. ] + [0. 0. 0. 0. 0. 0.05 0.6 0.35 0. 0. ] + [0. 0. 0. 0. 0. 0. 0.05 0.6 0.35 0. ] + [0. 0. 0. 0. 0. 0. 0. 0.05 0.6 0.35 ] + [0. 0. 0. 0. 0. 0. 0. 0. 0.05 0.6 ]] + + [[0. 0.2 0.8 0. 0. 0. 0. 0. 0. 0. ] + [0. 0. 0.2 0.8 0. 0. 0. 0. 0. 0. ] + [0. 0. 0. 0.2 0.8 0. 0. 0. 0. 0. ] + [0. 0. 0. 0. 0.2 0.8 0. 0. 0. 0. ] + [0. 0. 0. 0. 0. 0.2 0.8 0. 0. 0. ] + [0. 0. 0. 0. 0. 0. 0.2 0.8 0. 0. ] + [0. 0. 0. 0. 0. 0. 0. 0.2 0.8 0. ] + [0. 0. 0. 0. 0. 0. 0. 0. 0.2 0.8 ] + [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.2 ] + [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. ]]] + """ + return matrix_P @staticmethod @@ -97,7 +131,7 @@ def generate_R(estado_actual, demand, n_states: np.int32 = 100) -> np.ndarray: # cambiar a 100x100 # quitar DEBUGGING # son recompensas, poner costes negativos - + # Se calcula la matriz de distancias entre el estado actual s y el estado futuro s' # Aunque no se pueden alcanzar algunos estados (ej, pasar de s a s + 40), # como en la matriz de probabilidades esa probabilidad es nula, el coste es indiferente From d22d5fe47b65e122dade5f59d746b7af64d7de27 Mon Sep 17 00:00:00 2001 From: codeMGL Date: Fri, 15 May 2026 00:17:26 +0200 Subject: [PATCH 3/8] Inicio control_interation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TO DO - Comprobar que la matriz R tiene recompensas y no costes - Comprobar si la demanda es [0, 1] o [0, 100] - Hacer tests con diferentes demandas y matriz 10x10 - Revisar codigo base para ver args de funciones y orden de ejecución - Añadir método para subir/bajar de estado, una vez se ha elegido la acción --- .gitignore | 1 + ControlModule.py | 167 +++++++++++++++++++++++++---------------------- main.py | 87 +++++++++++++++--------- 3 files changed, 146 insertions(+), 109 deletions(-) diff --git a/.gitignore b/.gitignore index c18dd8d..5e43c01 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ __pycache__/ +/__pycache__ diff --git a/ControlModule.py b/ControlModule.py index 9979471..aa5a7a5 100644 --- a/ControlModule.py +++ b/ControlModule.py @@ -9,18 +9,19 @@ def __init__(self): pass @staticmethod - def generate_P(probs) -> np.ndarray: + def generate_P(probs, n_states) -> np.ndarray: """Function that generates the probabilities (transition) matrix""" ### TO BE COMPLETED BY THE STUDENTS ### - # 3x3 o 3x3x3 o 100x100x3 - matrix_P = np.zeros((3, 10, 10), dtype=np.float64) # cambiar a 100x100 + matrix_P = np.zeros( + (3, n_states, n_states), dtype=np.float64 + ) # cambiar a 100x100 probs_decrease = probs[0] probs_maintain = probs[1] probs_increase = probs[2] # ---------------- DECREASE ---------------- - for estado_inicial in range(10): - for estado_final in range(10): + for estado_inicial in range(n_states): + for estado_final in range(n_states): if estado_inicial == estado_final: matrix_P[0][estado_inicial][estado_final] = probs_decrease[2] elif estado_inicial - 1 == estado_final: @@ -29,8 +30,8 @@ def generate_P(probs) -> np.ndarray: matrix_P[0][estado_inicial][estado_final] = probs_decrease[0] # ---------------- MAINTAIN ---------------- - for estado_inicial in range(10): - for estado_final in range(10): + for estado_inicial in range(n_states): + for estado_final in range(n_states): if estado_inicial == estado_final: matrix_P[1][estado_inicial][estado_final] = probs_maintain[1] elif estado_inicial + 1 == estado_final: @@ -39,8 +40,8 @@ def generate_P(probs) -> np.ndarray: matrix_P[1][estado_inicial][estado_final] = probs_maintain[0] # ---------------- INCREASE ---------------- - for estado_inicial in range(10): - for estado_final in range(10): + for estado_inicial in range(n_states): + for estado_final in range(n_states): if estado_inicial == estado_final: matrix_P[2][estado_inicial][estado_final] = probs_increase[0] elif estado_inicial + 1 == estado_final: @@ -88,46 +89,12 @@ def generate_P(probs) -> np.ndarray: return matrix_P @staticmethod - def generate_R(estado_actual, demand, n_states: np.int32 = 100) -> np.ndarray: + def generate_R(demand_t: np.float64, n_states: np.int32 = 100) -> np.ndarray: """Function that generates the rewards (costs) matrix""" - demand = np.floor(demand[0] * 100) - # demand = 2 - """ - Coste_inicial = abs(estado_actual - demand) - matriz_calculo_costes = np.zeros((3, 3)) - - print(matriz_calculo_costes) # debería printearse una matriz 3x3 llena de ceros - - # Se mantiene constanteeeeeee - matriz_cambios_estado = np.array([[-2, -1, 0], [-1, 0, 1], [0, 1, 2]]) # 3 x 3 - matriz_P = np.zeros((3, 100, 100), dtype=np.float64) # cambiar a 100x100 - # Calculas la matriz que guarda los costes a partir de cada cambio de estado a partir de las posibles acciones - for estado_inicial in range(3): - for state in range(100): - for j in range(3): - coste_final_asociado = matriz_cambios_estado[estado_inicial][ - j - ] # 10 x 3 - - next_state = state + coste_final_asociado - next_state = np.clip(next_state, 0, 100 - 1) - matriz_calculo_costes[estado_inicial][j] = coste_final_asociado - matriz_P[estado_inicial][state][next_state] = 1 - print(matriz_P) - - # -------------------------------Territorio de Angel------------------- - # for i in range(3): - # for j in range(3): - # coste_accion_asociado = matriz_cambios_estado[i][j]# 10 x 3 - # next_state = state + coste_final_asociado - # matriz_calculo_costes[i][j] = coste_final_asociado - # print (matriz_P) - - print(matriz_calculo_costes) - """ + demand = demand_t + print("Demanda:", demand) - ######################################################################## - matrix_R = np.zeros((3, 10, 10)) + matrix_R = np.zeros((3, n_states, n_states)) # cambiar a 100x100 # quitar DEBUGGING # son recompensas, poner costes negativos @@ -139,8 +106,8 @@ def generate_R(estado_actual, demand, n_states: np.int32 = 100) -> np.ndarray: # si la acción elegida se aleja del objetivo 'demand' # ---------------- DECREASE ---------------- - for estado_inicial in range(10): - for estado_final in range(10): + for estado_inicial in range(n_states): + for estado_final in range(n_states): delta_t = demand - estado_final @@ -156,15 +123,15 @@ def generate_R(estado_actual, demand, n_states: np.int32 = 100) -> np.ndarray: # delta_t, # ) delta_t = -abs(delta_t * 2) - else: - delta_t = abs(delta_t) # Para DEBUGING + # else: + # delta_t = abs(delta_t) # Para DEBUGING # Rellenamos la matriz para estado_final x estado_inicial - matrix_R[0][estado_final][estado_inicial] = delta_t + matrix_R[0][estado_final][estado_inicial] = -delta_t # ---------------- MAINTAIN ---------------- - for estado_inicial in range(10): - for estado_final in range(10): + for estado_inicial in range(n_states): + for estado_final in range(n_states): delta_t = demand - estado_final @@ -180,14 +147,14 @@ def generate_R(estado_actual, demand, n_states: np.int32 = 100) -> np.ndarray: # delta_t, # ) delta_t = -abs(delta_t * 2) - else: - delta_t = abs(delta_t) # Para DEBUGING + # else: + # delta_t = abs(delta_t) # Para DEBUGING - matrix_R[1][estado_final][estado_inicial] = delta_t + matrix_R[1][estado_final][estado_inicial] = -delta_t # ---------------- INCREASE ---------------- - for estado_inicial in range(10): - for estado_final in range(10): + for estado_inicial in range(n_states): + for estado_final in range(n_states): delta_t = demand - estado_final @@ -203,31 +170,31 @@ def generate_R(estado_actual, demand, n_states: np.int32 = 100) -> np.ndarray: # delta_t, # ) delta_t = -abs(delta_t * 2) - else: - delta_t = abs(delta_t) # Para DEBUGING + # else: + # delta_t = abs(delta_t) # Para DEBUGING - matrix_R[2][estado_final][estado_inicial] = delta_t + matrix_R[2][estado_final][estado_inicial] = -delta_t print() print("DEMANDA ACTUAL: ", demand) print(matrix_R) # Creamos unos tests - print() - for estado_inicial in range(1, 3): - for estado_final in range(estado_inicial - 1, estado_inicial + 2): - coste0 = matrix_R[0][estado_final][estado_inicial] - coste1 = matrix_R[1][estado_final][estado_inicial] - coste2 = matrix_R[2][estado_final][estado_inicial] - print( - f"ACCIÓN: decrease. Para ir desde {estado_inicial} hasta {estado_final} --> Coste: {coste0}" - ) - print( - f"ACCIÓN: maintain. Para ir desde {estado_inicial} hasta {estado_final} --> Coste: {coste1}" - ) - print( - f"ACCIÓN: increase. Para ir desde {estado_inicial} hasta {estado_final} --> Coste: {coste2}" - ) + # print() + # for estado_inicial in range(1, 3): + # for estado_final in range(estado_inicial - 1, estado_inicial + 2): + # coste0 = matrix_R[0][estado_final][estado_inicial] + # coste1 = matrix_R[1][estado_final][estado_inicial] + # coste2 = matrix_R[2][estado_final][estado_inicial] + # print( + # f"ACCIÓN: decrease. Para ir desde {estado_inicial} hasta {estado_final} --> Coste: {coste0}" + # ) + # print( + # f"ACCIÓN: maintain. Para ir desde {estado_inicial} hasta {estado_final} --> Coste: {coste1}" + # ) + # print( + # f"ACCIÓN: increase. Para ir desde {estado_inicial} hasta {estado_final} --> Coste: {coste2}" + # ) """ [[[ *4. *4. *4. *4. *4. *4. *4. *4. *4. *4.] [ *2. *2. *2. *2. *2. *2. *2. *2. *2. *2.] @@ -265,9 +232,32 @@ def generate_R(estado_actual, demand, n_states: np.int32 = 100) -> np.ndarray: return matrix_R @staticmethod - def control_iteration() -> np.int32: + def control_iteration(P, R, estado_actual, gamma, max_iter=1000) -> np.int32: """Function that computes one control-iteration""" - ### TO BE COMPLETED BY THE STUDENTS ### + # print("P y R", P.shape, R.shape) + # print() + # print(P[0][:3][:3]) + # print("P\n", P) + # print(R[0][:3][:3]) + # print() + + # -- Comprobacion provisional de si la matriz P es estocastica + # La última fila tiene todo ceros, rellenamos con uno en la posicion final + P[2][-1][-1] = 1 + + for a in range(3): + P[a] = P[a] / P[a].sum(axis=1, keepdims=True) # renormaliza + + # print() + # print("P normalizada\n", P) + # print(check_stochastic(P)) + # print() + + pi = mdptoolbox.mdp.PolicyIteration(P, R, gamma, max_iter=max_iter) + pi.setVerbose() + pi.run() + print("Policy: ", pi.policy) + return pi.policy[estado_actual] ... @staticmethod @@ -287,3 +277,22 @@ def control_loop( #:) + + +def check_stochastic(P, tol=1e-6): + P = np.array(P) + assert P.ndim == 3, f"P debe ser (A, S, S), tiene forma {P.shape}" + A, S, _ = P.shape + ok = True + for a in range(A): + row_sums = P[a].sum(axis=1) + bad = np.where(np.abs(row_sums - 1.0) > tol)[0] + if len(bad) > 0: + ok = False + for s in bad: + print(f" Acción {a}, Estado {s}: suma = {row_sums[s]:.8f}") + if ok: + print("✅ Matriz estocástica: todas las filas suman 1.") + else: + print("❌ Matriz NO estocástica.") + return ok diff --git a/main.py b/main.py index 46481dc..75870c6 100644 --- a/main.py +++ b/main.py @@ -8,39 +8,49 @@ from Metrics import * from Plotter import * -def get_args() -> tuple[Reactor, np.float64, np.float64]: # 3 salidas (?) + +def get_args() -> tuple[Reactor, np.float64, np.float64]: # 3 salidas (?) # Define the parser object parser = argparse.ArgumentParser() # Define the expected arguments to parse and their data types - parser.add_argument("--input-reactor", "-i", type=str, help="Path of the reactor's JSON file") - parser.add_argument("--gamma", "-g", type=float, help="Discount factor used in the MDP") - parser.add_argument("--random-seed", "-r", type=int, help="Pseudo-random number generator seed") + parser.add_argument( + "--input-reactor", "-i", type=str, help="Path of the reactor's JSON file" + ) + parser.add_argument( + "--gamma", "-g", type=float, help="Discount factor used in the MDP" + ) + parser.add_argument( + "--random-seed", "-r", type=int, help="Pseudo-random number generator seed" + ) # Parse the arguments args = parser.parse_args() - + # Some verbose to check the correct parsing of the input arguments print(f"Loading reactor from file: {args.input_reactor}") print(f"Using gamma (discount factor): {args.gamma}") print(f"Using {args.random_seed} as random seed") # Build the Reactor object by reading the reactor's JSON file - with open(args.input_reactor, 'r', encoding='utf-8') as file: + with open(args.input_reactor, "r", encoding="utf-8") as file: json_data = json.load(fp=file) - reactor = Reactor(model=json_data['model'], - effective_section=float(json_data['effective_section']), - neutron_flux=float(json_data['neutron_flux']), - core_volume=float(json_data['core_volume']), - fision_energy=float(json_data['fision_energy']), - probabilities=dict(json_data['probabilities'])) - + reactor = Reactor( + model=json_data["model"], + effective_section=float(json_data["effective_section"]), + neutron_flux=float(json_data["neutron_flux"]), + core_volume=float(json_data["core_volume"]), + fision_energy=float(json_data["fision_energy"]), + probabilities=dict(json_data["probabilities"]), + ) + # Some verbose of the reactor loaded print(reactor) # Overloaded in the __str__ method of Reactor's class - + # Return the Reactor object, gamma and the random seed return reactor, args.gamma, args.random_seed + def main() -> None: # Parse the main arguments reactor, gamma, random_seed = get_args() @@ -49,30 +59,46 @@ def main() -> None: np.random.seed(random_seed) # Get the probabilities from the reactor's dynamics - probs = np.array([reactor.probabilities['decrease'], - reactor.probabilities['maintain'], - reactor.probabilities['increase']], dtype=np.float64) + probs = np.array( + [ + reactor.probabilities["decrease"], + reactor.probabilities["maintain"], + reactor.probabilities["increase"], + ], + dtype=np.float64, + ) - matriz_P = ControlModule.generate_P(probs) + matriz_P = ControlModule.generate_P(probs, 100) # Make a radar-plot with the reactor probabilities # plot_reactor_as_radar(probs=probs) # Generate a random power demand - demand = generate_demand(n_samples=512) + # demand = generate_demand(n_samples=512) + # print("Demand:\n", demand) # Array con 512 demands + + estado_actual = 5 + # demand = 0.02 + # for i in range(0, 100, 20): + i = 90 + if True: + demand = i / 100 + matriz_R = ControlModule.generate_R(demand) - matriz_R = ControlModule.generate_R(0, [0.02]) + # Ejecutamos para un solo estado + response = ControlModule.control_iteration(matriz_P, matriz_R, estado_actual, gamma) + print("Response 'unitaria':", response) # Define the number of MDP's states, actions and the discount factor (gamma) - n_states = 100 + n_states = 100 n_actions = 3 # Get the response time-series (answer to the demand time-series) - response = ControlModule.control_loop(demand=demand, - probs=probs, - n_states=n_states, - n_actions=n_actions, - gamma=gamma) + response = ControlModule.control_loop( + demand=demand, probs=probs, n_states=n_states, n_actions=n_actions, gamma=gamma + ) + + # print("Response:\n", response) # Array con 512 respuestas # Plot the original power demand plot_demand(demand=demand) @@ -87,9 +113,9 @@ def main() -> None: plot_correlation(demand=demand, response=response) # Print the four regression metrics for the current demand-response data - _MAE = MAE(y_true=demand, y_pred=response) - _MSE = MSE(y_true=demand, y_pred=response) - _R2 = R2(y_true=demand, y_pred=response) + _MAE = MAE(y_true=demand, y_pred=response) + _MSE = MSE(y_true=demand, y_pred=response) + _R2 = R2(y_true=demand, y_pred=response) _Corr = Corr(y_true=demand, y_pred=response) print(f"MAE={_MAE:.6f}") print(f"MSE={_MSE:.6f}") @@ -102,5 +128,6 @@ def main() -> None: # Plot the R2 and the Corr in a bar-plot plot_r2_and_pearson(R2=_R2, Pearson=_Corr) -if __name__ == '__main__': + +if __name__ == "__main__": main() From 93ae8d2085eea3849db3c9b57e1123151ab3f613 Mon Sep 17 00:00:00 2001 From: Angel Date: Fri, 15 May 2026 16:05:56 +0200 Subject: [PATCH 4/8] Loop_control, Matrix_P cambiada Ahora la matriz_P no se genera bien --- ControlModule.py | 153 +++++++++++++++------- __pycache__/ControlModule.cpython-313.pyc | Bin 2086 -> 8842 bytes main.py | 23 ++-- 3 files changed, 119 insertions(+), 57 deletions(-) diff --git a/ControlModule.py b/ControlModule.py index aa5a7a5..41812c4 100644 --- a/ControlModule.py +++ b/ControlModule.py @@ -9,17 +9,35 @@ def __init__(self): pass @staticmethod - def generate_P(probs, n_states) -> np.ndarray: + def generate_P(probs: np.ndarray, n_states: np.int32 = 100) -> np.ndarray: """Function that generates the probabilities (transition) matrix""" - ### TO BE COMPLETED BY THE STUDENTS ### - matrix_P = np.zeros( - (3, n_states, n_states), dtype=np.float64 - ) # cambiar a 100x100 + matrix_P = np.zeros((3, n_states, n_states), dtype=np.float64) # cambiar a 100x100 + #saca las probabilidades del Json probs_decrease = probs[0] probs_maintain = probs[1] probs_increase = probs[2] + + #Las probabilidades en los bordes se pierden, así que las filas no suman 1. (Y creo que normalizar es un apaño que no debería estar bien) + #Ej: COn decrease en estado 1, sumas las probabilidad de bajar a 0, pero no a la de bajar a -1 porque nunca se cumple en los IFs + + #Tantas iteraciones creo que son ineficientes, y mi pc es una patata, así que creo que hay que aprovechar mejor el hecho que + #sabemos que solo hay que modificar 3 IJs, no hace falta comprobar los 100, el 97% de las comprobaciones son inncesarias + # ---------------- DECREASE ---------------- + """ + + DECREASE ANGEL + for estado_inicial in range(n_states): + dest_0 = max(0, estado_inicial - 2) + dest_1 = max(0, estado_inicial - 1) + dest_2 = estado_inicial + + matrix_P[0][estado_inicial][dest_0] += probs_decrease[0] + matrix_P[0][estado_inicial][dest_1] += probs_decrease[1] + matrix_P[0][estado_inicial][dest_2] += probs_decrease[2] + + """ for estado_inicial in range(n_states): for estado_final in range(n_states): if estado_inicial == estado_final: @@ -49,6 +67,33 @@ def generate_P(probs, n_states) -> np.ndarray: elif estado_inicial + 2 == estado_final: matrix_P[2][estado_inicial][estado_final] = probs_increase[2] + # ---------------- CORRECCIÓN DE BORDES ---------------- + # Si una acción intenta llevar el reactor por debajo del estado 0 + # o por encima del estado n_states - 1, esa probabilidad no se pierde: + # se acumula en el borde correspondiente. + + # DECREASE: + # En estado 0, los movimientos -2 y -1 se quedan en 0. + matrix_P[0][0][0] += probs_decrease[0] + probs_decrease[1] + + # En estado 1, el movimiento -2 se queda en 0. + matrix_P[0][1][0] += probs_decrease[0] + + # MAINTAIN: + # En estado 0, el movimiento -1 se queda en 0. + matrix_P[1][0][0] += probs_maintain[0] + + # En el último estado, el movimiento +1 se queda en el último estado. + matrix_P[1][n_states - 1][n_states - 1] += probs_maintain[2] + + # INCREASE: + # En el penúltimo estado, el movimiento +2 se queda en el último estado. + matrix_P[2][n_states - 2][n_states - 1] += probs_increase[2] + + # En el último estado, los movimientos +1 y +2 se quedan en el último estado. + matrix_P[2][n_states - 1][n_states - 1] += probs_increase[1] + probs_increase[2] + + print("Probabilidades:\n") print(matrix_P) """ @@ -91,11 +136,10 @@ def generate_P(probs, n_states) -> np.ndarray: @staticmethod def generate_R(demand_t: np.float64, n_states: np.int32 = 100) -> np.ndarray: """Function that generates the rewards (costs) matrix""" - demand = demand_t + demand = np.float64(demand_t) print("Demanda:", demand) - matrix_R = np.zeros((3, n_states, n_states)) - # cambiar a 100x100 + matrix_R = np.zeros((3, n_states, n_states), dtype=np.float64) # (3x)100x100 # quitar DEBUGGING # son recompensas, poner costes negativos @@ -105,16 +149,19 @@ def generate_R(demand_t: np.float64, n_states: np.int32 = 100) -> np.ndarray: # Entonces, calculamos la distancia entre 'estado_inicial' y 'estado_final' y la duplicamos # si la acción elegida se aleja del objetivo 'demand' + + #al final hacer otra iteración exterior, y probar con np.where # ---------------- DECREASE ---------------- for estado_inicial in range(n_states): for estado_final in range(n_states): - delta_t = demand - estado_final + delta_t = demand - (estado_final/ n_states) + coste = abs(delta_t) # Comprobamos si la acción nos aleja del estado final (demanda) # Si la distancia hasta la demanda es mayor en el estado actual vs. en el estado final, # nos hemos alejado. Hay que multiplicar x2 la distancia - if delta_t > 0: + if demand > (estado_inicial/ n_states): # print( # "Nos alejamos (decrease)", # estado_inicial, @@ -122,46 +169,34 @@ def generate_R(demand_t: np.float64, n_states: np.int32 = 100) -> np.ndarray: # "d_t", # delta_t, # ) - delta_t = -abs(delta_t * 2) + coste *= 2 # else: # delta_t = abs(delta_t) # Para DEBUGING - # Rellenamos la matriz para estado_final x estado_inicial - matrix_R[0][estado_final][estado_inicial] = -delta_t + matrix_R[0][estado_inicial][estado_final] = -coste # ---------------- MAINTAIN ---------------- for estado_inicial in range(n_states): for estado_final in range(n_states): - delta_t = demand - estado_final + delta_t = demand - (estado_final/ n_states) - # Comprobamos si la acción nos aleja del estado final (demanda) - # Si la distancia hasta la demanda es mayor en el estado actual vs. en el estado final, - # nos hemos alejado. Hay que multiplicar x2 la distancia - if delta_t != 0: - # print( - # "Nos alejamos (maintain)", - # estado_inicial, - # estado_final, - # "d_t", - # delta_t, - # ) - delta_t = -abs(delta_t * 2) - # else: - # delta_t = abs(delta_t) # Para DEBUGING + coste = abs(delta_t) - matrix_R[1][estado_final][estado_inicial] = -delta_t + + matrix_R[1][estado_inicial][estado_final] = -coste # ---------------- INCREASE ---------------- for estado_inicial in range(n_states): for estado_final in range(n_states): - delta_t = demand - estado_final + delta_t = demand - (estado_final/ n_states) + coste = abs(delta_t) # Comprobamos si la acción nos aleja del estado final (demanda) # Si la distancia hasta la demanda es mayor en el estado actual vs. en el estado final, # nos hemos alejado. Hay que multiplicar x2 la distancia - if delta_t < 0: + if demand < (estado_inicial/ n_states): # print( # "Nos alejamos (increase)", # estado_inicial, @@ -169,11 +204,11 @@ def generate_R(demand_t: np.float64, n_states: np.int32 = 100) -> np.ndarray: # "d_t", # delta_t, # ) - delta_t = -abs(delta_t * 2) + coste *= 2 # else: # delta_t = abs(delta_t) # Para DEBUGING - matrix_R[2][estado_final][estado_inicial] = -delta_t + matrix_R[2][estado_inicial][estado_final] = -coste print() print("DEMANDA ACTUAL: ", demand) @@ -234,6 +269,10 @@ def generate_R(demand_t: np.float64, n_states: np.int32 = 100) -> np.ndarray: @staticmethod def control_iteration(P, R, estado_actual, gamma, max_iter=1000) -> np.int32: """Function that computes one control-iteration""" + + # ECUACION BELLMAN: V(s) = max_a [ sum_s'( P[s,s',a] * (R[s,s',a] + gamma * V[s']) ) ] + + # print("P y R", P.shape, R.shape) # print() # print(P[0][:3][:3]) @@ -246,40 +285,57 @@ def control_iteration(P, R, estado_actual, gamma, max_iter=1000) -> np.int32: P[2][-1][-1] = 1 for a in range(3): - P[a] = P[a] / P[a].sum(axis=1, keepdims=True) # renormaliza + P[a] = P[a] / P[a].sum(axis=1, keepdims=True) # renormaliza # Cambiar si hay tiempo, en vez de distribuir las probabilidades uniformemente, truncarlas a los bordes # print() # print("P normalizada\n", P) # print(check_stochastic(P)) # print() + #politica optima con la libreria .... pi = mdptoolbox.mdp.PolicyIteration(P, R, gamma, max_iter=max_iter) pi.setVerbose() pi.run() print("Policy: ", pi.policy) return pi.policy[estado_actual] - ... + + @staticmethod - def control_loop( - demand: np.ndarray, - probs: np.ndarray, - n_states: np.int32, - n_actions: np.int32, - gamma: np.float64, - ) -> np.ndarray: + def control_loop(demand: np.ndarray, + probs: np.ndarray, + n_states: np.int32, + n_actions: np.int32, + gamma: np.float64,) -> np.ndarray: + """Function that computes all the required iterations (control-loop) to satisfy the power demand""" - ### TO BE COMPLETED BY THE STUDENTS ### + ControlModule._probs = probs + ControlModule._n_states = n_states + ControlModule._n_actions = n_actions + + respuesta = np.zeros_like(a=demand, dtype=np.float64) # Almacena las acciones para cada demanda + current_state = np.int32(0) # Estado inicial, se puede modificar si se desea empezar en otro estado + + action_deltas = [np.array([-2, -1, 0], dtype=np.int32), np.array([-1, 0, 1], dtype=np.int32),np.array([ 0, 1, 2], dtype=np.int32)] + ControlModule._P = ControlModule.generate_P(probs, n_states) + + for t in range(demand.shape[0]): # La demanda cambia en el tiempo - ### DUMMY BEHAVIOUR TO PREVENT CRASHING (MUST BE DELETED AFTER THE FULL IMPLEMENTATION) ### - return np.zeros_like(a=demand, dtype=np.float64) - ### ### + ControlModule._demand_t = np.float64(demand[t]) + ControlModule._current_state = current_state + ControlModule._R = ControlModule.generate_R(demand_t = ControlModule._demand_t, n_states) # esta demanda concreta. + action = ControlModule.control_iteration(P= ControlModule._P, R= ControlModule._R, current_state = ControlModule._current_state, gamma=gamma) -#:) + state_increment = np.random.choice( a=action_deltas[action], p=probs[action]) + current_state = current_state + state_increment + current_state = np.int32(np.clip(a=current_state, a_min=0, a_max=n_states - 1)) + respuesta[t] = current_state / 100.0 + return respuesta def check_stochastic(P, tol=1e-6): + P = np.array(P) assert P.ndim == 3, f"P debe ser (A, S, S), tiene forma {P.shape}" A, S, _ = P.shape @@ -296,3 +352,6 @@ def check_stochastic(P, tol=1e-6): else: print("❌ Matriz NO estocástica.") return ok + + + diff --git a/__pycache__/ControlModule.cpython-313.pyc b/__pycache__/ControlModule.cpython-313.pyc index 87888329d161bbae779494d33dad907291b3e813..43629b4449631ce9d92e6dd72d39eb26fd96968e 100644 GIT binary patch literal 8842 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 M`%5Zl2bu7H0p9`;5&!@I literal 2086 zcma)6&1)M+6rWvb<&`4Yv6}?fP3yJOLj-k7nxw?01X`Omq{IX*q2P)x0+gq7l0_mZ-i73!(-`ka3i^xd^>Fsacym|A!d$n4H z!20p;f1H+^mK< zE2p*oruUhJnwpswY5SHepaxlNI)0&9YK$Mhl;f+mUz{P|7O(Y>r29%)XGpf(mpwC5 zZ)r&O6v&Q^w!wE#;Fp0vLbqQzfqx44(=Xd{qVH9|I%H$bugUSv@%n_REeo!th;NHl z8nb7RIub%`j~3zr{Ck+hT>^QrA1Nz(B`!IhS2sD<>j@KVJ*y~Vsc9la&Ew;WTY zJPJRL(}bxu4VkxkNa~g;Di&`j)a;p+<)!9b#iVL}djIn6%gq%LrU~O(HNS}T&2+t) zwAu@jQG8{Ar(w*fY!2CcsogPd5JWuEL14}epAGmWcub*lJLHL5?ExUBB$-YnA1bg> z?%w!3<)MziC%r|rx5+q@R5O)%+m>RTu19gCBj8-rl5z!D@Vb{!Eu(F3RgS@HIjJHl zNy z63H7`w=is7D3W%H!4#ZfMPV&2L>eQE5g#4A$-ZE4Bxq)bWB8K5xgje}sl^h?TgJis zDdX}$Y0Rl9^8jiMo>s=$q)9?UteU|>oOQ!Z0K4St0iQJblk129V4mDPE-{#b$3%Q< z(SDymM}2cbP-q-yRVLZJG?J|49XXt3FppL&M7xe1s32x)qm$RAc)+BWd+F6}V^QO@ zbf?Yg1!MEJsXSy-s34BMV`gk47F2(HweCn9D)Mb4Gf3V+avn(5J07mQe5->1ZM+L05mlW!r*iMYP< zk<7|r9=R8gdp5}OAB6$c(6sAVk)Stg+@qeAn8A!-8K~cYd{3U+wo`-VEKPOof>YhI z4=VeW9s$@Z44B=@0KM*59&GP#kG@@Y7WWzlYx`?m0`SlC?;YIQztt@Oelk0U*SZei zZi&oY_{II%?T+EjCGXB=a^-yY!KKGbhf6)&W#;v4KzRbtxq8t!JWbl2JbV?Hy;_KP tU2NyR568o}pX3R;AwPu6I6Bo?Al-sxSx?E-Uu5#%;+(bkoB+ul`42su>Qw*$ diff --git a/main.py b/main.py index 75870c6..026f352 100644 --- a/main.py +++ b/main.py @@ -74,20 +74,23 @@ def main() -> None: # plot_reactor_as_radar(probs=probs) # Generate a random power demand - # demand = generate_demand(n_samples=512) - # print("Demand:\n", demand) # Array con 512 demands + # Generate a random power demand + demand = generate_demand(n_samples=512) + # print("Demand:\n", demand) estado_actual = 5 - # demand = 0.02 - # for i in range(0, 100, 20): i = 90 if True: - demand = i / 100 - matriz_R = ControlModule.generate_R(demand) - - # Ejecutamos para un solo estado - response = ControlModule.control_iteration(matriz_P, matriz_R, estado_actual, gamma) - print("Response 'unitaria':", response) + demand_test = i / 100 + matriz_R = ControlModule.generate_R(demand_test) + + response_test = ControlModule.control_iteration( + matriz_P, + matriz_R, + estado_actual, + gamma + ) + print("Response 'unitaria':", response_test) # Define the number of MDP's states, actions and the discount factor (gamma) n_states = 100 From 0c660e18cdafb21cca96732957f1288f2677d36e Mon Sep 17 00:00:00 2001 From: Angel Date: Fri, 15 May 2026 16:29:54 +0200 Subject: [PATCH 5/8] =?UTF-8?q?P=5Fmax,=20K=20y=20P=20en=20funci=C3=B3n=20?= =?UTF-8?q?de=20P=5Fmax?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Reactor.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Reactor.py b/Reactor.py index 2fcfb3a..9a65604 100644 --- a/Reactor.py +++ b/Reactor.py @@ -31,20 +31,19 @@ def __str__(self) -> str: def compute_max_power(self) -> np.float64: """ Computes the maximum power of a reactor based on its physical features """ - ### TO BE COMPLETED BY THE STUDENTS ### - ... + return np.float64(self.effective_section * self.neutron_flux * self.core_volume * self.fision_energy) def compute_k(self) -> np.float64: """ Computes the value of the k-constant """ - ### TO BE COMPLETED BY THE STUDENTS ### - ... + self.P_max = self.compute_max_power() + return - np.log(10** -6/self.P_max) def compute_power(self, control_bars_insertion: np.float64) -> np.float64: """ Computes the power delivered (%) by the reactor based on the % of control-bars inserted """ - ### TO BE COMPLETED BY THE STUDENTS ### - ... + k = self.compute_k() + return np.float64(self.P_max * (np.e**(-k * control_bars_insertion))) def compute_control_bars_insertion(self, power: np.float64) -> np.float64: """ Computes the % of controls-bars inserted based on the % of power delivered by the reactor """ ### TO BE COMPLETED BY THE STUDENTS ### - ... + From 93894bb246c9ce1b52ad6e4fb0cdf6c22992bc40 Mon Sep 17 00:00:00 2001 From: Angel Date: Fri, 15 May 2026 17:11:42 +0200 Subject: [PATCH 6/8] Update Metrics.py --- Metrics.py | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/Metrics.py b/Metrics.py index 2515656..a4c25ea 100644 --- a/Metrics.py +++ b/Metrics.py @@ -3,32 +3,20 @@ def MAE(y_true: np.ndarray, y_pred: np.ndarray) -> np.float64: """ Implementation of the Mean Absolute Error (MAE) """ - ### TO BE COMPLETED BY THE STUDENTS ### - - ### DUMMY BEHAVIOUR TO PREVENT CRASHING (MUST BE DELETED AFTER THE FULL IMPLEMENTATION) ### - return 0.0 - ### ### + return np.float64((np.sum(abs(y_pred - y_true)))/len(y_pred)) + # return 0.0 DUMMY def MSE(y_true: np.ndarray, y_pred: np.ndarray) -> np.float64: """ Implementation of the Mean Squared Error (MSE) """ - ### TO BE COMPLETED BY THE STUDENTS ### - - ### DUMMY BEHAVIOUR TO PREVENT CRASHING (MUST BE DELETED AFTER THE FULL IMPLEMENTATION) ### - return 0.0 - ### ### + return np.float64(np.sum(abs((y_pred - y_true)**2))/len(y_pred)) + # return 0.0 DUMMY def R2(y_true: np.ndarray, y_pred: np.ndarray) -> np.float64: """ Implementation of the R2 metric """ - ### TO BE COMPLETED BY THE STUDENTS ### - - ### DUMMY BEHAVIOUR TO PREVENT CRASHING (MUST BE DELETED AFTER THE FULL IMPLEMENTATION) ### - return 0.0 - ### ### + return np.float64(1-(np.sum((y_true - y_pred)**2)/np.sum((y_true - np.mean(y_true))**2))) + # return 0.0 DUMMY def Corr(y_true: np.ndarray, y_pred: np.ndarray) -> np.float64: """ Implementation of the Pearson's Correlation Coefficient """ - ### TO BE COMPLETED BY THE STUDENTS ### - - ### DUMMY BEHAVIOUR TO PREVENT CRASHING (MUST BE DELETED AFTER THE FULL IMPLEMENTATION) ### - return 0.0 - ### ### + return np.float64(np.sqrt((np.sum((y_true - np.mean(y_true))*(y_pred - np.mean(y_pred)))/len(y_true))/((np.sum((y_true - np.mean(y_true))**2))/len(y_true)* (np.sum((y_pred - np.mean(y_pred))**2)/len(y_pred))))) + # return 0.0 DUMMY \ No newline at end of file From 0121b03cc5d60836bc11a654e01b7acccedb9fce Mon Sep 17 00:00:00 2001 From: codeMGL Date: Fri, 15 May 2026 17:17:34 +0200 Subject: [PATCH 7/8] quitado demand_t= --- ControlModule.py | 4 ++-- __pycache__/ControlModule.cpython-312.pyc | Bin 2812 -> 8984 bytes __pycache__/Reactor.cpython-312.pyc | Bin 3065 -> 3065 bytes 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ControlModule.py b/ControlModule.py index 41812c4..535b54d 100644 --- a/ControlModule.py +++ b/ControlModule.py @@ -136,7 +136,7 @@ def generate_P(probs: np.ndarray, n_states: np.int32 = 100) -> np.ndarray: @staticmethod def generate_R(demand_t: np.float64, n_states: np.int32 = 100) -> np.ndarray: """Function that generates the rewards (costs) matrix""" - demand = np.float64(demand_t) + demand = np.float64(demand_t) # Debug print("Demanda:", demand) matrix_R = np.zeros((3, n_states, n_states), dtype=np.float64) # (3x)100x100 @@ -324,7 +324,7 @@ def control_loop(demand: np.ndarray, ControlModule._demand_t = np.float64(demand[t]) ControlModule._current_state = current_state - ControlModule._R = ControlModule.generate_R(demand_t = ControlModule._demand_t, n_states) # esta demanda concreta. + ControlModule._R = ControlModule.generate_R(ControlModule._demand_t, n_states) # esta demanda concreta. action = ControlModule.control_iteration(P= ControlModule._P, R= ControlModule._R, current_state = ControlModule._current_state, gamma=gamma) state_increment = np.random.choice( a=action_deltas[action], p=probs[action]) diff --git a/__pycache__/ControlModule.cpython-312.pyc b/__pycache__/ControlModule.cpython-312.pyc index 5d3bcb1dfc4efbcbc1022030cd887f2a5079af54..cfc526d4f316d0cdc7c797ad73561597a13e7191 100644 GIT binary patch literal 8984 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 From 04868bd72b48ebf2c57a959e602d31644ceb1da4 Mon Sep 17 00:00:00 2001 From: Arleking558 Date: Fri, 15 May 2026 18:18:23 +0200 Subject: [PATCH 8/8] Errores resueltos --- ControlModule.py | 40 ++++++++++++++++++++-------------------- Metrics.py | 9 ++++++--- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/ControlModule.py b/ControlModule.py index 535b54d..a3a5277 100644 --- a/ControlModule.py +++ b/ControlModule.py @@ -94,8 +94,7 @@ def generate_P(probs: np.ndarray, n_states: np.int32 = 100) -> np.ndarray: matrix_P[2][n_states - 1][n_states - 1] += probs_increase[1] + probs_increase[2] - print("Probabilidades:\n") - print(matrix_P) + """ [[[0.8 0. 0. 0. 0. 0. 0. 0. 0. 0. ] [0.025 0.8 0. 0. 0. 0. 0. 0. 0. 0. ] @@ -137,7 +136,6 @@ def generate_P(probs: np.ndarray, n_states: np.int32 = 100) -> np.ndarray: def generate_R(demand_t: np.float64, n_states: np.int32 = 100) -> np.ndarray: """Function that generates the rewards (costs) matrix""" demand = np.float64(demand_t) # Debug - print("Demanda:", demand) matrix_R = np.zeros((3, n_states, n_states), dtype=np.float64) # (3x)100x100 # quitar DEBUGGING @@ -210,9 +208,7 @@ def generate_R(demand_t: np.float64, n_states: np.int32 = 100) -> np.ndarray: matrix_R[2][estado_inicial][estado_final] = -coste - print() - print("DEMANDA ACTUAL: ", demand) - print(matrix_R) + # Creamos unos tests # print() @@ -282,22 +278,28 @@ def control_iteration(P, R, estado_actual, gamma, max_iter=1000) -> np.int32: # -- Comprobacion provisional de si la matriz P es estocastica # La última fila tiene todo ceros, rellenamos con uno en la posicion final - P[2][-1][-1] = 1 - - for a in range(3): - P[a] = P[a] / P[a].sum(axis=1, keepdims=True) # renormaliza # Cambiar si hay tiempo, en vez de distribuir las probabilidades uniformemente, truncarlas a los bordes - # print() # print("P normalizada\n", P) # print(check_stochastic(P)) # print() - + """ #politica optima con la libreria .... pi = mdptoolbox.mdp.PolicyIteration(P, R, gamma, max_iter=max_iter) pi.setVerbose() pi.run() print("Policy: ", pi.policy) - return pi.policy[estado_actual] + return pi.policy[estado_actual]""" + + mdp = mdptoolbox.mdp.ValueIteration( + transitions=P, + reward=R, + discount=gamma, + max_iter=max_iter + ) + + mdp.run() + + return np.int32(mdp.policy[estado_actual]) @@ -309,9 +311,7 @@ def control_loop(demand: np.ndarray, gamma: np.float64,) -> np.ndarray: """Function that computes all the required iterations (control-loop) to satisfy the power demand""" - ControlModule._probs = probs - ControlModule._n_states = n_states - ControlModule._n_actions = n_actions + respuesta = np.zeros_like(a=demand, dtype=np.float64) # Almacena las acciones para cada demanda current_state = np.int32(0) # Estado inicial, se puede modificar si se desea empezar en otro estado @@ -325,15 +325,15 @@ def control_loop(demand: np.ndarray, ControlModule._current_state = current_state ControlModule._R = ControlModule.generate_R(ControlModule._demand_t, n_states) # esta demanda concreta. - action = ControlModule.control_iteration(P= ControlModule._P, R= ControlModule._R, current_state = ControlModule._current_state, gamma=gamma) + action = ControlModule.control_iteration(P= ControlModule._P, R= ControlModule._R, estado_actual = ControlModule._current_state, gamma=gamma) state_increment = np.random.choice( a=action_deltas[action], p=probs[action]) current_state = current_state + state_increment current_state = np.int32(np.clip(a=current_state, a_min=0, a_max=n_states - 1)) - respuesta[t] = current_state / 100.0 + respuesta[t] = current_state / n_states return respuesta - +""" def check_stochastic(P, tol=1e-6): P = np.array(P) @@ -353,5 +353,5 @@ def check_stochastic(P, tol=1e-6): print("❌ Matriz NO estocástica.") return ok - +""" diff --git a/Metrics.py b/Metrics.py index a4c25ea..e31c215 100644 --- a/Metrics.py +++ b/Metrics.py @@ -17,6 +17,9 @@ def R2(y_true: np.ndarray, y_pred: np.ndarray) -> np.float64: # return 0.0 DUMMY def Corr(y_true: np.ndarray, y_pred: np.ndarray) -> np.float64: - """ Implementation of the Pearson's Correlation Coefficient """ - return np.float64(np.sqrt((np.sum((y_true - np.mean(y_true))*(y_pred - np.mean(y_pred)))/len(y_true))/((np.sum((y_true - np.mean(y_true))**2))/len(y_true)* (np.sum((y_pred - np.mean(y_pred))**2)/len(y_pred))))) - # return 0.0 DUMMY \ No newline at end of file + """Implementation of the Pearson's Correlation Coefficient""" + + if np.std(y_true) == 0 or np.std(y_pred) == 0: + return np.float64(0.0) + + return np.float64(np.corrcoef(y_true, y_pred)[0, 1]) \ No newline at end of file