From 40d8a99eae5ed2de374f500a994efdebf4517203 Mon Sep 17 00:00:00 2001 From: Adrienucl <adrien.payen@student.uclouvain.be> Date: Fri, 3 May 2024 12:44:15 +0200 Subject: [PATCH] update plot + validation --- .DS_Store | Bin 6148 -> 6148 bytes markovDecision.py | 2 + plot.py | 82 ++++++++++++++++++++++++++++++++++++++++ strategy_comparison.png | Bin 0 -> 23502 bytes validation.py | 69 +++++++++++++++++++++++++++++++++ 5 files changed, 153 insertions(+) create mode 100644 plot.py create mode 100644 strategy_comparison.png diff --git a/.DS_Store b/.DS_Store index 895bd9eae285819cae90199894867d4ed1ce3958..55d82a11e81b11f3bbb9102c10fed3bcce6672f9 100644 GIT binary patch delta 162 zcmZoMXfc=|#>B)qu~2NHo+2ar#(>?7jO>$nSS)1)8FCpC8HyOP8S)v*7+e@q8Il<? z8H#~8pCNDZ1UAXZ-7Gwu><k4AIY5z;$pLI4OpLOVJ6L)rd$Q?>@&Yv_0;Mt;Qh;;` zR9gU>DC-Ia28Q{Y-?2$DZfr<k-ptOy&jED7W<iec%#-;=965l}42%p6ESn=l)-VGA D$Y~@g delta 490 zcmZuuK}!Nb6n-<SIa<*sDoGcktLdU)NvEt!w`ik+ifvcT7S|nfS2qyz;;BHCy$jJb zs91ua|IuIRShKoC2M1=p_vU*a@69(op(hMt*cTdJ$A+mD6nfqNK#wmRMj?9+=hxy; z0~s1n1qv<Lg)$UD1%qu0I!Iu$8-txH%PRH&N9-0}wBPV;H}uCzaLIVht=!XSQPHRZ z06YM$Fid@q7mEO<Y81<;dzyEpuBnD82%iXZKL1RB1jsBo7q6%#nzGq63UcGr%?@do zYRYdSD@SVClK99D)lFH|%Z;%@EtOfx*|DmZs8yg%y=08V;)EbU5|sF*c003~O(wFr zjZQMr&S!*VVm+Jdbb=(hn%+8)s#;B_cjNH^p$Wn~WWC6PdxleA*Ag4LMs?Q-WD8sx z@%9B5^-IjH8`sY;JTq$a&!n(h5b&(G`*<0RoIV#vPJk>B_LI&7_r=)@k!`}J!ES%& IB=W@l0MqAv(f|Me diff --git a/markovDecision.py b/markovDecision.py index 6bd17bc..25c5df1 100644 --- a/markovDecision.py +++ b/markovDecision.py @@ -60,6 +60,7 @@ def markovDecision(layout : list, circle : bool): # Exemple d'utilisation de la fonction markovDecision avec les paramètres layout et circle layout = [0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 1, 0] +""" # Résolution du problème avec différents modes de jeu result_false = markovDecision(layout, circle=False) print("\nWin as soon as land on or overstep the final square") @@ -68,3 +69,4 @@ print(result_false) result_true = markovDecision(layout, circle=True) print("\nStopping on the square to win") print(result_true) +""" \ No newline at end of file diff --git a/plot.py b/plot.py new file mode 100644 index 0000000..c548380 --- /dev/null +++ b/plot.py @@ -0,0 +1,82 @@ +import matplotlib.pyplot as plt +from validation import validation +import numpy as np + +# Example layout and circle settings +layout = [0, 0, 3, 0, 2, 0, 2, 0, 0, 0, 3, 0, 0, 1, 0] +circle = False + +# Create an instance of validation +validation_instance = validation(layout, circle) + + +# Plotting function for strategy comparison +def plot_strategy_comparison(num_games=1000): + strategy_costs = validation_instance.compare_strategies(num_games=num_games) + + # Bar plot for strategy comparison + plt.figure(figsize=(10, 6)) + plt.bar(strategy_costs.keys(), strategy_costs.values(), color=['blue', 'green', 'orange', 'red', 'purple']) + plt.xlabel('Strategies') + plt.ylabel('Average Cost') + plt.title('Comparison of Strategies') + plt.savefig('strategy_comparison.png') # Save the plot + plt.show() + +# Plotting function for state-based average turns for all strategies on the same plot +def plot_state_based_turns(save=True): + strategies = [validation_instance.optimal_strategy, + validation_instance.safe_strategy, + validation_instance.normal_strategy, + validation_instance.risky_strategy, + validation_instance.random_strategy] + strategy_names = ['Optimal', 'SafeDice', 'NormalDice', 'RiskyDice', 'Random'] + + plt.figure(figsize=(12, 6)) + for strategy, name in zip(strategies, strategy_names): + mean_turns = validation_instance.simulate_state(strategy, layout, circle) + plt.plot(range(len(mean_turns)), mean_turns, marker='o', linestyle='-', label=name) + + plt.xlabel('State') + plt.ylabel('Average Turns') + plt.title('Average Turns per State for Different Strategies') + plt.grid(True) + plt.legend() + + #if save: + #plt.savefig('state_based_turns_all_strategies.png') # Save the plot + + plt.show() + +def plot_state_based_comparison(validation_instance, num_games=1000): + optimal_turns, empirical_turns = validation_instance.compare_state_based_turns(num_games=num_games) + + # Plotting the state-based average turns comparison + plt.figure(figsize=(12, 6)) + + # Plot optimal strategy turns + plt.plot(range(len(optimal_turns)), optimal_turns, marker='o', linestyle='-', label='ValueIteration') + + # Plot empirical strategy turns + plt.plot(range(len(empirical_turns)), empirical_turns, marker='x', linestyle='-', label='Empirical') + + plt.xlabel('State') + plt.ylabel('Average Turns') + plt.title('Average Turns per State - ValueIteration vs. Empirical') + plt.grid(True) + plt.legend() + + plt.show() + + + + +# Main function to generate and save plots +if __name__ == '__main__': + # Example of strategy comparison plot + plot_strategy_comparison(num_games=1000) + + # Example of state-based average turns plot for all strategies on the same plot + plot_state_based_turns(save=True) + + plot_state_based_comparison(validation_instance, num_games=1000) \ No newline at end of file diff --git a/strategy_comparison.png b/strategy_comparison.png new file mode 100644 index 0000000000000000000000000000000000000000..aefb1f990b1c89957981a9281815083011fbc9d2 GIT binary patch literal 23502 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 literal 0 HcmV?d00001 diff --git a/validation.py b/validation.py index 85cd231..ee6b922 100644 --- a/validation.py +++ b/validation.py @@ -134,6 +134,53 @@ class validation: def play_random_strategy(self, n_iterations=10000): return self.simulate_game(self.random_strategy, n_iterations) + + def play_empirical_strategy(self): + k = 0 # état initial + total_turns = 0 + + while k < len(self.layout) - 1: + action = self.optimal_strategy[k] # Utiliser la stratégie empirique pour la simulation + action_index = int(action) - 1 + transition_matrix = self.normal_dice # Utiliser le dé normal pour la stratégie empirique + + # Aplatir la matrice de transition en une distribution de probabilité 1D + flattened_probs = transition_matrix[k] + flattened_probs /= np.sum(flattened_probs) # Normalisation des probabilités + + # Mise à jour de l'état (k) en fonction de la distribution de probabilité aplatie + k = np.random.choice(len(self.layout), p=flattened_probs) + + # Mise à jour du nombre de tours en fonction de l'état actuel + if self.layout[k] == 3 and action == 2: + total_turns += 1 if np.random.uniform(0, 1) < 0.5 else 2 + elif self.layout[k] == 3 and action == 3: + total_turns += 2 + else: + total_turns += 1 + + return total_turns + + + def compare_empirical_vs_value_iteration(self, num_games=1000): + value_iteration_turns = self.simulate_state(self.optimal_strategy, self.layout, self.circle) + empirical_turns = self.simulate_state(self.optimal_strategy, self.layout, self.circle, n_iterations=num_games) + + # Calculer la moyenne des tours pour chaque état + mean_turns_by_state = { + 'ValueIteration': value_iteration_turns.tolist(), + 'Empirical': empirical_turns.tolist() + } + + return mean_turns_by_state + + def compare_state_based_turns(self, num_games=1000): + optimal_turns = self.simulate_state(self.optimal_strategy, self.layout, self.circle, n_iterations=num_games) + empirical_turns = self.simulate_state(self.optimal_strategy, self.layout, self.circle, n_iterations=num_games) + + return optimal_turns, empirical_turns + + def compare_strategies(self, num_games=1000): optimal_cost = self.simulate_game(self.optimal_strategy, n_iterations=num_games) @@ -157,6 +204,26 @@ circle = False validation_instance = validation(layout, circle) +# Comparer la stratégie empirique avec la stratégie de value iteration +turns_by_state = validation_instance.compare_empirical_vs_value_iteration(num_games=1000) + +# Imprimer les moyennes des tours pour chaque état +num_states = len(layout) +for state in range(num_states - 1): + print(f"État {state}:") + print(f" ValueIteration - Tours moyens : {turns_by_state['ValueIteration'][state]:.2f}") + print(f" Empirical - Tours moyens : {turns_by_state['Empirical'][state]:.2f}") + +# Exécuter la stratégie empirique une fois +empirical_strategy_result = validation_instance.play_empirical_strategy() +print("Coût de la stratégie empirique sur un tour :", empirical_strategy_result) + +# Comparer la stratégie empirique avec la stratégie de value iteration sur plusieurs jeux +comparison_result = validation_instance.compare_empirical_vs_value_iteration(num_games=1000) +print("Coût moyen de la stratégie de value iteration :", comparison_result['ValueIteration']) +print("Coût moyen de la stratégie empirique :", comparison_result['Empirical']) +""" + optimal_cost = validation_instance.play_optimal_strategy(n_iterations=10000) print("Optimal Strategy Cost:", optimal_cost) @@ -189,3 +256,5 @@ print("Mean Turns for Risky Dice Strategy:", mean_turns_risky_dice) random_dice_strategy = validation_instance.random_strategy mean_turns_random_dice = validation_instance.simulate_state(random_dice_strategy, layout, circle, n_iterations=10000) print("Mean Turns for Random Dice Strategy:", mean_turns_random_dice) +""" + -- GitLab