From 0ce6ad9fe6f4c8f1eb57a513341a7ba1f37eb332 Mon Sep 17 00:00:00 2001 From: Tue Herlau <tuhe@dtu.dk> Date: Wed, 10 Jul 2024 18:21:11 +0200 Subject: [PATCH] updates --- irlc/__init__.py | 261 +++++ irlc/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 14164 bytes irlc/car/__init__.py | 1 + irlc/car/car_model.py | 304 ++++++ irlc/car/car_viewer.py | 51 + irlc/car/sym_map.py | 450 ++++++++ irlc/ex00/__init__.py | 2 + irlc/ex00/fruit_homework.py | 119 +++ irlc/ex01/__init__.py | 2 + .../ex01/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 232 bytes irlc/ex01/__pycache__/agent.cpython-311.pyc | Bin 0 -> 21673 bytes .../inventory_environment.cpython-311.pyc | Bin 0 -> 4674 bytes irlc/ex01/agent.py | 385 +++++++ irlc/ex01/bobs_friend.py | 59 ++ irlc/ex01/chess.py | 99 ++ irlc/ex01/inventory_environment.py | 71 ++ irlc/ex01/pacman_hardcoded.py | 60 ++ irlc/ex02/__init__.py | 2 + .../ex02/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 232 bytes irlc/ex02/__pycache__/dp.cpython-311.pyc | Bin 0 -> 3570 bytes .../ex02/__pycache__/dp_model.cpython-311.pyc | Bin 0 -> 9583 bytes .../graph_traversal.cpython-311.pyc | Bin 0 -> 4952 bytes .../__pycache__/inventory.cpython-311.pyc | Bin 0 -> 3722 bytes irlc/ex02/dp.py | 71 ++ irlc/ex02/dp_agent.py | 44 + irlc/ex02/dp_model.py | 185 ++++ irlc/ex02/flower_store.py | 27 + irlc/ex02/graph_traversal.py | 67 ++ irlc/ex02/inventory.py | 44 + irlc/ex03/__init__.py | 2 + .../ex03/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 232 bytes .../basic_pendulum.cpython-311.pyc | Bin 0 -> 2978 bytes .../__pycache__/control_cost.cpython-311.pyc | Bin 0 -> 16900 bytes .../__pycache__/control_model.cpython-311.pyc | Bin 0 -> 27734 bytes irlc/ex03/basic_pendulum.py | 39 + irlc/ex03/control_cost.py | 289 +++++ irlc/ex03/control_model.py | 423 ++++++++ irlc/ex03/inventory_evaluation.py | 26 + irlc/ex03/kuramoto.py | 123 +++ irlc/ex03/toy_2d_control.py | 23 + irlc/ex04/__init__.py | 20 + .../ex04/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1505 bytes .../control_environment.cpython-311.pyc | Bin 0 -> 11647 bytes .../discrete_control_cost.cpython-311.pyc | Bin 0 -> 11299 bytes .../discrete_control_model.cpython-311.pyc | Bin 0 -> 17247 bytes .../model_linear_quadratic.cpython-311.pyc | Bin 0 -> 2638 bytes .../model_pendulum.cpython-311.pyc | Bin 0 -> 12005 bytes irlc/ex04/control_environment.py | 171 +++ irlc/ex04/discrete_control_cost.py | 195 ++++ irlc/ex04/discrete_control_model.py | 346 ++++++ irlc/ex04/discrete_kuramoto.py | 101 ++ irlc/ex04/locomotive.py | 105 ++ irlc/ex04/model_harmonic.py | 113 ++ irlc/ex04/model_linear_quadratic.py | 29 + irlc/ex04/model_pendulum.py | 164 +++ irlc/ex04/pid.py | 60 ++ irlc/ex04/pid_car.py | 61 ++ irlc/ex04/pid_locomotive_agent.py | 70 ++ irlc/ex04/pid_lunar.py | 136 +++ irlc/ex04/pid_pendulum.py | 74 ++ irlc/ex05/__init__.py | 2 + .../ex05/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 232 bytes irlc/ex05/__pycache__/direct.cpython-311.pyc | Bin 0 -> 14745 bytes irlc/ex05/direct.py | 370 +++++++ irlc/ex05/direct_agent.py | 77 ++ irlc/ex05/direct_brachistochrone.py | 59 ++ irlc/ex05/direct_cartpole_kelly.py | 56 + irlc/ex05/direct_cartpole_time.py | 28 + irlc/ex05/direct_pendulum.py | 27 + irlc/ex05/direct_plot.py | 82 ++ irlc/ex05/model_brachistochrone.py | 55 + irlc/ex05/model_cartpole.py | 173 +++ irlc/ex06/__init__.py | 2 + .../ex06/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 232 bytes irlc/ex06/__pycache__/dlqr.cpython-311.pyc | Bin 0 -> 8856 bytes irlc/ex06/boeing_lqr.py | 85 ++ irlc/ex06/dlqr.py | 207 ++++ irlc/ex06/dlqr_check.py | 40 + irlc/ex06/lqr_agent.py | 54 + irlc/ex06/lqr_pid.py | 79 ++ irlc/ex06/model_boeing.py | 62 ++ irlc/ex06/model_rendevouz.py | 95 ++ irlc/ex07/__init__.py | 2 + .../ex07/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 232 bytes irlc/ex07/__pycache__/ilqr.cpython-311.pyc | Bin 0 -> 10002 bytes irlc/ex07/ilqr.py | 273 +++++ irlc/ex07/ilqr_agent.py | 56 + irlc/ex07/ilqr_cartpole.py | 83 ++ irlc/ex07/ilqr_cartpole_agent.py | 43 + irlc/ex07/ilqr_pendulum.py | 68 ++ irlc/ex07/ilqr_pendulum_agent.py | 63 ++ irlc/ex07/ilqr_rendevoyz.py | 5 + irlc/ex07/ilqr_rendovouz_basic.py | 97 ++ irlc/ex07/linearization_agent.py | 67 ++ irlc/ex08/__init__.py | 2 + .../ex08/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 232 bytes irlc/ex08/__pycache__/bandits.cpython-311.pyc | Bin 0 -> 12883 bytes .../__pycache__/simple_agents.cpython-311.pyc | Bin 0 -> 3703 bytes irlc/ex08/bandit_example.py | 27 + irlc/ex08/bandits.py | 216 ++++ irlc/ex08/gradient_agent.py | 48 + irlc/ex08/grand_bandit_race.py | 78 ++ irlc/ex08/nonstationary.py | 62 ++ irlc/ex08/simple_agents.py | 57 + irlc/ex08/ucb_agent.py | 45 + irlc/ex09/__init__.py | 2 + .../ex09/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 232 bytes irlc/ex09/__pycache__/mdp.cpython-311.pyc | Bin 0 -> 17378 bytes .../__pycache__/mdp_warmup.cpython-311.pyc | Bin 0 -> 3718 bytes .../ex09/__pycache__/rl_agent.cpython-311.pyc | Bin 0 -> 14871 bytes .../value_iteration.cpython-311.pyc | Bin 0 -> 3718 bytes .../value_iteration_agent.cpython-311.pyc | Bin 0 -> 2758 bytes irlc/ex09/gambler.py | 81 ++ irlc/ex09/mdp.py | 303 ++++++ irlc/ex09/mdp_warmup.py | 86 ++ irlc/ex09/policy_evaluation.py | 68 ++ irlc/ex09/policy_iteration.py | 63 ++ irlc/ex09/rl_agent.py | 212 ++++ irlc/ex09/small_gridworld.py | 39 + irlc/ex09/value_iteration.py | 73 ++ irlc/ex09/value_iteration_agent.py | 42 + irlc/ex10/__init__.py | 2 + irlc/ex10/blackjack/__init__.py | 1 + irlc/ex10/blackjack/mc_agent_blackjack.py | 48 + irlc/ex10/blackjack/mc_evaluate_blackjack.py | 93 ++ irlc/ex10/blackjack/random_walk_example.py | 112 ++ irlc/ex10/envs.py | 50 + irlc/ex10/mc_agent.py | 86 ++ irlc/ex10/mc_evaluate.py | 120 +++ irlc/ex10/question_td0.py | 36 + irlc/ex10/td0_evaluate.py | 43 + irlc/ex11/__init__.py | 2 + .../ex11/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 233 bytes .../feature_encoder.cpython-311.pyc | Bin 0 -> 21274 bytes irlc/ex11/__pycache__/q_agent.cpython-311.pyc | Bin 0 -> 4605 bytes irlc/ex11/feature_encoder.py | 402 +++++++ irlc/ex11/nstep_sarsa_agent.py | 84 ++ irlc/ex11/q_agent.py | 85 ++ irlc/ex11/sarsa_agent.py | 52 + irlc/ex11/semi_grad_q.py | 45 + irlc/ex11/semi_grad_sarsa.py | 52 + irlc/ex12/__init__.py | 2 + irlc/ex12/mountain_car.py | 155 +++ irlc/ex12/sarsa_lambda_agent.py | 68 ++ irlc/ex12/sarsa_lambda_open.py | 35 + irlc/ex12/semi_grad_nstep_sarsa.py | 53 + irlc/ex12/semi_grad_sarsa_lambda.py | 74 ++ irlc/ex13/__init__.py | 2 + .../ex13/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 233 bytes irlc/ex13/__pycache__/buffer.cpython-311.pyc | Bin 0 -> 5802 bytes .../__pycache__/dqn_network.cpython-311.pyc | Bin 0 -> 3213 bytes .../torch_networks.cpython-311.pyc | Bin 0 -> 9539 bytes irlc/ex13/buffer.py | 109 ++ irlc/ex13/deepq_agent.py | 130 +++ irlc/ex13/double_deepq_agent.py | 73 ++ irlc/ex13/dqn_network.py | 63 ++ irlc/ex13/duel_deepq_agent.py | 35 + irlc/ex13/dyna_q.py | 89 ++ irlc/ex13/maximization_bias_environment.py | 93 ++ irlc/ex13/maze_dyna_environment.py | 118 +++ irlc/ex13/tabular_double_q.py | 78 ++ irlc/ex13/torch_networks.py | 131 +++ irlc/exam/__init__.py | 2 + irlc/exam/exam2023spring/__init__.py | 1 + irlc/exam/exam2023spring/readme.md | 2 + irlc/exam/exam2023spring/solution/readme.md | 1 + irlc/exam/exam2024spring/__init__.py | 1 + irlc/exam/exam2024spring/readme.md | 2 + irlc/exam/midterm2023a/__init__.py | 1 + irlc/exam/midterm2023a/readme.md | 2 + irlc/exam/midterm2023a/solution/readme.md | 1 + irlc/exam/midterm2023b/__init__.py | 1 + irlc/exam/midterm2023b/readme.md | 2 + irlc/exam/midterm2023b/solution/readme.md | 1 + irlc/exam/readme.md | 15 + irlc/exam_tabular_examples/__init__.py | 1 + irlc/exam_tabular_examples/helper.py | 11 + .../lecture_10_mc_value_every.py | 9 + .../lecture_10_mc_value_first.py | 13 + .../sarsa_lambda_delay.py | 45 + .../sarsa_nstep_delay.py | 77 ++ .../exam_tabular_examples/tabular_examples.py | 78 ++ irlc/gridworld/__init__.py | 1 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 174 bytes .../gridworld_environments.cpython-311.pyc | Bin 0 -> 20009 bytes ...gridworld_graphics_display.cpython-311.pyc | Bin 0 -> 28983 bytes .../__pycache__/gridworld_mdp.cpython-311.pyc | Bin 0 -> 4836 bytes irlc/gridworld/demo_agents/__init__.py | 1 + irlc/gridworld/demo_agents/hidden_agents.py | 235 +++++ irlc/gridworld/gridworld_environments.py | 362 +++++++ irlc/gridworld/gridworld_graphics_display.py | 543 ++++++++++ irlc/gridworld/gridworld_mdp.py | 71 ++ irlc/lectures/__init__.py | 1 + irlc/lectures/lec01/__init__.py | 1 + irlc/lectures/lec01/lecture_01_car_random.py | 10 + irlc/lectures/lec01/lecture_01_pacman.py | 15 + .../lec01/lecture_01_pendulum_random.py | 9 + irlc/lectures/lec02/__init__.py | 1 + .../lec02/lecture_02_dp_gridworld_short.py | 8 + irlc/lectures/lec02/lecture_02_frozen_lake.py | 13 + .../lec02/lecture_02_frozen_long_slippery.py | 8 + .../lec02/lecture_02_keyboard_pacman_g1.py | 23 + .../lec02/lecture_02_keyboard_pacman_g2.py | 6 + .../lec02/lecture_02_optimal_dp_g0.py | 38 + .../lec02/lecture_02_optimal_dp_g1.py | 25 + .../lec02/lecture_02_optimal_dp_g2.py | 6 + irlc/lectures/lec03/__init__.py | 1 + irlc/lectures/lec03/ex_03_search.py | 18 + irlc/lectures/lec03/lecture_03_alphab.py | 7 + .../lecture_03_dotsearch_astar_manhattan.py | 8 + .../lec03/lecture_03_dotsearch_bfs.py | 9 + .../lec03/lecture_03_dotsearch_dfs.py | 9 + .../lectures/lec03/lecture_03_dotsearch_dp.py | 12 + irlc/lectures/lec03/lecture_03_expectimax.py | 7 + irlc/lectures/lec03/lecture_03_minimax.py | 35 + .../lec03/lecture_03_squaresearch_bfs.py | 12 + .../lec03/lecture_03_tricksearch_astar.py | 10 + .../lec03/lecture_03_tricksearch_bfs.py | 21 + .../lec03/lecture_03_tricksearch_dfs.py | 10 + ...enaigym.video.0.8068.video000000.meta.json | 1 + .../openaigym.video.0.8068.video000000.mp4 | Bin 0 -> 48 bytes irlc/lectures/lec04/__init__.py | 1 + .../lec04/lecture_04_car_basic_pid.py | 20 + irlc/lectures/lec04/lecture_04_cartpole_A.py | 10 + irlc/lectures/lec04/lecture_04_cartpole_B.py | 14 + irlc/lectures/lec04/lecture_04_harmonic.py | 14 + irlc/lectures/lec04/lecture_04_lunar.py | 15 + .../lec04/lecture_04_pendulum_random.py | 8 + irlc/lectures/lec04/lecture_04_pid_d.py | 5 + irlc/lectures/lec04/lecture_04_pid_iA.py | 6 + irlc/lectures/lec04/lecture_04_pid_iB.py | 6 + irlc/lectures/lec04/lecture_04_pid_p.py | 19 + irlc/lectures/lec05/__init__.py | 1 + .../lec05/lecture_05_carpole_random.py | 9 + .../lec05/lecture_05_cartpole_kelly.py | 10 + .../lec05/lecture_05_cartpole_time.py | 11 + irlc/lectures/lec06/__init__.py | 1 + .../lectures/lec06/lecture6_lqr_locomotive.py | 37 + .../lec06/lecture_06_cartpole_ilqr.py | 47 + irlc/lectures/lec06/lecture_06_linearize.py | 6 + irlc/lectures/lec06/lecture_06_linearize_b.py | 18 + .../lec06/lecture_06_pendulum_bilqr_L.py | 7 + .../lec06/lecture_06_pendulum_bilqr_ubar.py | 66 ++ .../lec06/lecture_06_pendulum_ilqr_L.py | 5 + .../lec06/lecture_06_pendulum_ilqr_ubar.py | 5 + irlc/lectures/lec07/__init__.py | 1 + irlc/lectures/lec07/lecture_07_boing_lqr.py | 19 + .../lec07/lecture_07_boing_lqr_mpc.py | 14 + .../lec07/lecture_07_boing_lqr_mpc_local.py | 9 + .../lec07/lecture_07_boing_lqr_mpc_optim.py | 8 + irlc/lectures/lec07/lecture_07_lmpc.py | 5 + .../lec07/lecture_07_pendulum_mpc_lqr.py | 4 + .../lec07/lecture_07_pendulum_mpc_optm.py | 4 + .../lec07/lecture_07_pendulum_simple.py | 41 + .../2021-03-19_08-21-20.207/log.txt | 17 + .../2021-03-19_08-21-20.207/trajectories.pkl | Bin 0 -> 75688 bytes .../2022-03-17_14-16-10.758/log.txt | 17 + .../2022-03-17_14-16-10.758/trajectories.pkl | Bin 0 -> 74800 bytes .../2023-03-17_08-13-45.172/log.txt | 17 + .../2023-03-17_08-13-45.172/trajectories.pkl | Bin 0 -> 75880 bytes irlc/lectures/lec07/tmp-pdfcrop-10536.tex | 131 +++ irlc/lectures/lec07/tmp-pdfcrop-12592.tex | 131 +++ irlc/lectures/lec08/__init__.py | 1 + irlc/lectures/lec08/demo_bandit.py | 25 + irlc/lectures/lec08/demo_bandit_ucb.py | 26 + irlc/lectures/lec09/__init__.py | 1 + irlc/lectures/lec09/unf_frozenlake.py | 11 + irlc/lectures/lec09/unf_gridworld.py | 12 + .../lec09/unf_policy_evaluation_frozen.py | 20 + .../lec09/unf_policy_evaluation_gridworld.py | 20 + ...nf_policy_evaluation_stepwise_gridworld.py | 20 + .../unf_policy_improvement_frozenlake.py | 7 + .../lec09/unf_policy_improvement_gridworld.py | 7 + irlc/lectures/lec09/unf_vi_frozenlake.py | 17 + irlc/lectures/lec09/unf_vi_gridworld.py | 19 + .../lec09/unf_vi_gridworld_stepwise.py | 16 + irlc/lectures/lec10/__init__.py | 1 + ...ture_10_mc_action_value_first_one_state.py | 60 ++ ...re_10_mc_action_value_first_one_state_b.py | 21 + irlc/lectures/lec10/lecture_10_mc_control.py | 13 + irlc/lectures/lec10/lecture_10_mc_corner.py | 10 + .../lec10/lecture_10_mc_onestate_every.py | 12 + .../lec10/lecture_10_mc_onestate_first.py | 18 + .../lec10/lecture_10_mc_q_estimation.py | 40 + .../lec10/lecture_10_mc_value_every.py | 11 + .../lecture_10_mc_value_every_one_state.py | 58 + .../lec10/lecture_10_mc_value_first.py | 32 + .../lecture_10_mc_value_first_one_state.py | 64 ++ .../lecture_10_mc_value_first_one_state_b.py | 58 + irlc/lectures/lec10/lecture_10_td_corner.py | 9 + irlc/lectures/lec10/lecture_10_td_keyboard.py | 9 + .../lec10/unf_gridworld_action_value.py | 42 + irlc/lectures/lec10/unf_gridworld_value.py | 42 + irlc/lectures/lec11/__init__.py | 1 + irlc/lectures/lec11/exam_sol.py | 11 + irlc/lectures/lec11/lecture_10_grid_lin_q.py | 10 + irlc/lectures/lec11/lecture_10_sarsa_open.py | 12 + irlc/lectures/lec11/lecture_11_nstep_open.py | 11 + .../lectures/lec11/lecture_11_pacman_lin_q.py | 32 + irlc/lectures/lec11/lecture_11_pacman_q.py | 35 + irlc/lectures/lec11/lecture_11_q.py | 10 + irlc/lectures/lec11/lecture_11_q_cliff.py | 18 + irlc/lectures/lec11/lecture_11_q_open.py | 12 + irlc/lectures/lec11/lecture_11_sarsa.py | 10 + irlc/lectures/lec11/lecture_11_sarsa_cliff.py | 33 + irlc/lectures/lec12/__init__.py | 1 + irlc/lectures/lec12/lecture_12_mc_open.py | 19 + irlc/lectures/lec12/lecture_12_pacman.py | 21 + .../lec12/lecture_12_sarsa_lamda_open.py | 6 + irlc/lectures/lec12/lecture_12_sarsa_nstep.py | 13 + irlc/lectures/lec12/lecture_12_sarsa_open.py | 11 + irlc/lectures/lec13/double_q_viz.py | 71 ++ irlc/lectures/lec13/lecture_13_Q_maze.py | 14 + irlc/lectures/lec13/lecture_13_Q_open.py | 6 + .../lec13/lecture_13_dyna_q_5_maze.py | 10 + .../lec13/lecture_13_sarsa_lambda_maze.py | 6 + irlc/lectures/readme.md | 6 + irlc/pacman/__init__.py | 2 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 257 bytes .../__pycache__/gamestate.cpython-311.pyc | Bin 0 -> 33196 bytes .../pacman/__pycache__/layout.cpython-311.pyc | Bin 0 -> 8491 bytes .../pacman_environment.cpython-311.pyc | Bin 0 -> 11293 bytes .../pacman_graphics_display.cpython-311.pyc | Bin 0 -> 45736 bytes .../pacman_text_display.cpython-311.pyc | Bin 0 -> 3505 bytes .../__pycache__/pacman_utils.cpython-311.pyc | Bin 0 -> 35617 bytes irlc/pacman/feature_extractor.py | 109 ++ irlc/pacman/gamestate.py | 812 ++++++++++++++ irlc/pacman/layout.py | 157 +++ irlc/pacman/layouts/bigCorners.lay | 37 + irlc/pacman/layouts/bigHunt.lay | 20 + irlc/pacman/layouts/bigMaze.lay | 37 + irlc/pacman/layouts/bigSafeSearch.lay | 8 + irlc/pacman/layouts/bigSearch.lay | 15 + irlc/pacman/layouts/boxSearch.lay | 14 + irlc/pacman/layouts/capsuleClassic.lay | 7 + irlc/pacman/layouts/contestClassic.lay | 9 + irlc/pacman/layouts/contoursMaze.lay | 11 + irlc/pacman/layouts/greedySearch.lay | 8 + irlc/pacman/layouts/mediumClassic.lay | 11 + irlc/pacman/layouts/mediumCorners.lay | 14 + irlc/pacman/layouts/mediumDottedMaze.lay | 18 + irlc/pacman/layouts/mediumGrid.lay | 7 + irlc/pacman/layouts/mediumMaze.lay | 18 + irlc/pacman/layouts/mediumSafeSearch.lay | 6 + irlc/pacman/layouts/mediumScaryMaze.lay | 18 + irlc/pacman/layouts/mediumSearch.lay | 8 + irlc/pacman/layouts/minimaxClassic.lay | 5 + irlc/pacman/layouts/oddSearch.lay | 7 + irlc/pacman/layouts/oneHunt.lay | 16 + irlc/pacman/layouts/openClassic.lay | 9 + irlc/pacman/layouts/openHunt.lay | 13 + irlc/pacman/layouts/openMaze.lay | 23 + irlc/pacman/layouts/openSearch.lay | 7 + irlc/pacman/layouts/originalClassic.lay | 27 + irlc/pacman/layouts/powerClassic.lay | 7 + irlc/pacman/layouts/smallClassic.lay | 7 + irlc/pacman/layouts/smallGrid.lay | 7 + irlc/pacman/layouts/smallHunt.lay | 8 + irlc/pacman/layouts/smallMaze.lay | 10 + irlc/pacman/layouts/smallSafeSearch.lay | 15 + irlc/pacman/layouts/smallSearch.lay | 5 + irlc/pacman/layouts/testClassic.lay | 10 + irlc/pacman/layouts/testMaze.lay | 3 + irlc/pacman/layouts/testSearch.lay | 5 + irlc/pacman/layouts/tinyCorners.lay | 8 + irlc/pacman/layouts/tinyMaze.lay | 7 + irlc/pacman/layouts/tinySafeSearch.lay | 7 + irlc/pacman/layouts/tinySearch.lay | 7 + irlc/pacman/layouts/trappedClassic.lay | 5 + irlc/pacman/layouts/trickyClassic.lay | 13 + irlc/pacman/layouts/trickySearch.lay | 7 + irlc/pacman/pacman_environment.py | 243 +++++ irlc/pacman/pacman_graphics_display.py | 700 +++++++++++++ irlc/pacman/pacman_resources.py | 266 +++++ irlc/pacman/pacman_text_display.py | 64 ++ irlc/pacman/pacman_utils.py | 680 ++++++++++++ irlc/project0/__init__.py | 1 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 173 bytes irlc/project0/fruit_project_grade.py | 4 + irlc/project0/fruit_project_tests.py | 121 +++ .../fruit_project_tests_complete_grade.py | 4 + .../unitgrade_data/AdditionQuestion.pkl | Bin 0 -> 161 bytes irlc/project0/unitgrade_data/BasicClass.pkl | Bin 0 -> 446 bytes irlc/project0/unitgrade_data/ClassUse.pkl | Bin 0 -> 1380 bytes .../project0/unitgrade_data/FruitsOrdered.pkl | Bin 0 -> 307 bytes irlc/project0/unitgrade_data/Inheritance.pkl | Bin 0 -> 875 bytes irlc/project0/unitgrade_data/MeanOfDie.pkl | Bin 0 -> 546 bytes .../unitgrade_data/MisterfyQuestion.pkl | Bin 0 -> 490 bytes irlc/project1/Latex/02465project1_handin.tex | 107 ++ irlc/project1/Latex/figures/kiosk1.pdf | Bin 0 -> 7780 bytes irlc/project1/Latex/figures/kiosk2.pdf | Bin 0 -> 8067 bytes irlc/project1/Latex/figures/your_answer.pdf | Bin 0 -> 6498 bytes irlc/project1/__init__.py | 1 + irlc/project1/kiosk.py | 70 ++ irlc/project1/pacman.py | 169 +++ irlc/project1/pacman_demo1.py | 53 + irlc/project1/pacman_demo2.py | 11 + irlc/project1/project1_grade.py | 4 + irlc/project1/project1_tests.py | 377 +++++++ .../project1/project1_tests_complete_grade.py | 4 + irlc/project1/unitgrade_data/Kiosk1.pkl | Bin 0 -> 1975 bytes irlc/project1/unitgrade_data/Kiosk2.pkl | Bin 0 -> 11083 bytes irlc/project1/unitgrade_data/Kiosk3.pkl | Bin 0 -> 11083 bytes irlc/project1/unitgrade_data/Pacman1.pkl | Bin 0 -> 1605 bytes irlc/project1/unitgrade_data/Pacman10.pkl | Bin 0 -> 32230 bytes irlc/project1/unitgrade_data/Pacman11.pkl | Bin 0 -> 486956 bytes irlc/project1/unitgrade_data/Pacman12.pkl | Bin 0 -> 11970 bytes irlc/project1/unitgrade_data/Pacman3.pkl | Bin 0 -> 32230 bytes irlc/project1/unitgrade_data/Pacman4.pkl | Bin 0 -> 486956 bytes irlc/project1/unitgrade_data/Pacman6a.pkl | Bin 0 -> 15361 bytes irlc/project1/unitgrade_data/Pacman6b.pkl | Bin 0 -> 15361 bytes irlc/project1/unitgrade_data/Pacman6c.pkl | Bin 0 -> 15361 bytes irlc/project1/unitgrade_data/Pacman7a.pkl | Bin 0 -> 32230 bytes irlc/project1/unitgrade_data/Pacman7b.pkl | Bin 0 -> 32230 bytes irlc/project1/unitgrade_data/Pacman8a.pkl | Bin 0 -> 486956 bytes irlc/project1/unitgrade_data/Pacman8b.pkl | Bin 0 -> 486956 bytes irlc/project1/unitgrade_data/Pacman9.pkl | Bin 0 -> 11970 bytes irlc/project2/Latex/02465project2_handin.tex | 146 +++ irlc/project2/Latex/figures/your_answer.pdf | Bin 0 -> 6498 bytes irlc/project2/__init__.py | 2 + irlc/project2/project2_grade.py | 4 + irlc/project2/project2_tests.py | 184 ++++ .../project2/project2_tests_complete_grade.py | 4 + irlc/project2/r2d2.py | 210 ++++ irlc/project2/unitgrade_data/R2D2Direct.pkl | Bin 0 -> 17340 bytes .../unitgrade_data/R2D2Linearization.pkl | Bin 0 -> 10767 bytes .../project2/unitgrade_data/R2D2Problem15.pkl | Bin 0 -> 5640 bytes irlc/project2/unitgrade_data/R2D2_MPC.pkl | Bin 0 -> 10904 bytes irlc/project2/unitgrade_data/YodaProblem1.pkl | Bin 0 -> 1139 bytes irlc/project2/unitgrade_data/YodaProblem2.pkl | Bin 0 -> 1991 bytes irlc/project2/unitgrade_data/YodaProblem3.pkl | Bin 0 -> 3483 bytes irlc/project2/unitgrade_data/YodaProblem6.pkl | Bin 0 -> 635 bytes irlc/project2/unitgrade_data/YodaProblem7.pkl | Bin 0 -> 693 bytes irlc/project2/utils.py | 53 + irlc/project2/yoda.py | 97 ++ irlc/project3/Latex/02465project3_handin.tex | 74 ++ irlc/project3/Latex/figures/your_answer.pdf | Bin 0 -> 6498 bytes irlc/project3/__init__.py | 2 + irlc/project3/jarjar.py | 44 + irlc/project3/project3_grade.py | 4 + irlc/project3/project3_tests.py | 142 +++ .../project3/project3_tests_complete_grade.py | 4 + irlc/project3/rebels.py | 58 + irlc/project3/rebels_demo.py | 50 + .../unitgrade_data/JarJarPiOptimal.pkl | Bin 0 -> 606 bytes .../unitgrade_data/JarJarQ0Estimated.pkl | Bin 0 -> 1252 bytes irlc/project3/unitgrade_data/JarJarQExact.pkl | Bin 0 -> 4156 bytes irlc/project3/unitgrade_data/RebelsBridge.pkl | Bin 0 -> 14048 bytes irlc/project3/unitgrade_data/RebelsSimple.pkl | Bin 0 -> 14306 bytes irlc/project3i/__init__.py | 2 + irlc/project3i/project3_individual_grade.py | 4 + irlc/project3i/project3_individual_tests.py | 61 ++ ...roject3_individual_tests_complete_grade.py | 4 + irlc/project3i/sarlacc.py | 120 +++ .../project3i/unitgrade_data/SarlacReturn.pkl | Bin 0 -> 7307 bytes .../unitgrade_data/SarlaccGameRules.pkl | Bin 0 -> 3332 bytes irlc/tests/__init__.py | 1 + irlc/tests/tests_week01.py | 132 +++ irlc/tests/tests_week02.py | 270 +++++ irlc/tests/tests_week03.py | 88 ++ irlc/tests/tests_week04.py | 131 +++ irlc/tests/tests_week05.py | 114 ++ irlc/tests/tests_week06.py | 147 +++ irlc/tests/tests_week07.py | 62 ++ irlc/tests/tests_week08.py | 278 +++++ irlc/tests/tests_week09.py | 314 ++++++ irlc/tests/tests_week10.py | 132 +++ irlc/tests/tests_week11.py | 199 ++++ irlc/tests/tests_week12.py | 64 ++ irlc/tests/tests_week13.py | 76 ++ irlc/tests/unitgrade_data/BanditQuestion.pkl | Bin 0 -> 96266 bytes .../BrachistochroneConstrainedQuestion.pkl | Bin 0 -> 7561 bytes .../BrachistochroneQuestion.pkl | Bin 0 -> 7561 bytes .../unitgrade_data/CartpoleCostQuestion.pkl | Bin 0 -> 7561 bytes .../unitgrade_data/CartpoleTimeQuestion.pkl | Bin 0 -> 7561 bytes .../unitgrade_data/DirectAgentPendulum.pkl | Bin 0 -> 230 bytes irlc/tests/unitgrade_data/DirectMethods.pkl | Bin 0 -> 1352 bytes .../unitgrade_data/DirectSolverQuestion.pkl | Bin 0 -> 7561 bytes irlc/tests/unitgrade_data/DoubleQQuestion.pkl | Bin 0 -> 278 bytes irlc/tests/unitgrade_data/DynaQQuestion.pkl | Bin 0 -> 276 bytes .../Exam5InventoryEvaluation.pkl | Bin 0 -> 217 bytes irlc/tests/unitgrade_data/Exam6Toy2d.pkl | Bin 0 -> 282 bytes .../ExamQuestion7FlowersStore.pkl | Bin 0 -> 182 bytes irlc/tests/unitgrade_data/ExamQuestionTD0.pkl | Bin 0 -> 468 bytes .../unitgrade_data/GradientBanditQuestion.pkl | Bin 0 -> 96266 bytes .../unitgrade_data/ILQRAgentQuestion.pkl | Bin 0 -> 325 bytes .../unitgrade_data/ILQRPendulumQuestion.pkl | Bin 0 -> 297 bytes .../unitgrade_data/LinearQAgentQuestion.pkl | Bin 0 -> 28763 bytes .../LinearSarsaAgentQuestion.pkl | Bin 0 -> 28767 bytes .../LinearSarsaLambdaAgentQuestion.pkl | Bin 0 -> 28773 bytes .../LinearSarsaNstepAgentQuestion.pkl | Bin 0 -> 28772 bytes irlc/tests/unitgrade_data/MCAgentQuestion.pkl | Bin 0 -> 4712 bytes .../unitgrade_data/MCEvaluationQuestion.pkl | Bin 0 -> 2394 bytes .../unitgrade_data/NStepSarsaQuestion.pkl | Bin 0 -> 281 bytes .../NonstatiotnaryAgentQuestion.pkl | Bin 0 -> 96266 bytes .../tests/unitgrade_data/PendulumQuestion.pkl | Bin 0 -> 7561 bytes .../unitgrade_data/Problem1BobsFriend.pkl | Bin 0 -> 170 bytes .../Problem1DiscreteKuromoto.pkl | Bin 0 -> 569 bytes .../tests/unitgrade_data/Problem1Kuramoto.pkl | Bin 0 -> 3013 bytes .../unitgrade_data/Problem1SmallGraph.pkl | Bin 0 -> 3834 bytes .../unitgrade_data/Problem1_to_3_Warmup.pkl | Bin 0 -> 497 bytes .../unitgrade_data/Problem2BobsPolicy.pkl | Bin 0 -> 368 bytes .../Problem2DeterministicDP.pkl | Bin 0 -> 203 bytes .../Problem3InventoryInventoryEnvironment.pkl | Bin 0 -> 322 bytes irlc/tests/unitgrade_data/Problem3LQR.pkl | Bin 0 -> 2024 bytes irlc/tests/unitgrade_data/Problem3PID.pkl | Bin 0 -> 334 bytes .../unitgrade_data/Problem3StochasticDP.pkl | Bin 0 -> 345 bytes irlc/tests/unitgrade_data/Problem4DPAgent.pkl | Bin 0 -> 121 bytes .../unitgrade_data/Problem4InventoryTrain.pkl | Bin 0 -> 241 bytes .../tests/unitgrade_data/Problem4LQRAgent.pkl | Bin 0 -> 442 bytes .../tests/unitgrade_data/Problem4PIDAgent.pkl | Bin 0 -> 4672 bytes .../Problem4PolicyEvaluation.pkl | Bin 0 -> 620 bytes .../Problem5PacmanHardcoded.pkl | Bin 0 -> 125 bytes .../Problem5PolicyIteration.pkl | Bin 0 -> 401 bytes .../unitgrade_data/Problem5_6_Boeing.pkl | Bin 0 -> 4218 bytes .../Problem6ChessTournament.pkl | Bin 0 -> 197 bytes .../unitgrade_data/Problem6ValueIteration.pkl | Bin 0 -> 399 bytes irlc/tests/unitgrade_data/Problem7PIDCar.pkl | Bin 0 -> 419 bytes .../unitgrade_data/Problem7_8_PidLQR.pkl | Bin 0 -> 414 bytes .../Problem8ValueIterationAgent.pkl | Bin 0 -> 323 bytes irlc/tests/unitgrade_data/Problem9Gambler.pkl | Bin 0 -> 1082 bytes irlc/tests/unitgrade_data/QAgentQuestion.pkl | Bin 0 -> 6895 bytes irlc/tests/unitgrade_data/RendevouzItem.pkl | Bin 0 -> 602 bytes .../unitgrade_data/SarsaLambdaQuestion.pkl | Bin 0 -> 279 bytes irlc/tests/unitgrade_data/SarsaQuestion.pkl | Bin 0 -> 276 bytes irlc/tests/unitgrade_data/TD0Question.pkl | Bin 0 -> 8326 bytes .../tests/unitgrade_data/UCBAgentQuestion.pkl | Bin 0 -> 96266 bytes irlc/update_files.py | 109 ++ irlc/utils/__init__.py | 1 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 170 bytes irlc/utils/__pycache__/common.cpython-311.pyc | Bin 0 -> 14184 bytes .../graphics_util_pygame.cpython-311.pyc | Bin 0 -> 28061 bytes .../__pycache__/irlc_plot.cpython-311.pyc | Bin 0 -> 13152 bytes .../utils/__pycache__/lazylog.cpython-311.pyc | Bin 0 -> 7720 bytes .../player_wrapper.cpython-311.pyc | Bin 0 -> 14670 bytes irlc/utils/__pycache__/ptext.cpython-311.pyc | Bin 0 -> 52471 bytes irlc/utils/__pycache__/timer.cpython-311.pyc | Bin 0 -> 3743 bytes irlc/utils/common.py | 206 ++++ irlc/utils/graphics/car.png | Bin 0 -> 21921 bytes irlc/utils/graphics/dtu_icon.png | Bin 0 -> 18108 bytes irlc/utils/graphics/locomotive.png | Bin 0 -> 73324 bytes irlc/utils/graphics_util_pygame.py | 415 ++++++++ irlc/utils/irlc_plot.py | 266 +++++ irlc/utils/lazylog.py | 140 +++ irlc/utils/minigrid.py | 102 ++ irlc/utils/player_wrapper.py | 370 +++++++ irlc/utils/ptext.py | 991 ++++++++++++++++++ irlc/utils/timer.py | 45 + requirements_conda.txt | 16 + requirements_pip.txt | 3 + solutions/ex00/fruit_homework_TODO_1.py | 1 + solutions/ex00/fruit_homework_TODO_2.py | 1 + solutions/ex00/fruit_homework_TODO_3.py | 1 + solutions/ex00/fruit_homework_TODO_4.py | 1 + solutions/ex00/fruit_homework_TODO_5.py | 1 + solutions/ex00/fruit_homework_TODO_6.py | 1 + solutions/ex00/fruit_homework_TODO_7.py | 2 + solutions/ex01/bobs_friend_TODO_1.py | 3 + solutions/ex01/bobs_friend_TODO_2.py | 9 + solutions/ex01/bobs_friend_TODO_3.py | 1 + solutions/ex01/bobs_friend_TODO_4.py | 1 + solutions/ex01/chess_TODO_1.py | 1 + solutions/ex01/chess_TODO_2.py | 7 + solutions/ex01/chess_TODO_3.py | 1 + solutions/ex01/chess_TODO_4.py | 1 + solutions/ex01/chess_TODO_5.py | 1 + .../ex01/inventory_environment_TODO_1.py | 5 + .../ex01/inventory_environment_TODO_2.py | 1 + .../ex01/inventory_environment_TODO_3.py | 7 + solutions/ex01/pacman_hardcoded_TODO_1.py | 7 + solutions/ex02/dp_TODO_1.py | 4 + solutions/ex02/dp_agent_TODO_1.py | 1 + solutions/ex02/flower_store_TODO_1.py | 23 + solutions/ex02/flower_store_TODO_2.py | 3 + solutions/ex02/flower_store_TODO_3.py | 3 + solutions/ex02/graph_traversal_TODO_1.py | 1 + solutions/ex02/graph_traversal_TODO_2.py | 1 + solutions/ex02/graph_traversal_TODO_3.py | 1 + solutions/ex02/inventory_TODO_1.py | 1 + solutions/ex03/inventory_evaluation_TODO_1.py | 2 + solutions/ex03/inventory_evaluation_TODO_2.py | 12 + solutions/ex03/kuramoto_TODO_1.py | 1 + solutions/ex03/kuramoto_TODO_2.py | 1 + solutions/ex03/kuramoto_TODO_3.py | 7 + solutions/ex03/toy_2d_control_TODO_1.py | 2 + solutions/ex03/toy_2d_control_TODO_2.py | 4 + solutions/ex04/discrete_kuramoto_TODO_1.py | 1 + solutions/ex04/discrete_kuramoto_TODO_2.py | 1 + solutions/ex04/discrete_kuramoto_TODO_3.py | 1 + solutions/ex04/model_pendulum_TODO_1.py | 1 + solutions/ex04/model_pendulum_TODO_2.py | 1 + solutions/ex04/pid_TODO_1.py | 6 + solutions/ex04/pid_TODO_2.py | 1 + solutions/ex04/pid_car_TODO_1.py | 2 + solutions/ex04/pid_car_TODO_2.py | 2 + solutions/ex04/pid_locomotive_agent_TODO_1.py | 1 + solutions/ex04/pid_locomotive_agent_TODO_2.py | 1 + solutions/ex04/pid_lunar_TODO_1.py | 2 + solutions/ex04/pid_pendulum_TODO_1.py | 2 + solutions/ex04/pid_pendulum_TODO_2.py | 1 + solutions/ex04/pid_pendulum_TODO_3.py | 1 + solutions/ex05/direct_TODO_1.py | 1 + solutions/ex05/direct_TODO_10.py | 1 + solutions/ex05/direct_TODO_2.py | 2 + solutions/ex05/direct_TODO_3.py | 2 + solutions/ex05/direct_TODO_4.py | 2 + solutions/ex05/direct_TODO_5.py | 2 + solutions/ex05/direct_TODO_6.py | 1 + solutions/ex05/direct_TODO_7.py | 1 + solutions/ex05/direct_TODO_8.py | 1 + solutions/ex05/direct_TODO_9.py | 3 + solutions/ex05/direct_agent_TODO_1.py | 1 + solutions/ex05/direct_agent_TODO_2.py | 7 + .../ex05/direct_cartpole_kelly_TODO_1.py | 2 + .../ex05/direct_cartpole_kelly_TODO_2.py | 2 + .../ex05/model_brachistochrone_TODO_1.py | 1 + .../ex05/model_brachistochrone_TODO_2.py | 3 + .../ex05/model_brachistochrone_TODO_3.py | 1 + solutions/ex06/boeing_lqr_TODO_1.py | 1 + solutions/ex06/boeing_lqr_TODO_2.py | 1 + solutions/ex06/boeing_lqr_TODO_3.py | 3 + solutions/ex06/boeing_lqr_TODO_4.py | 2 + solutions/ex06/dlqr_TODO_1.py | 2 + solutions/ex06/dlqr_TODO_2.py | 1 + solutions/ex06/dlqr_TODO_3.py | 4 + solutions/ex06/lqr_agent_TODO_1.py | 1 + solutions/ex06/lqr_agent_TODO_2.py | 1 + solutions/ex06/lqr_pid_TODO_1.py | 3 + solutions/ex06/lqr_pid_TODO_2.py | 1 + solutions/ex07/ilqr_TODO_1.py | 2 + solutions/ex07/ilqr_TODO_10.py | 1 + solutions/ex07/ilqr_TODO_11.py | 4 + solutions/ex07/ilqr_TODO_12.py | 4 + solutions/ex07/ilqr_TODO_13.py | 2 + solutions/ex07/ilqr_TODO_14.py | 3 + solutions/ex07/ilqr_TODO_15.py | 1 + solutions/ex07/ilqr_TODO_16.py | 1 + solutions/ex07/ilqr_TODO_2.py | 2 + solutions/ex07/ilqr_TODO_3.py | 1 + solutions/ex07/ilqr_TODO_4.py | 1 + solutions/ex07/ilqr_TODO_5.py | 2 + solutions/ex07/ilqr_TODO_6.py | 2 + solutions/ex07/ilqr_TODO_7.py | 1 + solutions/ex07/ilqr_TODO_8.py | 1 + solutions/ex07/ilqr_TODO_9.py | 1 + solutions/ex07/ilqr_agent_TODO_1.py | 1 + solutions/ex07/ilqr_pendulum_TODO_1.py | 1 + solutions/ex07/linearization_agent_TODO_1.py | 4 + solutions/ex07/linearization_agent_TODO_2.py | 1 + solutions/ex07/linearization_agent_TODO_3.py | 1 + solutions/ex08/bandits_TODO_1.py | 2 + solutions/ex08/gradient_agent_TODO_1.py | 9 + solutions/ex08/grand_bandit_race_TODO_1.py | 1 + solutions/ex08/grand_bandit_race_TODO_2.py | 5 + solutions/ex08/grand_bandit_race_TODO_3.py | 1 + solutions/ex08/grand_bandit_race_TODO_4.py | 1 + solutions/ex08/grand_bandit_race_TODO_5.py | 1 + solutions/ex08/grand_bandit_race_TODO_6.py | 1 + solutions/ex08/grand_bandit_race_TODO_7.py | 1 + solutions/ex08/grand_bandit_race_TODO_8.py | 1 + solutions/ex08/nonstationary_TODO_1.py | 2 + solutions/ex08/nonstationary_TODO_2.py | 2 + solutions/ex08/nonstationary_TODO_3.py | 1 + solutions/ex08/nonstationary_TODO_4.py | 4 + solutions/ex08/nonstationary_TODO_5.py | 1 + solutions/ex08/simple_agents_TODO_1.py | 2 + solutions/ex08/simple_agents_TODO_2.py | 1 + solutions/ex08/simple_agents_TODO_3.py | 2 + solutions/ex08/ucb_agent_TODO_1.py | 2 + solutions/ex08/ucb_agent_TODO_2.py | 3 + solutions/ex08/ucb_agent_TODO_3.py | 1 + solutions/ex09/gambler_TODO_1.py | 1 + solutions/ex09/gambler_TODO_2.py | 1 + solutions/ex09/gambler_TODO_3.py | 4 + solutions/ex09/jacks_car_rental_TODO_1.py | 3 + solutions/ex09/jacks_car_rental_TODO_2.py | 1 + solutions/ex09/jacks_car_rental_TODO_3.py | 1 + solutions/ex09/mdp_warmup_TODO_1.py | 1 + solutions/ex09/mdp_warmup_TODO_2.py | 1 + solutions/ex09/mdp_warmup_TODO_3.py | 1 + solutions/ex09/mdp_warmup_TODO_4.py | 1 + solutions/ex09/policy_evaluation_TODO_1.py | 2 + solutions/ex09/policy_iteration_TODO_1.py | 6 + solutions/ex09/value_iteration_TODO_1.py | 2 + solutions/ex09/value_iteration_TODO_2.py | 2 + .../ex09/value_iteration_agent_TODO_1.py | 1 + .../ex09/value_iteration_agent_TODO_2.py | 1 + solutions/ex10/mc_agent_TODO_1.py | 2 + solutions/ex10/mc_agent_TODO_2.py | 1 + solutions/ex10/mc_agent_TODO_3.py | 1 + solutions/ex10/mc_agent_TODO_4.py | 12 + solutions/ex10/mc_agent_blackjack_TODO_1.py | 1 + solutions/ex10/mc_evaluate_TODO_1.py | 2 + solutions/ex10/mc_evaluate_TODO_2.py | 1 + solutions/ex10/mc_evaluate_TODO_3.py | 1 + solutions/ex10/mc_evaluate_TODO_4.py | 3 + solutions/ex10/mc_evaluate_TODO_5.py | 1 + solutions/ex10/mc_evaluate_TODO_6.py | 1 + .../ex10/mc_evaluate_blackjack_TODO_1.py | 1 + .../ex10/mc_evaluate_blackjack_TODO_2.py | 2 + solutions/ex10/question_td0_TODO_1.py | 5 + solutions/ex10/question_td0_TODO_2.py | 6 + solutions/ex10/question_td0_TODO_3.py | 4 + solutions/ex10/random_walk_example_TODO_1.py | 1 + solutions/ex10/td0_evaluate_TODO_1.py | 3 + solutions/ex11/nstep_sarsa_agent_TODO_1.py | 4 + solutions/ex11/q_agent_TODO_1.py | 1 + solutions/ex11/q_agent_TODO_2.py | 3 + solutions/ex11/sarsa_agent_TODO_1.py | 1 + solutions/ex11/sarsa_agent_TODO_2.py | 1 + solutions/ex11/sarsa_agent_TODO_3.py | 1 + solutions/ex11/sarsa_agent_TODO_4.py | 2 + solutions/ex11/semi_grad_q_TODO_1.py | 4 + solutions/ex11/semi_grad_sarsa_TODO_1.py | 1 + solutions/ex11/semi_grad_sarsa_TODO_2.py | 4 + solutions/ex12/minigrid_wrappers_TODO_1.py | 1 + solutions/ex12/minigrid_wrappers_TODO_2.py | 2 + solutions/ex12/minigrid_wrappers_TODO_3.py | 1 + solutions/ex12/minigrid_wrappers_TODO_4.py | 1 + solutions/ex12/mountain_car_TODO_1.py | 16 + solutions/ex12/sarsa_lambda_agent_TODO_1.py | 1 + solutions/ex12/sarsa_lambda_agent_TODO_2.py | 1 + solutions/ex12/sarsa_lambda_agent_TODO_3.py | 1 + solutions/ex12/sarsa_lambda_agent_TODO_4.py | 2 + .../ex12/semi_grad_nstep_sarsa_TODO_1.py | 1 + .../ex12/semi_grad_nstep_sarsa_TODO_2.py | 1 + .../ex12/semi_grad_sarsa_lambda_TODO_1.py | 5 + solutions/ex13/deepq_agent_TODO_1.py | 3 + solutions/ex13/double_deepq_agent_TODO_1.py | 1 + solutions/ex13/double_deepq_agent_TODO_2.py | 5 + solutions/ex13/dyna_q_TODO_1.py | 1 + solutions/ex13/dyna_q_TODO_2.py | 2 + solutions/ex13/dyna_q_TODO_3.py | 1 + solutions/ex13/keras_networks_TODO_1.py | 6 + .../maximization_bias_environment_TODO_1.py | 1 + .../maximization_bias_environment_TODO_2.py | 1 + solutions/ex13/tabular_double_q_TODO_1.py | 1 + solutions/ex13/tabular_double_q_TODO_2.py | 4 + solutions/ex13/torch_networks_TODO_1.py | 4 + 739 files changed, 25796 insertions(+) create mode 100644 irlc/__init__.py create mode 100644 irlc/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/car/__init__.py create mode 100644 irlc/car/car_model.py create mode 100644 irlc/car/car_viewer.py create mode 100644 irlc/car/sym_map.py create mode 100644 irlc/ex00/__init__.py create mode 100644 irlc/ex00/fruit_homework.py create mode 100644 irlc/ex01/__init__.py create mode 100644 irlc/ex01/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/ex01/__pycache__/agent.cpython-311.pyc create mode 100644 irlc/ex01/__pycache__/inventory_environment.cpython-311.pyc create mode 100644 irlc/ex01/agent.py create mode 100644 irlc/ex01/bobs_friend.py create mode 100644 irlc/ex01/chess.py create mode 100644 irlc/ex01/inventory_environment.py create mode 100644 irlc/ex01/pacman_hardcoded.py create mode 100644 irlc/ex02/__init__.py create mode 100644 irlc/ex02/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/ex02/__pycache__/dp.cpython-311.pyc create mode 100644 irlc/ex02/__pycache__/dp_model.cpython-311.pyc create mode 100644 irlc/ex02/__pycache__/graph_traversal.cpython-311.pyc create mode 100644 irlc/ex02/__pycache__/inventory.cpython-311.pyc create mode 100644 irlc/ex02/dp.py create mode 100644 irlc/ex02/dp_agent.py create mode 100644 irlc/ex02/dp_model.py create mode 100644 irlc/ex02/flower_store.py create mode 100644 irlc/ex02/graph_traversal.py create mode 100644 irlc/ex02/inventory.py create mode 100644 irlc/ex03/__init__.py create mode 100644 irlc/ex03/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/ex03/__pycache__/basic_pendulum.cpython-311.pyc create mode 100644 irlc/ex03/__pycache__/control_cost.cpython-311.pyc create mode 100644 irlc/ex03/__pycache__/control_model.cpython-311.pyc create mode 100644 irlc/ex03/basic_pendulum.py create mode 100644 irlc/ex03/control_cost.py create mode 100644 irlc/ex03/control_model.py create mode 100644 irlc/ex03/inventory_evaluation.py create mode 100644 irlc/ex03/kuramoto.py create mode 100644 irlc/ex03/toy_2d_control.py create mode 100644 irlc/ex04/__init__.py create mode 100644 irlc/ex04/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/ex04/__pycache__/control_environment.cpython-311.pyc create mode 100644 irlc/ex04/__pycache__/discrete_control_cost.cpython-311.pyc create mode 100644 irlc/ex04/__pycache__/discrete_control_model.cpython-311.pyc create mode 100644 irlc/ex04/__pycache__/model_linear_quadratic.cpython-311.pyc create mode 100644 irlc/ex04/__pycache__/model_pendulum.cpython-311.pyc create mode 100644 irlc/ex04/control_environment.py create mode 100644 irlc/ex04/discrete_control_cost.py create mode 100644 irlc/ex04/discrete_control_model.py create mode 100644 irlc/ex04/discrete_kuramoto.py create mode 100644 irlc/ex04/locomotive.py create mode 100644 irlc/ex04/model_harmonic.py create mode 100644 irlc/ex04/model_linear_quadratic.py create mode 100644 irlc/ex04/model_pendulum.py create mode 100644 irlc/ex04/pid.py create mode 100644 irlc/ex04/pid_car.py create mode 100644 irlc/ex04/pid_locomotive_agent.py create mode 100644 irlc/ex04/pid_lunar.py create mode 100644 irlc/ex04/pid_pendulum.py create mode 100644 irlc/ex05/__init__.py create mode 100644 irlc/ex05/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/ex05/__pycache__/direct.cpython-311.pyc create mode 100644 irlc/ex05/direct.py create mode 100644 irlc/ex05/direct_agent.py create mode 100644 irlc/ex05/direct_brachistochrone.py create mode 100644 irlc/ex05/direct_cartpole_kelly.py create mode 100644 irlc/ex05/direct_cartpole_time.py create mode 100644 irlc/ex05/direct_pendulum.py create mode 100644 irlc/ex05/direct_plot.py create mode 100644 irlc/ex05/model_brachistochrone.py create mode 100644 irlc/ex05/model_cartpole.py create mode 100644 irlc/ex06/__init__.py create mode 100644 irlc/ex06/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/ex06/__pycache__/dlqr.cpython-311.pyc create mode 100644 irlc/ex06/boeing_lqr.py create mode 100644 irlc/ex06/dlqr.py create mode 100644 irlc/ex06/dlqr_check.py create mode 100644 irlc/ex06/lqr_agent.py create mode 100644 irlc/ex06/lqr_pid.py create mode 100644 irlc/ex06/model_boeing.py create mode 100644 irlc/ex06/model_rendevouz.py create mode 100644 irlc/ex07/__init__.py create mode 100644 irlc/ex07/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/ex07/__pycache__/ilqr.cpython-311.pyc create mode 100644 irlc/ex07/ilqr.py create mode 100644 irlc/ex07/ilqr_agent.py create mode 100644 irlc/ex07/ilqr_cartpole.py create mode 100644 irlc/ex07/ilqr_cartpole_agent.py create mode 100644 irlc/ex07/ilqr_pendulum.py create mode 100644 irlc/ex07/ilqr_pendulum_agent.py create mode 100644 irlc/ex07/ilqr_rendevoyz.py create mode 100644 irlc/ex07/ilqr_rendovouz_basic.py create mode 100644 irlc/ex07/linearization_agent.py create mode 100644 irlc/ex08/__init__.py create mode 100644 irlc/ex08/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/ex08/__pycache__/bandits.cpython-311.pyc create mode 100644 irlc/ex08/__pycache__/simple_agents.cpython-311.pyc create mode 100644 irlc/ex08/bandit_example.py create mode 100644 irlc/ex08/bandits.py create mode 100644 irlc/ex08/gradient_agent.py create mode 100644 irlc/ex08/grand_bandit_race.py create mode 100644 irlc/ex08/nonstationary.py create mode 100644 irlc/ex08/simple_agents.py create mode 100644 irlc/ex08/ucb_agent.py create mode 100644 irlc/ex09/__init__.py create mode 100644 irlc/ex09/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/ex09/__pycache__/mdp.cpython-311.pyc create mode 100644 irlc/ex09/__pycache__/mdp_warmup.cpython-311.pyc create mode 100644 irlc/ex09/__pycache__/rl_agent.cpython-311.pyc create mode 100644 irlc/ex09/__pycache__/value_iteration.cpython-311.pyc create mode 100644 irlc/ex09/__pycache__/value_iteration_agent.cpython-311.pyc create mode 100644 irlc/ex09/gambler.py create mode 100644 irlc/ex09/mdp.py create mode 100644 irlc/ex09/mdp_warmup.py create mode 100644 irlc/ex09/policy_evaluation.py create mode 100644 irlc/ex09/policy_iteration.py create mode 100644 irlc/ex09/rl_agent.py create mode 100644 irlc/ex09/small_gridworld.py create mode 100644 irlc/ex09/value_iteration.py create mode 100644 irlc/ex09/value_iteration_agent.py create mode 100644 irlc/ex10/__init__.py create mode 100644 irlc/ex10/blackjack/__init__.py create mode 100644 irlc/ex10/blackjack/mc_agent_blackjack.py create mode 100644 irlc/ex10/blackjack/mc_evaluate_blackjack.py create mode 100644 irlc/ex10/blackjack/random_walk_example.py create mode 100644 irlc/ex10/envs.py create mode 100644 irlc/ex10/mc_agent.py create mode 100644 irlc/ex10/mc_evaluate.py create mode 100644 irlc/ex10/question_td0.py create mode 100644 irlc/ex10/td0_evaluate.py create mode 100644 irlc/ex11/__init__.py create mode 100644 irlc/ex11/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/ex11/__pycache__/feature_encoder.cpython-311.pyc create mode 100644 irlc/ex11/__pycache__/q_agent.cpython-311.pyc create mode 100644 irlc/ex11/feature_encoder.py create mode 100644 irlc/ex11/nstep_sarsa_agent.py create mode 100644 irlc/ex11/q_agent.py create mode 100644 irlc/ex11/sarsa_agent.py create mode 100644 irlc/ex11/semi_grad_q.py create mode 100644 irlc/ex11/semi_grad_sarsa.py create mode 100644 irlc/ex12/__init__.py create mode 100644 irlc/ex12/mountain_car.py create mode 100644 irlc/ex12/sarsa_lambda_agent.py create mode 100644 irlc/ex12/sarsa_lambda_open.py create mode 100644 irlc/ex12/semi_grad_nstep_sarsa.py create mode 100644 irlc/ex12/semi_grad_sarsa_lambda.py create mode 100644 irlc/ex13/__init__.py create mode 100644 irlc/ex13/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/ex13/__pycache__/buffer.cpython-311.pyc create mode 100644 irlc/ex13/__pycache__/dqn_network.cpython-311.pyc create mode 100644 irlc/ex13/__pycache__/torch_networks.cpython-311.pyc create mode 100644 irlc/ex13/buffer.py create mode 100644 irlc/ex13/deepq_agent.py create mode 100644 irlc/ex13/double_deepq_agent.py create mode 100644 irlc/ex13/dqn_network.py create mode 100644 irlc/ex13/duel_deepq_agent.py create mode 100644 irlc/ex13/dyna_q.py create mode 100644 irlc/ex13/maximization_bias_environment.py create mode 100644 irlc/ex13/maze_dyna_environment.py create mode 100644 irlc/ex13/tabular_double_q.py create mode 100644 irlc/ex13/torch_networks.py create mode 100644 irlc/exam/__init__.py create mode 100644 irlc/exam/exam2023spring/__init__.py create mode 100644 irlc/exam/exam2023spring/readme.md create mode 100644 irlc/exam/exam2023spring/solution/readme.md create mode 100644 irlc/exam/exam2024spring/__init__.py create mode 100644 irlc/exam/exam2024spring/readme.md create mode 100644 irlc/exam/midterm2023a/__init__.py create mode 100644 irlc/exam/midterm2023a/readme.md create mode 100644 irlc/exam/midterm2023a/solution/readme.md create mode 100644 irlc/exam/midterm2023b/__init__.py create mode 100644 irlc/exam/midterm2023b/readme.md create mode 100644 irlc/exam/midterm2023b/solution/readme.md create mode 100644 irlc/exam/readme.md create mode 100644 irlc/exam_tabular_examples/__init__.py create mode 100644 irlc/exam_tabular_examples/helper.py create mode 100644 irlc/exam_tabular_examples/lecture_10_mc_value_every.py create mode 100644 irlc/exam_tabular_examples/lecture_10_mc_value_first.py create mode 100644 irlc/exam_tabular_examples/sarsa_lambda_delay.py create mode 100644 irlc/exam_tabular_examples/sarsa_nstep_delay.py create mode 100644 irlc/exam_tabular_examples/tabular_examples.py create mode 100644 irlc/gridworld/__init__.py create mode 100644 irlc/gridworld/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/gridworld/__pycache__/gridworld_environments.cpython-311.pyc create mode 100644 irlc/gridworld/__pycache__/gridworld_graphics_display.cpython-311.pyc create mode 100644 irlc/gridworld/__pycache__/gridworld_mdp.cpython-311.pyc create mode 100644 irlc/gridworld/demo_agents/__init__.py create mode 100644 irlc/gridworld/demo_agents/hidden_agents.py create mode 100644 irlc/gridworld/gridworld_environments.py create mode 100644 irlc/gridworld/gridworld_graphics_display.py create mode 100644 irlc/gridworld/gridworld_mdp.py create mode 100644 irlc/lectures/__init__.py create mode 100644 irlc/lectures/lec01/__init__.py create mode 100644 irlc/lectures/lec01/lecture_01_car_random.py create mode 100644 irlc/lectures/lec01/lecture_01_pacman.py create mode 100644 irlc/lectures/lec01/lecture_01_pendulum_random.py create mode 100644 irlc/lectures/lec02/__init__.py create mode 100644 irlc/lectures/lec02/lecture_02_dp_gridworld_short.py create mode 100644 irlc/lectures/lec02/lecture_02_frozen_lake.py create mode 100644 irlc/lectures/lec02/lecture_02_frozen_long_slippery.py create mode 100644 irlc/lectures/lec02/lecture_02_keyboard_pacman_g1.py create mode 100644 irlc/lectures/lec02/lecture_02_keyboard_pacman_g2.py create mode 100644 irlc/lectures/lec02/lecture_02_optimal_dp_g0.py create mode 100644 irlc/lectures/lec02/lecture_02_optimal_dp_g1.py create mode 100644 irlc/lectures/lec02/lecture_02_optimal_dp_g2.py create mode 100644 irlc/lectures/lec03/__init__.py create mode 100644 irlc/lectures/lec03/ex_03_search.py create mode 100644 irlc/lectures/lec03/lecture_03_alphab.py create mode 100644 irlc/lectures/lec03/lecture_03_dotsearch_astar_manhattan.py create mode 100644 irlc/lectures/lec03/lecture_03_dotsearch_bfs.py create mode 100644 irlc/lectures/lec03/lecture_03_dotsearch_dfs.py create mode 100644 irlc/lectures/lec03/lecture_03_dotsearch_dp.py create mode 100644 irlc/lectures/lec03/lecture_03_expectimax.py create mode 100644 irlc/lectures/lec03/lecture_03_minimax.py create mode 100644 irlc/lectures/lec03/lecture_03_squaresearch_bfs.py create mode 100644 irlc/lectures/lec03/lecture_03_tricksearch_astar.py create mode 100644 irlc/lectures/lec03/lecture_03_tricksearch_bfs.py create mode 100644 irlc/lectures/lec03/lecture_03_tricksearch_dfs.py create mode 100644 irlc/lectures/lec03/snapshot_base/openaigym.video.0.8068.video000000.meta.json create mode 100644 irlc/lectures/lec03/snapshot_base/openaigym.video.0.8068.video000000.mp4 create mode 100644 irlc/lectures/lec04/__init__.py create mode 100644 irlc/lectures/lec04/lecture_04_car_basic_pid.py create mode 100644 irlc/lectures/lec04/lecture_04_cartpole_A.py create mode 100644 irlc/lectures/lec04/lecture_04_cartpole_B.py create mode 100644 irlc/lectures/lec04/lecture_04_harmonic.py create mode 100644 irlc/lectures/lec04/lecture_04_lunar.py create mode 100644 irlc/lectures/lec04/lecture_04_pendulum_random.py create mode 100644 irlc/lectures/lec04/lecture_04_pid_d.py create mode 100644 irlc/lectures/lec04/lecture_04_pid_iA.py create mode 100644 irlc/lectures/lec04/lecture_04_pid_iB.py create mode 100644 irlc/lectures/lec04/lecture_04_pid_p.py create mode 100644 irlc/lectures/lec05/__init__.py create mode 100644 irlc/lectures/lec05/lecture_05_carpole_random.py create mode 100644 irlc/lectures/lec05/lecture_05_cartpole_kelly.py create mode 100644 irlc/lectures/lec05/lecture_05_cartpole_time.py create mode 100644 irlc/lectures/lec06/__init__.py create mode 100644 irlc/lectures/lec06/lecture6_lqr_locomotive.py create mode 100644 irlc/lectures/lec06/lecture_06_cartpole_ilqr.py create mode 100644 irlc/lectures/lec06/lecture_06_linearize.py create mode 100644 irlc/lectures/lec06/lecture_06_linearize_b.py create mode 100644 irlc/lectures/lec06/lecture_06_pendulum_bilqr_L.py create mode 100644 irlc/lectures/lec06/lecture_06_pendulum_bilqr_ubar.py create mode 100644 irlc/lectures/lec06/lecture_06_pendulum_ilqr_L.py create mode 100644 irlc/lectures/lec06/lecture_06_pendulum_ilqr_ubar.py create mode 100644 irlc/lectures/lec07/__init__.py create mode 100644 irlc/lectures/lec07/lecture_07_boing_lqr.py create mode 100644 irlc/lectures/lec07/lecture_07_boing_lqr_mpc.py create mode 100644 irlc/lectures/lec07/lecture_07_boing_lqr_mpc_local.py create mode 100644 irlc/lectures/lec07/lecture_07_boing_lqr_mpc_optim.py create mode 100644 irlc/lectures/lec07/lecture_07_lmpc.py create mode 100644 irlc/lectures/lec07/lecture_07_pendulum_mpc_lqr.py create mode 100644 irlc/lectures/lec07/lecture_07_pendulum_mpc_optm.py create mode 100644 irlc/lectures/lec07/lecture_07_pendulum_simple.py create mode 100644 irlc/lectures/lec07/pendulum12/2021-03-19_08-21-20.207/log.txt create mode 100644 irlc/lectures/lec07/pendulum12/2021-03-19_08-21-20.207/trajectories.pkl create mode 100644 irlc/lectures/lec07/pendulum12/2022-03-17_14-16-10.758/log.txt create mode 100644 irlc/lectures/lec07/pendulum12/2022-03-17_14-16-10.758/trajectories.pkl create mode 100644 irlc/lectures/lec07/pendulum12_lqr/2023-03-17_08-13-45.172/log.txt create mode 100644 irlc/lectures/lec07/pendulum12_lqr/2023-03-17_08-13-45.172/trajectories.pkl create mode 100644 irlc/lectures/lec07/tmp-pdfcrop-10536.tex create mode 100644 irlc/lectures/lec07/tmp-pdfcrop-12592.tex create mode 100644 irlc/lectures/lec08/__init__.py create mode 100644 irlc/lectures/lec08/demo_bandit.py create mode 100644 irlc/lectures/lec08/demo_bandit_ucb.py create mode 100644 irlc/lectures/lec09/__init__.py create mode 100644 irlc/lectures/lec09/unf_frozenlake.py create mode 100644 irlc/lectures/lec09/unf_gridworld.py create mode 100644 irlc/lectures/lec09/unf_policy_evaluation_frozen.py create mode 100644 irlc/lectures/lec09/unf_policy_evaluation_gridworld.py create mode 100644 irlc/lectures/lec09/unf_policy_evaluation_stepwise_gridworld.py create mode 100644 irlc/lectures/lec09/unf_policy_improvement_frozenlake.py create mode 100644 irlc/lectures/lec09/unf_policy_improvement_gridworld.py create mode 100644 irlc/lectures/lec09/unf_vi_frozenlake.py create mode 100644 irlc/lectures/lec09/unf_vi_gridworld.py create mode 100644 irlc/lectures/lec09/unf_vi_gridworld_stepwise.py create mode 100644 irlc/lectures/lec10/__init__.py create mode 100644 irlc/lectures/lec10/lecture_10_mc_action_value_first_one_state.py create mode 100644 irlc/lectures/lec10/lecture_10_mc_action_value_first_one_state_b.py create mode 100644 irlc/lectures/lec10/lecture_10_mc_control.py create mode 100644 irlc/lectures/lec10/lecture_10_mc_corner.py create mode 100644 irlc/lectures/lec10/lecture_10_mc_onestate_every.py create mode 100644 irlc/lectures/lec10/lecture_10_mc_onestate_first.py create mode 100644 irlc/lectures/lec10/lecture_10_mc_q_estimation.py create mode 100644 irlc/lectures/lec10/lecture_10_mc_value_every.py create mode 100644 irlc/lectures/lec10/lecture_10_mc_value_every_one_state.py create mode 100644 irlc/lectures/lec10/lecture_10_mc_value_first.py create mode 100644 irlc/lectures/lec10/lecture_10_mc_value_first_one_state.py create mode 100644 irlc/lectures/lec10/lecture_10_mc_value_first_one_state_b.py create mode 100644 irlc/lectures/lec10/lecture_10_td_corner.py create mode 100644 irlc/lectures/lec10/lecture_10_td_keyboard.py create mode 100644 irlc/lectures/lec10/unf_gridworld_action_value.py create mode 100644 irlc/lectures/lec10/unf_gridworld_value.py create mode 100644 irlc/lectures/lec11/__init__.py create mode 100644 irlc/lectures/lec11/exam_sol.py create mode 100644 irlc/lectures/lec11/lecture_10_grid_lin_q.py create mode 100644 irlc/lectures/lec11/lecture_10_sarsa_open.py create mode 100644 irlc/lectures/lec11/lecture_11_nstep_open.py create mode 100644 irlc/lectures/lec11/lecture_11_pacman_lin_q.py create mode 100644 irlc/lectures/lec11/lecture_11_pacman_q.py create mode 100644 irlc/lectures/lec11/lecture_11_q.py create mode 100644 irlc/lectures/lec11/lecture_11_q_cliff.py create mode 100644 irlc/lectures/lec11/lecture_11_q_open.py create mode 100644 irlc/lectures/lec11/lecture_11_sarsa.py create mode 100644 irlc/lectures/lec11/lecture_11_sarsa_cliff.py create mode 100644 irlc/lectures/lec12/__init__.py create mode 100644 irlc/lectures/lec12/lecture_12_mc_open.py create mode 100644 irlc/lectures/lec12/lecture_12_pacman.py create mode 100644 irlc/lectures/lec12/lecture_12_sarsa_lamda_open.py create mode 100644 irlc/lectures/lec12/lecture_12_sarsa_nstep.py create mode 100644 irlc/lectures/lec12/lecture_12_sarsa_open.py create mode 100644 irlc/lectures/lec13/double_q_viz.py create mode 100644 irlc/lectures/lec13/lecture_13_Q_maze.py create mode 100644 irlc/lectures/lec13/lecture_13_Q_open.py create mode 100644 irlc/lectures/lec13/lecture_13_dyna_q_5_maze.py create mode 100644 irlc/lectures/lec13/lecture_13_sarsa_lambda_maze.py create mode 100644 irlc/lectures/readme.md create mode 100644 irlc/pacman/__init__.py create mode 100644 irlc/pacman/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/pacman/__pycache__/gamestate.cpython-311.pyc create mode 100644 irlc/pacman/__pycache__/layout.cpython-311.pyc create mode 100644 irlc/pacman/__pycache__/pacman_environment.cpython-311.pyc create mode 100644 irlc/pacman/__pycache__/pacman_graphics_display.cpython-311.pyc create mode 100644 irlc/pacman/__pycache__/pacman_text_display.cpython-311.pyc create mode 100644 irlc/pacman/__pycache__/pacman_utils.cpython-311.pyc create mode 100644 irlc/pacman/feature_extractor.py create mode 100644 irlc/pacman/gamestate.py create mode 100644 irlc/pacman/layout.py create mode 100644 irlc/pacman/layouts/bigCorners.lay create mode 100644 irlc/pacman/layouts/bigHunt.lay create mode 100644 irlc/pacman/layouts/bigMaze.lay create mode 100644 irlc/pacman/layouts/bigSafeSearch.lay create mode 100644 irlc/pacman/layouts/bigSearch.lay create mode 100644 irlc/pacman/layouts/boxSearch.lay create mode 100644 irlc/pacman/layouts/capsuleClassic.lay create mode 100644 irlc/pacman/layouts/contestClassic.lay create mode 100644 irlc/pacman/layouts/contoursMaze.lay create mode 100644 irlc/pacman/layouts/greedySearch.lay create mode 100644 irlc/pacman/layouts/mediumClassic.lay create mode 100644 irlc/pacman/layouts/mediumCorners.lay create mode 100644 irlc/pacman/layouts/mediumDottedMaze.lay create mode 100644 irlc/pacman/layouts/mediumGrid.lay create mode 100644 irlc/pacman/layouts/mediumMaze.lay create mode 100644 irlc/pacman/layouts/mediumSafeSearch.lay create mode 100644 irlc/pacman/layouts/mediumScaryMaze.lay create mode 100644 irlc/pacman/layouts/mediumSearch.lay create mode 100644 irlc/pacman/layouts/minimaxClassic.lay create mode 100644 irlc/pacman/layouts/oddSearch.lay create mode 100644 irlc/pacman/layouts/oneHunt.lay create mode 100644 irlc/pacman/layouts/openClassic.lay create mode 100644 irlc/pacman/layouts/openHunt.lay create mode 100644 irlc/pacman/layouts/openMaze.lay create mode 100644 irlc/pacman/layouts/openSearch.lay create mode 100644 irlc/pacman/layouts/originalClassic.lay create mode 100644 irlc/pacman/layouts/powerClassic.lay create mode 100644 irlc/pacman/layouts/smallClassic.lay create mode 100644 irlc/pacman/layouts/smallGrid.lay create mode 100644 irlc/pacman/layouts/smallHunt.lay create mode 100644 irlc/pacman/layouts/smallMaze.lay create mode 100644 irlc/pacman/layouts/smallSafeSearch.lay create mode 100644 irlc/pacman/layouts/smallSearch.lay create mode 100644 irlc/pacman/layouts/testClassic.lay create mode 100644 irlc/pacman/layouts/testMaze.lay create mode 100644 irlc/pacman/layouts/testSearch.lay create mode 100644 irlc/pacman/layouts/tinyCorners.lay create mode 100644 irlc/pacman/layouts/tinyMaze.lay create mode 100644 irlc/pacman/layouts/tinySafeSearch.lay create mode 100644 irlc/pacman/layouts/tinySearch.lay create mode 100644 irlc/pacman/layouts/trappedClassic.lay create mode 100644 irlc/pacman/layouts/trickyClassic.lay create mode 100644 irlc/pacman/layouts/trickySearch.lay create mode 100644 irlc/pacman/pacman_environment.py create mode 100644 irlc/pacman/pacman_graphics_display.py create mode 100644 irlc/pacman/pacman_resources.py create mode 100644 irlc/pacman/pacman_text_display.py create mode 100644 irlc/pacman/pacman_utils.py create mode 100644 irlc/project0/__init__.py create mode 100644 irlc/project0/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/project0/fruit_project_grade.py create mode 100644 irlc/project0/fruit_project_tests.py create mode 100644 irlc/project0/fruit_project_tests_complete_grade.py create mode 100644 irlc/project0/unitgrade_data/AdditionQuestion.pkl create mode 100644 irlc/project0/unitgrade_data/BasicClass.pkl create mode 100644 irlc/project0/unitgrade_data/ClassUse.pkl create mode 100644 irlc/project0/unitgrade_data/FruitsOrdered.pkl create mode 100644 irlc/project0/unitgrade_data/Inheritance.pkl create mode 100644 irlc/project0/unitgrade_data/MeanOfDie.pkl create mode 100644 irlc/project0/unitgrade_data/MisterfyQuestion.pkl create mode 100644 irlc/project1/Latex/02465project1_handin.tex create mode 100644 irlc/project1/Latex/figures/kiosk1.pdf create mode 100644 irlc/project1/Latex/figures/kiosk2.pdf create mode 100644 irlc/project1/Latex/figures/your_answer.pdf create mode 100644 irlc/project1/__init__.py create mode 100644 irlc/project1/kiosk.py create mode 100644 irlc/project1/pacman.py create mode 100644 irlc/project1/pacman_demo1.py create mode 100644 irlc/project1/pacman_demo2.py create mode 100644 irlc/project1/project1_grade.py create mode 100644 irlc/project1/project1_tests.py create mode 100644 irlc/project1/project1_tests_complete_grade.py create mode 100644 irlc/project1/unitgrade_data/Kiosk1.pkl create mode 100644 irlc/project1/unitgrade_data/Kiosk2.pkl create mode 100644 irlc/project1/unitgrade_data/Kiosk3.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman1.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman10.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman11.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman12.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman3.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman4.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman6a.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman6b.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman6c.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman7a.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman7b.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman8a.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman8b.pkl create mode 100644 irlc/project1/unitgrade_data/Pacman9.pkl create mode 100644 irlc/project2/Latex/02465project2_handin.tex create mode 100644 irlc/project2/Latex/figures/your_answer.pdf create mode 100644 irlc/project2/__init__.py create mode 100644 irlc/project2/project2_grade.py create mode 100644 irlc/project2/project2_tests.py create mode 100644 irlc/project2/project2_tests_complete_grade.py create mode 100644 irlc/project2/r2d2.py create mode 100644 irlc/project2/unitgrade_data/R2D2Direct.pkl create mode 100644 irlc/project2/unitgrade_data/R2D2Linearization.pkl create mode 100644 irlc/project2/unitgrade_data/R2D2Problem15.pkl create mode 100644 irlc/project2/unitgrade_data/R2D2_MPC.pkl create mode 100644 irlc/project2/unitgrade_data/YodaProblem1.pkl create mode 100644 irlc/project2/unitgrade_data/YodaProblem2.pkl create mode 100644 irlc/project2/unitgrade_data/YodaProblem3.pkl create mode 100644 irlc/project2/unitgrade_data/YodaProblem6.pkl create mode 100644 irlc/project2/unitgrade_data/YodaProblem7.pkl create mode 100644 irlc/project2/utils.py create mode 100644 irlc/project2/yoda.py create mode 100644 irlc/project3/Latex/02465project3_handin.tex create mode 100644 irlc/project3/Latex/figures/your_answer.pdf create mode 100644 irlc/project3/__init__.py create mode 100644 irlc/project3/jarjar.py create mode 100644 irlc/project3/project3_grade.py create mode 100644 irlc/project3/project3_tests.py create mode 100644 irlc/project3/project3_tests_complete_grade.py create mode 100644 irlc/project3/rebels.py create mode 100644 irlc/project3/rebels_demo.py create mode 100644 irlc/project3/unitgrade_data/JarJarPiOptimal.pkl create mode 100644 irlc/project3/unitgrade_data/JarJarQ0Estimated.pkl create mode 100644 irlc/project3/unitgrade_data/JarJarQExact.pkl create mode 100644 irlc/project3/unitgrade_data/RebelsBridge.pkl create mode 100644 irlc/project3/unitgrade_data/RebelsSimple.pkl create mode 100644 irlc/project3i/__init__.py create mode 100644 irlc/project3i/project3_individual_grade.py create mode 100644 irlc/project3i/project3_individual_tests.py create mode 100644 irlc/project3i/project3_individual_tests_complete_grade.py create mode 100644 irlc/project3i/sarlacc.py create mode 100644 irlc/project3i/unitgrade_data/SarlacReturn.pkl create mode 100644 irlc/project3i/unitgrade_data/SarlaccGameRules.pkl create mode 100644 irlc/tests/__init__.py create mode 100644 irlc/tests/tests_week01.py create mode 100644 irlc/tests/tests_week02.py create mode 100644 irlc/tests/tests_week03.py create mode 100644 irlc/tests/tests_week04.py create mode 100644 irlc/tests/tests_week05.py create mode 100644 irlc/tests/tests_week06.py create mode 100644 irlc/tests/tests_week07.py create mode 100644 irlc/tests/tests_week08.py create mode 100644 irlc/tests/tests_week09.py create mode 100644 irlc/tests/tests_week10.py create mode 100644 irlc/tests/tests_week11.py create mode 100644 irlc/tests/tests_week12.py create mode 100644 irlc/tests/tests_week13.py create mode 100644 irlc/tests/unitgrade_data/BanditQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/BrachistochroneConstrainedQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/BrachistochroneQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/CartpoleCostQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/CartpoleTimeQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/DirectAgentPendulum.pkl create mode 100644 irlc/tests/unitgrade_data/DirectMethods.pkl create mode 100644 irlc/tests/unitgrade_data/DirectSolverQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/DoubleQQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/DynaQQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/Exam5InventoryEvaluation.pkl create mode 100644 irlc/tests/unitgrade_data/Exam6Toy2d.pkl create mode 100644 irlc/tests/unitgrade_data/ExamQuestion7FlowersStore.pkl create mode 100644 irlc/tests/unitgrade_data/ExamQuestionTD0.pkl create mode 100644 irlc/tests/unitgrade_data/GradientBanditQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/ILQRAgentQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/ILQRPendulumQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/LinearQAgentQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/LinearSarsaAgentQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/LinearSarsaLambdaAgentQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/LinearSarsaNstepAgentQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/MCAgentQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/MCEvaluationQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/NStepSarsaQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/NonstatiotnaryAgentQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/PendulumQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/Problem1BobsFriend.pkl create mode 100644 irlc/tests/unitgrade_data/Problem1DiscreteKuromoto.pkl create mode 100644 irlc/tests/unitgrade_data/Problem1Kuramoto.pkl create mode 100644 irlc/tests/unitgrade_data/Problem1SmallGraph.pkl create mode 100644 irlc/tests/unitgrade_data/Problem1_to_3_Warmup.pkl create mode 100644 irlc/tests/unitgrade_data/Problem2BobsPolicy.pkl create mode 100644 irlc/tests/unitgrade_data/Problem2DeterministicDP.pkl create mode 100644 irlc/tests/unitgrade_data/Problem3InventoryInventoryEnvironment.pkl create mode 100644 irlc/tests/unitgrade_data/Problem3LQR.pkl create mode 100644 irlc/tests/unitgrade_data/Problem3PID.pkl create mode 100644 irlc/tests/unitgrade_data/Problem3StochasticDP.pkl create mode 100644 irlc/tests/unitgrade_data/Problem4DPAgent.pkl create mode 100644 irlc/tests/unitgrade_data/Problem4InventoryTrain.pkl create mode 100644 irlc/tests/unitgrade_data/Problem4LQRAgent.pkl create mode 100644 irlc/tests/unitgrade_data/Problem4PIDAgent.pkl create mode 100644 irlc/tests/unitgrade_data/Problem4PolicyEvaluation.pkl create mode 100644 irlc/tests/unitgrade_data/Problem5PacmanHardcoded.pkl create mode 100644 irlc/tests/unitgrade_data/Problem5PolicyIteration.pkl create mode 100644 irlc/tests/unitgrade_data/Problem5_6_Boeing.pkl create mode 100644 irlc/tests/unitgrade_data/Problem6ChessTournament.pkl create mode 100644 irlc/tests/unitgrade_data/Problem6ValueIteration.pkl create mode 100644 irlc/tests/unitgrade_data/Problem7PIDCar.pkl create mode 100644 irlc/tests/unitgrade_data/Problem7_8_PidLQR.pkl create mode 100644 irlc/tests/unitgrade_data/Problem8ValueIterationAgent.pkl create mode 100644 irlc/tests/unitgrade_data/Problem9Gambler.pkl create mode 100644 irlc/tests/unitgrade_data/QAgentQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/RendevouzItem.pkl create mode 100644 irlc/tests/unitgrade_data/SarsaLambdaQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/SarsaQuestion.pkl create mode 100644 irlc/tests/unitgrade_data/TD0Question.pkl create mode 100644 irlc/tests/unitgrade_data/UCBAgentQuestion.pkl create mode 100644 irlc/update_files.py create mode 100644 irlc/utils/__init__.py create mode 100644 irlc/utils/__pycache__/__init__.cpython-311.pyc create mode 100644 irlc/utils/__pycache__/common.cpython-311.pyc create mode 100644 irlc/utils/__pycache__/graphics_util_pygame.cpython-311.pyc create mode 100644 irlc/utils/__pycache__/irlc_plot.cpython-311.pyc create mode 100644 irlc/utils/__pycache__/lazylog.cpython-311.pyc create mode 100644 irlc/utils/__pycache__/player_wrapper.cpython-311.pyc create mode 100644 irlc/utils/__pycache__/ptext.cpython-311.pyc create mode 100644 irlc/utils/__pycache__/timer.cpython-311.pyc create mode 100644 irlc/utils/common.py create mode 100644 irlc/utils/graphics/car.png create mode 100644 irlc/utils/graphics/dtu_icon.png create mode 100644 irlc/utils/graphics/locomotive.png create mode 100644 irlc/utils/graphics_util_pygame.py create mode 100644 irlc/utils/irlc_plot.py create mode 100644 irlc/utils/lazylog.py create mode 100644 irlc/utils/minigrid.py create mode 100644 irlc/utils/player_wrapper.py create mode 100644 irlc/utils/ptext.py create mode 100644 irlc/utils/timer.py create mode 100644 requirements_conda.txt create mode 100644 requirements_pip.txt create mode 100644 solutions/ex00/fruit_homework_TODO_1.py create mode 100644 solutions/ex00/fruit_homework_TODO_2.py create mode 100644 solutions/ex00/fruit_homework_TODO_3.py create mode 100644 solutions/ex00/fruit_homework_TODO_4.py create mode 100644 solutions/ex00/fruit_homework_TODO_5.py create mode 100644 solutions/ex00/fruit_homework_TODO_6.py create mode 100644 solutions/ex00/fruit_homework_TODO_7.py create mode 100644 solutions/ex01/bobs_friend_TODO_1.py create mode 100644 solutions/ex01/bobs_friend_TODO_2.py create mode 100644 solutions/ex01/bobs_friend_TODO_3.py create mode 100644 solutions/ex01/bobs_friend_TODO_4.py create mode 100644 solutions/ex01/chess_TODO_1.py create mode 100644 solutions/ex01/chess_TODO_2.py create mode 100644 solutions/ex01/chess_TODO_3.py create mode 100644 solutions/ex01/chess_TODO_4.py create mode 100644 solutions/ex01/chess_TODO_5.py create mode 100644 solutions/ex01/inventory_environment_TODO_1.py create mode 100644 solutions/ex01/inventory_environment_TODO_2.py create mode 100644 solutions/ex01/inventory_environment_TODO_3.py create mode 100644 solutions/ex01/pacman_hardcoded_TODO_1.py create mode 100644 solutions/ex02/dp_TODO_1.py create mode 100644 solutions/ex02/dp_agent_TODO_1.py create mode 100644 solutions/ex02/flower_store_TODO_1.py create mode 100644 solutions/ex02/flower_store_TODO_2.py create mode 100644 solutions/ex02/flower_store_TODO_3.py create mode 100644 solutions/ex02/graph_traversal_TODO_1.py create mode 100644 solutions/ex02/graph_traversal_TODO_2.py create mode 100644 solutions/ex02/graph_traversal_TODO_3.py create mode 100644 solutions/ex02/inventory_TODO_1.py create mode 100644 solutions/ex03/inventory_evaluation_TODO_1.py create mode 100644 solutions/ex03/inventory_evaluation_TODO_2.py create mode 100644 solutions/ex03/kuramoto_TODO_1.py create mode 100644 solutions/ex03/kuramoto_TODO_2.py create mode 100644 solutions/ex03/kuramoto_TODO_3.py create mode 100644 solutions/ex03/toy_2d_control_TODO_1.py create mode 100644 solutions/ex03/toy_2d_control_TODO_2.py create mode 100644 solutions/ex04/discrete_kuramoto_TODO_1.py create mode 100644 solutions/ex04/discrete_kuramoto_TODO_2.py create mode 100644 solutions/ex04/discrete_kuramoto_TODO_3.py create mode 100644 solutions/ex04/model_pendulum_TODO_1.py create mode 100644 solutions/ex04/model_pendulum_TODO_2.py create mode 100644 solutions/ex04/pid_TODO_1.py create mode 100644 solutions/ex04/pid_TODO_2.py create mode 100644 solutions/ex04/pid_car_TODO_1.py create mode 100644 solutions/ex04/pid_car_TODO_2.py create mode 100644 solutions/ex04/pid_locomotive_agent_TODO_1.py create mode 100644 solutions/ex04/pid_locomotive_agent_TODO_2.py create mode 100644 solutions/ex04/pid_lunar_TODO_1.py create mode 100644 solutions/ex04/pid_pendulum_TODO_1.py create mode 100644 solutions/ex04/pid_pendulum_TODO_2.py create mode 100644 solutions/ex04/pid_pendulum_TODO_3.py create mode 100644 solutions/ex05/direct_TODO_1.py create mode 100644 solutions/ex05/direct_TODO_10.py create mode 100644 solutions/ex05/direct_TODO_2.py create mode 100644 solutions/ex05/direct_TODO_3.py create mode 100644 solutions/ex05/direct_TODO_4.py create mode 100644 solutions/ex05/direct_TODO_5.py create mode 100644 solutions/ex05/direct_TODO_6.py create mode 100644 solutions/ex05/direct_TODO_7.py create mode 100644 solutions/ex05/direct_TODO_8.py create mode 100644 solutions/ex05/direct_TODO_9.py create mode 100644 solutions/ex05/direct_agent_TODO_1.py create mode 100644 solutions/ex05/direct_agent_TODO_2.py create mode 100644 solutions/ex05/direct_cartpole_kelly_TODO_1.py create mode 100644 solutions/ex05/direct_cartpole_kelly_TODO_2.py create mode 100644 solutions/ex05/model_brachistochrone_TODO_1.py create mode 100644 solutions/ex05/model_brachistochrone_TODO_2.py create mode 100644 solutions/ex05/model_brachistochrone_TODO_3.py create mode 100644 solutions/ex06/boeing_lqr_TODO_1.py create mode 100644 solutions/ex06/boeing_lqr_TODO_2.py create mode 100644 solutions/ex06/boeing_lqr_TODO_3.py create mode 100644 solutions/ex06/boeing_lqr_TODO_4.py create mode 100644 solutions/ex06/dlqr_TODO_1.py create mode 100644 solutions/ex06/dlqr_TODO_2.py create mode 100644 solutions/ex06/dlqr_TODO_3.py create mode 100644 solutions/ex06/lqr_agent_TODO_1.py create mode 100644 solutions/ex06/lqr_agent_TODO_2.py create mode 100644 solutions/ex06/lqr_pid_TODO_1.py create mode 100644 solutions/ex06/lqr_pid_TODO_2.py create mode 100644 solutions/ex07/ilqr_TODO_1.py create mode 100644 solutions/ex07/ilqr_TODO_10.py create mode 100644 solutions/ex07/ilqr_TODO_11.py create mode 100644 solutions/ex07/ilqr_TODO_12.py create mode 100644 solutions/ex07/ilqr_TODO_13.py create mode 100644 solutions/ex07/ilqr_TODO_14.py create mode 100644 solutions/ex07/ilqr_TODO_15.py create mode 100644 solutions/ex07/ilqr_TODO_16.py create mode 100644 solutions/ex07/ilqr_TODO_2.py create mode 100644 solutions/ex07/ilqr_TODO_3.py create mode 100644 solutions/ex07/ilqr_TODO_4.py create mode 100644 solutions/ex07/ilqr_TODO_5.py create mode 100644 solutions/ex07/ilqr_TODO_6.py create mode 100644 solutions/ex07/ilqr_TODO_7.py create mode 100644 solutions/ex07/ilqr_TODO_8.py create mode 100644 solutions/ex07/ilqr_TODO_9.py create mode 100644 solutions/ex07/ilqr_agent_TODO_1.py create mode 100644 solutions/ex07/ilqr_pendulum_TODO_1.py create mode 100644 solutions/ex07/linearization_agent_TODO_1.py create mode 100644 solutions/ex07/linearization_agent_TODO_2.py create mode 100644 solutions/ex07/linearization_agent_TODO_3.py create mode 100644 solutions/ex08/bandits_TODO_1.py create mode 100644 solutions/ex08/gradient_agent_TODO_1.py create mode 100644 solutions/ex08/grand_bandit_race_TODO_1.py create mode 100644 solutions/ex08/grand_bandit_race_TODO_2.py create mode 100644 solutions/ex08/grand_bandit_race_TODO_3.py create mode 100644 solutions/ex08/grand_bandit_race_TODO_4.py create mode 100644 solutions/ex08/grand_bandit_race_TODO_5.py create mode 100644 solutions/ex08/grand_bandit_race_TODO_6.py create mode 100644 solutions/ex08/grand_bandit_race_TODO_7.py create mode 100644 solutions/ex08/grand_bandit_race_TODO_8.py create mode 100644 solutions/ex08/nonstationary_TODO_1.py create mode 100644 solutions/ex08/nonstationary_TODO_2.py create mode 100644 solutions/ex08/nonstationary_TODO_3.py create mode 100644 solutions/ex08/nonstationary_TODO_4.py create mode 100644 solutions/ex08/nonstationary_TODO_5.py create mode 100644 solutions/ex08/simple_agents_TODO_1.py create mode 100644 solutions/ex08/simple_agents_TODO_2.py create mode 100644 solutions/ex08/simple_agents_TODO_3.py create mode 100644 solutions/ex08/ucb_agent_TODO_1.py create mode 100644 solutions/ex08/ucb_agent_TODO_2.py create mode 100644 solutions/ex08/ucb_agent_TODO_3.py create mode 100644 solutions/ex09/gambler_TODO_1.py create mode 100644 solutions/ex09/gambler_TODO_2.py create mode 100644 solutions/ex09/gambler_TODO_3.py create mode 100644 solutions/ex09/jacks_car_rental_TODO_1.py create mode 100644 solutions/ex09/jacks_car_rental_TODO_2.py create mode 100644 solutions/ex09/jacks_car_rental_TODO_3.py create mode 100644 solutions/ex09/mdp_warmup_TODO_1.py create mode 100644 solutions/ex09/mdp_warmup_TODO_2.py create mode 100644 solutions/ex09/mdp_warmup_TODO_3.py create mode 100644 solutions/ex09/mdp_warmup_TODO_4.py create mode 100644 solutions/ex09/policy_evaluation_TODO_1.py create mode 100644 solutions/ex09/policy_iteration_TODO_1.py create mode 100644 solutions/ex09/value_iteration_TODO_1.py create mode 100644 solutions/ex09/value_iteration_TODO_2.py create mode 100644 solutions/ex09/value_iteration_agent_TODO_1.py create mode 100644 solutions/ex09/value_iteration_agent_TODO_2.py create mode 100644 solutions/ex10/mc_agent_TODO_1.py create mode 100644 solutions/ex10/mc_agent_TODO_2.py create mode 100644 solutions/ex10/mc_agent_TODO_3.py create mode 100644 solutions/ex10/mc_agent_TODO_4.py create mode 100644 solutions/ex10/mc_agent_blackjack_TODO_1.py create mode 100644 solutions/ex10/mc_evaluate_TODO_1.py create mode 100644 solutions/ex10/mc_evaluate_TODO_2.py create mode 100644 solutions/ex10/mc_evaluate_TODO_3.py create mode 100644 solutions/ex10/mc_evaluate_TODO_4.py create mode 100644 solutions/ex10/mc_evaluate_TODO_5.py create mode 100644 solutions/ex10/mc_evaluate_TODO_6.py create mode 100644 solutions/ex10/mc_evaluate_blackjack_TODO_1.py create mode 100644 solutions/ex10/mc_evaluate_blackjack_TODO_2.py create mode 100644 solutions/ex10/question_td0_TODO_1.py create mode 100644 solutions/ex10/question_td0_TODO_2.py create mode 100644 solutions/ex10/question_td0_TODO_3.py create mode 100644 solutions/ex10/random_walk_example_TODO_1.py create mode 100644 solutions/ex10/td0_evaluate_TODO_1.py create mode 100644 solutions/ex11/nstep_sarsa_agent_TODO_1.py create mode 100644 solutions/ex11/q_agent_TODO_1.py create mode 100644 solutions/ex11/q_agent_TODO_2.py create mode 100644 solutions/ex11/sarsa_agent_TODO_1.py create mode 100644 solutions/ex11/sarsa_agent_TODO_2.py create mode 100644 solutions/ex11/sarsa_agent_TODO_3.py create mode 100644 solutions/ex11/sarsa_agent_TODO_4.py create mode 100644 solutions/ex11/semi_grad_q_TODO_1.py create mode 100644 solutions/ex11/semi_grad_sarsa_TODO_1.py create mode 100644 solutions/ex11/semi_grad_sarsa_TODO_2.py create mode 100644 solutions/ex12/minigrid_wrappers_TODO_1.py create mode 100644 solutions/ex12/minigrid_wrappers_TODO_2.py create mode 100644 solutions/ex12/minigrid_wrappers_TODO_3.py create mode 100644 solutions/ex12/minigrid_wrappers_TODO_4.py create mode 100644 solutions/ex12/mountain_car_TODO_1.py create mode 100644 solutions/ex12/sarsa_lambda_agent_TODO_1.py create mode 100644 solutions/ex12/sarsa_lambda_agent_TODO_2.py create mode 100644 solutions/ex12/sarsa_lambda_agent_TODO_3.py create mode 100644 solutions/ex12/sarsa_lambda_agent_TODO_4.py create mode 100644 solutions/ex12/semi_grad_nstep_sarsa_TODO_1.py create mode 100644 solutions/ex12/semi_grad_nstep_sarsa_TODO_2.py create mode 100644 solutions/ex12/semi_grad_sarsa_lambda_TODO_1.py create mode 100644 solutions/ex13/deepq_agent_TODO_1.py create mode 100644 solutions/ex13/double_deepq_agent_TODO_1.py create mode 100644 solutions/ex13/double_deepq_agent_TODO_2.py create mode 100644 solutions/ex13/dyna_q_TODO_1.py create mode 100644 solutions/ex13/dyna_q_TODO_2.py create mode 100644 solutions/ex13/dyna_q_TODO_3.py create mode 100644 solutions/ex13/keras_networks_TODO_1.py create mode 100644 solutions/ex13/maximization_bias_environment_TODO_1.py create mode 100644 solutions/ex13/maximization_bias_environment_TODO_2.py create mode 100644 solutions/ex13/tabular_double_q_TODO_1.py create mode 100644 solutions/ex13/tabular_double_q_TODO_2.py create mode 100644 solutions/ex13/torch_networks_TODO_1.py diff --git a/irlc/__init__.py b/irlc/__init__.py new file mode 100644 index 0000000..a5273e7 --- /dev/null +++ b/irlc/__init__.py @@ -0,0 +1,261 @@ +""" Source code for 02466, Introduction to reinforcement learning and control, offered at DTU """ +__version__ = "0.0.1" + +# Do not import Matplotlib (or imports which import matplotlib) in case you have to run in headless mode. +import shutil +import inspect +import lzma, pickle + +import gymnasium +import numpy as np +import os + +# Global imports from across the API. Allows imports like +# > from irlc import Agent, train +from irlc.utils.irlc_plot import main_plot as main_plot +from irlc.utils.irlc_plot import plot_trajectory as plot_trajectory +try: + from irlc.ex01.agent import Agent as Agent, train as train + from irlc.ex09.rl_agent import TabularAgent, ValueAgent +except ImportError: + pass +from irlc.utils.player_wrapper import interactive as interactive +from irlc.utils.lazylog import LazyLog # This one is unclear. Is it required? +from irlc.utils.timer import Timer + + +def get_irlc_base(): + dir_path = os.path.dirname(os.path.realpath(__file__)) + return dir_path + +def get_students_base(): + return os.path.join(get_irlc_base(), "../../../02465students/") + + +def pd2latex_(pd, index=False, escape=False, column_spec=None, **kwargs): # You can add column specs. + for c in pd.columns: + if pd[c].values.dtype == 'float64' and all(pd[c].values - np.round(pd[c].values)==0): + pd[c] = pd[c].astype(int) + ss = pd.to_latex(index=index, escape=escape, **kwargs) + return fix_bookstabs_latex_(ss,column_spec=column_spec) + +def fix_bookstabs_latex_(ss, linewidth=True, first_column_left=True, column_spec=None): + to_tabular_x = linewidth + + if to_tabular_x: + ss = ss.replace("tabular", "tabularx") + lines = ss.split("\n") + hd = lines[0].split("{") + if column_spec is None: + adj = (('l' if to_tabular_x else 'l') if first_column_left else 'C') + ("".join(["C"] * (len(hd[-1][:-1]) - 1))) + else: + adj = column_spec + + # adj = ( ('l' if to_tabular_x else 'l') if first_column_left else 'C') + ("".join(["C"] * (len(hd[-1][:-1])-1))) + if linewidth: + lines[0] = "\\begin{tabularx}{\\linewidth}{" + adj + "}" + else: + lines[0] = "\\begin{tabular}{" + adj.lower() + "}" + + ss = '\n'.join(lines) + return ss + +def plotenv(env : gymnasium.Env): + """ + Given a Gymnasium environment instance, this function will plot the environment as a matplotlib image. Remember to call ``plt.show()`` to actually see the image. + + For this function to work, you must create the environment with :python:`render_mode='human'`. + + .. note:: + + This function may not work for all gymnasium environments, however, it will work for most environments we use in this course. + + :param env: The environment to plot. + """ + + from PIL import Image + import matplotlib.pyplot as plt + if hasattr(env, 'render_mode') and not env.render_mode == 'rgb_array': + env.render_mode, rmt = 'rgb_array', env.render_mode + frame = env.render() + if hasattr(env, 'render_mode') and not env.render_mode == 'rgb_array': + env.render_mode = rmt + + im = Image.fromarray(frame) + + plt.figure(figsize=(16, 16)) + plt.imshow(im) + plt.axis('off') + plt.tight_layout() + + + + +def _savepdf_env(file, env): + from PIL import Image + import matplotlib.pyplot as plt + if hasattr(env, 'render_mode') and not env.render_mode == 'rgb_array': + env.render_mode, rmt = 'rgb_array', env.render_mode + frame = env.render() + if hasattr(env, 'render_mode') and not env.render_mode == 'rgb_array': + env.render_mode = rmt + + im = Image.fromarray(frame) + snapshot_base = file + if snapshot_base.endswith(".png"): + sf = snapshot_base[:-4] + fext = 'png' + else: + fext = 'pdf' + if snapshot_base.endswith(".pdf"): + sf = snapshot_base[:-4] + else: + sf = snapshot_base + + sf = f"{sf}.{fext}" + dn = os.path.dirname(sf) + if len(dn) > 0 and not os.path.isdir(dn): + os.makedirs(dn) + print("Saving snapshot of environment to", os.path.abspath(sf)) + if fext == 'png': + im.save(sf) + from irlc import _move_to_output_directory + _move_to_output_directory(sf) + else: + plt.figure(figsize=(16, 16)) + plt.imshow(im) + plt.axis('off') + plt.tight_layout() + from irlc import savepdf + savepdf(sf, verbose=True) + # plt.show() + + + +def savepdf(pdf, verbose=False, watermark=False, env=None): + """ + Convenience function for saving PDFs. Just call it after you have created your plot as ``savepdf('my_file.pdf')`` + to save a PDF of the plot. + You can also pass an environment, in which case the environment will be stored to a pdf file. + + + :param pdf: The file to save to, for instance ``"my_pdf.pdf"`` + :param verbose: Print output destination (optional) + :param watermark: Include a watermark (optional) + :return: Full path of the created PDF. + """ + if env is not None: + _savepdf_env(pdf, env) + return + + import matplotlib.pyplot as plt + pdf = os.path.normpath(pdf.strip()) + pdf = pdf+".pdf" if not pdf.endswith(".pdf") else pdf + + if os.sep in pdf: + pdf = os.path.abspath(pdf) + else: + pdf = os.path.join(os.getcwd(), "pdf", pdf) + if not os.path.isdir(os.path.dirname(pdf)): + os.makedirs(os.path.dirname(pdf)) + + + + # filename = None + stack = inspect.stack() + modules = [inspect.getmodule(s[0]) for s in inspect.stack()] + files = [m.__file__ for m in modules if m is not None] + if any( [f.endswith("RUN_OUTPUT_CAPTURE.py") for f in files] ): + return + + # for s in stack: + # print(s) + # print(stack) + # for k in range(len(stack)-1, -1, -1): + # frame = stack[k] + # module = inspect.getmodule(frame[0]) + # filename = module.__file__ + # print(filename) + # if not any([filename.endswith(f) for f in ["pydev_code_executor.py", "pydevd.py", "_pydev_execfile.py", "pydevconsole.py", "pydev_ipython_console.py"] ]): + # # print("breaking c. debugger", filename) + # break + # if any( [filename.endswith(f) for f in ["pydevd.py", "_pydev_execfile.py"]]): + # print("pdf path could not be resolved due to debug mode being active in pycharm", filename) + # return + # print("Selected filename", filename) + # wd = os.path.dirname(filename) + # pdf_dir = wd +"/pdf" + # if filename.endswith("_RUN_OUTPUT_CAPTURE.py"): + # return + # if not os.path.isdir(pdf_dir): + # os.mkdir(pdf_dir) + wd = os.getcwd() + irlc_base = os.path.dirname(__file__) + if False: + pass + else: + plt.savefig(fname=pdf) + outf = os.path.normpath(os.path.abspath(pdf)) + print("> [savepdf]", pdf + (f" [full path: {outf}]" if verbose else "")) + + return outf + + +def _move_to_output_directory(file): + """ + Hidden function: Move file given file to static output dir. + """ + if not is_this_my_computer(): + return + CDIR = os.path.dirname(os.path.realpath(__file__)).replace('\\', '/') + shared_output_dir = CDIR + "/../../shared/output" + shutil.copy(file, shared_output_dir + "/"+ os.path.basename(file) ) + + +def bmatrix(a): + if False: + return a.__str__() + else: + np.set_printoptions(suppress=True) + """Returns a LaTeX bmatrix + :a: numpy array + :returns: LaTeX bmatrix as a string + """ + if len(a.shape) > 2: + raise ValueError('bmatrix can at most display two dimensions') + lines = str(a).replace('[', '').replace(']', '').splitlines() + rv = [r'\begin{bmatrix}'] + rv += [' ' + ' & '.join(l.split()) + r'\\' for l in lines] + rv += [r'\end{bmatrix}'] + return '\n'.join(rv) + + +def is_this_my_computer(): + CDIR = os.path.dirname(os.path.realpath(__file__)).replace('\\', '/') + return os.path.exists(CDIR + "/../../Exercises") + +def cache_write(object, file_name, only_on_professors_computer=False, verbose=True, protocol=-1): # -1 is default protocol. Fix crash issue with large files. + if only_on_professors_computer and not is_this_my_computer(): + """ Probably for your own good :-). """ + return + + dn = os.path.dirname(file_name) + if not os.path.exists(dn): + os.mkdir(dn) + if verbose: print("Writing cache...", file_name) + with lzma.open(file_name, 'wb') as f: + pickle.dump(object, f) + # compress_pickle.dump(object, f, compression="lzma", protocol=protocol) + if verbose: + print("Done!") + + +def cache_exists(file_name): + return os.path.exists(file_name) + +def cache_read(file_name): + if os.path.exists(file_name): + with lzma.open(file_name, 'rb') as f: + return pickle.load(f) + else: + return None diff --git a/irlc/__pycache__/__init__.cpython-311.pyc b/irlc/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..97a0dcea2a082392c4fe14d86fedd5de91689215 GIT binary patch literal 14164 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 aLrkI=Gy=3vz@A}0t0Oz}K{iH5c4h$i2@f^^ literal 0 HcmV?d00001 diff --git a/irlc/car/__init__.py b/irlc/car/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/car/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/car/car_model.py b/irlc/car/car_model.py new file mode 100644 index 0000000..d991684 --- /dev/null +++ b/irlc/car/car_model.py @@ -0,0 +1,304 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# from irlc.car.car_viewer import CarViewer +from irlc.car.car_viewer import CarViewerPygame +import numpy as np +import sympy as sym +from scipy.optimize import Bounds +from gymnasium.spaces import Box +from irlc.car.sym_map import SymMap, wrap_angle +from irlc.ex03.control_model import ControlModel +from irlc.ex03.control_cost import SymbolicQRCost +from irlc.ex04.discrete_control_model import DiscreteControlModel +from irlc.ex04.control_environment import ControlEnvironment +# from irlc.ex03.control_specification import ControlSpecification + +""" +class MySpecification(): + def get_bounds(self): + return bounds + + def get_cost(self): + pass + + def sym_f(self): + return ... + + def simulate(self): + # Simulate using RK4. + + pass + + +spec = MySpecification() +model = Model(spec) +model.simulate(...) + + + +""" + + +class SymbolicBicycleModel(ControlModel): + metadata = { + 'render.modes': ['human', 'rgb_array'], + 'video.frames_per_second': 30 + } + def __init__(self, map_width=0.8, simple_bounds=None, cost=None, hot_start=False, verbose=True): + s = """ + Coordinate system of the car: + State x consist of + x[0] = Vx (speed in direction of the car body) + x[1] = Vy (speed perpendicular to car body) + x[2] = wz (Yaw rate; how fast the car is turning) + x[3] = e_psi (Angle of rotation between car body and centerline) + x[4] = s (How far we are along the track) + x[5] = e_y (Distance between car body and closest point on centerline) + + Meanwhile the actions are + u[0] : Angle between wheels and car body (i.e. are we steering to the right or to the left) + u[1] : Engine force (applied to the rear wheels, i.e. accelerates car) + """ + if verbose: + print(s) + # if simple_bounds is None: + # simple_bounds = dict() + self.map = SymMap(width=map_width) + self.v_max = 3.0 + + self.viewer = None # rendering + self.hot_start = hot_start + # self.observation_space = Box(low=np.asarray([-np.inf, -np.inf, -np.inf, -np.inf, -np.inf, -map_width], dtype=float), + # high=np.asarray([v_max, np.inf, np.inf, np.inf, np.inf, map_width]), dtype=float) + # self.action_space = Box(low=np.asarray([-0.5, -1]), high=np.asarray([0.5, 1]), dtype=float) + + # xl = np.zeros((6,)) + # xl[4] = self.map.TrackLength + # simple_bounds = {'x0': Bounds([-np.inf, -np.inf, -np.inf, -np.inf, -np.inf, -map_width], [v_max, np.inf, np.inf, np.inf, np.inf, map_width]), + # 'xF': Bounds(list(xl), list(xl)), **simple_bounds} + # n = 6 + # d = 2 + # if cost is None: + # cost = SymbolicQRCost(Q=np.zeros((6,6)), R=np.eye(2)*10, qc=0*1.) + # bounds = dict(x_low=[-np.inf, -np.inf, -np.inf, -np.inf, -np.inf, -map_width], x_high=[self.v_max, np.inf, np.inf, np.inf, np.inf, map_width], + # u_low=[-0.5, -1], u_high=[0.5, 1]) + + super().__init__() + + def get_cost(self) -> SymbolicQRCost: + return SymbolicQRCost(Q=np.zeros((6,6)), R=np.eye(2)*10, qc=1.*0) + + def x_bound(self) -> Box: + return Box(np.asarray([-np.inf, -np.inf, -np.inf, -np.inf, -np.inf, -self.map.width]), + np.asarray([self.v_max, np.inf, np.inf, np.inf, np.inf, self.map.width])) + + def u_bound(self) -> Box: + return Box(np.asarray([-0.5, -1]),np.asarray([0.5, 1])) + + def render(self, x, render_mode='human'): + if self.viewer == None: + self.viewer = CarViewerPygame(self) + + self.viewer.update(self.x_curv2x_XY(x)) + return self.viewer.blit(render_mode=render_mode) + # return self.viewer.render(return_rgb_array=mode == 'rgb_array') + + def close(self): + if self.viewer is not None: + self.viewer.close() + + def x_curv2x_XY(self, x_curv): + ''' + Utility function for converting x (including velocities, etc.) from local (curvilinear) coordinates to global XY position. + ''' + Xc, Yc, vangle = self.map.getGlobalPosition(s=x_curv[4], ey=x_curv[5], epsi=x_curv[3]) + dglob = np.asarray([x_curv[0], x_curv[1], x_curv[2], vangle, Xc, Yc]) + return dglob + + def sym_f(self, x, u, t=None, curvelinear_coordinates=True, curvature_s=None): + ''' + Create derivative function + + \dot{x} = f(x, u) + + We will both create it in curvelinear coordinates or normal (global) coordinates. + ''' + # Vehicle Parameters + m = 1.98 + lf = 0.125 + lr = 0.125 + Iz = 0.024 + Df = 0.8 * m * 9.81 / 2.0 + Cf = 1.25 + Bf = 1.0 + Dr = 0.8 * m * 9.81 / 2.0 + Cr = 1.25 + Br = 1.0 + + vx = x[0] + vy = x[1] + wz = x[2] + if curvelinear_coordinates: + epsi = x[3] + s = x[4] + ey = x[5] + else: + psi = x[3] + + delta = u[0] + a = u[1] + + alpha_f = delta - sym.atan2(vy + lf * wz, vx) + alpha_r = -sym.atan2(vy - lf * wz, vx) + + # Compute lateral force at front and rear tire + Fyf = 2 * Df * sym.sin(Cf * sym.atan(Bf * alpha_f)) + Fyr = 2 * Dr * sym.sin(Cr * sym.atan(Br * alpha_r)) + + d_vx = (a - 1 / m * Fyf * sym.sin(delta) + wz * vy) + d_vy = (1 / m * (Fyf * sym.cos(delta) + Fyr) - wz * vx) + d_wz = (1 / Iz * (lf * Fyf * sym.cos(delta) - lr * Fyr)) + + if curvelinear_coordinates: + cur = self.map.sym_curvature(s) + d_epsi = (wz - (vx * sym.cos(epsi) - vy * sym.sin(epsi)) / (1 - cur * ey) * cur) + d_s = ((vx * sym.cos(epsi) - vy * sym.sin(epsi)) / (1 - cur * ey)) + """ + Compute derivative of e_y here (d_ey). See paper for details. + """ + d_ey = (vx * sym.sin(epsi) + vy * sym.cos(epsi)) # Old ex here ! b ! b + # implement the ODE governing ey (distane from center of road) in curveliner coordinates + xp = [d_vx, d_vy, d_wz, d_epsi, d_s, d_ey] + + else: + d_psi = wz + d_X = ((vx * sym.cos(psi) - vy * sym.sin(psi))) + d_Y = (vx * sym.sin(psi) + vy * sym.cos(psi)) + + xp = [d_vx, d_vy, d_wz, d_psi, d_X, d_Y] + return xp + + def fix_angles(self, x): + # fix angular component of x + if x.size == self.state_size: + x[3] = wrap_angle(x[3]) + elif x.shape[1] == self.state_size: + x[:,3] = wrap_angle(x[:,3]) + return x + + +class DiscreteCarModel(DiscreteControlModel): + def __init__(self, dt=0.1, cost=None, **kwargs): + model = SymbolicBicycleModel(**kwargs) + # self.observation_space = model.observation_space + # self.action_space = model.action_space + # n = 6 + # d = 2 + # if cost is None: + # from irlc.ex04.cost_discrete import DiscreteQRCost + # cost = DiscreteQRCost(Q=np.zeros((model.state_size, model.state_size)), R=np.eye(model.action_size)) + super().__init__(model=model, dt=dt, cost=cost) + # self.cost = cost + self.map = model.map + + +class CarEnvironment(ControlEnvironment): + def __init__(self, Tmax=10, noise_scale=1.0, cost=None, max_laps=10, hot_start=False, render_mode=None, **kwargs): + discrete_model = DiscreteCarModel(cost=cost, hot_start=hot_start, **kwargs) + super().__init__(discrete_model, Tmax=Tmax, render_mode=render_mode) + self.map = discrete_model.map + self.noise_scale = noise_scale + self.cost = cost + self.completed_laps = 0 + self.max_laps = max_laps + + def simple_bounds(self): + simple_bounds = {'x': Bounds(self.observation_space.low, self.observation_space.high), + 't0': Bounds([0], [0]), + 'u': Bounds(self.action_space.low, self.action_space.high)} + return simple_bounds + + """ We add a bit of noise for backward compatibility. """ + def step(self, u): + # We don't want to render the car before we have added jitter (below). These lines therefore disable rendering + self.render_mode, rmt_ = None, self.render_mode + xp, cost, terminated, truncated, info = super().step(u) + self.render_mode = rmt_ + + x = xp + if hasattr(self, 'seed') and self.seed is not None and not callable(self.seed): + np.random.seed(self.seed) + + noise_vx = np.maximum(-0.05, np.minimum(np.random.randn() * 0.01, 0.05)) + noise_vy = np.maximum(-0.1, np.minimum(np.random.randn() * 0.01, 0.1)) + noise_wz = np.maximum(-0.05, np.minimum(np.random.randn() * 0.005, 0.05)) + if True: #self.noise_scale > 0: + x[0] = x[0] + 0.03 * noise_vx #* self.noise_scale + x[1] = x[1] + 0.03 * noise_vy #* self.noise_scale + x[2] = x[2] + 0.03 * noise_wz #* self.noise_scale + + if x[4] > self.map.TrackLength: + self.completed_laps += 1 + x[4] -= self.map.TrackLength + + done = self.completed_laps >= self.max_laps + if x[4] < 0: + assert(False) + if self.render_mode == 'human': + self.render() + return x, cost, done, False, info + + def L(self, x): + ''' + Implement whether we have obtained the terminal condition. see eq. 4 in "Autonomous Racing using LMPC" + + :param x: + :return: + ''' + return x[4] > self.map.TrackLength + + def epoch_reset(self, x): + ''' + After completing one epoch, i.e. when L(x) == True, reset the x-vector using this method to + restart the epoch. In practice, take one more lap on the track. + + :param x: + :return: + ''' + x = x.copy() + x[4] -= self.map.TrackLength + return x + + def _get_initial_state(self): + x0 = np.zeros((6,)) + if self.discrete_model.continuous_model.hot_start: + x0[0] = 0.5 # Start velocity is 0.5 + # self.render() + return x0 + +if __name__ == "__main__": + # car = SymbolicBicycleModel() + # car.render(car.reset()) + # sleep(2.0) + # car.close() + # print("Hello world") + env = CarEnvironment(render_mode='human') + env.metadata['video.frames_per_second'] = 10000 + # from irlc import VideoMonitor + # env = wrappers.Monitor(env, "carvid2", force=True, video_callable=lambda episode_id: True) + # env = VideoMonitor(env) + env.reset() + import time + t0 = time.time() + n = 300 + for _ in range(n): + u = env.action_space.sample() + # print(u) + # u *= 0 + u[0] = 0 + u[1] = 0.01 + s, cost, done, truncated, info = env.step(u) + # print(s) + # sleep(5) + env.close() + tpf = (time.time()- t0)/n + print("TPF", tpf, "fps", 1/tpf) diff --git a/irlc/car/car_viewer.py b/irlc/car/car_viewer.py new file mode 100644 index 0000000..0952d40 --- /dev/null +++ b/irlc/car/car_viewer.py @@ -0,0 +1,51 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# from pyglet.shapes import Rectangle, Circle +# from irlc.utils.pyglet_rendering import PygletViewer, PolygonOutline, GroupedElement +import pygame +from irlc.utils.graphics_util_pygame import UpgradedGraphicsUtil +import numpy as np + +track_outline = (0, 0, 0) +track_middle = (220, 25, 25) + +class CarViewerPygame(UpgradedGraphicsUtil): + def __init__(self, car): + + n = int(10 * (car.map.PointAndTangent[-1, 3] + car.map.PointAndTangent[-1, 4])) + center = [car.map.getGlobalPosition(i * 0.1, 0) for i in range(n)] + outer = [car.map.getGlobalPosition(i * 0.1, -car.map.width) for i in range(n)] + inner = [car.map.getGlobalPosition(i * 0.1, car.map.width) for i in range(n)] + fudge = 0.2 + xs, ys = zip(*outer) + super().__init__(screen_width=1000, xmin=min(xs) - fudge, xmax=max(xs) + fudge, + ymax=min(ys) - fudge, ymin=max(ys) + fudge, title="Racecar environment") + self.center = center + self.outer = outer + self.inner = inner + # Load ze sprite. + from irlc.utils.graphics_util_pygame import Object + self.car = Object("car.png", image_width=90) + + + def render(self): + green = (126, 200, 80) + track = (144,)*3 + self.draw_background(background_color=green) + + self.polygon("safd", self.outer, fillColor=track, outlineColor=track_outline, width=3) + self.polygon("in", self.inner, fillColor=green, outlineColor=track_outline, width=3) + self.polygon("in", self.center, fillColor=None, filled=False, outlineColor=(100, 100, 100), width=5) + # Now draw the pretty car. + x, y, psi = self.xglob[4], self.xglob[5], self.xglob[3] + xy = self.fixxy((x,y)) + # self.car.rect.move() + self.car.rect.center = xy + # self.car.rect.center = xy[1] + + self.car.rotate(psi / (2*np.pi) * 360) + # self.car.rotate(45) + self.car.blit(self.surf) + self.circle("in", (x,y), 4, fillColor=(255, 0, 0)) # drawn on the center of the car. + + def update(self, xglob): + self.xglob = xglob diff --git a/irlc/car/sym_map.py b/irlc/car/sym_map.py new file mode 100644 index 0000000..0142042 --- /dev/null +++ b/irlc/car/sym_map.py @@ -0,0 +1,450 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import pdb +import matplotlib.pyplot as plt +import numpy as np +import numpy.linalg as la +import sympy as sym + +""" +This is a bunch of pretty awful code to define a map and compute useful quantities like tangents, etc. +Defining a map is pretty straight forward (it consist of circle archs and lines), but +don't try to read on. +""" +class SymMap: + def plot(self, show=False): + PointAndTangent, TrackLength, extra = self.spec2PointAndTangent(self.spec) + for i in range(PointAndTangent.shape[0]-1): + extra_ = extra[i] + if 'CenterX' in extra_: + CenterX, CenterY = extra_['CenterX'], extra_['CenterY'] + angle, spanAng = extra_['angle'], extra_['spanAng'] + r = self.spec[i,1] + direction = 1 if r >= 0 else -1 + + # Plotting. Ignore this + plt.plot(CenterX, CenterY, 'ro') + tt = np.linspace(angle, angle + direction * spanAng) + plt.plot(CenterX + np.cos(tt) * np.abs(r), CenterY + np.abs(r) * np.sin(tt), 'r-') + + x, y = PointAndTangent[:, 0], PointAndTangent[:, 1] + plt.plot(x, y, '.-') + print(np.sum(np.sum(np.abs(self.PointAndTangent - PointAndTangent)))) + + if show: + plt.show() + ''' + Format: + PointAndTangent = [x, + y, + psi: angle of tangent vector at the last point of segment, + total-distance-travelled, + segment-length, curvature] + + Also creates a symbolic expression to evaluate track position. + ''' + def spec2PointAndTangent(self, spec): + # also create a symbolic piecewise expression to evaluate the curvature as a function of track length location. + + # spec = self.spec + # PointAndTangent = self.PointAndTangent.copy() + PointAndTangent = np.zeros((spec.shape[0] + 1, 6)) + extra = [] + + N = spec.shape[0] + segment_s_cur = 0 # Distance travelled to start of segment (s-coordinate). + angle_prev = 0 # Angle of the tangent vector at the starting point of the segment + x_prev, y_prev = 0, 0 # x,y coordinate of last point of previous segment. + for i in range(N): + l, r = spec[i,0], spec[i,1] # Length of segment and radius of curvature + ang = angle_prev # Angle of the tangent vector at the starting point of the segment + + if r == 0.0: # If the current segment is a straight line + x = x_prev + l * np.cos(ang) # x coordinate of the last point of the segment + y = y_prev + l * np.sin(ang) # y coordinate of the last point of the segment + psi = ang # Angle of the tangent vector at the last point of the segment + curvature = 0 + extra_ = {} + else: + direction = 1 if r >= 0 else -1 + CenterX = x_prev + np.abs(r) * np.cos(ang + direction * np.pi / 2) # x coordinate center of circle + CenterY = y_prev + np.abs(r) * np.sin(ang + direction * np.pi / 2) # y coordinate center of circle + spanAng = l / np.abs(r) # Angle spanned by the circle + psi = wrap_angle(ang + spanAng * np.sign(r)) # Angle of the tangent vector at the last point of the segment + angleNormal = wrap_angle((direction * np.pi / 2 + ang)) + angle = -(np.pi - np.abs(angleNormal)) * (sign(angleNormal)) + x = CenterX + np.abs(r) * np.cos(angle + direction * spanAng) # x coordinate of the last point of the segment + y = CenterY + np.abs(r) * np.sin(angle + direction * spanAng) # y coordinate of the last point of the segment + curvature = 1/r + + extra_ = {'CenterX': CenterX, + 'CenterY': CenterY, + 'angle': angle, + 'direction': direction, + 'spanAng': spanAng} + + extra.append(extra_) + NewLine = np.array([x, y, psi, segment_s_cur, l, curvature]) + PointAndTangent[i, :] = NewLine # Write the new info + x_prev, y_prev, angle_prev = PointAndTangent[i, 0], PointAndTangent[i, 1], PointAndTangent[i, 2] + segment_s_cur += l + + xs = PointAndTangent[-2, 0] + ys = PointAndTangent[-2, 1] + xf = 0 + yf = 0 + psif = 0 + + l = np.sqrt((xf - xs) ** 2 + (yf - ys) ** 2) + + NewLine = np.array([xf, yf, psif, PointAndTangent[-2, 3] + PointAndTangent[-2, 4], l, 0]) + PointAndTangent[-1, :] = NewLine + TrackLength = PointAndTangent[-1, 3] + PointAndTangent[-1, 4] + + return PointAndTangent, TrackLength, extra + + + """map object + Attributes: + getGlobalPosition: convert position from (s, ey) to (X,Y) + """ + def __init__(self, width): + """Initialization + width: track width + Modify the vector spec to change the geometry of the track + """ + self.width = width + self.halfWidth = 0.4 + self.slack = 0.45 + lengthCurve = 3.5 # 3.0 + straight = 1.0 + spec = np.array([[1.0, 0], + [lengthCurve, lengthCurve / np.pi], + # Note s = 1 * np.pi / 2 and r = -1 ---> Angle spanned = np.pi / 2 + [straight, 0], + [lengthCurve / 2, -lengthCurve / np.pi], + [straight, 0], + [lengthCurve, lengthCurve / np.pi], + [lengthCurve / np.pi * 2 + 1.0, 0], + [lengthCurve / 2, lengthCurve / np.pi]]) + + + PointAndTangent, TrackLength, extra = self.spec2PointAndTangent(spec) + self.PointAndTangent = PointAndTangent + self.TrackLength = TrackLength + self.spec = spec + + + ''' + Creates a symbolic expression for the curvature + +def Curvature(s, PointAndTangent): + """curvature computation + s: curvilinear abscissa at which the curvature has to be evaluated + PointAndTangent: points and tangent vectors defining the map (these quantities are initialized in the map object) + """ + TrackLength = PointAndTangent[-1,3]+PointAndTangent[-1,4] + + # In case on a lap after the first one + while (s > TrackLength): + s = s - TrackLength + + # Given s \in [0, TrackLength] compute the curvature + # Compute the segment in which system is evolving + index = np.all([[s >= PointAndTangent[:, 3]], [s < PointAndTangent[:, 3] + PointAndTangent[:, 4]]], axis=0) + + i = int(np.where(np.squeeze(index))[0]) + curvature = PointAndTangent[i, 5] + + return curvature + + ''' + def sym_curvature(self, s): + s = s - self.TrackLength * sym.floor(s / self.TrackLength) + n = self.PointAndTangent.shape[0] + pw = [] + for i in range(n): + pw.append( (self.PointAndTangent[i,5], s - (self.PointAndTangent[i, 3] + self.PointAndTangent[i, 4]) <= 0) ) + p = sym.Piecewise(*pw) + return p + + def getGlobalPosition(self, s, ey, epsi=None, vangle_true=None): + """coordinate transformation from curvilinear reference frame (e, ey) to inertial reference frame (X, Y) + (s, ey): position in the curvilinear reference frame + """ + # wrap s along the track + # while (s > self.TrackLength): + # s = s - self.TrackLength + s = np.mod(s, self.TrackLength) + + # Compute the segment in which system is evolving + PointAndTangent = self.PointAndTangent + + index = np.all([[s >= PointAndTangent[:, 3]], [s < PointAndTangent[:, 3] + PointAndTangent[:, 4]]], axis=0) + dx = np.where(np.squeeze(index)) + if len(dx) < 1: + a = 234 + raise Exception("bad") + try: + i = int(np.where(np.squeeze(index))[0]) + except Exception as e: + print(e) + + + if PointAndTangent[i, 5] == 0.0: # If segment is a straight line + # Extract the first final and initial point of the segment + xf = PointAndTangent[i, 0] + yf = PointAndTangent[i, 1] + xs = PointAndTangent[i - 1, 0] + ys = PointAndTangent[i - 1, 1] + psi = PointAndTangent[i, 2] + + # Compute the segment length + deltaL = PointAndTangent[i, 4] + reltaL = s - PointAndTangent[i, 3] + + # Do the linear combination + x = (1 - reltaL / deltaL) * xs + reltaL / deltaL * xf + ey * np.cos(psi + np.pi / 2) + y = (1 - reltaL / deltaL) * ys + reltaL / deltaL * yf + ey * np.sin(psi + np.pi / 2) + if epsi is not None: + vangle = psi + epsi + else: + r = 1 / PointAndTangent[i, 5] # Extract curvature + ang = PointAndTangent[i - 1, 2] # Extract angle of the tangent at the initial point (i-1) + # Compute the center of the arc + direction = 1 if r >= 0 else -1 + # if r >= 0: + # direction = 1 + # else: + # direction = -1 + + CenterX = PointAndTangent[i - 1, 0] + np.abs(r) * np.cos(ang + direction * np.pi / 2) # x coordinate center of circle + CenterY = PointAndTangent[i - 1, 1] + np.abs(r) * np.sin(ang + direction * np.pi / 2) # y coordinate center of circle + + spanAng = (s - PointAndTangent[i, 3]) / (np.pi * np.abs(r)) * np.pi + + angleNormal = wrap_angle(direction * np.pi / 2 + ang) + + angle = -(np.pi - np.abs(angleNormal)) * (sign(angleNormal)) + + x = CenterX + (np.abs(r) - direction * ey) * np.cos(angle + direction * spanAng) # x coordinate of the last point of the segment + y = CenterY + (np.abs(r) - direction * ey) * np.sin(angle + direction * spanAng) # y coordinate of the last point of the segment + + if epsi is not None: + vangle = epsi + direction * spanAng + PointAndTangent[i - 1, 2] + + if epsi is None: + return x,y + else: + vangle = wrap_angle(vangle) + if vangle_true is not None: + vangle_true = wrap_angle(vangle_true) + # vangle, vangle_true = np.unwrap([vangle, vangle_true]) + if err(vangle - vangle_true, exception=False) > 1e-3: # debug code + print([vangle_true, vangle]) + print("Bad angle, delta: ", vangle - vangle_true) + raise Exception("bad angle") + return x, y, vangle + + def getLocalPosition(self, x, y, psi): + """coordinate transformation from inertial reference frame (X, Y) to curvilinear reference frame (s, ey) + (X, Y): position in the inertial reference frame + """ + PointAndTangent = self.PointAndTangent + CompletedFlag = 0 + + for i in range(0, PointAndTangent.shape[0]): + if CompletedFlag == 1: + break + + if PointAndTangent[i, 5] == 0.0: # If segment is a straight line + # Extract the first final and initial point of the segment + xf = PointAndTangent[i, 0] + yf = PointAndTangent[i, 1] + xs = PointAndTangent[i - 1, 0] + ys = PointAndTangent[i - 1, 1] + + psi_unwrap = np.unwrap([PointAndTangent[i - 1, 2], psi])[1] + epsi = psi_unwrap - PointAndTangent[i - 1, 2] + # Check if on the segment using angles + if (la.norm(np.array([xs, ys]) - np.array([x, y]))) == 0: + s = PointAndTangent[i, 3] + ey = 0 + CompletedFlag = 1 + + elif (la.norm(np.array([xf, yf]) - np.array([x, y]))) == 0: + s = PointAndTangent[i, 3] + PointAndTangent[i, 4] + ey = 0 + CompletedFlag = 1 + else: + if np.abs(computeAngle( [x,y] , [xs, ys], [xf, yf])) <= np.pi/2 and np.abs(computeAngle( [x,y] , [xf, yf], [xs, ys])) <= np.pi/2: + v1 = np.array([x,y]) - np.array([xs, ys]) + angle = computeAngle( [xf,yf] , [xs, ys], [x, y]) + s_local = la.norm(v1) * np.cos(angle) + s = s_local + PointAndTangent[i, 3] + ey = la.norm(v1) * np.sin(angle) + + if np.abs(ey)<= self.width: + CompletedFlag = 1 + + else: + xf = PointAndTangent[i, 0] + yf = PointAndTangent[i, 1] + xs = PointAndTangent[i - 1, 0] + ys = PointAndTangent[i - 1, 1] + + r = 1 / PointAndTangent[i, 5] # Extract curvature + direction = 1 if r >= 0 else -1 + # if r >= 0: + # direction = 1 + # else: + # direction = -1 + ang = PointAndTangent[i - 1, 2] # Extract angle of the tangent at the initial point (i-1) + + # Compute the center of the arc + CenterX = xs + np.abs(r) * np.cos(ang + direction * np.pi / 2) # x coordinate center of circle + CenterY = ys + np.abs(r) * np.sin(ang + direction * np.pi / 2) # y coordinate center of circle + + # Check if on the segment using angles + if (la.norm(np.array([xs, ys]) - np.array([x, y]))) == 0: + ey = 0 + psi_unwrap = np.unwrap([ang, psi])[1] + epsi = psi_unwrap - ang + s = PointAndTangent[i, 3] + CompletedFlag = 1 + elif (la.norm(np.array([xf, yf]) - np.array([x, y]))) == 0: + s = PointAndTangent[i, 3] + PointAndTangent[i, 4] + ey = 0 + psi_unwrap = np.unwrap([PointAndTangent[i, 2], psi])[1] + epsi = psi_unwrap - PointAndTangent[i, 2] + CompletedFlag = 1 + else: + arc1 = PointAndTangent[i, 4] * PointAndTangent[i, 5] + arc2 = computeAngle([xs, ys], [CenterX, CenterY], [x, y]) + if np.sign(arc1) == np.sign(arc2) and np.abs(arc1) >= np.abs(arc2): + v = np.array([x, y]) - np.array([CenterX, CenterY]) + s_local = np.abs(arc2)*np.abs(r) + s = s_local + PointAndTangent[i, 3] + ey = -np.sign(direction) * (la.norm(v) - np.abs(r)) + psi_unwrap = np.unwrap([ang + arc2, psi])[1] + epsi = psi_unwrap - (ang + arc2) + + if np.abs(ey) <= self.width: + CompletedFlag = 1 + + if epsi>1.0: + raise Exception("epsi very large; car in wrong direction") + pdb.set_trace() + + if CompletedFlag == 0: + s = 10000 + ey = 10000 + epsi = 10000 + + print("Error!! POINT OUT OF THE TRACK!!!! <==================") + raise Exception("car outside track") + # pdb.set_trace() + + return s, ey, epsi, CompletedFlag + + + def curvature_and_angle(self, s): + """curvature computation + s: curvilinear abscissa at which the curvature has to be evaluated + PointAndTangent: points and tangent vectors defining the map (these quantities are initialized in the map object) + """ + PointAndTangent = self.PointAndTangent + TrackLength = PointAndTangent[-1, 3] + PointAndTangent[-1, 4] + + # In case on a lap after the first one + while (s > TrackLength): + s = s - TrackLength + + # Given s \in [0, TrackLength] compute the curvature + # Compute the segment in which system is evolving + index = np.all([[s >= PointAndTangent[:, 3]], [s < PointAndTangent[:, 3] + PointAndTangent[:, 4]]], axis=0) + i = int(np.where(np.squeeze(index))[0]) + curvature = PointAndTangent[i, 5] + angle = PointAndTangent[i, 4] # tangent angle of path + return curvature, angle, i + + + +# ====================================================================================================================== +# ====================================================================================================================== +# ====================================== Internal utilities functions ================================================== +# ====================================================================================================================== +# ====================================================================================================================== +def computeAngle(point1, origin, point2): + # The orientation of this angle matches that of the coordinate system. Tha is why a minus sign is needed + v1 = np.array(point1) - np.array(origin) + v2 = np.array(point2) - np.array(origin) + + dot = v1[0] * v2[0] + v1[1] * v2[1] # dot product between [x1, y1] and [x2, y2] + det = v1[0] * v2[1] - v1[1] * v2[0] # determinant + angle = np.arctan2(det, dot) # atan2(y, x) or atan2(sin, cos) + return angle + +''' +This is used because np.sign(a) return 0 when a=0, which is pretty stupid. +''' +def sign(a): + return 1 if a >= 0 else -1 + +def wrap_angle(angle): + return np.mod(angle+np.pi, 2 * np.pi) - np.pi + +''' +Compute difference of these two vectors taking into account the angular component wraps +''' +def xy_diff(x,y): + dx = x-y + if len(dx.shape) == 1: + dx[3] = wrap_angle(dx[3]) + else: + dx[:,3] = wrap_angle(dx[:,3]) + return dx + + +def unityTestChangeOfCoordinates(map, ClosedLoopData): + """For each point in ClosedLoopData change (X, Y) into (s, ey) and back to (X, Y) to check accurancy + """ + TestResult = 1 + for i in range(0, ClosedLoopData.x.shape[0]): + xdat = ClosedLoopData.x + xglobdat = ClosedLoopData.x_glob + + s, ey, epsi, _ = map.getLocalPosition(x=xglobdat[i, 4], y=xglobdat[i, 5], psi=xglobdat[i, 3]) + v1 = np.array([epsi, s, ey]) + v2 = np.array(xdat[i, 3:6]) + x,y,vangle = np.array(map.getGlobalPosition(s=v1[1], ey=v1[2],epsi=v1[0], vangle_true=xglobdat[i,3] )) + v3 = np.array([ vangle, x, y]) + v4 = np.array( [wrap_angle( xglobdat[i, 3] )] + xglobdat[i, 4:6].tolist() ) + # print(i) + if np.abs( wrap_angle( xglobdat[i, 3] ) - vangle ) > 0.1: + print("BAD") + raise Exception("bad angle test result") + + if np.dot(v3 - v4, v3 - v4) > 0.00000001: + TestResult = 0 + print("ERROR", v1, v2, v3, v4) + # pdb.set_trace() + v1 = np.array(map.getLocalPosition(xglobdat[i, 4], xglobdat[i, 5])) + v2 = np.array(xdat[i, 4:6]) + v3 = np.array(map.getGlobalPosition(v1[0], v1[1])) + v4 = np.array([xglobdat[i, 4], xglobdat[i, 5]]) + print(np.dot(v3 - v4, v3 - v4)) + # pdb.set_trace() + + if TestResult == 1: + print("Change of coordinates test passed!") + + +def err(x, exception=True, tol=1e-5, message="Error too large!"): + er = np.mean(np.abs(x).flat) + if er > tol: + print(message) + print(x) + print(er) + if exception: + raise Exception(message) + return er diff --git a/irlc/ex00/__init__.py b/irlc/ex00/__init__.py new file mode 100644 index 0000000..8239917 --- /dev/null +++ b/irlc/ex00/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 0.""" diff --git a/irlc/ex00/fruit_homework.py b/irlc/ex00/fruit_homework.py new file mode 100644 index 0000000..c2538c5 --- /dev/null +++ b/irlc/ex00/fruit_homework.py @@ -0,0 +1,119 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +def add(a, b): + """ This function shuold return the sum of a and b. I.e. if print(add(2,3)) should print '5'. """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + +def misterfy(animals): + """ + Given a list of animals like animals=["cat", "wolf", "elephans"], this function should return + a list like ["mr cat", "mr wolf", "mr elephant"] """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + +def mean_value(p_dict): + """ + Given a dictionary of the form: {x: probability_of_x, ...} compute the mean value of + x, i.e. sum_i x_i * p(x_i). The recommended way is to use list comprehension and not numpy. + Hint: Look at the .items() method and the build-in sum(my_list) method. """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + +def fruits_ordered(order_dict): + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + +class BasicFruitShop: + """ This is a simple class that represents a fruit-shop. + You instantiate it with a dictionary of prices """ + def __init__(self, name, prices): + """ prices is a dictionary of the form {fruit_name: cost}. For instance + prices = {'apple': 5, 'orange': 6} """ + self.name = name + self.prices = prices + + def cost(self, fruit): + """ Return the cost in pounds of the fruit with name 'fruit'. It uses the self.prices variable + to get the price. + You don't need to do exception handling here. """ + # TODO: 1 lines missing. + raise NotImplementedError("Return cost of fruit as a floating point number") + +class OnlineFruitShop(BasicFruitShop): + def price_of_order(self, order): + """ + order_dict = {'apple': 5, 'pear': 2, ...} where the numbers are the quantity ordered. + + Hints: Dictionary comprehension like: + > for fruit, pounds in order_dict.items() + > self.getCostPerPound(fruit) allows you to get cost of a fruit + > the total is sum of {pounds} * {cost_per_pound} + """ + # TODO: 1 lines missing. + raise NotImplementedError("return the total cost of the order") + + +def shop_smart(order, fruit_shops): + """ + order_dict: dictionary {'apple': 3, ...} of fruits and the pounds ordered + fruitShops: List of OnlineFruitShops + + Hints: + > Remember there is a s.price_of_order method + > Use this method to first make a list containing the cost of the order at each fruit shop + > List has form [cost1, cost2], then find the index of the smallest value (the list has an index-function) + > return fruitShops[lowest_index]. + """ + # TODO: 2 lines missing. + raise NotImplementedError("Implement function body") + return best_shop + + +if __name__ == '__main__': + "This code runs when you invoke the script from the command line (but not otherwise)" + + """ Quesion 1: Lists and basic data types """ + print("add(2,5) function should return 7, and it returned", add(2, 5)) + + animals = ["cat", "giraffe", "wolf"] + print("The nice animals are", misterfy(animals)) + + """ + This problem represents the probabilities of a loaded die as a dictionary such that + > p(roll=3) = p_dict[3] = 0.15. + """ + p_die = {1: 0.20, + 2: 0.10, + 3: 0.15, + 4: 0.05, + 5: 0.10, + 6: 0.40} + print("Mean roll of die, sum_{i=1}^6 i * p(i) =", mean_value(p_die)) + + order = {'apples': 1.0, + 'oranges': 3.0} + print("The different fruits in the fruit-order is", fruits_ordered(order)) + + """ Part B: A simple class """ + price1 = {"apple": 4, "pear": 8, 'orange': 10} + shop1 = BasicFruitShop("Alis Funky Fruits", price1) + + price2 = {'banana': 9, "apple": 5, "pear": 7, 'orange': 11} + shop2 = BasicFruitShop("Hansen Fruit Emporium", price2) + + fruit = "apple" + print("The cost of", fruit, "in", shop1.name, "is", shop1.cost(fruit)) + print("The cost of", fruit, "in", shop2.name, "is", shop2.cost(fruit)) + + """ Part C: Class inheritance """ + price_of_fruits = {'apples': 2, 'oranges': 1, 'pears': 1.5, 'mellon': 10} + shopA = OnlineFruitShop('shopA', price_of_fruits) + print("The price of the given order in shopA is", shopA.price_of_order(order)) + + """ Part C: Using classes """ + shopB = OnlineFruitShop('shopB', {'apples': 1.0, 'oranges': 5.0}) + + shops = [shopA, shopB] + print("For the order", order, " the best shop is", shop_smart(order, shops).name) + order = {'apples': 3.0} # test with a new order. + print("For the order", order, " the best shop is", shop_smart(order, shops).name) diff --git a/irlc/ex01/__init__.py b/irlc/ex01/__init__.py new file mode 100644 index 0000000..51d06d4 --- /dev/null +++ b/irlc/ex01/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 1.""" diff --git a/irlc/ex01/__pycache__/__init__.cpython-311.pyc b/irlc/ex01/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31afb3e3eb30d987d8b13ffdca6fad503c42634e GIT binary patch literal 232 zcmZ3^%ge>Uz`$Uh-<$T5fq~&Mhy%lnP{wDFlIaX73{eazjKK_=OjU*<8JWcjDVas7 z$tC$kl?uuEc_oRNdBqAP8L0}X6{$tZnZ>Ea3TgR83gxM(*$RewewvK8*yH0<@{{A^ zS2BDCnf%K}KO;XkRllS(BURreKe;qFHLs*tKQlK+-@wSk)S$SeGzB73l#{HVT47+Q zA0MBYmst`YuUAm{i^C>2KczG$)vkz*fq?<!)?z^h28IvJjEsyA7|bugP!S6Q0|Nls C_(1;v literal 0 HcmV?d00001 diff --git a/irlc/ex01/__pycache__/agent.cpython-311.pyc b/irlc/ex01/__pycache__/agent.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38d6cdd2e0550830a1f3c3198566c6e9aa1b77b5 GIT binary patch literal 21673 zcmZ3^%ge>Uz`$Uh-<x*Mn}Ojmhy%kMP{!v&j0_CZ8B!Rc7*ZHhm~t4S7{N4C6cd<c zj$#JWEKw{ej48}HthsDaY`N@F?2Hig98sJpj43QRT)A9PTwpQQ9PV76D4ty2C|)q1 zEr&0cKZ+mBX37zW5=dc8Vb2lF6^ar9i*e)#=ZZv$FfuSPxHF`1wlJh{En{L}Sj_}= zAw!gC3U`zk6GJL{3Qww73U3ty0|S~0@l+A8ZoU?V6n<2>Wef}qt6@elL`iTmV23F( zDIzV5QIe@rDWch6yNiNT7*oV@q;qAWWI(P<l}Qm_Be9H;fnhZx%)lsFCWchWR1hhe zDvK(I>W&yD28JlPD0wD^RE1PIRFz=UB~k=ZBvYhPq*9nN8P-TIV`E@g%?7te5v)%U zU0(`QFaro{%2pMIWTYxMrl;nWC?w}378mPraRsHOr52^;C8ri!aVaQ7d!!Z_nZzoD zl%^_pq!#5Qmg*@4rxuo`=9Oe7<|w43CTA9B=I1HoCT3^mrRynZxD}<Q=2R*qmL+E9 zBqrsgD&*(oWag!6>L?f)7@6pCy#%?=Pm}2uw|`MeYEf#6OJ;J(Ev~%8+|-nk(t?~+ zO~zX+C50)unoPF@a`F>X;!84fQ{#(Mi!xJ-Z}I2kry~n!GT!1%t;j4c$;?ZSFDlI| z)?~cJ?3!1m$#{!1C9xzC?5Sjsl`sqoozGbe3=HiI(-~43q8L*cKq)thIfW^eC5<VC zxrHT)HH9~YHI*%eEtNeBmhKr+IVEA{Fr=}hu(z;Aai#F3aJDc;ad$AJF{W^}a76K> zaHn#nF{SXdutf28FjO!`@dYzz^50?whjZd%76t}TsOKhT<|!m11-(LWYN~<;IJ|Wf zf=iQ%Q<F<TL2IICqGznBkd|MhkeHH^2@(T`d`V(v4k*GD6ciLf@)b&pQx!@wQjv|+ zQK-x>RVdELFU?6&NXslLE>TD>N=+<DRY=TJNX;wDEXvQzP0cIOQ}E1FD9OkyR!B}P zPE{yRRVdHQ$x+BEMbVI%S6q^qmz=7Qp9Zps3uJFXf@fY?YF<fxQKc)wyo3Y=jbdD$ zG14>E)Z_x|wsNgV%q_@CwSsU#2I}c46qV*B<>V)4TUjX-R3_)=AtXTx?Ck6m(u(qP z6*7x*k`*#@3-XIfpeYz6O*B?kh|DilNKVXynURuNl$u<UQwcG>B)>p6C$%g!N1-4w zIXf{u73^S`=^#fyt<EdWEvQsTELO-Xz)+G`pjVWbmy(~WSDc!fqG4jB2{V9rT3Nv@ zvjP;}3LrDUsh}vepeR43G&wUdDKjUtq!Pnkc=+h0Ru~xSWx}E;9x2XY-o_Sx7zU>1 zl_}UNU{k6=w3n0>oZ)E?Eh!<VMGU(kS;Q6+#~P`5WklPE2xNSAgU#2&u(sGhM<FvW zE#E-F7UVp=qSWHl65@Rewp&@jF{eDS5|piSaumQOD3s(Y6qh6xm4KrZDLyb9kO;CF z;<$oL4UluPZJ}<m1v`w0a8OnVNzKUtTLm@=WP5UcZb2!i2!NC>Dv9yc*|r9?Di{tZ zD9X$$(MVJB%mcZ&Bvqlh*ub_{2gS7fYzP-(R&}C*ZLN|f*rZ#`sd;6|;5rdnWP;et z3=9mPMHoP>hZ@EjhIptH149a9FoPyjq68xYgD1G0DaiztQ=kG3Tx`OtCvd=mN<4T` zmszZko>`U(D#20}@(WV)5;GOjD|11y1}oqcGD{S4L8Vz{UP)?EVseQ>d1gt5o<azy z%uCG4$uBR4_yb%Vm*gvC=jE3xlxHM@qY3OEkiCfzZzkrYDC8#<rxukZf(m1W;)2BF zRE11fSqxHXRghSe2zG*%0;sS@a#liuYhGDGf&x4bfcyxF9cW37>PWclewvI$ybKHs znoPG?ic@paz?@=Gs46J@veeJW&rQ`YDa}aLcgasK1r_VX`kA>o`UXZOrUu0&r75X- zCB^!nQd1vPD(Hi))GMgG#StH$nU`4-A78}>4r)CZUz34>p_re6fuVung8+kwcn3=l zM+Zj-$7fKi`Q2j7zQqDch{-G<J`{u4;7I-iiDc$RmK3HM<}$`2xf%vgl?zdq1#b*3 z0C@l+h(w|`z=9b#8ETkQm=Klk0+1a@>LE;2T`A1jAlEPy@t1Hy<UwQ#3u<$yiIEg{ zp}JxXE2>$+44Q0-G8_yHu4Rcir6}oFy;z|jKPNM}Qb8kAFI7)RAsLzt!LbiXS70VM z1(qk~m4NbUNn&=YrUEDxX6B|U6qlqHC?q6ggA)%lPbMT3CnO+BFL+`Br|jhXqN3E| zg8aM`uwfagD0w0&H8U?=0n`YAnw1K1HAvJdH?btcDxo4iJ3&VQl-@yZODoNTI24*r zk-d<YT2TVG9GXu+dcdhnp**uV1MGyv>{L*z5|l*{7_LuGPXTN%s*=+9Yz13|nB3C% zY>kTeY)J6}(hb)K_H1ryVjd_LCzdFH14Y4B0m&C&Pe8&BE}pGm8&hqdqhP3`pr@x7 zQ=0%P5K<M;y;+o6Qd*P;YBIt7l~|&XlbKo!3OukU!NH;nE(hR_g0zy5LmX=~rGjf2 zg_KON8Hq)esGbKE9tjDcY?hFqi%_JHoS#>cn3)GkRmH`bpmug@MM+U2*s!8pNVx=Y zcxno?MS~jsI^d=RybvnSNX=77PRz*x#XiVS2?@oJ3J|saOGto+55ha3$N)JM+@uAy zLo-2zF{nA2Us_ZQDjGo{1#)sxevXbpc}8jxq^*k0Lx~EYWSFV|@pZI1wE3T$pO;ds z9t&z(mS<!pXDA>NcQH6=Wuz(;XXcjXK>QBU1&jX@P+_Z3oC-EV6V=)9=mPm69NO?r z%qd2+r$J$l6g?oja#F$d0<@_Ot}BvLi$L+A07)Xn3W-Ij3VHb@h<*?#ZDkfKWELx= z<maU-BvmRDr<Q=aE#Qg==GolD;%ty7b+c0|^%PJX=a*js3N%n*0IIbzi$OiBN`<1- zoYXQ<aRKTd6s3Y(Ta=s%D*hF6QWJ~vGV{_QIT)!c0BW0q;y49bQGkO?KeZyYC^@q@ zwHTZ-up0%I!qy7`1s@2*oeWA3DXD3Rr8y-ENvRo$WtsU!(4GS{+%m!O21%p}i3*UG zGBg176ddyuQenLVkij4fHym3p0i*zg;fg>UP(vNj8ZJmo&P~kIgHYHS!vSCgNIe<c zhQZp;;3^YC8Kl9CVVnk{@PfGxYc9hu4^oWcY6N3ft_Ny1>L{SL8Z{M^71C2n(8HUM z2`Ft%Wd+YPa6tn~&7eeHT#%ZanU<NFqN9+QlLL)HNFGQmE-uYYO;IRFEy~S=lvJo0 z5EKrG9v-yaRBWZ-Tv}8F8kQ(7fz_i(jb)I<nRy6<pxQv09#lypbc00TezSt4HAssL zl2O5#4-&Y@buOs50%Z_LyAt9AaK=l8H8nGHQ}q;_DivT!9Hbgz4#bjToFVLYiv^U+ zUxHddRh&+VDGDI2q9$XJ7^rc_3U1cj;(@p?9$cr~Vk-vslW#HSCRW_ybgf8EEdaGV zHCc*4&9hsK#YMsl3=Bn}hIKKh%>xS5A^`>lhFeSpnN=L%G^$sSX$)%6RYMwd9*hh; z0v$Fp%vOk8kk-8*t$RaQe2T>tVU6p;`j>?DFA5u85jMQQWB7rEnb+<E2ZMmf1h<}= z>-_SU_~kG1D_-GOT;O<#U-bgN>RmDU1>6_Kbgqc$ToBMfHD*J|4z(>Y7eMAYT@iM= zz~fXT#K6GdmJA<KVPIeYg#@TQ_Zc)cGac3ySj)x0;0YQX0GDOp(Fu6XoCzL*fR-Z} ziQs|+T-qsUB&8~p6eVWnrKV`=A<`A1@B|fu`FS~&3K@xIsi49<6Neq(Vxv4YHCw@4 zAwRD?u_&cjL04BHDK#x0Tze&!=zvB_U<Ez6(Vkjdl9~caJkYvMAvd)oBR>V&ECIU^ zk!a!R5>!+|(hjJ-2TD14rMXF|;Nmhfub{L<A+abO(xTS`k6J+6Uzxdy>6v+uN&#*d zqSDZUwu3<BY(}a=GD?O*Y8oZL^@4OHf?Ag#2d6^wF;W&O$<NOQ`3{mHz^yDD1yFNV zAt3>z4{E5b0(z4T)rum76-B9_fCXED$U*7(C9oz-VhPk0C~hn+05t=ObqjJzi#0)I z0Z1>zQ6Ls_K~Vx~*OU|`<`shn&Qd`wVYr*Y=D;0Y5nr9HZCH!!R`rAgP;H%%piq*U zlLHMEa0?xp0+Fo(rNiQq{DOki6cpEjs^s`$gr7ltXcG;&MF%N2Qd2-p19V>`7K3`Q zXx@NCFBYpnp#zO{YT8wR+|f`#q%%<RP0I&$qCss(Xr&DqLCnZ6NKGrv$*BZ&--|NS zDnZ@=HGMMj%R!1W^2@<Pl;z+N%G|`f(nPRgP%Q!q18`2(g=hQxyyR5m<}uvw@PR~7 z!H48D1yr^Iwsr&D5Qts{1=KbJsIN@=2pY&NWmppdDUsl}45k5GUSm}XX;;vHAP(do zP`E&fDO~LkkSfBM#KAa_fgr1)4W;;E)D8(qnrN)70B(VUk`_vFh&8Me6>K3j4AzEJ zd@)L!2!|7t!J|KrP=glkdFUk?Oe@%v1v&~vI^ZsXjzT=70~TLg0QEAcZKIJ$$X;ay zqz0@)X+cV2Nop~6AA*W9J#Z$|DArL(1lwI)0J9%dc*Mhly#Twt$_gI&<&Xj#RPBOt zH9Wt9dVq;JIjJd#iWu$=&pdD+wkSUb+%-?B%uCG8Ois*EC@9KLFG|eK1$SHua#BGv z5=E(?uBk!^bU;o4T5V(&E2I{dCgy;u@!ZV3Qb+-voL^jmrIv-Z5iy#U(DENN)B$%K zRBfV_f+M(Ft^kU=JXn9SG(H<qNkEkrSt$fT>azSKP)872j)P~#pb-w!o*17E>5zh3 zws@>BE`T&uVKp1H1&UOhfSNkUH5<%|>X?|MG=+*<^coH7SV+V|3<t5HwGnbJ7ty;0 z#b`-Bq_R;!uA~wYQuE3n<Km#|7(9Xi^-Z>|L4qbYUh_*bQj5wni$VQ)kaAEGMy^Lt zTm<zml9P}tNNi35Rdtwdf>?qco1mK9N+CQW733u3aT$dYQ0F8s5!7}A`vOtXB0OJ^ zfE4EtE3Fj#^79ZALw+k6G&#Tx@*){f)0;8z7Gu#Zrs9HIEFi0Iv4Q**Uwn%lLKhTs zFfcH{GC!oX&I-<pRovhT0Fp65lb6MyDftG54<U>UoV*<@;3jl3sMQP_&;()77%I30 z?ZUvoFqLsSLkW^B>Zs@fBpHxa2u4*C%%I6wm8zxX5AJ0o=2&TIDL5*W=4BR^rYeAD zYQe(*;3he^Xwy>&Ed~uU<rgXBBqpWi6oZC%@)Qbk^1&k<ItodpCE%&Hq*R6M)B@1p zSvIKInpv!;$#jdgxU?X(=oWi?d~r!pe7q(TI1F!b#>azaZ{y=3W84kkASwb4N>}kh z0tl+3AJnZ8XJBCX(ZKMOU!=3Vr@X(utNtRt!WDjn3mgjI@VdnYi8PdO1BC@R+#o%V zOa`#e@1pt~PbUP_nShOL7NsWV7o{j*4#R;v5}+z4Apz{{gan21jLaNpKLs>vjwl{s zbCSi0X`os3%=A1+XCt#1+LZv!G-iUPFLH7q<3CBMpqbwkaE!ou9VHp5`9+nWQV}}c zo0plKS_F=dVud1k1_p+ejNm{n1_giuIACvagIyjEDr}0Y1i>!VLlT+{3S`hYdIJNf zHz?G>2@ckkjDDKTZhn56{GfRRP}+!(zr__FpPQdjnv)tIe~TwR9#lj_W!U56Q}UDJ z<BLEh6$yf}33Fy%$t|{$%7V<i^jjRTBzKDiG&Wcy3+mRYfe28%7wLgC@In(ta%xUa ze7q)Okrv2lAfGsZeNw~&QV$}){o%uqgwenNfghNJSUEm0fCvo^R`D6m9~d}T#nA~7 zT~=qt4-6o31~Y_S;I_nngUb~aO9&SWnZT&U%KL!<m55+uVpaUWfQ8^-VHKJY@_~Vc zRfq@z9NJ*7X|mj60gY?iVg<!j>Mb_NPyr}`gE~{UxI&5&vr>~mbMl&uw>VPs%HlyK z4yYi3WOfDy22i30aloq}5NjYp8B&>3SyC8n7#JWdCNPUNl_iB4%mT@>fLJN4QEaK~ zsVpgMP##ArXDUkyJBXLcmBP`&fLf$Pai_2bGiY+&Vht`yEGfRlo?4JuoS%|<ix0|( z&q>WoFUhzil$e}c3LeHyO^Jup^S8K5@=FqP;z7lFvEMDO61e|vaf8brNTNl_+3*rk z0WuGTH1|})fS7%%;$~n7W+>7Jjl3`wIfD|86Nu1-B`Ij;;7cq^ElNyJg}SIp1ndhv zRMF)iO`w6828IXx!dLj!R)}2Dw7JM{bAiJK9DSNRMFt?#4MBtvh%f;qX#V*4#Js%x z67Vo=aeVwO*0h}b#F8RckP2H6;RYhiL25Y)it-Cmi%KesJV0WgybLxPlJXruVjyBJ z$SF18kse602aykW1sZ%Bd>Vajh=^Zc0ila5;x{B@FR*~nMHblyf+81KK<FZi$PGEA z2CoTH7g&@ouqa(*QMw^1+u%Jx1)-Le_X86ntL+B{MpoO8%nWRNEfEL-uqeb~Am<c; zO6QR0p!zO;0h5zkGH4zXl>R^%lv6?J@$)lY28MP+&;U>hQw~EeV=ZJY7;_FoE>kTZ zBSQ*HEq@AYtw0T9gIozaNGk-Vu%k}HF)|=e_|-6=%GNU0a2J`@Ff|&NfT~r95e!+N z8UV~*fMhaQ08G>{p_)=8QUWTyz;X->S)k$!%tlwo$WX)7XkWwLXj>u*Rsbf@Rn@R( zvw|dwv`RoB1!6KVFw`)u;Xt(&v>vQhuvVysqlll0p@y$UD1{TevJGW@S*>s$Q#wPf zaE)M%a2iuELpnpPU<zZcND5=EXboorQw@I}V-065X9`=bPz`6136XXRHOkirrf?x9 zVN<w~*gPP2pvm(h<ZDH0ML}*#VW|}>K?pO{FxRl~FqB9^z0APCki`dM*D$B>L8owq zN<b+cDghD)Wn9#-$zx1mTf@JMg@Iu;Xb2Rn)|8=EyhIVq1QRvPsCrx&CNRf-t(B+| zD`IA3n82L(K9iwVvWB&otwth+5o)(t4Ns#?4Z{MY_y!vWCTe)r2%wq?jw7jB$rQF) zp1crT`cO+pn4UbF5>>FVV4{X0MG$p8U=c?RLl&rn0n67)<*A^l7s8?*R13n?^VBe8 z!P6nKN$Cu=(j}l$53G`bAsr6a2rpx0U|0=KpCHLD!xY9^nG#Tu3F3lcOajV4EAw3# zCNRd{s+Fx_T!0kgFtrQ}HBvP)HImDi85mZB@;_LjR<1@S1)P>@L1B)RF2K@Yq6Tdx zWDF|<L#=$RLak!0Qmt~0VgX}~Qmsmja-(62NR4tCLy>Nca*7DT2@9mb#-I_XF_OXq zjeUNUl13CYt{E9>7#DyV`)Fo?{U%qVP$OTXQX^TTyo{ZJVKuy5VPvS`DB9F%m<4Lx zfORgA15;>3i9JFf3sjGRxhY~bl4T4<95s?DVhBIwG1iEnx($`b$k1t+1y2ds?W>W( zq6eOPaOgpc3$Q&(V23g=Fksh%-Cs2dsJ5f>z~(CBH@8L-T~CcPb{C-A#mG=2lEPEP z%fL`8QlnDLRwGiw1}%|GhzK`%bbC7uvk19W8H*mu(t|Q-=>g%#S}{h3JhmG7TB#c4 zTFD8FJ$Gt2in2ICYqiC5RB}~oRT&vdd|_eFz)-_bql#9}s3DgfDH@p!9foO)DH1Il zC4LBfE@<V$62=rs<dDi_T*BDL*kza}uFOypfY7JHP{dWM7RivpR;yO0md631%NffV zDwrb~${A~fvBz?!A$l0sNI=S#8m=lf(3&&onr-hILF^{fNYsde>a~(!gllS~QB5rg z#VuDOk|H&SrG{~VHbM=8g<9e)WkfZXk%4fXSF2v54zH)GYb0vaQT$be;x<84^Wpkp zYs44mAY6rDl|&=4W0BZM;;1z~stpT}>Ij5xR9~a&NMTEnZbe$=g(|y729*!0@fjIv z#20`X)d&lqEL3|ywR_L^6gCh<O}mT?dECkjh783l<xG(D#K;iIz{tRe+A0CH*}*0+ z05#mfEMx-Rwi?bN=^B9|$r_<X@e*!?$}G?vESOs(lp+gCTc~~lw--}u1d5VNGQrBg zL=97o;2Jqpch_n_TY<ba!ZjMub|A_g2u22!x=X%>X*NTOLW<%7Q?Q|EM2%nyBceW8 zV1_0Q=A!x%)#bApQk3SREr?@eD9HzF1QRvFs5)F2V!wl1KAN>!DU2z~ITpE=wc4P4 z4K>;+DlO>kcAXk6M5)?%6PcI7gK&A{nG{uAa%Bufdr?cI*xXuO6gMK-f#KRPuxn*% z^-@%8^vW2E7<;&C^iot2b}z63dlZeR(M2^W%NnMjR=-9jg%Mf`G3IgA=%?_cup#Gw zTKyWG8eJqCu(lLx^igeKWatU+$wTw0cC9W-%?s+PgB_Bh*1~{l3wlYN!nj5qHT8ki zgAC}=K`;4hbU@{LIzuM7G_N(NF{lx)(FCjg0qc=yY9^lN0&RoHEQT*915JMAfEO-7 zhVj9R$-v{Gph4K2{QLsY*jGwwadJ^+5@ePg$7Tr=*vvm@W)iFsyqy8MIt(=M2wHRp zSqKc;V3CwsQl6R$+l-L_9#TjEk6wdD?NSl@8Wcby-q6*SAhY2U9iXY-M1`FE63_~# zV$f=s#2mQC5<zS9brg#8L6e`E#h~H3v{LY#MRI;#ab`+t5qSC}IX^cyAG8LqIJFpc z`4e~`8$3G%8amNYh*z)$4g6>3fmXxoK<21)6!J=Q<Dp|I#kNM!9Tvfvkf9U>@bU!6 zKoNMTu%tX+0j3(VBo+IJc(DRVC1|**7#t#*#gKLE&}DQ9pdqN@1juY}QmR6tLQZBe zI20hmIbhwOVadcy&`LD$sv+2H19)6CH8D8@wBrLZ1d8Oz64)RQXq_ct|LQ=eCgKr; zU$!AdrK!+xNI*7@0_TDf1UNvDTnAldg5-AW5tLd{kXn=pTFnv<8V$8oM+g+_=T?HY zFR9~-M$lRnXjns5^CA032Q<=~sE`I4Q--dM1nuuhEY8fSR7gry0PUhmP0<Gr$ET)1 zw&o;5R%RCGr<Ih0mau?U4??Hzi$RGPG`J6qV{l3bn+@6&l$5FfN)5WjC5gEOsVSgj zU0Mvvp~b17A+j9sBGO{;tUhRSO;Kt=Ds<keI59U>0pVu_jiS;#O@-XVyh^Z%u;ueK z2}d1;+{6k{2p8KL8bH&8W3fVFQhr$~WO^bcAG}_(AhjqhzbIEB7c%ain5ST907{?5 z;5iOZz6FI8#8;`H(SBH*!kiDC&`QlKvjVMQge?5mb+61-z*zXN0ZL6s#S3I{Ak+YG zDFikGF>L@_tqU#?pz06-3Qkp!Nxl5ilH~kc=uR!rEGazc!E<VHVi}|mO;kwB&jA%e zpe+%QU0|T(30<!WE;+$FB*0Nxk`D?Dh1}AdlFWjfR0R!KNN6I*ENH=aS!Qu*Voqii zq_{0gEiTO|0WX+NQ~)KHoK*011ZXiZXfbbQu|ipDQ6;Dj$S*1ZEoaTlQ^39i6*9F8 z^*wT-XQki=Up56V+CbZFpk*L(sFkG_CFK{VS}C|>78m3sRw{sJol}d86_OH*kQIVA z?N})|gI1&<O?YZ(CM3X?f<fyQP)!2f*`uf60$ul-S*(zd04jwNz)Q;^%YVU(&q|9y z>taA_sleVY0%bwa-n(KH-+|IBc+lHQAp|x>sQ_Mi1ey;5WgM_9WGP!}PGSLQ7ES|{ zK=bnRbYZiapv;Ms%8F5v8ORFIzDX+u-^7Z{+|pc7Jpx^O28&yys4WJ?cwuQ~Q7Xu5 zXlXAY0mW#@d|N!cq^bl>k%O1g!-YU)JGjEo@J~wvEqsD4r!39{Z8Xd*QOM0q&nN+{ z6aXzF1=X<N(kVAJH@~P7%{Gt<$V>ppA`lO}uR$R>KPLyel@eU#<RliCfK#yssE|`A zN`?9dlp7NgF#M!YmROVt-pN{$4=PQIQ%g`R2JJ`%*RExWIaUfj`RQO=ixqM}sVNO) zdTJhMTVY8CxKK{cfYrP35+ySYoVQ>LP>V`INguorDkncL9Xa$-Qb$T^PHIVNe11+! zJi^h%R-nbXB}JvFItuwYDGHEmjwBB+03g~^p!popE=egZ0;QOg)TGk%bnxsXXpS11 z-#~j1!G#jY$LXm>Al<33rQ6U|i|MI(sYQt;h~?f$i4Sf&IA4M4EpQxwj0G(nhO7z$ zC1Cg-N6^*=Xz2m<JtSRODL6vf8j#%t;C4hRr2UA#H2^H90nVGLDVm7j2UToPEs({^ zpee`9{JccaR%1vt3vIf98)%@W4rr%wGGu{#31~42w48ystOzveq{(=TJ2^2qBQ?If zD6<5#o0$v3ElN#HaSQRQiirj{YGW1r@*zz(h4RE=1#qJgw1gUzDnQ{6+Nh-mo`nUq z@-!77i4|NcC={oH5_B<iT}d%$gAio(yrw4OEq+8~gKLB;L4D->rdN=i^YZ`y|Nn2X zyF#Ymz>_nedAZbr;+H9)nJ|`Htl$~9TkI*B#h|2riv`rUxW%0dYQ>d+HooP6wrPW+ ztq3&ySp@3$XtEYrg65w<>>^MXrwG*OFR}xPftEJkVopj-xy1u&J;cK{V=&$la?Z~y zDay}5TC;>Qkq4Ti0gZTrXDUHU8!{Pc7-IEn8EY7k7darN^imjF7)s!y)eH=sOf`(C zeHZlJ4Qk(MGE<KMXc+*CD?sLfT><JAPiII6xk0QJhYM=ZMsg-H^@s;Efal#cnQk%V z72IM^EKV#cN~{EN^$cz?RY2D`KxP|%aoK<hMbP#tyDAlMYSFXF$xlwqDYnzI0VPtf zlpaEr9U}unF=(W=f#HI41r&ux9(6k6b)x8?-w{8kkaGoiPEM1#2(<GOJb|2?eTzLk zwIs2mq)3ywC=oQr$eNa!nv(*aek=wJ%qu8B)?WPLLRelUiPK$R$3#G8-9Ioe82dA! zk@bu&OdCx1D(%sLIO}R`%7xVY3x#DDW6Q6^mS1qLxaeGQ#ku05Rpk|{N;J*J{!Cy$ zfYX&GOHmL514EUNBVy7Rx(@3Wn-6$Gxd=3L_YxF;nvA!2@*!sq#DfB{ibFpqKV7e+ zqC}JF78fGd+~NR*etdpXag|I6Y)u;|#6iVviXNzl2bGHoRm@fj>QziS3cncDLAf4U zcY%yf2KTF>1ZZUfIPHL@7(r<VI^hgX5D)^iCLTP4`-{USCowlECDE=*96f-c5{aO= z1{u}But2DR0UQ{&xWQ{^AiD%m5-uqIz?Oro09jtc5X%C}JQJCESfPm$>;_FHNaQnC zL6+M<l423aCzx>!3LsF3*yV#91DgJ6V7Q=e2|+6oS1>|Y7t}4m&I6Sdi4~c}5Q}VY zv49G<BGAZikv}-Wfwvli7dPBu$}hgfQjl1Zaf>yxI3=^_7F%&fX-Q_zEw-ZElA_eq zBG9U-B9Q-!K#_Wjxwx|U7F%&iN`7fc5qLVCwJ0$!J@pnVxQe;Oo{?A#O5BKY>K1Em zeoAUi5ol)p7H4KjYEemkeopZ%*5v%syb|z|lUppHhE)-0_NfTG`UF(4-C|2DC`ipq z0q32f1W>VtTFTv$1^ElK=iWpQRB;sL=OAw~DvAO5l`FFt){MW!2F_^3MWFepTg=6! zxwn{eQu83IT)2x<OX3Uii%ZfnD~dp|c#8!T>bF=kOHy--Z?Qqvb%K4KT2usDGEiEa z0a^o+n_re%1e$BQ#gdhunRkmNJGHX-7H4W+X)dT*PQAsAXb=?_<$>HJ5FZaM0y2|I zOF*l37(+nH@{$uvQbFtDG>ss;Qdq(DPZ4Nr{uU2%+xr$fv_)N14>FJw)T{&rVeu^v z5EInGyd?;!xRDx!w|GD`JLq%|(7?tm9^|IfEip&~1-*S!6bTA=MB3p4wQxW^T+ouE z)SO#fAU>oS2rl1Bia~*roSIj1iwC(L1WBeA6yM@VEdZ%5D!Ij-RFs;S9iLxXl3H|& zsig20XC`bwrAP&2DY&Ks*J+>}b&D~+2s9~I1e)zC0u{cuxL{50)RbGCB}Jv+@JlHI zP3aba=7S(9fHCzJOHpD;YEcC!s2DSEF_u80fhn)#7Gv5irqs-$VvrPQHDHzzq#Onf zI)mC_Bw^@!C~yh}5$iy!LT++^7s`FeVq{=dyuhM>jBc>VUqD4SM5P-19tesyc->&< zX{f!+!Fz!(=ORb$6^`5s9JzM|L?<Lq<eI|O!TNw*7PRO?eS!W3CEKG)N7Rq&9@4!K z5P#7r;fhnj1tr_N9DF^z6Y?)|s9oVuyTGCLfL-hYyV8P+3+mQKc~9hDbcnm+5O*Od z>yks(1&6G=5*j<?FGzS^l<>SF;n~UC!P-%FgIneU12d=G4QbUGRtwTD=sH|fbGRt& zctzT=!>7aNfwXLg&kcT&2{{+|l`e27-QeMCaJ|99+u(YGU!cL`hN|HORm%x>6YO@> zH26H=6>M<3!7luPftl5l5xZ@I7r13_$SE&ynv=PL^NO6&2E&VTCL2<BIBm&1z<$Nd zV?t_&#{*%}2A>B);tk$UIe91etVmy>z1Mk<*M;253stq3a%(T-)?N(>zYvjfAvNP- zM8?IC%qt<87eX>WFfh0<d4Ot0E>EV93=CYJOkcp{2L>NTR*4S`48BbMOm`*aX4G7i z)VU(5^MS#ekyGL$nC$Sp!7ufJfst42hJffq)*GVY9d0-HMLsZa^D4~XT;Mp1cLwhb zVet#X$~P30mvb)STv4)s^P+;u6$O)to)a7=l--b)pWrgV<pD%?A@>q)i1>uEyMhuk zgl8mQ6jZt*sPut>l~>`0i1-xO35*jMAyVlV1=X$ys(oN!hDdpWq#lTfPw|}MJ%RB7 z$SHRvl~)LDFxruHLg+$R#0AO7i;|I7BqKY#ZU_i=INlYNn-YIfRPBnW+6M-CUd4|f zVglm>5y|NulRRbwE?`_>c2Pv@iip+(#v3A{GZ-hjPGG!YVZEPY7smm?o!oo4FAA7W zV4C1Kp=yEUiu4=eiWkK77DP^9c_1uxL0D~t*@o~7+BO%oZ4QW^5IZ7&-7(~nW5`9v zuq%#X7b2rBIYwP@jJhi#IYV`#&lH~tJ`V&$r*lu@p5Zv7aDn22pcNu3$~Kf=6tKS{ zV1Gft{(-Q{2L@I_^BW>^Q~a-sXk8M~T5Gh%>Ow%=g`|uN0U)#?ZAaV{GoK4)J{R(e zFKU-u(Jr|tQhG(C^nys~4H3C3A}ZHKv@eNhuW-C5qIX3^?}CUPSXlMCh|VPuofUx> zMf9(T=wA@gM;2Ziv?gi?<I31Iu@^<GuZUP*5U~bJt6vw<yCkBwqU@rG*%cA93nFF@ z1jMHEPU4-Bcu_#%ih#le0fid^qB8_1a!p|Uz`-CQ0dl|84ATXkmmu5xke%d&YB$XA z@{1zoS47M&h+z0TF#bYv=7m5I+K|2@?~0l41vB3Z`6U;%ORs2`UKA<2B2soir0j;0 z`U=ZSN+uJ$Z-_`vaJ?ZSHi7Ymq{0NYiEKCc6+r3K-~$tfpyUmafD5STuDId?<qPVT z7saivh+BPNU=+<`x~r=Hfq_9S50qOVBxak^*q`Yu1A_;XA4rk0KPXEX`-8F+L@7iY zgp6WJ0ZBwL<$}~g#Ngx%t{*?Xaxh3Jeqdk}ltd6WL?kA-K;VxbKYn~*W)zeJ(QFKY zveyNaF9|3w@VY3Ve?>t5f`I-F0m&JT6L}ZNT;$i?Ab5%2=mNjd4FS>VJd=1<NN$L@ zsA+rG#C!+aM(-`&Pc^hxxUJ+~!+k?t=L09JoaqM!5W&TusCHe!@REYzMFrz43dSF} zS>;SWGO!AoeE|`mI5qpq#~>m;p=LqyMRCoG!dh2^wK`mG@C#2!?5gOfnBlpC<)Vzv z2F6P=h8JWE@1|v5$jZN%R&XV);6ic9rL>X@X(bbwrt?kWTkE}-WpDHe(Gx{yBrn<q zU$G6oZX0>YHu9ov^cCCaixx3gEMhLi#$SkwzYrUL#UkONPU01v#0h*C1(L1^BwY|l zx=>a3;|333zh{?cr+1Hchj*v<he#$!DTW|Fg3GlpU=miwA!IQ{K!J-x@z)q823C$1 zuj?!#msmtDvWQ(_5xc-5_5f6xGqS4A-~v@dstd|4s9WCU;OgO=pf*G5qLA`M4wWk$ zDi=6Zpfyj`1$L#o{BkSw54c|7_qxdMb%o!ng9Tj4FmgID-ry1M@Sef5AmxI#-9<IK zi#+yMc<e9m*gpkTfe9<(FYqN?;7d3la$NF|<O$acLBVG{&ikJ7J?VeO|Dt2e6~`Ee zf(v{J7daBIa3o&fNPH?FIYZ~7fcg~y^$!d}tSVrllcj^P!|(=&_61aQgIA&>dWO^t zsf)ZSS9n!Am~L?M^jKZsR$P#{Bx{4<lH3bw_6K|~goa%SjlYnPcqKIHf(r=U6_x(L zz{#ruCMGc6l~r3%xTNZ$tkD%&qYn%mf+}EQqU!|52}L)=RaQ7%5ZAjPu6IL1;f93N z4BIObn%5<)E=gGJFuW*Xdj*8-Cpg{^mzd!=scb^o4GEbCGO{xgXC%!?n&Ucy5tOwH zr?^h{ndGxTaH9Vd{|WvR{67eC2&#M)VGxr6RZ>oj5OM<JT?wf<e2}ie2BQs$TTDS2 zUET7Ey5)|-3lfeOB^<9vI8I=iU^tO=0_$B7xeFqO7eovf2tnu-Nf7#ih+&884LRiw zpBaLk{y#qOFz^UY(7C`ZcY#H&*n)w9;fRKpY=|}Uc{ZB>W|j*~j3L&{7nr#M#Mv+K zvVzz`tRS|yi$sVu^A&5B5PSBkOpGD+?4T9wpjk)IqViiJ*f!a{1dT>$GTvhJdkGrr zc?nu*sL5932x=XI*A0VL5Q8>hfLm=vpmn>NJbr%QA(oJkA|D0@2EPyp*Ue8;sR*<h zpa?V_U(^ILqZ~wlmhBcz1+hTQ{vwbaw^;K)$BaRG9^h_|Ah@dm>KGO4L1qpieIjtf zUj#`K#Eb_`{XjZSRiK6?XL@CBUSe@(X)bsj{w;3!QF*DwMIbMNyJAHhAUA+|Nk!l_ zyr32&c>VG%d61!?eh!Ya#fo--bb{9S7A*nU#{z127nOko!EI>JT264s5Z33-1@9KH zD>?$*4PGqC#K7=@nURt40}Bfy%LfJ!!NtJH*T4&cHy8viz|ai_&IT~N!NAo3hBp}W zFJMDA7=$js&<zIB3#jM@gZ%|;=mvw{1ypo{0qlqd-Wv>(7f{g+2E_}g=mU#06Qj@v z2JGZVu=p1+30338!oa29z;=UIyd!D`&w{iSwHMWFF7n!5;k9kx`oPA(#QlMZo6+_I z119kiB=!YFd}L-|;%<?Is8nJQ6uluOcSBs_hLG3|0g)Rb5;ug!Z^$Uz5SIoCDyrS! z7ycmW$;>GKfdPYzU}Iq6>8QHIEO~)h@&Sv>1ypo{OYQ=f+ybEsTq+m2RIYHTG&tW7 z5}%+tgLy{ijL-$fGo$82T@=!|BBasi-Qe0`a)X7l!L>uR(Wk|y!RH1CZwKpy#1)J? t5>EtPh>pLIn}30$;37xC6^?=iM~G6zMvoSc1~B}<&%h#efmsrqbO1!P4kZ8p literal 0 HcmV?d00001 diff --git a/irlc/ex01/__pycache__/inventory_environment.cpython-311.pyc b/irlc/ex01/__pycache__/inventory_environment.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c931bc5d63994b85ecd853b1a4743d0e84ee3b9c GIT binary patch literal 4674 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 AJOBUy literal 0 HcmV?d00001 diff --git a/irlc/ex01/agent.py b/irlc/ex01/agent.py new file mode 100644 index 0000000..093e841 --- /dev/null +++ b/irlc/ex01/agent.py @@ -0,0 +1,385 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""The Agent class. + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +import typing +import itertools +import os +import sys +from collections import OrderedDict, namedtuple +import numpy as np +from tqdm import tqdm +from irlc.utils.common import load_time_series, log_time_series +from irlc.utils.irlc_plot import existing_runs +import shutil +from gymnasium import Env +from dataclasses import dataclass + +class Agent: + r"""The main agent class. See (Her24, Subsection 4.4.3) for additional details. + + To use the agent class, you should first create an environment. In this case we will just create an instance of the + ``InventoryEnvironment`` (see (Her24, Subsection 4.2.3)) + + :Example: + + .. runblock:: pycon + + >>> from irlc import Agent # You can import directly from top-level package + >>> import numpy as np + >>> np.random.seed(42) # Fix the seed for reproduciability + >>> from irlc.ex01.inventory_environment import InventoryEnvironment + >>> env = InventoryEnvironment() # Create an instance of the environment + >>> agent = Agent(env) # Create an instance of the agent. + >>> s0, info0 = env.reset() # Always call reset to start the environment + >>> a0 = agent.pi(s0, k=0, info=info0) # Tell the agent to compute action $a_{k=0}$ + >>> print(f"In state {s0=}, the agent took the action {a0=}") + """ + + def __init__(self, env: Env): + """Instantiate the Agent class. + + The agent is given the openai gym environment it must interact with. This allows the agent to know what the + action and observation space is. + + :param env: The openai gym ``Env`` instance the agent should interact with. + """ + self.env = env + + def pi(self, s, k : int, info : typing.Optional[dict] =None): + r"""Evaluate the Agent's policy (i.e., compute the action the agent want to take) at time step ``k`` in state ``s``. + + This correspond to the environment being in a state evaluating :math:`x_k`, and the function should compute the next + action the agent wish to take: + + .. math:: + u_k = \mu_k(x_k) + + This means that ``s`` = :math:`x_k` and ``k`` = :math:`k =\{0, 1, ...\}`. The function should return an action that lies in the action-space + of the environment. + + The info dictionary: + The ``info``-dictionary contains possible extra information returned from the environment, for instance when calling the ``s, info = env.reset()`` function. + The main use in this course is in control, where the dictionary contains a value ``info['time_seconds']`` (which corresponds to the simulation time :math:`t` in seconds). + + We will also use the info dictionary to let the agent know certain actions are not available. This is done by setting the ``info['mask']``-key. + Note that this is only relevant for reinforcement learning, and you should see the documentation/exercises for reinforcement learning for additional details. + + The default behavior of the agent is to return a random action. An example: + + .. runblock:: pycon + + >>> from irlc.pacman.pacman_environment import PacmanEnvironment + >>> from irlc import Agent + >>> env = PacmanEnvironment() + >>> s, info = env.reset() + >>> agent = Agent(env) + >>> agent.pi(s, k=0, info=info) # get a random action + >>> agent.pi(s, k=0) # If info is not specified, all actions are assumed permissible. + + + :param s: Current state the environment is in. + :param timestep: Current time + :return: The action the agent want to take in the given state at the given time. By default the agent returns a random action + """ + if info is None or 'mask' not in info: + return self.env.action_space.sample() + else: + """ In the case where the actions available in each state differ, openAI deals with that by specifying a + ``mask``-entry in the info-dictionary. The mask can then be passed on to the + env.action_space.sample-function to make sure we don't sample illegal actions. I consider this the most + difficult and annoying thing about openai gym.""" + if info['mask'].max() > 1: + raise Exception("Bad mask!") + return self.env.action_space.sample(mask=info['mask']) + + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + r"""Implement this function if the agent has to learn (be trained). + + Note that you only have to implement this function from week 7 onwards -- before that, we are not interested in control methods that learn. + + The agent takes a number of input arguments. You should imagine that + + * ``s`` is the current state :math:`x_k`` + * ``a`` is the action the agent took in state ``s``, i.e. ``a`` :math:`= u_k = \mu_k(x_k)` + * ``r`` is the reward the the agent got from that action + * ``sp`` (s-plus) is the state the environment then transitioned to, i.e. ``sp`` :math:`= x_{k+1}` + * '``done`` tells the agent if the environment has stopped + * ``info_s`` is the information-dictionary returned by the environment as it transitioned to ``s`` + * ``info_sp`` is the information-dictionary returned by the environment as it transitioned to ``sp``. + + The following example will hopefully clarify it by showing how you would manually call the train-function once: + + :Example: + + .. runblock:: pycon + + >>> from irlc.ex01.inventory_environment import InventoryEnvironment # import environment + >>> from irlc import Agent + >>> env = InventoryEnvironment() # Create an instance of the environment + >>> agent = Agent(env) # Create an instance of the agent. + >>> s, info_s = env.reset() # s is the current state + >>> a = agent.pi(s, k=0, info=info_s) # The agent takes an action + >>> sp, r, done, _, info_sp = env.step(a) # Environment updates + >>> agent.train(s, a, r, sp, done, info_s, info_sp) # How the training function is called + + + In control and dynamical programming, please recall that the reward is equal to minus the cost. + + :param s: Current state :math:`x_k` + :param a: Action taken :math:`u_k` + :param r: Reward obtained by taking action :math:`a_k` in state :math:`x_k` + :param sp: The state that the environment transitioned to :math:`{\\bf x}_{k+1}` + :param info_s: The information dictionary corresponding to ``s`` returned by ``env.reset`` (when :math:`k=0`) and otherwise ``env.step``. + :param info_sp: The information-dictionary corresponding to ``sp`` returned by ``env.step`` + :param done: Whether environment terminated when transitioning to ``sp`` + :return: None + """ + pass + + def __str__(self): + """**Optional:** A unique name for this agent. Used for labels when plotting, but can be kept like this.""" + return super().__str__() + + def extra_stats(self) -> dict: + """**Optional:** Implement this function if you wish to record extra information from the ``Agent`` while training. + + You can safely ignore this method as it will only be used for control theory to create nicer plots """ + return {} + +fields = ('time', 'state', 'action', 'reward') +Trajectory = namedtuple('Trajectory', fields + ("env_info",)) + +# Experiment using a dataclass. +@dataclass +class Stats: + episode: int + episode_length: int + accumulated_reward: float + + total_steps: int + trajectory : Trajectory = None + agent_stats : dict = None + + @property + def average_reward(self): + return self.accumulated_reward / self.episode_length + +# s = Stats(episode=0, episode_length=5, accumulated_reward=4, total_steps=2, trajectory=Trajectory()) + + +def train(env, + agent=None, + experiment_name=None, + num_episodes=1, + verbose=True, + reset=True, # If True we will call env.reset() upon episode start. + max_steps=1e10, + max_runs=None, + return_trajectory=True, # Return the current trajectories as a list + resume_stats=None, # Resume stat collection from last save. + log_interval=1, # Only log every log_interval steps. Reduces size of log files. + delete_old_experiments=False, # Remove the old experiments folder. Useful while debugging a model (or to conserve disk space) + seed=None, # Attempt to set the seed of the random number generator to produce reproducible results. + ): + """This function implements the main training loop as described in (Her24, Subsection 4.4.4). + + The loop will simulate the interaction between agent `agent` and the environment `env`. + The function has a lot of special functionality, so it is useful to consider the common cases. An example: + + >>> stats, _ = train(env, agent, num_episodes=2) + + Simulate interaction for two episodes (i.e. environment terminates two times and is reset). + `stats` will be a list of length two containing information from each run + + >>> stats, trajectories = train(env, agent, num_episodes=2, return_Trajectory=True) + + `trajectories` will be a list of length two containing information from the two trajectories. + + >>> stats, _ = train(env, agent, experiment_name='experiments/my_run', num_episodes=2) + + Save `stats`, and trajectories, to a file which can easily be loaded/plotted (see course software for examples of this). + The file will be time-stamped so using several calls you can repeat the same experiment (run) many times. + + >>> stats, _ = train(env, agent, experiment_name='experiments/my_run', num_episodes=2, max_runs=10) + + As above, but do not perform more than 10 runs. Useful for repeated experiments. + + :param env: An openai-Gym ``Env`` instance (the environment) + :param agent: An ``Agent`` instance + :param experiment_name: The outcome of this experiment will be saved in a folder with this name. This will allow you to run multiple (repeated) experiment and visualize the results in a single plot, which is very important in reinforcement learning. + :param num_episodes: Number of episodes to simulate + :param verbose: Display progress bar + :param reset: Call ``env.reset()`` before simulation start. Default is ``True``. This is only useful in very rare cases. + :param max_steps: Terminate if this many steps have elapsed (for non-terminating environments) + :param max_runs: Maximum number of repeated experiments (requires ``experiment_name``) + :param return_trajectory: Return trajectories list (Off by default since it might consume lots of memory) + :param resume_stats: Resume stat collection from last run (this requires the ``experiment_name`` variable to be set) + :param log_interval: Log stats less frequently than each episode. Useful if you want to run really long experiments. + :param delete_old_experiments: If true, old saved experiments will be deleted. This is useful during debugging. + :param seed: An integer. The random number generator of the environment will be reset to this seed allowing for reproducible results. + :return: A list where each element corresponds to each (started) episode. The elements are dictionaries, and contain the statistics for that episode. + """ + + from irlc import cache_write + from irlc import cache_read + saveload_model = False + # temporal_policy = None + save_stats = True + if agent is None: + print("[train] No agent was specified. Using irlc.Agent(env) (this agent selects actions at random)") + agent = Agent(env) + + if delete_old_experiments and experiment_name is not None and os.path.isdir(experiment_name): + shutil.rmtree(experiment_name) + + if experiment_name is not None and max_runs is not None and existing_runs(experiment_name) >= max_runs: + stats, recent = load_time_series(experiment_name=experiment_name) + if return_trajectory: + trajectories = cache_read(recent+"/trajectories.pkl") + else: + trajectories = [] + return stats, trajectories + stats = [] + steps = 0 + ep_start = 0 + resume_stats = saveload_model if resume_stats is None else resume_stats + + recent = None + if resume_stats: + stats, recent = load_time_series(experiment_name=experiment_name) + if recent is not None: + ep_start, steps = stats[-1]['Episode']+1, stats[-1]['Steps'] + + trajectories = [] + # include_metadata = len(inspect.getfullargspec(agent.train).args) >= 7 + break_outer = False + + with tqdm(total=num_episodes, disable=not verbose, file=sys.stdout, mininterval=int(num_episodes/100) if num_episodes>100 else None) as tq: + for i_episode in range(num_episodes): + if break_outer: + break + info_s = {} + if reset or i_episode > 0: + if seed is not None: + s, info_s = env.reset(seed=seed) + seed = None + else: + s, info_s = env.reset() + elif hasattr(env, "s"): # This is doing what, exactly? Perhaps save/load of agent? + s = env.s + elif hasattr(env, 'state'): + s = env.state + else: + s = env.model.s + # time = 0 + reward = [] + trajectory = Trajectory(time=[], state=[], action=[], reward=[], env_info=[]) + k = 0 # initial state k. + for _ in itertools.count(): + # policy is always temporal + a = agent.pi(s, k, info_s) # if temporal_policy else agent.pi(s) + k = k + 1 + sp, r, terminated, truncated, info_sp = env.step(a) + done = terminated or truncated + + if info_sp is not None and 'mask' in info_sp and info_sp['mask'].max() > 1: + print("bad") + + agent.train(s, a, r, sp, done, info_s, info_sp) + + if return_trajectory: + trajectory.time.append(np.asarray(info_s['time_seconds'] if 'time_seconds' in info_s else steps)) #np.asarray(time)) + trajectory.state.append(s) + trajectory.action.append(a) + trajectory.reward.append(np.asarray(r)) + trajectory.env_info.append(info_s) + + reward.append(r) + steps += 1 + # time += info_sp['dt'] if 'dt' in info_sp else 1 + # time += 1 + + if done or steps >= max_steps: + trajectory.state.append(sp) + trajectory.env_info.append(info_sp) + trajectory.time.append(np.asarray(info_sp['time_seconds'] if 'time_seconds' in info_s else steps)) + break_outer = steps >= max_steps + break + s = sp + info_s = info_sp + if return_trajectory: + try: + from irlc.ex04.control_environment import ControlEnvironment + if isinstance(env, ControlEnvironment): # TODO: this is too hacky. States/actions should be lists, and subsequent methods should stack. + trajectory = Trajectory(**{field: np.stack([np.asarray(x_) for x_ in getattr(trajectory, field)]) for field in fields}, env_info=trajectory.env_info) + # else: + # trajectory = Trajectory(**{field: np.stack([np.asarray(x_) for x_ in getattr(trajectory, field)]) for field in fields}, env_info=trajectory.env_info) + + except Exception as e: + pass + + trajectories.append(trajectory) + if (i_episode + 1) % log_interval == 0: + stats.append({"Episode": i_episode + ep_start, + "Accumulated Reward": sum(reward), + # "Average Reward": np.mean(reward), # Not sure we need this anymore. + "Length": len(reward), + "Steps": steps, # Useful for deep learning applications. This should be kept, or week 13 will have issues. + **agent.extra_stats()}) + + rate = int(num_episodes / 100) + if rate > 0 and i_episode % rate == 0: + tq.set_postfix(ordered_dict=OrderedDict(list(OrderedDict(stats[-1]).items())[:5])) if len(stats) > 0 else None + tq.update() + + sys.stderr.flush() + + if resume_stats and save_stats and recent is not None: + os.remove(recent+"/log.txt") + + if experiment_name is not None and save_stats: + path = log_time_series(experiment=experiment_name, list_obs=stats) + if return_trajectory: + cache_write(trajectories, path+"/trajectories.pkl") + + print(f"Training completed. Logging {experiment_name}: '{', '.join( stats[0].keys()) }'") + + for i, t in enumerate(trajectories): + from collections import defaultdict + nt = defaultdict(lambda: []) + if t.env_info is not None and t.env_info[1] is not None and "supersample" in t.env_info[1]: + for f in fields: + for k, ei in enumerate(t.env_info): + if 'supersample' not in ei: + continue + z = ei['supersample'].__getattribute__(f).T + if k == 0: + pass + else: + z = z[1:] + nt[f].append(z) + + for f in fields: + nt[f] = np.concatenate([z for z in nt[f]],axis=0) + traj2 = Trajectory(**nt, env_info=[]) + trajectories[i] = traj2 + + # for k, t in enumerate(stats): + # if k < len(trajectories): + # stats[k]['trajectory'] = trajectories[k] + # Turn this into a single episodes-list (refactor later) + return stats, trajectories + + +if __name__ == "__main__": + # Use the trajectories here. + from irlc.ex01.inventory_environment import InventoryEnvironment + env = InventoryEnvironment(N=10) + stats, traj = train(env, Agent(env)) + print(stats) + s = Stats(episode=1, episode_length=2, accumulated_reward=4, total_steps=4, trajectory=None, agent_stats={}) + print(s) diff --git a/irlc/ex01/bobs_friend.py b/irlc/ex01/bobs_friend.py new file mode 100644 index 0000000..0d515d8 --- /dev/null +++ b/irlc/ex01/bobs_friend.py @@ -0,0 +1,59 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import gymnasium +import numpy as np +from gymnasium.spaces.discrete import Discrete +from irlc.ex01.agent import Agent, train + +class BobFriendEnvironment(gymnasium.Env): + def __init__(self, x0=20): + self.x0 = x0 + self.action_space = Discrete(2) # Possible actions {0, 1} + + def reset(self): + # TODO: 1 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + return self.s, {} + + def step(self, a): + # TODO: 9 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + return s_next, reward, terminated, False, {} + +class AlwaysAction_u0(Agent): + def pi(self, s, k, info=None): + """This agent should always take action u=0.""" + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + +class AlwaysAction_u1(Agent): + def pi(self, s, k, info=None): + """This agent should always take action u=1.""" + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + +if __name__ == "__main__": + # Part A: + env = BobFriendEnvironment() + x0, _ = env.reset() + print(f"Initial amount of money is x0 = {x0} (should be 20 kroner)") + print("Lets put it in the bank, we should end up in state x1=22 and get a reward of 2 kroner") + x1, reward, _, _, _ = env.step(0) + print("we got", x1, reward) + # Since we reset the environment, we should get the same result as before: + env.reset() + x1, reward, _, _, _ = env.step(0) + print("(once more) we got", x1, reward, "(should be the same as before)") + + env.reset() # We must call reset -- the environment has possibly been changed! + print("Lets lend it to our friend -- what happens will now be random") + x1, reward, _, _, _ = env.step(1) + print("we got", x1, reward) + + # Part B: + stats, _ = train(env, AlwaysAction_u0(env), num_episodes=1000) + average_u0 = np.mean([stat['Accumulated Reward'] for stat in stats]) + + stats, _ = train(env, AlwaysAction_u1(env), num_episodes=1000) + average_u1 = np.mean([stat['Accumulated Reward'] for stat in stats]) + print(f"Average reward while taking action u=0 was {average_u0} (should be 2)") + print(f"Average reward while taking action u=1 was {average_u1} (should be 4)") diff --git a/irlc/ex01/chess.py b/irlc/ex01/chess.py new file mode 100644 index 0000000..935e1fc --- /dev/null +++ b/irlc/ex01/chess.py @@ -0,0 +1,99 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This file contains code for the Chess Tournament problem.""" +import numpy as np +from gymnasium.spaces.discrete import Discrete +from gymnasium import Env + +class ChessTournament(Env): + """The ChessTournament gymnasium-environment which simulate a chess tournament. + + In the problem, a chess tournament ends when a player wins two games in a row. The results + of each game are -1, 0, 1 corresponding to a loss, draw and win for player 1. See: + https://www.youtube.com/watch?v=5UQU1oBpAic + + To implement this, we define the step-function such that one episode of the environment corresponds to playing + a chess tournament to completion. Once the environment completes, it returns a reward of +1 if the player won + the tournament, and otherwise 0. + + Each step therefore corresponds to playing a single game in the tournament. + To implement this, we use a state corresponding to the sequence of games in the tournament: + + >>> self.s = [0, -1, 1, 0, 0, 1] + + In the self.step(action)-function, we ignore the action, simulate the outcome of a single game, + and append the outcome to self.s. We then compute whether the tournament has completed, and if so + a reward of 1 if we won. + """ + + def __init__(self, p_draw=3 / 4, p_win=2 / 3): + self.action_space = Discrete(1) + self.p_draw = p_draw + self.p_win = p_win + self.s = [] # A chess tournament is a sequence of won/lost games s = [0, -1, 1, 0, ...] + + def reset(self): + """Reset the tournament environment to begin to simulate a new tournament. + + After each episode is complete, this function will reset :python:`self.s` and return the current state s and an empty dictionary. + :return: + - s - The initial state (what is it?) + - info - An empty dictionary, ``{}`` + """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + return self.s, {} + + def step(self, action): + """Play a single game in the current tournament + + The variable action is required by gymnasium but it is not used since no (player) actions occur in this problem. + + The step-method should update `self.state` to be the next (new) state, compute the reward, and determine whether + the environment has terminated (:python:`done`). + + :param action: This input is required by gymnasium but it is not used in this case. + :return: A tuple of the form :python:`(new_state, reward, done, False, {})` + """ + game_outcome = None # should be -1, 0, or 1 depending on outcome of single game. + ## TODO: Oy veh, the following 7 lines below have been permuted. Uncomment, rearrange to the correct order and remove the error. + #------------------------------------------------------------------------------------------------------------------------------- + # else: + # else: + # game_outcome = 1 + # if np.random.rand() < self.p_win: + # game_outcome = -1 + # game_outcome = 0 + # if np.random.rand() < self.p_draw: + raise NotImplementedError("Compute game_outcome here") + self.s.append(game_outcome) + + #done = True if the tournament has ended otherwise false. Compute using s. + # TODO: 1 lines missing. + raise NotImplementedError("Compute 'done', whether the tournament has ended.") + # r = ... . Compute reward. Let r=1 if we won the tournament otherwise 0. + # TODO: 1 lines missing. + raise NotImplementedError("Compute the reward 'r' here.") + return self.s, r, done, False, {} + +def main(): + """The main method of the chess-game problem. + + This function will simulate T tournament games and estimate average win probability for player 1 as p_win (answer to riddle) and also + the average length. Note the later should be a 1-liner, but would require non-trivial computations to solve + analytically. Please see the :class:`gymnasium.Env` class for additional details. + """ + T = 5000 + from irlc import train, Agent + env = ChessTournament() + # Compute stats using the train function. Simulate the tournament for a total of T=10'000 episodes. + # TODO: 1 lines missing. + raise NotImplementedError("Compute stats here using train(env, ...). Use num_episodes.") + p_win = np.mean([st['Accumulated Reward'] for st in stats]) + avg_length = np.mean([st['Length'] for st in stats]) + + print("Agent: Estimated chance I won the tournament: ", p_win) + print("Agent: Average tournament length", avg_length) + + +if __name__ == "__main__": + main() diff --git a/irlc/ex01/inventory_environment.py b/irlc/ex01/inventory_environment.py new file mode 100644 index 0000000..a460159 --- /dev/null +++ b/irlc/ex01/inventory_environment.py @@ -0,0 +1,71 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from gymnasium.spaces.discrete import Discrete +from gymnasium import Env +from irlc.ex01.agent import Agent, train + +class InventoryEnvironment(Env): + def __init__(self, N=2): + self.N = N # planning horizon + self.action_space = Discrete(3) # Possible actions {0, 1, 2} + self.observation_space = Discrete(3) # Possible observations {0, 1, 2} + + def reset(self): + self.s = 0 # reset initial state x0=0 + self.k = 0 # reset time step k=0 + return self.s, {} # Return the state we reset to (and an empty dict) + + def step(self, a): + w = np.random.choice(3, p=(.1, .7, .2)) # Generate random disturbance + # TODO: 5 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + return s_next, reward, terminated, False, {} # return transition information + +class RandomAgent(Agent): + def pi(self, s, k, info=None): + """ Return action to take in state s at time step k """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + + +def simplified_train(env: Env, agent: Agent) -> float: + s, _ = env.reset() + J = 0 # Accumulated reward for this rollout + for k in range(1000): + ## TODO: Oy veh, the following 7 lines below have been permuted. Uncomment, rearrange to the correct order and remove the error. + #------------------------------------------------------------------------------------------------------------------------------- + # if terminated or truncated: + # sp, r, terminated, truncated, metadata = env.step(a) + # a = agent.pi(s, k) + # s = sp + # J += r + # agent.train(s, a, sp, r, terminated) + # break + raise NotImplementedError("Remove this exception after the above lines have been uncommented and rearranged.") + return J + +def run_inventory(): + env = InventoryEnvironment() + agent = RandomAgent(env) + stats, _ = train(env,agent,num_episodes=1,verbose=False) # Perform one rollout. + print("Accumulated reward of first episode", stats[0]['Accumulated Reward']) + # I recommend inspecting 'stats' in a debugger; why do you think it is a list of length 1? + + stats, _ = train(env, agent, num_episodes=1000,verbose=False) # do 1000 rollouts + avg_reward = np.mean([stat['Accumulated Reward'] for stat in stats]) + print("[RandomAgent class] Average cost of random policy J_pi_random(0)=", -avg_reward) + # Try to inspect stats again in a debugger here. How long is the list now? + + stats, _ = train(env, Agent(env), num_episodes=1000,verbose=False) # Perform 1000 rollouts using Agent class + avg_reward = np.mean([stat['Accumulated Reward'] for stat in stats]) + print("[Agent class] Average cost of random policy J_pi_random(0)=", -avg_reward) + + """ Second part: Using the simplified training method. I.e. do not use train() below. + You can find some pretty strong hints about what goes on in simplified_train in the lecture slides for today. """ + avg_reward_simplified_train = np.mean( [simplified_train(env, agent) for i in range(1000)]) + print("[simplified train] Average cost of random policy J_pi_random(0) =", -avg_reward_simplified_train) + + + +if __name__ == "__main__": + run_inventory() diff --git a/irlc/ex01/pacman_hardcoded.py b/irlc/ex01/pacman_hardcoded.py new file mode 100644 index 0000000..6254756 --- /dev/null +++ b/irlc/ex01/pacman_hardcoded.py @@ -0,0 +1,60 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.pacman.pacman_environment import PacmanEnvironment +from irlc import Agent, train, savepdf + + +# Maze layouts can be specified using a string. +layout = """ +%%%%%%%%%% +%P.......% +%.%%%%%%.% +%.% %.% +%.% %.% +%.% %.% +%.% %.% +%.%%%%%%.% +%........% +%%%%%%%%%% +""" + +# This is our first agent. Note it inherits from the Agent class. Use <ctrl>+click in pycharm to navigate to code definitions -- +# this is a very useful habbit when you work with other peoples code in general, and object-oriented code in particular. +class GoAroundAgent(Agent): + def pi(self, x, k, info=None): + """ Collect all dots in the maze in the smallest amount of time. + This function should return an action, check the output of the code below to see what actions you can potentially + return. + Remember Pacman only have to solve this single maze, so don't make the function general. + + Hints: + - Insert a breakpoint in the function. Try to write self.env and self.env.action_space.actions in the interpreter. Where did self.env get set? + - Remember that k is the current step number. + - Ignore the info dictionary; you can probably also ignore the state x. + - The function should return a string (the actions are strings such as 'North') + """ + # TODO: 7 lines missing. + raise NotImplementedError("Implement function body") + return 'West' + +if __name__ == "__main__": + # Create an environment with the given layout. animate_movement is just for a nicer visualization. + env = PacmanEnvironment(layout_str=layout, render_mode='human') + # This creates a visualization (Note this makes the environment slower) which can help us see what Pacman does + # This create the GoAroundAgent-instance + agent = GoAroundAgent(env) + # Uncomment the following line to input actions instead of the agent using the keyboard: + # env, agent = interactive(env, agent) + s, info = env.reset() # Reset (and start) the environment + + savepdf("pacman_roundabout.pdf", env=env) # Saves a snapshot of the start layout + # The next two lines display two ways to get the available actions. The 'canonical' way using the + # env.action_space, and a way particular to Pacman by using the s.A() function on the state. + # You can read more about the functions in the state in project 1. + # print("Available actions at start:", env.action_space.actions) # This will list the available actions. + print("Alternative way of getting actions:", s.A()) # See also project description + + # Simulate the agent for one episode + stats, _ = train(env, agent, num_episodes=1) + # Print your obtained score. + print("Your obtained score was", stats[0]['Accumulated Reward']) + env.close() # When working with visualizations, call env.close() to close windows it may have opened. " diff --git a/irlc/ex02/__init__.py b/irlc/ex02/__init__.py new file mode 100644 index 0000000..97bfecd --- /dev/null +++ b/irlc/ex02/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 2.""" diff --git a/irlc/ex02/__pycache__/__init__.cpython-311.pyc b/irlc/ex02/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4c0e4230c872e1b4fd8be12ef0dc7e0d21ce5642 GIT binary patch literal 232 zcmZ3^%ge>Uz`$Uh-<$T5fq~&Mhy%lnP{wDFlIaX73{eazjKK_=OjU*<8JWcjDVas7 z$tC$kl?uuEc_oRNdBqAP8L0}X6{$tZnZ>Ea3TgR83gxM(*$PH_ewvK8*yH0<@{{A^ zS2BDCnf%K}KO;XkRllS(BURreKe;qFHLs*tKQlK+-@wSk)S$SeGzB73l#{HVT47+M zA0MBYmst`YuUAm{i^C>2KczG$)vkz*fq?<!)?z^h28IvJjEsyA7|bugP!S6Q0|Nlt Cv_Sy? literal 0 HcmV?d00001 diff --git a/irlc/ex02/__pycache__/dp.cpython-311.pyc b/irlc/ex02/__pycache__/dp.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4a183932fe284d48d4142290e953c73af60cfb31 GIT binary patch literal 3570 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 literal 0 HcmV?d00001 diff --git a/irlc/ex02/__pycache__/dp_model.cpython-311.pyc b/irlc/ex02/__pycache__/dp_model.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4d9cd5bd2a1e51fd4f90d8072be63d1e1bea7167 GIT binary patch literal 9583 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 FK>#e8!({*f literal 0 HcmV?d00001 diff --git a/irlc/ex02/__pycache__/graph_traversal.cpython-311.pyc b/irlc/ex02/__pycache__/graph_traversal.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..539851022997c8a7f7a92f9e87749c2a08229cad GIT binary patch literal 4952 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 J7nmVU3;;*vGYkL# literal 0 HcmV?d00001 diff --git a/irlc/ex02/__pycache__/inventory.cpython-311.pyc b/irlc/ex02/__pycache__/inventory.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d5f7d3211a68b3c18faebe51fd3aa2a340afe6df GIT binary patch literal 3722 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 W(&*OW)&Pbdm>F24E-*`ioeco>=`{HO literal 0 HcmV?d00001 diff --git a/irlc/ex02/dp.py b/irlc/ex02/dp.py new file mode 100644 index 0000000..853d188 --- /dev/null +++ b/irlc/ex02/dp.py @@ -0,0 +1,71 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +from irlc.ex02.graph_traversal import SmallGraphDP +from irlc.ex02.dp_model import DPModel + +def DP_stochastic(model: DPModel): + """ + Implement the stochastic DP algorithm. The implementation follows (Her24, Algorithm 1). + Once you are done, you should be able to call the function as: + + .. runblock:: pycon + + >>> from irlc.ex02.graph_traversal import SmallGraphDP + >>> from irlc.ex02.dp import DP_stochastic + >>> model = SmallGraphDP(t=5) # Instantiate the small graph with target node 5 + >>> J, pi = DP_stochastic(model) + >>> print(pi[0][2]) # Action taken in state ``x=2`` at time step ``k=0``. + + :param model: An instance of :class:`irlc.ex02.dp_model.DPModel` class. This represents the problem we wish to solve. + :return: + - ``J`` - A list of of cost function so that ``J[k][x]`` represents :math:`J_k(x)` + - ``pi`` - A list of dictionaries so that ``pi[k][x]`` represents :math:`\mu_k(x)` + """ + + """ + In case you run into problems, I recommend following the hints in (Her24, Subsection 6.2.1) and focus on the + case without a noise term; once it works, you can add the w-terms. When you don't loop over noise terms, just specify + them as w = None in env.f and env.g. + """ + N = model.N + J = [{} for _ in range(N + 1)] + pi = [{} for _ in range(N)] + J[N] = {x: model.gN(x) for x in model.S(model.N)} + for k in range(N-1, -1, -1): + for x in model.S(k): + """ + Update pi[k][x] and Jstar[k][x] using the general DP algorithm given in (Her24, Algorithm 1). + If you implement it using the pseudo-code, I recommend you define Q (from the algorithm) as a dictionary like the J-function such that + + > Q[u] = Q_u (for all u in model.A(x,k)) + + Then you find the u with the lowest value of Q_u, i.e. + + > umin = arg_min_u Q[u] + + (for help, google: `python find key in dictionary with minimum value'). + Then you can use this to update J[k][x] = Q_umin and pi[k][x] = umin. + """ + # TODO: 4 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + """ + After the above update it should be the case that: + + J[k][x] = J_k(x) + pi[k][x] = pi_k(x) + """ + return J, pi + + +if __name__ == "__main__": # Test dp on small graph given in (Her24, Subsection 6.2.1) + print("Testing the deterministic DP algorithm on the small graph environment") + model = SmallGraphDP(t=5) # Instantiate the small graph with target node 5 + J, pi = DP_stochastic(model) + # Print all optimal cost functions J_k(x_k) + for k in range(len(J)): + print(", ".join([f"J_{k}({i}) = {v:.1f}" for i, v in J[k].items()])) + print(f"Cost of shortest path when starting in node 2 is: {J[0][2]=} (and should be 4.5)") diff --git a/irlc/ex02/dp_agent.py b/irlc/ex02/dp_agent.py new file mode 100644 index 0000000..7e49efd --- /dev/null +++ b/irlc/ex02/dp_agent.py @@ -0,0 +1,44 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex01.agent import Agent +from irlc.ex02.dp import DP_stochastic +from irlc import train +import numpy as np + + +class DynamicalProgrammingAgent(Agent): + """ + This is an agent which plan using dynamical programming. + """ + def __init__(self, env, model=None): + super().__init__(env) + self.J, self.pi_ = DP_stochastic(model) + + def pi(self, s, k, info=None): + if k >= len(self.pi_): + raise Exception("k >= N; I have not planned this far!") + ## TODO: Half of each line of code in the following 1 lines have been replaced by garbage. Make it work and remove the error. + #---------------------------------------------------------------------------------------------------------------------------- + # action = se???????????? + raise NotImplementedError("Get the action according to the DP policy.") + return action + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): # Do nothing; this is DP so no learning takes place. + pass + + +def main(): + from irlc.ex01.inventory_environment import InventoryEnvironment + from irlc.ex02.inventory import InventoryDPModel + + env = InventoryEnvironment(N=3) + inventory_model = InventoryDPModel(N=3) + agent = DynamicalProgrammingAgent(env, model=inventory_model) + stats, _ = train(env, agent, num_episodes=5000) + + s, _ = env.reset() # Get initial state + Er = np.mean([stat['Accumulated Reward'] for stat in stats]) + print("Estimated reward using trained policy and MC rollouts", Er) + print("Reward as computed using DP", -agent.J[0][s]) + +if __name__ == "__main__": + main() diff --git a/irlc/ex02/dp_model.py b/irlc/ex02/dp_model.py new file mode 100644 index 0000000..88dd27c --- /dev/null +++ b/irlc/ex02/dp_model.py @@ -0,0 +1,185 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np + +class DPModel: + r""" The Dynamical Programming model class + + The purpose of this class is to translate a dynamical programming problem, defined by the equations, + + .. math:: + + x_{k+1} & = f_k(x_k, u_k, w_k) \\ + \text{cost} & = g_k(x_k, u_k, w_k) \\ + \text{terminal cost} & = g_N(x_N) \\ + \text{Noise disturbances:} \quad w_k & \sim P_W(w_k | x_k, u_k) \\ + \text{State/action spaces:} \quad & \mathcal A_k(x_k), \mathcal S_k + + into a single python object which we can then use for planning. + + .. Note:: + + This is the first time many of you encounter a class. If so, you might wonder why you can't just implement + the functions as usual, i.e. ``def f(x, k, ...):``, ``def g(x, k, ...):``, + as regular python function and just let that be it? + + The reason is that we want to pass all these function (which taken together represents a planning problem) + to planning methods such as the DP-algorithm (see the function :func:`~irlc.ex02.dp.DP_stochastic`) + all at once. + It is not very convenient to pass the functions one at a time -- instead we collect them into a class and simply call the function as + + >>> from irlc.ex02.inventory import InventoryDPModel + >>> from irlc.ex02.dp import DP_stochastic + >>> model = InventoryDPModel() # Intialize the model + >>> J, pi = DP_stochastic(model) # All functions are passed to DP_stochastic + + + + To actually use the model, you need to extend it and implement the methods. The basic recipe for this is something like:: + + class MyDPModel(DPModel): + def f(self, x, u, w, k): # Note the `self`-variable. You can use it to access class variables such as`self.N`. + return x + u - w # Just an example + def S(self, k): + return [0, 1, 2] # State space S_k = {0, 1, 2} + # Implement the other functions A, g, gN and Pw here. + + + You should take a look at :func:`~irlc.ex02.inventory.InventoryDPModel` for a concrete example. + Once the functions have been implemented, you can call them as: + + .. runblock:: pycon + + >>> from irlc.ex02.inventory import InventoryDPModel + >>> model = InventoryDPModel(N=5) # Plan on a horizon of 5 + >>> print("State space S_2", model.S(2)) + >>> model.f(x=1, u=2, w=1, k=0) # Just an example. You don't have to use named arguments, although it helps on readability. + >>> model.A(1, k=2) # Action space A_1(2), i.e. the actions available at time step k=1 in state 2. + + """ + def __init__(self, N): + """ + Called when the DP Model is initialized. By default, it simply stores the planning horizon ``N`` + + :param N: The planning horizon in the DP problem :math:`N` + """ + self.N = N # Store the planning horizon. + + def f(self, x, u, w, k: int): + """ + Implements the transition function :math:`x_{k+1} = f_k(x, u, w)` and returns the next state :math:`x_{k+1}` + + :param x: The state :math:`x_k` + :param u: The action taken :math:`u_k` + :param w: The random noise disturbance :math:`w_k` + :param k: The current time step :math:`k` + :return: The state the environment (deterministically) transitions to, i.e. :math:`x_{k+1}` + """ + raise NotImplementedError("Return f_k(x,u,w)") + + def g(self, x, u, w, k: int) -> float: + """ + Implements the cost function :math:`c = g_k(x, u, w)` and returns the cost :math:`c` + + :param x: The state :math:`x_k` + :param u: The action taken :math:`u_k` + :param w: The random noise disturbance :math:`w_k` + :param k: The current time step :math:`k` + :return: The cost (as a ``float``) incurred by the environment, i.e. :math:`g_k(x, u, w)` + """ + raise NotImplementedError("Return g_k(x,u,w)") + + def gN(self, x) -> float: + """ + Implements the terminal cost function :math:`c = g_N(x)` and returns the terminal cost :math:`c`. + + :param x: A state seen at the last time step :math:`x_N` + :return: The terminal cost (as a ``float``) incurred by the environment, i.e. :math:`g_N(x)` + """ + raise NotImplementedError("Return g_N(x)") + + def S(self, k: int): + """ + Computes the state space :math:`\mathcal S_k` at time step :math:`k`. + In other words, this function returns a set of all states the system can possibly be in at time step :math:`k`. + + .. Note:: + I think the cleanest implementation is one where this function returns a python ``set``. However, it won't matter + if the function returns a ``list`` or ``tuple`` instead. + + :param k: The current time step :math:`k` + :return: The state space (as a ``list`` or ``set``) available at time step ``k``, i.e. :math:`\mathcal S_k` + """ + raise NotImplementedError("Return state space as set S_k = {x_1, x_2, ...}") + + def A(self, x, k: int): + """ + Computes the action space :math:`\mathcal A_k(x)` at time step :math:`k` in state `x`. + + In other words, this function returns a ``set`` of all actions the agent can take in time step :math:`k`. + + .. Note:: + An example where the actions depend on the state is chess (in this case, the state is board position, and the actions are the legal moves) + + :param k: The current time step :math:`k` + :param x: The state we want to compute the actions in :math:`x_k` + :return: The action space (as a ``list`` or ``set``) available at time step ``k``, i.e. :math:`\mathcal A_k(x_k)` + """ + raise NotImplementedError("Return action space as set A(x_k) = {u_1, u_2, ...}") + + def Pw(self, x, u, k: int): + """ + Returns the random noise disturbances and their probability. In other words, this function implements the distribution: + + .. math:: + + P_k(w_k | x_k, u_k) + + To implement this distribution, we must keep track of both the possible values of the noise disturbances :math:`w_k` + as well as the (numerical) value of their probability :math:`p(w_k| ...)`. + + To do this, the function returns a dictionary of the form ``P = {w1: p_w1, w2: p_w2, ...}`` where + + - The keys ``w`` represents random noise disturbances + - the values ``P[w]`` represents their probability (i.e. a ``float``) + + This can hopefully be made more clear with the Inventory environment: + + .. runblock:: pycon + + >>> from irlc.ex02.inventory import InventoryDPModel + >>> model = InventoryDPModel(N=5) # Plan on a horizon of 5 + >>> print("Random noise disturbances in state x=1 using action u=0 is:", model.Pw(x=1, u=0, k=0)) + >>> for w, pw in model.Pw(x=1, u=0, k=0).items(): # Iterate and print: + ... print(f"p_k({w}|x, u) =", pw) + + + :param x: The state :math:`x_k` + :param u: The action taken :math:`u_k` + :param k: The current time step :math:`k` + :return: A dictionary representing the distribution of random noise disturbances :math:`P_k(w |x_k, u_k)` of the form ``{..., w_i: pw_i, ...}`` such that ``pw_i = P_k(w_i | x, u)`` + """ + # Compute and return the random noise disturbances here. + # As an example: + return {'w_dummy': 1/3, 42: 2/3} # P(w_k="w_dummy") = 1/3, P(w_k =42)=2/3. + + def w_rnd(self, x, u, k): + """ + This helper function computes generates a random noise disturbance using the function + :func:`irlc.ex02.dp_model.DPModel.Pw`, i.e. it returns a sample: + + .. math:: + w \sim P_k(x_k, u_k) + + This will be useful for simulating the model. + + .. Note:: + You don't have to implement or change this function. + + :param x: The state :math:`x_k` + :param u: The action taken :math:`u_k` + :param k: The current time step :math:`k` + :return: A random noise disturbance :math:`w` distributed as :math:`P_k(x_k, u_k)` + """ + pW = self.Pw(x, u, k) + w, pw = zip(*pW.items()) # seperate w and p(w) + return np.random.choice(a=w, p=pw) diff --git a/irlc/ex02/flower_store.py b/irlc/ex02/flower_store.py new file mode 100644 index 0000000..35a4712 --- /dev/null +++ b/irlc/ex02/flower_store.py @@ -0,0 +1,27 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex02.inventory import InventoryDPModel +from irlc.ex02.dp import DP_stochastic +import numpy as np + +# TODO: Code has been removed from here. +raise NotImplementedError("Insert your solution and remove this error.") + +def a_get_policy(N: int, c: float, x0 : int) -> int: + # TODO: Code has been removed from here. + raise NotImplementedError("Insert your solution and remove this error.") + return u + +def b_prob_one(N : int, x0 : int) -> float: + # TODO: Code has been removed from here. + raise NotImplementedError("Insert your solution and remove this error.") + return pr_empty + + +if __name__ == "__main__": + model = InventoryDPModel() + pi = [{s: 0 for s in model.S(k)} for k in range(model.N)] + x0 = 0 + c = 0.5 + N = 3 + print(f"a) The policy choice for {c=} is {a_get_policy(N, c,x0)} should be 1") + print(f"b) The probability of ending up with a single element in the inventory is {b_prob_one(N, x0)} and should be 0.492") diff --git a/irlc/ex02/graph_traversal.py b/irlc/ex02/graph_traversal.py new file mode 100644 index 0000000..4fd25aa --- /dev/null +++ b/irlc/ex02/graph_traversal.py @@ -0,0 +1,67 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +import numpy as np +from irlc.ex02.dp_model import DPModel + +r""" +Graph of shortest path problem of (Her24, Subsection 5.1.1) +""" +G222 = {(1, 2): 6, (1, 3): 5, (1, 4): 2, (1, 5): 2, + (2, 3): .5, (2, 4): 5, (2, 5): 7, + (3, 4): 1, (3, 5): 5, (4, 5): 3} + +def symG(G): + """ make a graph symmetric. I.e. if it contains edge (a,b) with cost z add edge (b,a) with cost c """ + G.update({(b, a): l for (a, b), l in G.items()}) +symG(G222) + +class SmallGraphDP(DPModel): + r""" Implement the small-graph example in (Her24, Subsection 5.1.1). t is the terminal node. """ + def __init__(self, t, G=None): + self.G = G.copy() if G is not None else G222.copy() + self.G[(t,t)] = 0 # make target vertex absorbing + self.t = t # target vertex in graph + self.nodes = {node for edge in self.G for node in edge} # set of all nodes + super(SmallGraphDP, self).__init__(N=len(self.nodes)-1) + + def f(self, x, u, w, k): + if (x,u) in self.G: + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + else: + raise Exception("Nodes are not connected") + + def g(self, x, u, w, k): + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + + def gN(self, x): + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + + def S(self, k): + return self.nodes + + def A(self, x, k): + return {j for (i,j) in self.G if i == x} + +def main(): + t = 5 # target node + model = SmallGraphDP(t=t) + x0 = 1 # starting node + k = 0 + w = 0 # irrelevant. + u = 2 # as an example. + print(f"{model.f(x0, u, w, k)=} (should be 2)") + print(f"{model.g(x0, u, w, k)=} (should be 6)") + print(f"{model.gN(x0)=} (should be np.inf)") + print(f"{model.S(k)=}", "(should be {1, 2, 3, 4, 5})") + print(f"{model.A(x0, k)=}", "(should be {2, 3, 4, 5})") + print("Run the tests to check your implementation.") + +if __name__ == '__main__': + main() diff --git a/irlc/ex02/inventory.py b/irlc/ex02/inventory.py new file mode 100644 index 0000000..74c8eb8 --- /dev/null +++ b/irlc/ex02/inventory.py @@ -0,0 +1,44 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" +Implements the inventory-control problem from (Her24, Subsection 5.1.2). + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +from irlc.ex02.dp_model import DPModel +from irlc.ex02.dp import DP_stochastic + +class InventoryDPModel(DPModel): + def __init__(self, N=3): + super().__init__(N=N) + + def A(self, x, k): # Action space A_k(x) + return {0, 1, 2} + + def S(self, k): # State space S_k + return {0, 1, 2} + + def g(self, x, u, w, k): # Cost function g_k(x,u,w) + return u + (x + u - w) ** 2 + + def f(self, x, u, w, k): # Dynamics f_k(x,u,w) + return max(0, min(2, x + u - w )) + + def Pw(self, x, u, k): # Distribution over random disturbances + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + + def gN(self, x): + return 0 + +def main(): + inv = InventoryDPModel() + J,pi = DP_stochastic(inv) + print(f"Inventory control optimal policy/value functions") + for k in range(inv.N): + print(", ".join([f" J_{k}(x_{k}={i}) = {J[k][i]:.2f}" for i in inv.S(k)] ) ) + for k in range(inv.N): + print(", ".join([f"pi_{k}(x_{k}={i}) = {pi[k][i]}" for i in inv.S(k)] ) ) + +if __name__ == "__main__": + main() diff --git a/irlc/ex03/__init__.py b/irlc/ex03/__init__.py new file mode 100644 index 0000000..01980ca --- /dev/null +++ b/irlc/ex03/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 3.""" diff --git a/irlc/ex03/__pycache__/__init__.cpython-311.pyc b/irlc/ex03/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5b4f16c809b017449ec5929b058171c20265711 GIT binary patch literal 232 zcmZ3^%ge>Uz`$Uh-<$T5fq~&Mhy%lnP{wDFlIaX73{eazjKK_=OjU*<8JWcjDVas7 z$tC$kl?uuEc_oRNdBqAP8L0}X6{$tZnZ>Ea3TgR83gxM(*$T#bewvK8*yH0<@{{A^ zS2BDCnf%K}KO;XkRllS(BURreKe;qFHLs*tKQlK+-@wSk)S$SeGzB73l#{HVT47+U zA0MBYmst`YuUAm{i^C>2KczG$)vkz*fq?<!)?z^h28IvJjEsyA7|bugP!S6Q0|Nlu Ca6tnA literal 0 HcmV?d00001 diff --git a/irlc/ex03/__pycache__/basic_pendulum.cpython-311.pyc b/irlc/ex03/__pycache__/basic_pendulum.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8aea6b565bd95c52b88ab61c24199f4f2fc19207 GIT binary patch literal 2978 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 K0<$DIp#uO&@u@BV literal 0 HcmV?d00001 diff --git a/irlc/ex03/__pycache__/control_cost.cpython-311.pyc b/irlc/ex03/__pycache__/control_cost.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fbd4fa86d1447a69fa82333373f93802475e67a2 GIT binary patch literal 16900 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 literal 0 HcmV?d00001 diff --git a/irlc/ex03/__pycache__/control_model.cpython-311.pyc b/irlc/ex03/__pycache__/control_model.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..30de5a19f87513667a5d380652c9bb051c97ccc2 GIT binary patch literal 27734 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 WB8ZU_WD6=Grpze$fdP{MhZg`=_eL`S literal 0 HcmV?d00001 diff --git a/irlc/ex03/basic_pendulum.py b/irlc/ex03/basic_pendulum.py new file mode 100644 index 0000000..817e511 --- /dev/null +++ b/irlc/ex03/basic_pendulum.py @@ -0,0 +1,39 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import sympy as sym +import numpy as np +from irlc.ex03.control_model import ControlModel +from irlc.ex03.control_cost import SymbolicQRCost +from gymnasium.spaces import Box + +class BasicPendulumModel(ControlModel): + def sym_f(self, x, u, t=None): + g = 9.82 + l = 1 + m = 2 + theta_dot = x[1] # Parameterization: x = [theta, theta'] + theta_dot_dot = g / l * sym.sin(x[0]) + 1 / (m * l ** 2) * u[0] + return [theta_dot, theta_dot_dot] + + def get_cost(self) -> SymbolicQRCost: + return SymbolicQRCost(Q=np.eye(2), R=np.eye(1)) + + def u_bound(self) -> Box: + return Box(np.asarray([-10]), np.asarray([10])) + + def x0_bound(self) -> Box: + return Box(np.asarray( [np.pi, 0] ), np.asarray( [np.pi, 0])) + +if __name__ == "__main__": + p = BasicPendulumModel() + print(p) + + from irlc.ex04.discrete_control_model import DiscreteControlModel + model = BasicPendulumModel() + discrete_pendulum = DiscreteControlModel(model, dt=0.5) # Using a discretization time step: 0.5 seconds. + x0 = model.x0_bound().low # Get the initial state: x0 = [np.pi, 0]. + u0 = [0] # No action. Note the action must be a list. + x1 = discrete_pendulum.f(x0, u0) + print(x1) + print("Now, lets compute the Euler step manually to confirm") + x1_manual = x0 + 0.5 * model.f(x0, u0, 0) + print(x1_manual) diff --git a/irlc/ex03/control_cost.py b/irlc/ex03/control_cost.py new file mode 100644 index 0000000..43d1c79 --- /dev/null +++ b/irlc/ex03/control_cost.py @@ -0,0 +1,289 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +import sympy as sym +import numpy as np + + +def mat(x): # Helper function. + return sym.Matrix(x) if x is not None else x + + +class SymbolicQRCost: + """ + This class represents the cost function for a continuous-time model. In the simulations, we are going to assume + that the cost function takes the form: + + .. math:: + \int_{t_0}^{t_F} c(x(t), u(t)) dt + c_F(x_F) + + And this class will specifically implement the two functions :math:`c` and :math:`c_F`. They will be assumed to have the quadratic form: + + .. math:: + c(x, u) & = \\frac{1}{2} x^T Q x + \\frac{1}{2} u^T R u + u^T H x + q^T x + r^T u + q_0, \\\\ + c_F(x_F) & = \\frac{1}{2} x_F^T Q_F x_F + q_F^T x_F + q_{0,F}. + + So what all of this boils down to is that the class just need to store a bunch of matrices and vectors. + + You can add and scale cost-functions + ********************************************************** + + A slightly smart thing about the cost functions are that you can add and scale them. The following provides an + example: + + .. runblock:: pycon + + >>> from irlc.ex03.control_cost import SymbolicQRCost + >>> import numpy as np + >>> cost1 = SymbolicQRCost(np.eye(2), np.zeros(1) ) # Set Q = I, R = 0 + >>> cost2 = SymbolicQRCost(np.ones((2,2)), np.zeros(1) ) # Set Q = 2x2 matrices of 1's, R = 0 + >>> print(cost1.Q) # Will be the identity matrix. + >>> cost = cost1 * 3 + cost2 * 2 + >>> print(cost.Q) # Will be 3 x I + 2 + + """ + + def __init__(self, Q, R, q=None, qc=None, r=None, H=None, QN=None, qN=None, qcN=None): + """ + The constructor can be used to manually create a cost function. You will rarely want to call the constructor + directly but instead use the helper methods (see class documentation). + What the class basically does is that it stores the input parameters as fields. In other words, you can access the quadratic + term of the cost function, :math:`\\frac{1}{2}x^T Q x`, as ``cost.Q``. + + :param Q: The matrix :math:`Q` + :param R: The matrix :math:`R` + :param q: The vector :math:`q` + :param qc: The constant :math:`q_0` + :param r: The vector :math:`r` + :param H: The matrix :math:`H` + :param QN: The terminal cost matrix :math:`Q_N` + :param qN: The terminal cost vector :math:`q_N` + :param qcN: The terminal cost constant :math:`q_{0,N}` + """ + + n = Q.shape[0] + d = R.shape[0] + self.Q = Q + self.R = R + self.q = np.zeros( (n,)) if q is None else q + self.qc = 0 if qc == None else qc + self.r = np.zeros( (d,)) if r is None else r + self.H = np.zeros((d,n)) if H is None else H + self.QN = np.zeros((n,n)) if QN is None else QN + self.qN = np.zeros((n,)) if qN is None else qN + self.qcN = 0 if qcN == None else qcN + self.flds = ('Q', 'R', 'q', 'qc', 'r', 'H', 'QN', 'qN', 'qcN') + self.flds_term = ('QN', 'qN', 'qcN') + + self.c_numpy = None + self.cF_numpy = None + + + @classmethod + def zero(cls, state_size, action_size): + """ + Creates an all-zero cost function, i.e. all terms :math:`Q`, :math:`R` are set to zer0. + + .. runblock:: pycon + + >>> from irlc.ex03.control_cost import SymbolicQRCost + >>> cost = SymbolicQRCost.zero(2, 1) + >>> cost.Q # 2x2 zero matrix + >>> cost.R # 1x1 zero matrix. + + :param state_size: Dimension of the state vector :math:`n` + :param action_size: Dimension of the action vector :math:`d` + :return: A ``SymbolicQRCost`` with all zero terms. + """ + + return cls(Q=np.zeros( (state_size,state_size)), R=np.zeros((action_size,action_size)) ) + + + def sym_c(self, x, u, t=None): + """ + Evaluate the (instantaneous) part of the function :math:`c(x,u, t)`. An example: + + .. runblock:: pycon + + >>> from irlc.ex03.control_cost import SymbolicQRCost + >>> import numpy as np + >>> cost = SymbolicQRCost(np.eye(2), np.eye(1)) # Set Q = I, R = 0 + >>> cost.sym_c(x = np.asarray([1,2]), u=np.asarray([0])) # should return 0.5 * x^T Q x = 0.5 * (1 + 4) + + :param x: The state :math:`x(t)` + :param u: The action :math:`u(t)` + :param t: The current time step :math:`t` (this will be ignored) + :return: A ``sympy`` symbolic expression corresponding to the instantaneous cost. + """ + u = sym.Matrix(u) + x = sym.Matrix(x) + c = 1 / 2 * (x.transpose() @ self.Q @ x) + 1 / 2 * (u.transpose() @ self.R @ u) + u.transpose() @ self.H @ x + sym.Matrix(self.q).transpose() @ x + sym.Matrix(self.r).transpose() @ u + sym.Matrix([[self.qc]]) + assert c.shape == (1,1) + return c[0,0] + + + def sym_cf(self, t0, tF, x0, xF): + """ + Evaluate the terminal (constant) term in the cost function :math:`c_F(t_0, t_F, x_0, x_F)`. An example: + + .. runblock:: pycon + + >>> from irlc.ex03.control_cost import SymbolicQRCost + >>> import numpy as np + >>> cost = SymbolicQRCost(np.eye(2), np.zeros(1), QN=np.eye(2)) # Set Q = I, R = 0 + >>> cost.sym_cf(0, 0, 0, xF=2*np.ones((2,))) # should return 0.5 * xF^T * xF = 0.5 * 8 + + :param t0: Starting time :math:`t_0` (not used) + :param tF: Stopping time :math:`t_F` (not used) + :param x0: Initial state :math:`x_0` (not used) + :param xF: Termi lanstate :math:`x_F` (**this one is used**) + :return: A ``sympy`` symbolic expression corresponding to the terminal cost. + """ + xF = sym.Matrix(xF) + c = 0.5 * xF.transpose() @ self.QN @ xF + xF.transpose() @ sym.Matrix(self.qN) + sym.Matrix([[self.qcN]]) + assert c.shape == (1,1) + return c[0,0] + + def discretize(self, dt): + """ + Discretize the cost function so it is suitable for a discrete control problem. See (Her24, Subsection 13.1.5) for more information. + + :param dt: The discretization time step :math:`\Delta` + :return: An :class:`~irlc.ex04.cost_discrete.DiscreteQRCost` instance corresponding to a discretized version of this cost function. + """ + from irlc.ex04.discrete_control_cost import DiscreteQRCost + return DiscreteQRCost(**{f: self.__getattribute__(f) * (1 if f in self.flds_term else dt) for f in self.flds} ) + + + def __add__(self, c): + return SymbolicQRCost(**{k: self.__dict__[k] + c.__dict__[k] for k in self.flds}) + + def __mul__(self, c): + return SymbolicQRCost(**{k: self.__dict__[k] * c for k in self.flds}) + + def __str__(self): + title = "Continuous-time cost function" + label1 = "Non-zero terms in c(x, u)" + label2 = "Non-zero terms in c_F(x)" + terms1 = [s for s in self.flds if s not in self.flds_term] + terms2 = self.flds_term + return _repr_cost(self, title, label1, label2, terms1, terms2) + + def goal_seeking_terminal_cost(self, xF_target, QF=None): + """ + Create a cost function which is minimal when the terminal state :math:`x_F` is equal to a goal state :math:`x_F^*`. + Concretely, it will return a cost function of the form + + .. math:: + c_F(x_F) = \\frac{1}{2} (x_F^* - x_F)^\\top Q_F (x_F^* - x_F) + + .. runblock:: pycon + + >>> from irlc.ex03.control_cost import SymbolicQRCost + >>> import numpy as np + >>> cost = SymbolicQRCost.zero(2, 1) + >>> cost += cost.goal_seeking_terminal_cost(xF_target=np.ones((2,))) + >>> print(cost.qN) + >>> print(cost) + + :param xF_target: Target state :math:`x_F^*` + :param QF: Cost matrix :math:`Q_F` + :return: A ``SymbolicQRCost`` object corresponding to the goal-seeking cost function + """ + if QF is None: + QF = np.eye(xF_target.size) + QF, qN, qcN = targ2matrices(xF_target, Q=QF) + return SymbolicQRCost(Q=self.Q*0, R=self.R*0, QN=QF, qN=qN, qcN=qcN) + + def goal_seeking_cost(self, x_target, Q=None): + """ + Create a cost function which is minimal when the state :math:`x` is equal to a goal state :math:`x^*`. + Concretely, it will return a cost function of the form + + .. math:: + c(x, u) = \\frac{1}{2} (x^* - x)^\\top Q (x^* - x) + + .. runblock:: pycon + + >>> from irlc.ex03.control_cost import SymbolicQRCost + >>> import numpy as np + >>> cost = SymbolicQRCost.zero(2, 1) + >>> cost += cost.goal_seeking_cost(x_target=np.ones((2,))) + >>> print(cost.q) + >>> print(cost) + + :param x_target: Target state :math:`x^*` + :param Q: Cost matrix :math:`Q` + :return: A ``SymbolicQRCost`` object corresponding to the goal-seeking cost function + """ + if Q is None: + Q = np.eye(x_target.size) + Q, q, qc = targ2matrices(x_target, Q=Q) + return SymbolicQRCost(Q=Q, R=self.R*0, q=q, qc=qc) + + def term(self, Q=None, R=None,r=None): + dd = {} + lc = locals() + for f in self.flds: + if f in lc and lc[f] is not None: + dd[f] = lc[f] + else: + dd[f] = self.__getattribute__(f)*0 + return SymbolicQRCost(**dd) + + @property + def state_size(self): + return self.Q.shape[0] + + @property + def action_size(self): + return self.R.shape[0] + + + +def _repr_cost(cost, title, label1, label2, terms1, terms2): + self = cost + def _get(flds, label): + d = {s: self.__dict__[s] for s in flds if np.sum(np.sum(self.__dict__[s] != 0)) != 0} + out = "" + if len(d) > 0: + # out = "" + out += f"> {label}:\n" + for s, m in d.items(): + mm = f"{m}" + if len(mm.splitlines()) > 1: + mm = "\n" + mm + out += f" * {s} = {mm}\n" + + return d, out + + nz_c, o1 = _get([s for s in terms1], label1) + out = "" + out += f"{title}:\n" + out += o1 + nz_term, o2 = _get(terms2, label2) + out += o2 + if len(nz_c) + len(nz_term) == 0: + print("All terms in the cost-function are zero.") + return out + + +def targ2matrices(t, Q=None): # Helper function + """ + Given a target vector :math:`t` and a matrix :math:`Q` this function returns cost-matrices suitable for implementing: + + .. math:: + \\frac{1}{2} * (x - t)^Q (x - t) = \\frac{1}{2} * x^T Q x + 1/2 * t^T * t - x * t + + :param t: + :param Q: + :return: + """ + n = t.size + if Q is None: + Q = np.eye(n) + + return Q, -1/2 * (Q @ t + t @ Q.T), 1/2 * t @ Q @ t diff --git a/irlc/ex03/control_model.py b/irlc/ex03/control_model.py new file mode 100644 index 0000000..ed57c85 --- /dev/null +++ b/irlc/ex03/control_model.py @@ -0,0 +1,423 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +from collections import defaultdict +import tabulate +import sympy as sym +import numpy as np +import matplotlib.pyplot as plt +from gymnasium.spaces import Box +from irlc.ex03.control_cost import SymbolicQRCost + + +class ControlModel: + r"""Represents the continious time model of a control environment. + + + See (Her24, Section 13.2) for a top-level description. + + The model represents the physical system we are simulating and can be considered a control-equivalent of the + :class:`irlc.ex02.dp_model.DPModel`. The class must keep track of the following: + + .. math:: + \frac{dx}{dt} = f(x, u, t) + + And the cost-function which is defined as an integral + + .. math:: + c_F(t_0, t_F, x(t_0), x(t_F)) + \int_{t_0}^{t_F} c(t, x, u) dt + + as well as constraints and boundary conditions on :math:`x`, :math:`u` and the initial conditions state :math:`x(t_0)`. + this course, the cost function will always be quadratic, and can be accessed as ``model.get_cost``. + + If you want to implement your own model, the best approach is to start with an existing model and modify it for + your needs. The overall idea is that you implement the dynamics,``sym_f``, and the cost function ``get_cost``, + and optionally define bounds as needed. + """ + state_labels = None # Labels (as lists) used for visualizations. + action_labels = None # Labels (as lists) used for visualizations. + + def __init__(self): + """ + The cost must be an instance of :class:`irlc.ex04.cost_continuous.SymbolicQRCost`. + Bounds is a dictionary but otherwise optional; the model should give it a default value. + + :param cost: A quadratic cost function + :param dict bounds: A dictionary of boundary constraints. + """ + if self.state_labels is None: + self.state_labels = [f'x{i}' for i in range(self.state_size)] + if self.action_labels is None: + self.action_labels = [f'u{i}' for i in range(self.action_size)] + + t = sym.symbols("t") + x = sym.symbols(f"x0:{self.state_size}") + u = sym.symbols(f"u0:{self.action_size}") + try: + f = self.sym_f(x, u, t) + except Exception as e: + print("control_model.py> There is a problem with the way you have specified the dynamics. The function sym_f must accept lists as inputs") + raise e + if len(f) != len(x): + print("control_model.py> Your function ControlModel.sym_f must output a list of symbolic expressions.") + assert len(f) == len(x) + + self._f_np = sym.lambdify((x, u, t), self.sym_f(x, u, t)) + + def x0_bound(self) -> Box: + r"""The bound on the initial state :math:`\mathbf{x}_0`. + + The default bound is ``Box(0, 0, shape=(self.state_size,))``, i.e. :math:`\mathbf{x}_0 = 0`. + + :return: An appropriate gymnasium Box instance. + """ + return Box(0, 0, shape=(self.state_size,)) + + def xF_bound(self) -> Box: + r"""The bound on the terminal state :math:`\mathbf{x}_F`. + + :return: An appropriate gymnasium Box instance. + """ + return Box(-np.inf, np.inf, shape=(self.state_size,)) + + def x_bound(self) -> Box: + r"""The bound on all other states :math:`\mathbf{x}(t)`. + + :return: An appropriate gymnasium Box instance. + """ + return Box(-np.inf, np.inf, shape=(self.state_size,)) + + def u_bound(self) -> Box: + r"""The bound on the terminal state :math:`\mathbf{u}(t)`. + + :return: An appropriate gymnasium Box instance. + """ + return Box(-np.inf, np.inf, shape=(self.action_size,)) + + def t0_bound(self) -> Box: + r"""The bound on the initial time :math:`\mathbf{t}_0`. + + I have included this bound for completeness: In practice, there is no reason why you should change it + from the default bound is ``Box(0, 0, shape=(1,))``, i.e. :math:`\mathbf{t}_0 = 0`. + + :return: An appropriate gymnasium Box instance. + """ + return Box(0, 0, shape=(1,)) + + def tF_bound(self) -> Box: + r"""The bound on the final time :math:`\mathbf{t}_F`, i.e. when the environment terminates. + + :return: An appropriate gymnasium Box instance. + """ + return Box(-np.inf, np.inf, shape=(1,)) + + def get_cost(self) -> SymbolicQRCost: + raise NotImplementedError("When you implement the model, you must implement the get_cost() function.\nfor instance, use return SymbolicQRCost(Q=np.eye(n), R=np.eye(d))") + + def sym_f(self, x, u, t=None): + """ + The symbolic (``sympy``) version of the dynamics :math:`f(x, u, t)`. This is the main place where you specify + the dynamics when you build a new model. you should look at concrete implementations of models for specifics. + + :param x: A list of symbolic expressions ``['x0', 'x1', ..]`` corresponding to :math:`x` + :param u: A list of symbolic expressions ``['u0', 'u1', ..]`` corresponding to :math:`u` + :param t: A single symbolic expression corresponding to the time :math:`t` (seconds) + :return: A list of symbolic expressions ``[f0, f1, ...]`` of the same length as ``x`` where each element is a coordinate of :math:`f` + """ + raise NotImplementedError("Implement a function which return the environment dynamics f(x,u,t) as a sympy exression") + + def f(self, x, u, t=0) -> np.ndarray: + r"""Evaluate the dynamics. + + This function will evaluate the dynamics. In other words, it will evaluate :math:`\mathbf{f}` in the following expression: + + .. math:: + + \dot{\mathbf{x}} = \mathbf{f}(\mathbf{x}, \mathbf{u}, t) + + :param x: A numpy ndarray corresponding to the state + :param u: A numpy ndarray corresponding to the control + :param t: A :python:`float` corresponding to the time. + :return: The time derivative of the state, :math:`\mathbf{x}(t)`. + """ + return np.asarray( self._f_np(x, u, t) ) + + + def simulate(self, x0, u_fun, t0, tF, N_steps=1000, method='rk4'): + """ + Used to simulate the effect of a policy on the model. By default, it uses + Runge-Kutta 4 (RK4) with a fine discretization -- this is slow, but in nearly all cases exact. See (Her24, Algorithm 18) for more information. + + The input argument ``u_fun`` should be a function which returns a list or tuple with same dimension as + ``model.action_space``, :math:`d`. + + :param x0: The initial state of the simulation. Must be a list of floats of same dimension as ``env.observation_space``, :math:`n`. + :param u_fun: Can be either: + - Either a policy function that can be called as ``u_fun(x, t)`` and returns an action ``u`` in the ``action_space`` + - A single action (i.e. a list of floats of same length as the action space). The model will be simulated with a constant action in this case. + :param float t0: Starting time :math:`t_0` + :param float tF: Stopping time :math:`t_F`; the model will be simulated for :math:`t_F - t_0` seconds + :param int N_steps: Steps :math:`N` in the RK4 simulation + :param str method: Simulation method. Either ``'rk4'`` (default) or ``'euler'`` + :return: + - xs - A numpy ``ndarray`` of dimension :math:`(N+1)\\times n` containing the observations :math:`x` + - us - A numpy ``ndarray`` of dimension :math:`(N+1)\\times d` containing the actions :math:`u` + - ts - A numpy ``ndarray`` of dimension :math:`(N+1)` containing the corresponding times :math:`t` (seconds) + """ + + u_fun = ensure_policy(u_fun) + tt = np.linspace(t0, tF, N_steps+1) # Time grid t_k = tt[k] between t0 and tF. + xs = [ np.asarray(x0) ] + us = [ u_fun(x0, t0 )] + for k in range(N_steps): + Delta = tt[k+1] - tt[k] + tn = tt[k] + xn = xs[k] + un = us[k] # ensure the action u is a vector. + unp = u_fun(xn, tn + Delta) + if method == 'rk4': + """ Implementation of RK4 here. See: (Her24, Algorithm 18) """ + k1 = np.asarray(self.f(xn, un, tn)) + k2 = np.asarray(self.f(xn + Delta * k1/2, u_fun(xn, tn+Delta/2), tn+Delta/2)) + k3 = np.asarray(self.f(xn + Delta * k2/2, u_fun(xn, tn+Delta/2), tn+Delta/2)) + k4 = np.asarray(self.f(xn + Delta * k3, u_fun(xn, tn + Delta), tn+Delta)) + xnp = xn + 1/6 * Delta * (k1 + 2*k2 + 2*k3 + k4) + elif method == 'euler': + xnp = xn + Delta * np.asarray(self.f(xn, un, tn)) + else: + raise Exception("Bad integration method", method) + xs.append(xnp) + us.append(unp) + xs = np.stack(xs, axis=0) + us = np.stack(us, axis=0) + return xs, us, tt + + @property + def state_size(self): + """ + This field represents the dimensionality of the state-vector :math:`n`. Use it as ``model.state_size`` + :return: Dimensionality of the state vector :math:`x` + """ + return self.get_cost().state_size + # return len(list(self.bounds['x_low'])) + + @property + def action_size(self): + """ + This field represents the dimensionality of the action-vector :math:`d`. Use it as ``model.action_size`` + :return: Dimensionality of the action vector :math:`u` + """ + return self.get_cost().action_size + # return len(list(self.bounds['u_low'])) + + def render(self, x, render_mode="human"): + """ + Responsible for rendering the state. You don't have to worry about this function. + + :param x: State to render + :param str render_mode: Rendering mode. Select ``"human"`` for a visualization. + :return: Either none or a ``ndarray`` for plotting. + """ + raise NotImplementedError() + + def close(self): + pass + + def phi_x(self, x : list) -> list: + r"""Coordinate transformation of the state when the model is discretized. + + This function specifies the coordinate transformation :math:`x_k = \Phi_x(x(t_k))` which is applied to the environment when it is + discretized. It should accept a list of symbols, corresponding to :math:`x`, and return a new list + of symbols corresponding to the (discrete) coordinates. + + :param x: A list of symbols ``[x0, x1, ..., xn]`` corresponding to :math:`\mathbf{x}(t)` + :return: A new list of symbols corresponding to the discrete coordinates :math:`\mathbf{x}_k`. + """ + return x + + def phi_x_inv(self, x: list) -> list: + r"""Inverse of coordinate transformation for the state. + + This function should specify the inverse of the coordinate transformation :math:`\Phi_x`, i.e. :math:`\Phi_x^{-1}`. + In other words, it has to map from the discrete coordinates to the continuous-time coordinates: :math:`x(t) = \Phi_x^{-1}(x_k)`. + + :param x: A list of symbols ``[x0, x1, ..., xn]`` corresponding to :math:`\mathbf{x}_k` + :return: A new list of symbols corresponding to the continuous-time coordinates :math:`\mathbf{x}(t)`. + """ + return x + + def phi_u(self, u: list) -> list: + r"""Coordinate transformation of the action when the model is discretized. + + This function specifies the coordinate transformation :math:`x_k = \Phi_x(x(t_k))` which is applied to the environment when it is + discretized. It should accept a list of symbols, corresponding to :math:`x`, and return a new list + of symbols corresponding to the (discrete) coordinates. + + :param x: A list of symbols ``[x0, x1, ..., xn]`` corresponding to :math:`\mathbf{x}(t)` + :return: A new list of symbols corresponding to the discrete coordinates :math:`\mathbf{x}_k`. + """ + return u + + def phi_u_inv(self, u: list) -> list: + r"""Inverse of coordinate transformation for the action. + + This function should specify the inverse of the coordinate transformation :math:`\Phi_u`, i.e. :math:`\Phi_u^{-1}`. + In other words, it has to map from the discrete coordinates to the continuous-time coordinates: :math:`u(t) = \Phi_u^{-1}(u_k)`. + + :param x: A list of symbols ``[u0, u1, ..., ud]`` corresponding to :math:`\mathbf{u}_k` + :return: A new list of symbols corresponding to the continuous-time coordinates :math:`\mathbf{u}(t)`. + """ + return u + + def __str__(self): + """ + Return a string representation of the model. This is a potentially helpful way to summarize the content of the + model. You can use it as: + + .. runblock:: pycon + + >>> from irlc.ex04.model_pendulum import SinCosPendulumModel + >>> model = SinCosPendulumModel() + >>> print(model) + + :return: A string containing the details of the model. + """ + split = "-"*20 + s = [f"{self.__class__}"] + ['='*50] + s += ["Dynamics:", split] + t = sym.symbols("t") + x = sym.symbols(f"x0:{self.state_size}") + u = sym.symbols(f"u0:{self.action_size}") + + s += [typeset_eq(x, u, self.sym_f(x, u, t) )] + + s += ["Cost:", split, str(self.get_cost())] + + dd = defaultdict(list) + bounds = [ ('x', self.x_bound()), ('x0', self.x0_bound()), ('xF', self.xF_bound()), + ('u', self.u_bound()), + ('t0', self.t0_bound()), ('tF', self.tF_bound())] + + for v, box in bounds: + if (box.low == -np.inf).all() and (box.high == np.inf).all(): + continue + dd['low'].append(box.low_repr) + dd['variable'].append("<= " + v + " <=") + dd['high'].append(box.high_repr) + + if len(dd) > 0: + s += ["Bounds:", split] + s += [tabulate.tabulate(dd, headers='keys')] + else: + s += ['No bounds are applied to the x and u-variables.'] + return "\n".join(s) + + +def symv(s, n): + """ + Returns a vector of symbolic functions. For instance if s='x' and n=3 then it will return + [x0,x1,x2] + where x0,..,x2 are symbolic variables. + """ + return sym.symbols(" ".join(["%s%i," % (s, i) for i in range(n)])) + +def ensure_policy(u): + """ + Ensure u corresponds to a policy function with input arguments u(x, t) + """ + if callable(u): + return lambda x, t: np.asarray(u(x,t)).reshape((-1,)) + else: + return lambda x, t: np.asarray(u).reshape((-1,)) + +def plot_trajectory(x_res, tt, lt='k-', ax=None, labels=None, legend=None): + M = x_res.shape[1] + if labels is None: + labels = [f"x_{i}" for i in range(M)] + + if ax is None: + if M == 2: + a = 234 + if M == 3: + r = 1 + c = 3 + else: + r = 2 if M > 1 else 1 + c = (M + 1) // 2 + + H = 2*r if r > 1 else 3 + W = 6*c + # if M == 2: + # W = 12 + f, ax = plt.subplots(r,c, figsize=(W,H)) + if M == 1: + ax = np.asarray([ax]) + print(M,r,c) + + for i in range(M): + if len(ax) <= i: + print("issue!") + + a = ax.flat[i] + a.plot(tt, x_res[:, i], lt, label=legend) + + a.set_xlabel("Time/seconds") + a.set_ylabel(labels[i]) + # a.set_title(labels[i]) + a.grid(True) + if legend is not None and i == 0: + a.legend() + # if i == M: + plt.tight_layout() + return ax + +def make_space_above(axes, topmargin=1.0): + """ increase figure size to make topmargin (in inches) space for + titles, without changing the axes sizes""" + fig = axes.flatten()[0].figure + s = fig.subplotpars + w, h = fig.get_size_inches() + + figh = h - (1-s.top)*h + topmargin + fig.subplots_adjust(bottom=s.bottom*h/figh, top=1-topmargin/figh) + fig.set_figheight(figh) + +def typeset_eq(x, u, f): + def ascii_vector(ls): + ml = max(map(len, ls)) + ls = [" " * (ml - len(s)) + s for s in ls] + ls = ["[" + s + "]" for s in ls] + return "\n".join(ls) + + v = [str(z) for z in f] + + def cstack(ls: list): + # ls = [l.splitlines() for l in ls] + height = max([len(l) for l in ls]) + widths = [len(l[0]) for l in ls] + + for k in range(len(ls)): + missing2 = (height - len(ls[k])) // 2 + missing1 = (height - len(ls[k]) - missing2) + tpad = [" " * widths[k]] * missing1 + bpad = [" " * widths[k]] * missing2 + ls[k] = tpad + ls[k] + bpad + + r = [""] * len(ls[0]) + for w in range(len(ls)): + for h in range(len(ls[0])): + r[h] += ls[w][h] + + return r + + xx = [str(x) for x in x] + uu = [str(u) for u in u] + xx = ascii_vector(xx).splitlines() + uu = ascii_vector(uu).splitlines() + cm = cstack([xx, [", "], uu]) + eq = cstack([["f("], cm, [")"]]) + eq = cstack([[" "], eq, [" = "], ascii_vector(v).splitlines()]) + return "\n".join(eq) diff --git a/irlc/ex03/inventory_evaluation.py b/irlc/ex03/inventory_evaluation.py new file mode 100644 index 0000000..c5d7eda --- /dev/null +++ b/irlc/ex03/inventory_evaluation.py @@ -0,0 +1,26 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex02.inventory import InventoryDPModel + +def a_expected_items_next_day(x : int, u : int) -> float: + model = InventoryDPModel() + expected_number_of_items = None + # TODO: Code has been removed from here. + raise NotImplementedError("Insert your solution and remove this error.") + return expected_number_of_items + + +def b_evaluate_policy(pi : list, x0 : int) -> float: + # TODO: Code has been removed from here. + raise NotImplementedError("Insert your solution and remove this error.") + return J_pi_x0 + +if __name__ == "__main__": + model = InventoryDPModel() + # Create a policy that always buy an item if the inventory is empty. + pi = [{s: 1 if s == 0 else 0 for s in model.S(k)} for k in range(model.N)] + x = 0 + u = 1 + x0 = 1 + a_expected_items_next_day(x=0, u=1) + print(f"Given inventory is {x=} and we buy {u=}, the expected items on day k=1 is {a_expected_items_next_day(x, u)} and should be 0.1") + print(f"Evaluation of policy is {b_evaluate_policy(pi, x0)} and should be 2.7") diff --git a/irlc/ex03/kuramoto.py b/irlc/ex03/kuramoto.py new file mode 100644 index 0000000..e20844e --- /dev/null +++ b/irlc/ex03/kuramoto.py @@ -0,0 +1,123 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +import sympy as sym +from irlc.ex03.control_model import ControlModel +from irlc.ex03.control_cost import SymbolicQRCost +import numpy as np +from irlc import savepdf +from gymnasium.spaces import Box + + +class KuramotoModel(ControlModel): + r""" + The Kuramoto model. It implements the following dynamics: + + .. math:: + + \dot{x}(t) = u(t) +\cos(x(t)) + + I.e. the state and control variables are both one-dimensional. The cost function is simply: + + .. math:: + + c(t) = \frac{1}{2}x(t)^2 + \frac{1}{2}u(t)^2 + + This is a QR cost with :math:`Q=R=1`. + """ + def u_bound(self) -> Box: + return Box(-2, 2, shape=(1,)) + + def x0_bound(self) -> Box: + return Box(0, 0, shape=(1,)) + + def get_cost(self) -> SymbolicQRCost: + """ + Create a cost-object. The code defines a quadratic cost (with the given matrices) and allows easy computation + of derivatives, etc. There are automatic ways to discretize the cost so you don't have to bother with that. + See the online documentation for further details. + """ + return SymbolicQRCost(Q=np.zeros((1, 1)), R=np.ones((1,1))) + + def sym_f(self, x: list, u: list, t=None): + r""" Return a symbolic expression representing the Kuramoto model. + The inputs x, u are themselves *lists* of symbolic variables (insert breakpoint and check their value). + you have to use them to create a symbolic object representing f, and return it as a list. That is, you are going to return + + .. codeblock:: python + + return [f_val] + + where ``f_val`` is the symbolic expression corresponding to the dynamics, i.e. :math:`u(t) + \cos( x(t))`. + Note you can use trigonometric functions like ``sym.cos``. + """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement symbolic expression as a singleton list here") + # define the symbolic expression + return symbolic_f_list + + +def f(x, u): + """ Implement the kuramoto osscilator model's dynamics, i.e. f such that dx/dt = f(x,u). + The answer should be returned as a singleton list. """ + cmodel = KuramotoModel() + # TODO: 1 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + # Use the ContiniousKuramotoModel to compute f(x,u). If in doubt, insert a breakpoint and let pycharms autocomplete + # guide you. See my video to Exercise 2 for how to use the debugger. Don't forget to specify t (for instance t=0). + # Note that sympys error messages can be a bit unforgiving. + return f_value + +def rk4_simulate(x0, u, t0, tF, N=1000): + """ + Implement the RK4 algorithm (Her24, Algorithm 18). + In this function, x0 and u are constant numpy ndarrays. I.e. u is not a function, which simplify the RK4 + algorithm a bit. + + The function you want to integrate, f, is already defined above. You can likewise assume f is not a function of + time. t0 and tF play the same role as in the algorithm. + + The function should return a numpy ndarray xs of dimension (N,) (containing all the x-values) and a numpy ndarray + tt containing the corresponding time points. + + Hints: + * Call f as in f(x, u). You defined f earlier in this exercise. + """ + tt = np.linspace(t0, tF, N+1) # Time grid t_k = tt[k] between t0 and tF. + xs = [ x0 ] + f(x0, u) # This is how you can call f. + for k in range(N): + x_next = None # Obtain x_next = x_{k+1} using a single RK4 step. + # Remember to insert breakpoints and use the console to examine what the various variables are. + # TODO: 7 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + xs.append(x_next) + xs = np.stack(xs, axis=0) + return xs, tt + +if __name__ == "__main__": + # Create a symbolic model corresponding to the Kuramoto model: + # Evaluate the dynamics dx / dt = f(x, u). + + print("Value of f(x,u) in x=2, u=0.3", f([2], [0.3])) + print("Value of f(x,u) in x=0, u=1", f([0], [1])) + + cmodel = KuramotoModel() + print(cmodel) + x0 = cmodel.x0_bound().low # Get the starting state x0. We exploit that the bound on x0 is an equality constraint. + u = 1.3 + xs, ts = rk4_simulate(x0, [u], t0=0, tF=20, N=100) + xs_true, us_true, ts_true = cmodel.simulate(x0, u_fun=u, t0=0, tF=20, N_steps=100) + """You should generally use cmodel.simulate(...) to simulate the environment. Note that u_fun in the simulate + function can be set to a constant. Use this compute numpy ndarrays corresponding to the time, x and u values. + """ + # Plot the exact simulation of the environment + import matplotlib.pyplot as plt + plt.plot(ts_true, xs_true, 'k.-', label='RK4 state sequence x(t) (using model.simulate)') + plt.plot(ts, xs, 'r-', label='RK4 state sequence x(t) (using your code)') + plt.legend() + #savepdf('kuramoto_rk4') + plt.show(block=False) diff --git a/irlc/ex03/toy_2d_control.py b/irlc/ex03/toy_2d_control.py new file mode 100644 index 0000000..187dd03 --- /dev/null +++ b/irlc/ex03/toy_2d_control.py @@ -0,0 +1,23 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import sympy as sym +from irlc.ex03.control_model import ControlModel +from irlc.ex03.control_cost import SymbolicQRCost +import numpy as np + +class Toy2DControl(ControlModel): + def get_cost(self): + # You get the cost-function for free because it can be anything as far as this problem is concerned. + return SymbolicQRCost(Q=np.eye(2), R=np.eye(1)) + + # TODO: 2 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + +def toy_simulation(u0 : float, T : float) -> float: + # TODO: 4 lines missing. + raise NotImplementedError("Create a Toy2dControl instance and use model.simulate(..) to get the final state.") + return wT + +if __name__ == "__main__": + x0 = np.asarray([np.pi/2, 0]) + wT = toy_simulation(u0=0.4, T=5) + print(f"Starting in x0=[pi/2, 0], after T=5 seconds the system is an an angle {wT=} (should be 1.265)") diff --git a/irlc/ex04/__init__.py b/irlc/ex04/__init__.py new file mode 100644 index 0000000..d084853 --- /dev/null +++ b/irlc/ex04/__init__.py @@ -0,0 +1,20 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 4.""" + +speech = """ +Fate has ordained that the men who went to the moon to explore in peace will stay on the moon to rest in peace. + +These brave men, Neil Armstrong and Edwin Aldrin, know that there is no hope for their recovery. But they also know that there is hope for mankind in their sacrifice. + +These two men are laying down their lives in mankind’s most noble goal: the search for truth and understanding. + +They will be mourned by their families and friends; they will be mourned by their nation; they will be mourned by the people of the world; they will be mourned by a Mother Earth that dared send two of her sons into the unknown. + +In their exploration, they stirred the people of the world to feel as one; in their sacrifice, they bind more tightly the brotherhood of man. + +In ancient days, men looked at stars and saw their heroes in the constellations. In modern times, we do much the same, but our heroes are epic men of flesh and blood. + +Others will follow, and surely find their way home. Man’s search will not be denied. But these men were the first, and they will remain the foremost in our hearts. + +For every human being who looks up at the moon in the nights to come will know that there is some corner of another world that is forever mankind. +""" diff --git a/irlc/ex04/__pycache__/__init__.cpython-311.pyc b/irlc/ex04/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3164efb4748bc0ed4f1b2e1ee9f97c20e21d294b GIT binary patch literal 1505 zcmZ3^%ge>Uz`$UU-<x)qm4V?ghy%lnP{wCI1_p-d3@Hpz3@MCJj44dP44TYUh9Mc5 z#R@5zMXAXp`9+lq$@zIDiJ5uD3MCn-3aJ&TMah}Psl^Iu`9%ulsj1ltCVHihSr{0& z+!9Mt6*3Zw74nNx5;OBsQxr-v5=+3ka#QmZ$}{p6%2V@76iV_TV)^-bAa-g+K~8>A zszPR-LP2U`a;idkW=@VmaY<sO0!TqdszNSQWl?Hz30#>T7gtC|YH_MUQc+@AszPpR zo{oZFYG#gtV^MB#Nl|`Yx<X=Jih^rOd1ju1V@^s@W}c2hc3yrt+*Keuixu+n6*BS* zQo-IS$w<vCQYcDI&M!+Xs?<|(Dg`^gQXw&?I3Js4xX#?fyzI=p6p-s6h7>0z7iFep zCa1#PSyG-4a-~9IQK~{tVr6Dtx<X2Rc^)V%GK&;)GRsnnLE51vJ!+U)tdN^uT%wSd zpOllTke;8IV+B&HP@I}rl$-%^Z&7JU2H2aWc`2zy#U+V(DVcfc5GyMo0ht5}ztSR5 zbR<=R49F}}NK4Gk%*jkG25U_#%1q5mDYgd5;n9<qSdy8ahgX$CL27<MPO3tF8pte# z^8BKl6x<pT6@2qcGE$2aToa2*G9a;%l30|QqEMWgm!bd)uKY9wkb>g;JW$X;(@kj} zC>HbdxVSuFfd@%KU<c}etgcijF3Btc83jtRSX>24cWJ4qISQcEnwM$~3V5`5gBp|s ziq%|D`Yg#z&nU?O2cbez5!mS&`S~dz-{vMlos*cCoC!+eDT$TEI^fvO$<NPDO;JcJ z0j207NQf6Ff)XJpsb!=V<wK$!<j~~&yyBA7oE)%6iuDvc^AvLPQ&Nla6iPC4Q;T&J z%2O3m@)dGRlR?3is!*Jmo2sLbR9d2tUs?nTDUey9<ds^GnGCi)KTRPmC$$)oMv`*! z^HcP=xcot(UJOYcY56%h`Q<v`giu^sl$ukikOuNGBrwVoD-|;Gb5r#cd=vA)DH59a zz*#gezeFJ^RUsucFEcd-o>_{)c~PM}wI~%76$)vYMa3l$3raFlp$V)gH8(L69DAU2 zoC;3onR!reBo>tv>v3_p<rgWWg7Tq4Mrm$ho<dS8D9eCK5m1;GE0h+1LKPHl;PL@# zTplQvib3(4oSzFVOF-!blD<GbPgTe)RwxEZCg&IBr51rAFfk7tpO7RAQJM)Z;Xn>h zfM!WOE<a7CTkP@iDf!9q@weED3sO^)GgdNu29>72Z1h1PrC(B-k*e>KpIn-onpaY+ zpP8GZZ(w9%YEWEKngS6i%1PEwtuQdrkB`sH%PfhH*DI*}#bJ}1pHiBWYFEV0z`y`1 jpNqv97#Kb<GcqzhU@*VHVE%zcfQzMp4Fro=85kG<I?)E% literal 0 HcmV?d00001 diff --git a/irlc/ex04/__pycache__/control_environment.cpython-311.pyc b/irlc/ex04/__pycache__/control_environment.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d907d0d5b866124103b4679a0addcac96838cba2 GIT binary patch literal 11647 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 W0|Rz)hVUHmk6^hkU=mXu*ogqWU%4Ov literal 0 HcmV?d00001 diff --git a/irlc/ex04/__pycache__/discrete_control_cost.cpython-311.pyc b/irlc/ex04/__pycache__/discrete_control_cost.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a34b7db9927788c8e5d7bb03c37ab974e150ae1d GIT binary patch literal 11299 zcmZ3^%ge>Uz`$UU-<$SSo`K;phy%kcP{wBm1_p-d3@Hpz3@MB$OgW5EOeu^h%sI@t zEKw|s3@Pj>EG>*ttV|5<3@NNF3@L2Om>3vVGeLDTM6snX1v6-JR7r6KmL{eYC6;6+ zD<tO^mnfu_<|UV8=I0f2y#y)t(`3BGTas9mZj_r?Qk0pTTAa)b5{F`tb3lBkb7~kG zq)Ql~atsU%S#Wj@Qv-7iV;W-~a}8q+QySAUMh1q}aM?V@8irtom5hEXnQk%V72IO2 zN-fGS)?~iL7;%d+@fKrJF~|}H1%+Rp`WgATsrn_Q8L9d%`N^fZsd**E`kA>o`UXZO zrUu0&r6~}RqMT&?)CvO={glk&<f7D))cEB5ypp2)oOqBo^$IF)G38Yi@iH(la4;}1 z6l*dtFf=gSFg4o{*=y8eF~f0&=Y+rsE)!f<IIc)sVS16<@Cvu#1#ZIwju%*5KZAUj z3?g6{7O<a_z|oS*5XG3n0E&_*<`h0~RIsG*r?7#dBt;;Fy@fG~Erp|nA&NbPvxOmw zBZaGlA&N7VD}}p-VHpDh!)lnh3{l)Ef+;*Lj8Qx(f+@T$j8VMch!eWS=K}RtV32cu zaY<qlD+2?Uf`WoVNJeI{LUK-Gaj`;CYC%zIF(^C~N-|PW<5wXqzepib0Tw#CC7HRY z3c2|ysX2NIo_S#P#hJOKIf>xJprcTps*qTes*s+anU}6mlCO|hTwI!)3bwH%Be4Xm z0Ti<E1f)=sn4MY-7EjAB%C+JGtJTv}$W1KCu(AU4K<<qxF3pXv&bBqEjjQ(4HLO)g zj?dPph|kthD2>n7RM1vPj`!23i1*Xvf|%f#m!eRD@MC#qPL4uxL27blT4r)$PEMsl zW^O@FDkxom?Jg<LhdZfQ!3u17LUMvaVqOZI7w?y#2X;?LMrx%3*u<n%s1H*>p3O)s zO9h)&2+u5d{e<cTH3eIRn6#qA<Z8p(YNJ|(iumlf5QRVxt)Pt}Qwo*|0{L7)TcI>A zBtBcg1FEhtE(FRdiVK0ND2zAIQHY5FyB!pku%J@Fw9*e`WxSt4MZBMawnAY%h!0~| z8|e7e>Oq1xIA5V06rYJXISTn{kdRKw&&(-SNXakH0|iDVC{kfD4o+uTrNt!*d8w)3 zuqrOeFG^KNR7fh#OU?ip0V_DbL0*=cT#{c@47DsWzf>VPF;5{eB?T;7oSc{gNvFDq zatP!xEwTZ`SB?tBIhpAhB{`J}#kq+^pyUcl$B9Y#r64xMPNZ}KO6uTbU5V9&B^jx? zdI}*KsS0WNIXU^|AhQaJ^2;()Qi~N5^T6?uT9F7!h=_DwRGOERlb@VzWu;J1nVg>o zaT&;Wc6N3OX+`<D3YkSY$$FqtOAnSWQA#aP(#|g`Q9#Z5VB28EWabutROFTB7E~%E z7Axcxph$yqsG))_nh6?t1$wEKsTxL_ItqCOdf>uW!%$N}Q$blFIJHC}P{CHgQ%504 z!B)Wl!#E?X#^vXw7Heo2=@@C^G1I8R2viz?s})d6F;p+cW=la)W?qQ~*y(zKAUB1B z@_Z5`M`nV``^=I`h(Q&Qd<+W>kRAnFaKUG&prv4}psfJr7%6Be7@_zCVF#)e#tIb* zo(kFuMv&O@D*~1D$>91KT1K-mFff2>r_To%K{av>V-{3`fgy!a63(t+!Y*FRUCUJh z(hpTx!(PKx!?lc=fnhaV6h)q+h6}YWPiCrNhzB_fY(fn~Ja&DI1k7c@YA&dPhndR? zW-u@?pty&rhP#Fvk9(PGxbgajwT2tbKg=}@@t{xzTUWyn&kklVFfi0G#DgkpFt>)S zh7;^_PB0fD3y+s{h7_hnj5Q4L+%Va6h7@LyNETeA3ZjPxrXqzQm_d^T62qFzx0nL` zZZQ@5-C{0G_S0m$#Ta;tvG5jS&@D!fTZ~1wm<p3Md2g{6XCxM+f?E+qLJSNHMZzFL z6hw%D2yqZ00U|&Np-2kE5@BFqxW$>4lTsXCl3J8|iv`5g<hjLCoSKtX1lEht1~vtu z7hwn36vn(;j48z+4}cOp3>Sd}ZgIrNXXa&=#K%{OqZSu>FbO?SyXPRJ-NP@?Q$C@v zr)q}b9P<T+bF4ZHI~eau%g#tzAh^JArqvv)r9~^0Rs=4rSW<C;L!yJFhkb&`6!E)~ z(lZ=q6fRJlDLqGeY0?V86^;utmSlABb+GiXO<<YAc2`k(f#ZV06^aX`mq@Qo+90^W zaYNzC>^0eYjdmm+5Zr08$KnEq98C2LmN{%UWaJhwU*M30S|M>mQs)8~b+GjC-4HRp z07e^9w&YzDap_>`;q2h-;4I=}U|?`dhNn*k1_n_20p)|wY2aL$!dSyt!+^+vRV)k) zHH;v#iWQVkYnW<~8ml1j8YU14k_D#|kUTt(fn=b%!D%Q9WD__Up@<^#4#X^oTDU7g z=GL;NptuX!jaeW+fK3Id1i1uadJO}@K9Ec;8`unZV;b2fSj+&srG_C3?mDm;>@^Ho zaR1eEAiJZM6WPRCt{RpijvCe)wi@;t&Kiyyt~9n_h8osj22G~KMa<AfC@3wumL=wt zCYC^oX^qUh;*!L?lEl2!{L*4gg#u6|3~pbf!mC|GdkoS51hxMX^b{QP6j19@kl}iI z3b^Z2kOC^zsW7AP)T=Nh(8>lix1m+7pjy^Y6I6%ctXGkZ(@WN<P_PBn$%(~@MMa5~ z8qtP2MzNYY3Z=Gr1$uBn1CUU1er`c&Nost0QDRCasL^lhmY7qV3bL#?Bfm5!MWHCQ zq_ikc!9dScK}(?m)F4y<84uxW7%FHhm}o-kIglg3%^PTM5YkG^Db9zP0qRerq!wkC zC6=TXgX(UO05}9-4L60%G=+o&n4{ooZ9|GmQxg&p)>suJ7A58?R9J!AQ^h5q6a#Ih zSHx#0z-wu!x>AU`L~th+mSRe=D9nZ^1ovx-OHvD9YO@m*G{F4_SUW#6Jukl~HANHM zCYaOV;b{f&62t@G?f~4cV6&ha6yO@bZCa1i;^NH2ykbPl#0nA*h%OK)v~@v&m5`vI zs{jgja7ZQ=D<mo;B&6l!Czd220s^i&z5=cu8oZfhsS4$pB^e4ush}=V38=Xa3rmCn z&%uQX!vlLwcKr3tEyfT{?jku*g~eELi?Q?;WA-gUs4o%8>=tA4E#~C-3J_6xizPX} zv;ss{fXUL*Vo-$(ax)ZztEVDRf4fQmHLvI;n}e#PYv3yBgBAm?zy!kyB~!{KS}kCl zXm^oEX+iJ`#|<o7*j9S&5M1eZQPuh)kM)kk11d+<c4nP0+?jWg$LB=JnX(HJkteGz z@<d*UNw^Y|bRjkEVocgap0o>@xmPj^F7gy~Fy7!3oDec4Y(~nQv^g0UMb$3ysjpDH z$fvy`Wlh>eK9dgS8+^hbn-{PwVOzp+QC#C9pXLh3i+s8u+b{B&bui!H7w#$RU_qm} zWj-*laEd+<7MYMd!*~J9f|M057laKi@EAN07U}Q+*Hb9tC!mT0gg>tUj~n2xrjUza zNL2tTx{(WR5WkkWhN(ygTqQu_8B*=Q*{GEVO0@#7Lcr#*)G*huAXfxw%)tyb%;19l zA``BH9@M7E%uCEs&`8dQ6#1G8ATfnZ$e;o^WyA9gG;zZEt;4LehjpZM6axJ~<u$1E zHzKn1*HQ4Q0AWx84GJ^8WIv4xTO+N!0zFvY3e>g2$c^Cg6;YOfG99QYOjb}<z*-A{ z2LiOf!veO@n!y5V;hb8O3yxQ`650<@u0Ts@3@1@mZep!mFbh*~v6+)tT%w=>N^T&h zqP8+Xfe0T}fK>*`@ks73Qf6Ra&}2bs$%9(iMJgasR&X&`qzY=mYk&(xuUpJs@fF3O z<{T)H6~N`%Ev96@DnayO%`XB}uBAcBH3e9?RzA^sf#5{@i#*B;QkJA|U|g7ek;ia@ z%NCD|JT@JSH=t$74I%LvCUeXege(bP5_wTt@1l_Y2E~g)#v4+$q+b-W?Qp&UE^JKZ zm`||3z@vmz&cK^<$jxCV1_p+9hIYp349MfODNLCR9gH0eX-p}MEgYRlO<@<b@yI2N zeT=~jn#_L5@WKLWJgDpQ*@J<BVJg#fhD?SUhFG~;#u~;>W<;yI2B|;XiPRrP76%nQ zlbL$tgBeybtYidrV^T7cOXA~KvfN_QGbmCAMF6Ps0LMo$s1d86(9i%5{9jx)Ahn?M zXIG_#776k3i76@Z@p?8n`N@en#ddlKwFRKq(Pdy@_|d>{K_LQyP6#d#T;Q_AcZ1>; z6_X8xTdEEyZmGSf;sTMqpb!Br%!^DJ7#LPE6$yZxB@1DL>Pv9_Rt$=PgaokLZm~lh zP$h=lVfi3O7=aw|qk-Wrzw8D6NDzWK2V(7slrxzZ6e2DvL|jpb07>&lUf_rXyCfN8 z8LW^8^&G&}3T>hrl;*+F4RS9$x`pvaH>jqW%+w<i%m5CwA~R5sS%7?v5{X4t3=9ld zVlTHe2Yc)lgNy(r3vlfDTu=a^9f2sZcTvRxB7Q-^2OL@uCs>1=U<1+*3OuBk0$YY9 zroiGwAPpd&|A57m?*)EexcLyq0hJ?~7ZiLhD)?Mc@BvBl`(EJi1>231b3o%6;Ftm> z!gkP%4r4823R5jp3Ue)U2SXZT3JW+x!eW*IJww*AAZOQF))dwhwj8Eh=2|vJ1}26Y zwoV4ngbTPTXI;j|z_1#WHo&F@Gib8=RY}8=BV+~uR7%1-WL5Hh`FXmaS`1u;7lZ0> zl%ee^DQpTL!}TcM1Vu48#i)S_2*&9Q>7W9F7o1{{3W74m_1ra#6PbGWps7TYu}B6~ z{4y6=f(zYZNVW%sn1TX4*XLvwm*C3v#U({3=?1R05)_S~@*I?I1f4E`(G12FiW^L} z*j><ayrAVcK@mb<&~gOF9C+|glkpZ;JZNSGJdvcyQUuEOU{~G}gN@%B>mg4z6}f`E zzz%l$E!L9ElAP3AY&nTZsX2yF+UOP=sM0DngwjS}EybXLuLN-A0<B%x<Kw~p!ICt= z;-w%zC4dT%28J5~x*e=H1dTe_ZV2jv2&fk?2s+IOnG<<I(CMO}(-lD{kd){Yxem4) z9Htjg(G7mdj;a|d3s@JFtti`2wxjGKzuOglw+kF@;NVCGMFTh~F)%QI+zR4<&H=Y% znHXwNY8a%MK*kzI^!Y#Jx(G=n6Xs0e8b;K?LU3zT3b{4vT$Bp#lY*uda&jQ47bR8e zC}irT>M4LGIKY7pYYPM>=)jmk3E;`D;#6=C3X}n$6BeMzp!d)N*zxE?_TWK!4I>=| zLo98*{NfV5Km}z5(D*vY@zAkxcn25c3vi<lq%cT9S;4TvPytCHl4qf9I&h;ezBscg z)k?u7GdDG_I5R&F)-nT2DnMp-U?G@?(JX}Y*m0Qwkwr5k1<4R-pIO0CAt3=)WI?7r z6A~bOUQmRBJpqnYL<>=q38|M0D*ZH>Z!st56yM?kI~?qyTig%_fH|<qW=O@&0y48o z7}ZX2@YjKI8>j|rVECZGARydPJT+)a#EhyHRu|;VE{d985jEdyw8!E=^o5|<3odaN zt>dp)$6w%2xX7Pyg+Ji}M*^N)v;droYM2@%apVm~#Bd$zTzV~22`Dc@^ChV8U&Dl& zXJVKc7;2ennQK`}IHAfweMF`dW>6hn!;l54-@y`45hhUev4&+CD+9x7xLh!UCTpSw z@_-*C=P4j2mBDi@@Y+P7JR>tXLm{(RAvZHGGdD3up*$lM(kV;>HP;ou(E&?974d!v zAhoH5rHMJ9ag0QT^!&se3`KET(79VsqIS;D1JCv6RO%>XmMD~i=7}H)M<Ef-F|e`6 z{Gwbgc*ek-od%f->z$%a<7!mIX~p{~=z{uAnsG5D`2`Ar3JNHqC?*ey@k(&Q##62+ zXhWvc^gxjjU!0nnotc*op2z@2A-GD^sPKyitr$ry0rhziomI?&3Te`<&<~$9(x@b~ zK!V$0r4W)>l%86GEn&dp6{;!FN&&Q10$LoxQd%IfrA&TOR%&vILUMi)Xm~9@F9kI1 zTaphR2?Pa)E;Kk$QySb6ek&Ov1reyRsmTgqgQt2>r*&4c6@fDFE#}n9)LSf|GPej+ zu|oP7AoZG%&gd;pcp#v4S<ySCQXto1kE|+9w1N${(g~pAE)>#<)nVY_>#({jC_F`M z2Im~Ui-PJ`1l2p7?uscd@Z2DDLCoZ$n8_6}lTPjqrVghG%y;=^7cea_T*$J5WewYk z!j&8wf_69^aK6CragpES3ctq%4lHA1prRV&@y{~`pe)2v3NqKQtYKNk!oaW^)S3mC zkKi&;nmT15TIrWfOzD?Rm(mY18v|N$qKT~t%mx>M*=R)|Omw6afuL5JMg<uKABp82 z)COF|9w<e?OPs+`>=gxry4m1Dj|HjF15a&(XT(E5-6Lq3#sLdLh)TF3^de0VrJMo< zeihoH7StLFqyn_6uGk+^fN3%C@OD_<6%d-jHlbol?L`6AD*~z=j(3F>7D%iJydbQ9 zQCR<quzn{;2V;j}M-r$2V_XojBy5G_!iWum8;UOQTV3S0y25XDfx`;ijMHTI^MkA% zfKr-Fer}qKZbhI5lO`W%AS*91H#I)~7FT?HZhlH>4v5VY9}jBZKxNqD<5TjJ<Kv4I zK_Lbn<pPZ}6xo8fpaq{rKA>JOH+XelZfZ$Jeo9dwNDef<SQHInfySf2?g2MmA$105 za0)aDQ~Utz_XY+C{J^Bh%JG2#M7S`rv$`^VV89@S<XJ^OFrX4njG`bxR6>uDHHz^A z0}{!`$m$0cfs<_PtnOe-;G_@(o8Si~e%3_B4-6pkBQpb=U`sSqNJ)~_lko!s25Bb2 zYW;x$2LbUs$jgwBXD^CpU|_h#3SJQfu2_rQKmi4+Ss)8Hz-m#$?H7j)B#P{cKnprS zL!HIV3=9k(m>C%vKd>+{vV33w5o`>M!WS5XAm|2z!39+GfrXLL4HO3GBwGa&qxA;{ Q?BqwV_!lsVsRryn0BPKH(EtDd literal 0 HcmV?d00001 diff --git a/irlc/ex04/__pycache__/discrete_control_model.cpython-311.pyc b/irlc/ex04/__pycache__/discrete_control_model.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5c4477150f85d1c7b05871d85cef6908932f7aee GIT binary patch literal 17247 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 literal 0 HcmV?d00001 diff --git a/irlc/ex04/__pycache__/model_linear_quadratic.cpython-311.pyc b/irlc/ex04/__pycache__/model_linear_quadratic.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..421272b3d5c7dc0c25f34823cd4b2c1862685ce6 GIT binary patch literal 2638 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 AmjD0& literal 0 HcmV?d00001 diff --git a/irlc/ex04/__pycache__/model_pendulum.cpython-311.pyc b/irlc/ex04/__pycache__/model_pendulum.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fdff94ba6b6693e07f04de94d8bd44222e68cf01 GIT binary patch literal 12005 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 aT<S%xv@2X`7g*9h2r{rpU0{|3ryKw;Q}m4h literal 0 HcmV?d00001 diff --git a/irlc/ex04/control_environment.py b/irlc/ex04/control_environment.py new file mode 100644 index 0000000..ad44fe9 --- /dev/null +++ b/irlc/ex04/control_environment.py @@ -0,0 +1,171 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import gymnasium as gym +import numpy as np +from irlc.ex03.control_model import ensure_policy +from irlc.ex04.discrete_control_model import DiscreteControlModel + + +class ControlEnvironment(gym.Env): + """ + Helper class to convert a discretized model into an environment. + See the ``__init__`` function for how to create a new environment using this class. Once an environment has been + created, you can use it as any other gym environment: + + .. runblock:: pycon + + >>> from irlc.ex04.model_pendulum import GymSinCosPendulumEnvironment + >>> env = GymSinCosPendulumEnvironment(Tmax=4) # Specify we want it to run for a maximum of 4 seconds + >>> env.reset() # Reset both the time and state variable + >>> u = env.action_space.sample() + >>> next_state, cost, done, truncated, info = env.step(u) + >>> print("Current state: ", env.state) + >>> print("Current time", env.time) + + In this example, tell the environment to terminate after 4 seconds using ``Tmax`` (after which ``done=True``) + + .. Note:: + The ``step``-method will use the (nearly exact) RK4 method to integrate the enviorent over a timespan of ``dt``, + and **not** use the approximate ``model.f(x_k,u_k, k)``-method in the discrete environment which is based on + Euler discretization. + This is the correct behavior since we want the environment to reflect what happens in the real world and not + our apprixmation method. + """ + metadata = { + 'render.modes': ['human', 'rgb_array'], + 'video.frames_per_second': 30 + } + action_space = None + observation_space = None + + def __init__(self, discrete_model: DiscreteControlModel, Tmax=None, supersample_trajectory=False, render_mode=None): + """ + Creates a new instance. You should use this in conjunction with a discrete model to build a new class. An example: + + .. runblock:: pycon + + >>> from irlc.ex04.model_pendulum import DiscreteSinCosPendulumModel + >>> from irlc.ex04.control_environment import ControlEnvironment + >>> from gymnasium.spaces import Box + >>> import numpy as np + >>> class MyGymSinCosEnvironment(ControlEnvironment): + ... def __init__(self, Tmax=5): + ... discrete_model = DiscreteSinCosPendulumModel() + ... self.action_space = Box(low=-np.inf, high=np.inf, shape=(1,), dtype=np.float64) + ... self.observation_space = Box(low=-np.inf, high=np.inf, shape=(3,), dtype=np.float64) + ... super().__init__(discrete_model, Tmax=Tmax) + >>> + >>> env = MyGymSinCosEnvironment() + >>> env.reset() + >>> env.step(env.action_space.sample()) + + :param discrete_model: The discrete model the environment is based on + :param Tmax: Time in seconds until the environment terminates (``step`` returns ``done=True``) + :param supersample_trajectory: Used to create nicer (smooth) trajectories. Don't worry about it. + :param render_mode: If ``human`` the environment will be rendered (inherited from ``Env``) + """ + self.dt = discrete_model.dt # Discretization time + self.state = None # the current state + self.time = 0 # Current global time index + self.discrete_model = discrete_model + self.Tmax = Tmax + + # Try to guess action/observation spaces unless they are already defined. + if self.observation_space is None: + self.observation_space = gym.spaces.Box(-np.inf, np.inf, shape=(discrete_model.state_size,) ) + + if self.action_space is None: + u_bound = self.discrete_model.continuous_model.u_bound() + self.action_space = gym.spaces.Box(low=np.asarray(self.discrete_model.phi_u(u_bound.low)), + high=np.asarray(self.discrete_model.phi_u(u_bound.high)), + dtype=np.float64, + ) + self.state_labels = discrete_model.state_labels + self.action_labels = discrete_model.action_labels + self.supersample_trajectory = supersample_trajectory + self.render_mode = render_mode + + + def step(self, u): + """ + This works similar to the gym ``Env.step``-function. ``u`` is an action in the action-space, + and the environment will then assume we (constantly) apply the action ``u`` from the current time step, :math:`t_k`, until + the next time step :math:`t_{k+1} = t_k + \Delta`, where :math:`\Delta` is equal to ``env.model.dt``. + + During this period, the next state is computed using the relatively exact RK4 simulation, and the incurred cost will be + computed using Riemann integration. + + .. math:: + \int_{t_k}^{t_k+\Delta} c(x(t), u(t)) dt + + .. Note:: + The gym environment requires that we return a cost. The reward will therefore be equal to minus the (integral) of the cost function. + + In case the environment terminates, the reward will include the terminal cost. :math:`c_F`. + + :param u: The action we apply :math:`u` + :return: + - ``state`` - the state we arrive in + - ``reward`` - (minus) the total (integrated) cost incurred in this time period. + - ``done`` - ``True`` if the environment has finished, i.e. we reached ``env.Tmax``. + - ``truncated`` - ``True`` if the environment was forced to terminated prematurely. Assume it is ``False`` and ignore it. + - ``info`` - A dictionary of potential extra information. Includes ``info['time_seconds']``, which is the current time after the step function has completed. + """ + + def clip_action(self, u): + return np.clip(u, a_max=self.action_space.high, a_min=self.action_space.low) + + u = clip_action(self, u) + self.discrete_model.continuous_model._u_prev = u # for rendering. + if not ((self.action_space.low <= u).all() and (u <= self.action_space.high).all()): # u not in self.action_space: + raise Exception("Action", u, "not contained in action space", self.action_space) + # N=20 is a bit arbitrary; should probably be a parameter to the environment. + xx, uu, tt = self.discrete_model.simulate2(x0=self.state, policy=ensure_policy(u), t0=self.time, tF=self.time + self.discrete_model.dt, N=20) + self.state = xx[-1] + self.time = tt[-1] + cc = [self.discrete_model.cost.c(x, u, k=None) for x, u in zip(xx[:-1], uu[:-1])] + done = False + if self.time + self.discrete_model.dt/2 > self.Tmax: + cc[-1] += self.discrete_model.cost.cN(xx[-1]) + done = True + info = {'dt': self.discrete_model.dt, 'time_seconds': self.time} # Allow the train() function to figure out the simulation time step size + if self.supersample_trajectory: # This is only for nice visualizations. + from irlc.ex01.agent import Trajectory + traj = Trajectory(time=tt, state=xx.T, action=uu.T, reward=np.asarray(cc), env_info=[]) + info['supersample'] = traj # Supersample the trajectory + reward = -sum(cc) # To be compatible with openai gym we return the reward as -cost. + if not ( (self.observation_space.low <= self.state).all() and (self.state <= self.observation_space.high).all() ): #self.state not in self.observation_space: + print("> state", self.state) + print("> observation space", self.observation_space) + raise Exception("State no longer in observation space", self.state) + if self.render_mode == "human": # as in gym's carpole + self.render() + + return self.state, reward, done, False, info + + def reset(self): + """ + Reset the environment to the initial state. This will by default be `the value computed using `self.discrete_model.reset()``. + + :return: + - ``state`` - The initial state the environment has been reset to + - ``info`` - A dictionary with extra information, in this case that time begins at 0 seconds. + """ + self.state = self._get_initial_state() + self.time = 0 # Reset internal time (seconds) + if self.render_mode == "human": + self.render() + return self.state, {'time_seconds': self.time} + + def _get_initial_state(self) -> np.ndarray: + # This helper function returns an initial state. It will be used by the reset() function, and it is this function + # you should overwrite if you want to reset to a state which is not implied by the bounds. + if (self.discrete_model.continuous_model.x0_bound().low == self.discrete_model.continuous_model.x0_bound().high).all(): + return np.asarray(self.discrete_model.phi_x(self.discrete_model.continuous_model.x0_bound().low)) + else: + raise Exception("Since bounds do not agree I cannot return initial state.") + + def render(self): + return self.discrete_model.render(x=self.state, render_mode=self.render_mode) + + def close(self): + self.discrete_model.close() diff --git a/irlc/ex04/discrete_control_cost.py b/irlc/ex04/discrete_control_cost.py new file mode 100644 index 0000000..f9ad90d --- /dev/null +++ b/irlc/ex04/discrete_control_cost.py @@ -0,0 +1,195 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" +Quadratic cost functions +""" +import numpy as np +from irlc.ex03.control_cost import targ2matrices + +def nz(X,a,b=None): + return np.zeros((a,) if b is None else (a,b)) if X is None else X + +class DiscreteQRCost: #(DiscreteCost): + """ + This class represents the cost function for a discrete-time model. In the simulations, we are going to assume + that the cost function takes the form: + + .. math:: + \sum_{k=0}^{N-1} c_k(x_k, u_k) + c_N(x_N) + + + And this class will specifically implement the two functions :math:`c` and :math:`c_N`. + They will be assumed to have the quadratic form: + + .. math:: + c_k(x_k, u_k) & = \\frac{1}{2} x_k^T Q x_k + \\frac{1}{2} u_k^T R u_k + u^T_k H x_k + q^T x_k + r^T u_k + q_0, \\\\ + c_N(x_N) & = \\frac{1}{2} x_N^T Q_N x_N + q_N^T x_N + q_{0,N}. + + So what all of this boils down to is that the class just need to store a bunch of matrices and vectors. + + You can add and scale cost-functions + ********************************************************** + + A slightly smart thing about the cost functions are that you can add and scale them. The following provides an + example: + + .. runblock:: pycon + + >>> from irlc.ex04.discrete_control_cost import DiscreteQRCost + >>> import numpy as np + >>> cost1 = DiscreteQRCost(np.eye(2), np.zeros(1) ) # Set Q = I, R = 0 + >>> cost2 = DiscreteQRCost(np.ones((2,2)), np.zeros(1) ) # Set Q = 2x2 matrices of 1's, R = 0 + >>> print(cost1.Q) # Will be the identity matrix. + >>> cost = cost1 * 3 + cost2 * 2 + >>> print(cost.Q) # Will be 3 x I + 2 + + """ + def __init__(self, Q, R, H=None,q=None,r=None,qc=0, QN=None, qN=None,qcN=0): + n, d = Q.shape[0], R.shape[0] + self.QN, self.qN = nz(QN,n,n), nz(qN,n) + self.Q, self.q = nz(Q, n, n), nz(q, n) + self.R, self.H, self.r = nz(R, d, d), nz(H, d, n), nz(r, d) + self.qc, self.qcN = qc, qcN + self.flds_term = ['QN', 'qN', 'qcN'] + self.flds = ['Q', 'q', 'R', 'H', 'r', 'qc'] + self.flds_term + + def c(self, x, u, k=None, compute_gradients=False): + """ + Evaluate the (instantaneous) part of the function :math:`c_k(x_k,u_k)`. An example: + + .. runblock:: pycon + + >>> from irlc.ex04.discrete_control_cost import DiscreteQRCost + >>> import numpy as np + >>> cost = DiscreteQRCost(np.eye(2), np.eye(1)) # Set Q = I, R = 0 + >>> cost.c(x = np.asarray([1,2]), u=np.asarray([0]), compute_gradients=False) # should return 0.5 * x^T Q x = 0.5 * (1 + 4) + + The function can also return the derivates of the cost function if ``compute_derivates=True`` + + :param x: The state :math:`x_k` + :param u: The action :math:`u_k` + :param k: The time step :math:`k` (this will be ignored) + :param compute_gradients: if ``True`` the function will compute gradients and Hessians. + :return: + - ``c`` - The cost as a ``float`` + - ``c_x`` - The derivative with respect to :math:`x` + """ + c = 1/2 * (x @ self.Q @ x) + 1/2 * (u @ self.R @ u) + u @ self.H @ x + self.q @ x + self.r @ u + self.qc + c_x = 1/2 * (self.Q + self.Q.T) @ x + self.q + c_u = 1 / 2 * (self.R + self.R.T) @ u + self.r + c_ux = self.H + c_xx = self.Q + c_uu = self.R + if compute_gradients: + # this is useful for MPC when we apply an optimizer rather than LQR (iLQR) + return c, c_x, c_u, c_xx, c_ux, c_uu + else: + return c + + def cN(self, x, compute_gradients=False): + """ + Evaluate the terminal (constant) term in the cost function :math:`c_N(x_N)`. An example: + + .. runblock:: pycon + + >>> from irlc.ex04.discrete_control_cost import DiscreteQRCost + >>> import numpy as np + >>> cost = DiscreteQRCost(np.eye(2), np.zeros(1), QN=np.eye(2)) # Set Q = I, R = 0 + >>> c, Jx, Jxx = cost.cN(x=2*np.ones((2,)), compute_gradients=True) + >>> c # should return 0.5 * x_N^T * x_N = 0.5 * 8 + + :param x: Terminal state :math:`x_N` + :param compute_gradients: if ``True`` the function will compute gradients and Hessians of the cost function. + :return: The last (terminal) part of the cost-function :math:`c_N` + """ + J = 1/2 * (x @ self.QN @ x) + self.qN @ x + self.qcN + if compute_gradients: + J_x = 1 / 2 * (self.QN + self.QN.T) @ x + self.qN + return J, J_x, self.QN + else: + return J + + def __add__(self, c): + return DiscreteQRCost(**{k: self.__dict__[k] + c.__dict__[k] for k in self.flds}) + + def __mul__(self, c): + return DiscreteQRCost(**{k: self.__dict__[k] * c for k in self.flds}) + + def __str__(self): + title = "Discrete-time cost function" + label1 = "Non-zero terms in c_k(x_k, u_k)" + label2 = "Non-zero terms in c_N(x_N)" + terms1 = [s for s in self.flds if s not in self.flds_term] + terms2 = self.flds_term + from irlc.ex03.control_cost import _repr_cost + return _repr_cost(self, title, label1, label2, terms1, terms2) + + @classmethod + def zero(cls, state_size, action_size): + """ + Creates an all-zero cost function, i.e. all terms :math:`Q`, :math:`R` are set to zero. + + .. runblock:: pycon + + >>> from irlc.ex04.discrete_control_cost import DiscreteQRCost + >>> cost = DiscreteQRCost.zero(2, 1) + >>> cost.Q # 2x2 zero matrix + >>> cost.R # 1x1 zero matrix. + + :param state_size: Dimension of the state vector :math:`n` + :param action_size: Dimension of the action vector :math:`d` + :return: A ``DiscreteQRCost`` with all zero terms. + """ + return cls(Q=np.zeros((state_size, state_size)), R=np.zeros((action_size, action_size))) + + def goal_seeking_terminal_cost(self, xN_target, QN=None): + """ + Create a discrete cost function which is minimal when the final state :math:`x_N` is equal to a goal state :math:`x_N^*`. + Concretely, it will return a cost function of the form + + .. math:: + c_N(x_N) = \\frac{1}{2} (x^*_N - x_N)^\\top Q (x^*_N - x_N) + + .. runblock:: pycon + + >>> from irlc.ex04.discrete_control_cost import DiscreteQRCost + >>> import numpy as np + >>> cost = DiscreteQRCost.zero(2, 1) + >>> cost += cost.goal_seeking_terminal_cost(xN_target=np.ones((2,))) + >>> print(cost.qN) + >>> print(cost) + + :param xN_target: Target state :math:`x_N^*` + :param Q: Cost matrix :math:`Q` + :return: A ``DiscreteQRCost`` object corresponding to the goal-seeking cost function + """ + + if QN is None: + QN = np.eye(xN_target.size) + QN, qN, qcN = targ2matrices(xN_target, Q=QN) + return DiscreteQRCost(Q=QN*0, R=self.R*0, QN=QN, qN=qN, qcN=qcN) + + def goal_seeking_cost(self, x_target, Q=None): + """ + Create a discrete cost function which is minimal when the state :math:`x_k` is equal to a goal state :math:`x_k^*`. + Concretely, it will return a cost function of the form + + .. math:: + c_k(x_k, u_k) = \\frac{1}{2} (x^*_k - x_k)^\\top Q (x^*_k - x_k) + + .. runblock:: pycon + + >>> from irlc.ex04.discrete_control_cost import DiscreteQRCost + >>> import numpy as np + >>> cost = DiscreteQRCost.zero(2, 1) + >>> cost += cost.goal_seeking_cost(x_target=np.ones((2,))) + >>> print(cost.q) + >>> print(cost) + + :param x_target: Target state :math:`x_k^*` + :param Q: Cost matrix :math:`Q` + :return: A ``DiscreteQRCost`` object corresponding to the goal-seeking cost function + """ + if Q is None: + Q = np.eye(x_target.size) + Q, q, qc = targ2matrices(x_target, Q=Q) + return DiscreteQRCost(Q=Q, R=self.R*0, q=q, qc=qc) diff --git a/irlc/ex04/discrete_control_model.py b/irlc/ex04/discrete_control_model.py new file mode 100644 index 0000000..085a782 --- /dev/null +++ b/irlc/ex04/discrete_control_model.py @@ -0,0 +1,346 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +from irlc.ex03.control_model import ControlModel +import sympy as sym +import numpy as np +import sys +from irlc.ex03.control_model import ensure_policy +# Patch sympy with mapping to numpy functions. +sympy_modules_ = ['numpy', {'atan': np.arctan, 'atan2': np.arctan2, 'atanh': np.arctanh}, 'sympy'] + +class DiscreteControlModel: + """ + A discretized model. To create a model of this type, first specify a symbolic model, then pass it along to the constructor. + Since the symbolic model will specify the dynamics as a symbolic function, the discretized model can automatically discretize it + and create functions for computing derivatives. + + The class will also discretize the cost. Note that it is possible to specify coordinate transformations. + """ + state_labels = None + action_labels = None + + "This field represents the :class:`~irlc.ex04.continuous_time_model.ContinuousSymbolicModel` the discrete model is derived from." + continuous_model = None + + def __init__(self, model: ControlModel, dt: float, cost=None, discretization_method=None): + """ + Create the discretized model. + + :param model: The continuous-time model to discretize. + :param dt: Discretization timestep :math:`\Delta` + :param cost: If this parameter is not specified, the cost will be derived (discretized) automatically from ``model`` + :param discretization_method: Can be either ``'Euler'`` (default) or ``'ei'`` (exponential integration). The later will assume that the model is a linear. + """ + self.dt = dt + self.continuous_model = model + if discretization_method is None: + from irlc.ex04.model_linear_quadratic import LinearQuadraticModel + if isinstance(model, LinearQuadraticModel): + discretization_method = 'Ei' + else: + discretization_method = 'Euler' + self.discretization_method = discretization_method.lower() + + """ Initialize symbolic variables representing inputs and actions. """ + + uc = sym.symbols(f"uc:{model.action_size}") + xc = sym.symbols(f"xc:{model.state_size}") + + # xd, ud = self.sym_continious_xu2discrete_xu(xc, uc) + xd, ud = model.phi_x(xc), model.phi_u(uc) + + x = sym.symbols(f"x:{len(xd)}") + u = sym.symbols(f"u:{len(ud)}") + + """ x_next is a symbolic variable representing x_{k+1} = f_k(x_k, u_k) """ + x_next = self._f_discrete_sym(x, u, dt=dt) + """ compute the symbolic derivate of x_next wrt. z = (x,u): d x_{k+1}/dz """ + dy_dz = sym.Matrix([[sym.diff(f, zi) for zi in list(x) + list(u)] for f in x_next]) + """ Define (numpy) functions giving next state and the derivatives """ + self._f_z_np = sym.lambdify((tuple(x), tuple(u)), dy_dz, modules=sympy_modules_) + # Create a numpy function corresponding to the discretized model x_{k+1} = f_discrete(x_k, u_k) + self._f_np = sym.lambdify((tuple(x), tuple(u)), x_next, modules=sympy_modules_) + self._n = len(x) + self._d = len(u) + + # Make action/state transformation + # xc_, uc_ = self.sym_discrete_xu2continious_xu(x, u) + # self.discrete_states2continious_states = sym.lambdify( (x,), xc_, modules=sympy_modules_) # probably better to make these individual + # self.discrete_actions2continious_actions = sym.lambdify( (u,), uc_, modules=sympy_modules_) # probably better to make these individual + + self.phi_x_inv = sym.lambdify( (x,), model.phi_x_inv(x), modules=sympy_modules_) + self.phi_u_inv = sym.lambdify( (u,), model.phi_u_inv(u), modules=sympy_modules_) + + # xd, ud = self.sym_continious_xu2discrete_xu(xc, uc) + # self.continious_states2discrete_states = sym.lambdify((xc,), xd, modules=sympy_modules_) + # self.continious_actions2discrete_actions = sym.lambdify((uc,), ud, modules=sympy_modules_) + + self.phi_x = sym.lambdify((xc,), model.phi_x(xc), modules=sympy_modules_) + self.phi_u = sym.lambdify((uc,), model.phi_u(uc), modules=sympy_modules_) + + # set labels + if self.state_labels is None: + self.state_labels = self.continuous_model.state_labels + + if self.action_labels is None: + self.action_labels = self.continuous_model.action_labels + + if cost is None: + self.cost = model.get_cost().discretize(dt=dt) + else: + self.cost = cost + + @property + def state_size(self): + """ + The dimension of the state vector :math:`x`, i.e. :math:`n` + :return: Dimension of the state vector :math:`n` + """ + return self._n + + @property + def action_size(self): + """ + The dimension of the action vector :math:`u`, i.e. :math:`d` + :return: Dimension of the action vector :math:`d` + """ + return self._d + + def _f_discrete_sym(self, xs, us, dt): + """ + This is a helper function. It computes the discretized dynamics as a symbolic object: + + .. math:: + x_{k+1} = f_k(x_k, u_k, t_k) + + The parameters corresponds to states and actions and are lists of the form ``[x0, x1, ..]`` and ``[u0, u1, ..]`` + where each element is a symbolic expression. The function returns a list of the form ``[f0, f1, ..]`` where + each element is a symbolic expression corresponding to a coordinate of :math:`f_k`. + + :param xs: List of symbolic expressions corresponding to the coordinates of :math:`x_k` + :param us: List of symbolic expressions corresponding to the coordinates of :math:`x_u` + :param dt: A symbolic expressions corresponding to :math:`t_k` + :return: A list of symbolic expressions corresponding to the coordinates of :math:`f_k` + """ + # xc, uc = self.sym_discrete_xu2continious_xu(xs, us) + xc, uc = self.continuous_model.phi_x_inv(xs), self.continuous_model.phi_u_inv(us) + if self.discretization_method == 'euler': + xdot = self.continuous_model.sym_f(x=xc, u=uc) + xnext = [x_ + xdot_ * dt for x_, xdot_ in zip(xc, xdot)] + elif self.discretization_method == 'ei': # Assume the continuous model is linear; a bit hacky, but use exact Exponential integration in that case + A = self.continuous_model.A + B = self.continuous_model.B + d = self.continuous_model.d + """ These are the matrices of the continuous-time problem. + > dx/dt = Ax + Bu + d + and should be discretized using the exact integration technique (see (Her24, Subsection 13.1.3) and (Her24, Subsection 13.1.6)); + the precise formula you should implement is given in (Her24, eq. (13.19)) + + Remember the output matrix should be symbolic (see Euler integration for examples) but you can assume there are no variable transformations for simplicity. + """ + from scipy.linalg import expm, inv + """ + expm computes the matrix exponential: + > expm(A) = exp(A) + inv computes the inverse of a matrix inv(A) = A^{-1}. + """ + Ad = expm(A * dt) + n = Ad.shape[0] + d = d.reshape( (len(B),1) ) if d is not None else np.zeros( (n, 1) ) + Bud = B @ sym.Matrix(uc) + (sym.zeros(len(B),1) if d is None else d) + x_next = sym.Matrix(Ad) @ sym.Matrix(xc) + dt * phi1(A * dt) @ Bud + xnext = list(x_next) + else: + raise Exception("Unknown discreetization method", self.discretization_method) + # xnext, _ = self.sym_continious_xu2discrete_xu(xnext, uc) + xnext = self.continuous_model.phi_x(xnext) + return xnext + + def simulate2(self, x0, policy, t0, tF, N=1000): + policy3 = lambda x, t: self.phi_u_inv(ensure_policy(policy)(x, t)) + x, u, t = self.continuous_model.simulate(self.phi_x_inv(x0), policy3, t0, tF, N_steps=N, method='rk4') + # transform to discrete representations using phi. + xd = np.stack( [np.asarray(self.phi_x(x_)).reshape((-1,)) for x_ in x ] ) + ud = np.stack( [np.asarray(self.phi_u(u_)).reshape((-1,)) for u_ in u] ) + return xd, ud, t + + def f(self, x, u, k=0): + """ + This function implements the dynamics :math:`f_k(x_k, u_k)` of the model. They can be evaluated as: + + .. runblock:: pycon + + >>> from irlc.ex04.model_pendulum import DiscreteSinCosPendulumModel + >>> model = DiscreteSinCosPendulumModel() + >>> x = [0, 1, 0.4] + >>> u = [1] + >>> print(model.f(x,u) ) # Computes x_{k+1} = f_k(x_k, u_k) + + The model will by default be Euler discretized: + + .. math:: + + x_{k+1} = f_k(x_k, u_k) = x_k + \Delta f(x_k, u_k) + + except :python:`LinearQuadraticModel` which will be discretized using Exponential Integration by default. + + + :param x: The state as a numpy array + :param u: The action as a numpy array + :param k: The time step as an integer (currently this has no effect) + :return: The next state :math:`x_{x+1}` as a numpy array. + """ + fx = np.asarray( self._f_np(x, u) ) + return fx + # if compute_jacobian: + # assert False + # # J = self._f_z_np(x, u) + # return fx, J[:, :self.state_size], J[:, self.state_size:] + # else: + # return fx + + + def f_jacobian(self, x, u, k=0): + """Compute the Jacobians of the discretized dynamics. + + The function will compute the two Jacobian derives of the discrete dynamics :math:`f_k` with respect to :math:`x` and :math:`u`: + + .. math:: + J_x f_k(x,u), \quad J_u f_k(x, u) + + .. runblock:: pycon + + >>> from irlc.ex04.model_pendulum import DiscreteSinCosPendulumModel + >>> model = DiscreteSinCosPendulumModel() + >>> x = [0, 1, 0.4] + >>> u = [0] + >>> f, Jx, Ju = model.f(x,u) + >>> Jx, Ju = model.f_jacobian(x,u) + >>> print("Jacobian Jx is\\n", Jx) + >>> print("Jacobian Ju is\\n", Ju) + + + :param x: The state as a numpy array + :param u: The action as a numpy array + :param k: The time step as an integer (currently this has no effect) + :return: The two Jacobians computed wrt. :math:`x` and :math:`u`. + """ + J = self._f_z_np(x, u) + return J[:, :self.state_size], J[:, self.state_size:] + + + def render(self, x=None, render_mode="human"): + return self.continuous_model.render(x=self.phi_x_inv(x), render_mode=render_mode) + + # def sym_continious_xu2discrete_xu(self, x, u): + # """ + # This (optional) function handle coordinate transformations. + # ``x`` and ``u`` are lists of symbolic expressions (the state and action), and the function then computes and return + # the forward coordinate transformation (from continuous coordinates to discrete): + # + # .. math:: + # x_k & = \phi_x(x) \\\\ + # u_k & = \phi_u(u) + # + # :param x: Continuous state + # :param u: Continuous action + # :return: + # - ``x_k`` - Transformed (discrete) state + # - ``u_k`` - Transformed (discrete) action + # """ + # return x, u + + # def sym_discrete_xu2continious_xu(self, x_k, u_k): + # """ + # This (optional) function handle coordinate transformations. + # ``x_k`` and ``u_k`` are lists of symbolic expressions (the state and action), and the function then computes and return + # the **backward** coordinate transformation (from discrete coordinates to continuous coordinates): + # + # .. math:: + # x & = \phi^{-1}_x(x_k) \\\\ + # u & = \phi^{-1}_u(u_k) + # + # :param x_k: discrete state + # :param u_k: discrete action + # :return: + # - ``x`` - Transformed (Continuous) state + # - ``u`` - Transformed (Continuous) action + # """ + # return x_k, u_k + + def close(self): + self.continuous_model.close() + + def __str__(self): + """ + Return a string representation of the model. This is a potentially helpful way to summarize the content of the + model. You can use it as: + + .. runblock:: pycon + + >>> from irlc.ex04.model_pendulum import DiscreteSinCosPendulumModel + >>> model = DiscreteSinCosPendulumModel() + >>> print(model) + + :return: A string containing the details of the model. + """ + split = "-"*20 + s = [f"{self.__class__}"] + ['='*50] + s += [f"Dynamics (after discretization with Delta = {self.dt}):", split] + t = sym.symbols("t") + x = sym.symbols(f"x0:{self.state_size}") + u = sym.symbols(f"u0:{self.action_size}") + + # x = symv("x", self.state_size) + # u = symv("u", self.action_size) + # s += [f"f_k({x}, {u}) = {str(self.f_discrete_sym(x, u, self.dt))}", ''] + + f = self._f_discrete_sym(x, u, self.dt) + + # x = sym.symbols(f"x0:{self.state_size}") + # u = sym.symbols(f"u0:{self.action_size}") + from irlc.ex03.control_model import typeset_eq + + s += [typeset_eq(x, u, f)] + + # print(typeset_eq(x, u, f)) + + + s += ["Continuous-time dynamics:", split] + # xc = symv("x", self.continuous_model.state_size) + # uc = symv("u", self.continuous_model.action_size) + xc = sym.symbols(f"x:{self.continuous_model.state_size}") + uc = sym.symbols(f"u:{self.continuous_model.action_size}") + + s += [f"f_k({x}, {u}) = {str(self.continuous_model.sym_f(xc, uc))}", ''] + s += ["Variable transformations:", split] + # self.continious_states2discrete_states(xc) + xd, ud = self.continuous_model.phi_x(xc), self.continuous_model.phi_u(uc) + s += [f' * phi_x( x(t) ) -> x_k = {xd}'] + s += [f' * phi_u( u(t) ) -> u_k = {ud}', ''] + s += ["Cost:", split, str(self.cost)] + return "\n".join(s) + + +def phi1(A): + """ This is a helper functions which computes + .. math:: + A^{-1} (e^A - I) + + and importantly deals with potential numerical instability in the expression. + """ + from scipy.linalg import expm + from math import factorial + if np.linalg.cond(A) < 1 / sys.float_info.epsilon: + return np.linalg.solve(A, expm(A) - np.eye( len(A) ) ) + else: + C = np.zeros_like(A) + for k in range(1, 20): + dC = np.linalg.matrix_power(A, k - 1) / factorial(k) + C += dC + assert sum( np.abs(dC.flat)) < 1e-10 + return C diff --git a/irlc/ex04/discrete_kuramoto.py b/irlc/ex04/discrete_kuramoto.py new file mode 100644 index 0000000..50edc12 --- /dev/null +++ b/irlc/ex04/discrete_kuramoto.py @@ -0,0 +1,101 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex04.discrete_control_model import DiscreteControlModel +from irlc.ex04.control_environment import ControlEnvironment +import numpy as np +from irlc import train, Agent, savepdf +import matplotlib.pyplot as plt +from irlc.ex03.kuramoto import KuramotoModel, f + + +def fk(x,u): + """ Computes the discrete (Euler 1-step integrated) version of the Kuromoto update with discretization time dt=0.5,i.e. + + x_{k+1} = f_k(x,u). + + Look at dmodel.f for inspiration. As usual, use a debugger and experiment. Note you have to specify input arguments as lists, + and the function should return a numpy ndarray. + """ + dmodel = DiscreteControlModel(KuramotoModel(), dt=0.5) # this is how we discretize the Kuramoto model. + # TODO: 1 lines missing. + raise NotImplementedError("Compute Euler discretized dynamics here using the dmodel.") + return f_euler + +def dfk_dx(x,u): + """ Computes the derivative of the (Euler 1-step integrated) version of the Kuromoto update with discretization time dt=0.5, + i.e. if + + .. math:: + + x_{k+1} = f_k(x,u) + + this function should return + + .. math:: + + \frac{\partial f_k}{\partial x } + + (i.e. the Jacobian with respect to x) as a numpy matrix. + Look at dmodel.f for inspiration, and note it has an input argument that is relevant. + As usual, use a debugger and experiment. Note you have to specify input arguments as lists, + and the function should return a two-dimensional numpy ndarray. + + """ + dmodel = DiscreteControlModel(KuramotoModel(), dt=0.5) + # the function dmodel.f accept various parameters. Perhaps their name can give you an idea? + # TODO: 1 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + return f_euler_derivative + + +if __name__ == "__main__": + # Part 1: Making a model + cmodel = KuramotoModel() + print(cmodel) + # Computing f_k + dmodel = DiscreteControlModel(KuramotoModel(), dt=0.5) + print(dmodel) # This will print details about the discrete model. + + print("The Euler-discretized version, f_k(x,u) = x + Delta f(x,u), is") + print("f_k(x=0,u=0) =", fk([0], [0])) + print("f_k(x=1,u=0.3) =", fk([1], [0.3])) + + # Computing df_k / dx (The Jacobian). + print("The derivative of the Euler discretized version wrt. x is:") + print("df_k/dx(x=0,u=0) =", dfk_dx([0], [0])) + + # Part 2: The environment and simulation: + env = ControlEnvironment(dmodel, Tmax=20) # An environment that runs for 20 seconds. + u = 1.3 # Action to take in each time step. + + ts_step = [] # Current time (according to the environment, i.e. in increments of dt. + xs_step = [] # x_k using the env.step-function in the enviroment. + + x, _ = env.reset() # Get starting state. + ts_step.append(env.time) # env.time keeps track of the clock-time in the environment. + xs_step.append(x) # Initialize with first state + + # Use + # > next_x, cost, terminated, truncated, metadata = env.step([u]) + # to simulate a single step. + for _ in range(10000): + # TODO: 1 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + xs_step.append(next_x) + ts_step.append(env.time) # This is how you get the current time (in seconds) from the environment. + + if terminated: # Obtain 'terminated' from the step-function. It will be true when Tmax=20 seconds has passed. + break + + x0 = cmodel.x0_bound().low # Get the starting state x0. We exploit that the bound on x0 is an equality constraint. + xs_rk4, us_rk4, ts_rk4 = cmodel.simulate(x0, u_fun=u, t0=0, tF=20, N_steps=100) + + plt.plot(ts_rk4, xs_rk4, 'k-', label='RK4 (nearly exact)') + plt.plot(ts_step, xs_step, 'ro', label='RK4 (step-function in environment)') + + # Use the train-function to plot the result of simulating a random agent. + stats, trajectories = train(env, Agent(env), return_trajectory=True) + plt.plot(trajectories[0].time, trajectories[0].state, label='x(t) when using a random action sequence from agent') + plt.legend() + savepdf('kuramoto_step') + plt.show(block=False) + print("The total cost obtained using random actions", -stats[0]['Accumulated Reward']) diff --git a/irlc/ex04/locomotive.py b/irlc/ex04/locomotive.py new file mode 100644 index 0000000..10b0a14 --- /dev/null +++ b/irlc/ex04/locomotive.py @@ -0,0 +1,105 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex04.discrete_control_model import DiscreteControlModel +from irlc.ex04.control_environment import ControlEnvironment +from irlc.ex04.model_harmonic import HarmonicOscilatorModel +import numpy as np +from irlc.utils.graphics_util_pygame import UpgradedGraphicsUtil +from gymnasium.spaces import Box + +class LocomotiveModel(HarmonicOscilatorModel): + state_labels = ["x(t)", "v(t)"] + action_labels = ["u(t)"] + + + viewer = None + metadata = { + 'render.modes': ['human', 'rgb_array'], + 'video.frames_per_second': 20 + } + + def __init__(self, m=1., slope=0.0, target=0): + """ + Slope is the uphill slope of the train (in degrees). E.g. slope=15 makes it harder for the engine. + + :param m: + :param slope: + """ + self.target = target + self.slope = slope + super().__init__(m=m, k=0., drag=-np.sin(slope/360*2*np.pi) * m * 9.82) + + def x0_bound(self) -> Box: + return Box(np.asarray([-1, 0]), np.asarray([-1,0])) + + def u_bound(self) -> Box: + return Box(np.asarray([-100]), np.asarray([100])) # Min and Max engine power. + + def render(self, x, render_mode="human"): + """ Initialize a viewer and update the states. """ + if self.viewer is None: + self.viewer = LocomotiveViewer(self) + self.viewer.update(x, self.target) + import time + time.sleep(0.05) + return self.viewer.blit(render_mode=render_mode) + + def close(self): + if self.viewer is not None: + self.viewer.close() + +class DiscreteLocomotiveModel(DiscreteControlModel): + def __init__(self, *args, dt=0.1, **kwargs): + model = LocomotiveModel(*args, **kwargs) + super().__init__(model=model, dt=dt) + +class LocomotiveEnvironment(ControlEnvironment): + def __init__(self, *args, dt=0.1, Tmax=5, render_mode=None, **kwargs): + model = DiscreteLocomotiveModel(*args, dt=dt, **kwargs) + # self.dt = model.dt + super().__init__(discrete_model=model, Tmax=Tmax, render_mode=render_mode) + + +class LocomotiveViewer(UpgradedGraphicsUtil): + def __init__(self, train): + self.train = train + width = 1100 + self.scale = width / 4 + self.dw = self.scale * 0.1 + super().__init__(screen_width=width, xmin=-width / 2, xmax=width / 2, ymin=-width / 5, ymax=width / 5, title='Locomotive environment') + from irlc.utils.graphics_util_pygame import Object + self.locomotive = Object("locomotive.png", image_width=90, graphics=self) + + def render(self): + # fugly rendering code. + dw = self.dw + scale = self.scale + train = self.train + red = (200, 40, 40) + from irlc.utils.graphics_util_pygame import rotate_around + ptrack = [(-2 * scale, -dw / 2*0), + (-2 * scale, dw / 2), + (2 * scale, dw / 2), + (2 * scale, -dw / 2*0)] + ptrack.append( ptrack[-1]) + ptrack = rotate_around(ptrack,(0,0), -self.train.slope) + self.draw_background(background_color=(255, 255, 255)) + self.polygon("asdf", coords=ptrack, fillColor=(int(.7 * 255),) * 3, filled=True) + self.locomotive.surf.get_height() + self.locomotive.rotate(self.train.slope) + p0 = (0,0) + self.locomotive.move_center_to_xy( *rotate_around( (self.scale * self.x[0], -self.locomotive.surf.get_height()//2), p0, -self.train.slope)) + self.locomotive.blit(self.surf) + xx = 0*self.scale * self.x[0] + triangle = [(train.target * scale - dw / 2+ xx, dw/2), (train.target * scale + xx, -0*dw / 2), + (train.target * scale + dw / 2 + xx, dw/2)] + triangle = rotate_around(triangle, p0, -self.train.slope) + ddw = dw/2 + xx = self.scale * self.x[0] + trainloc = [(xx- ddw / 2, -ddw / 2), ( xx, -0 * ddw / 2), (xx + ddw / 2, -ddw / 2)] + trainloc = rotate_around(trainloc, p0, -self.train.slope) + self.trg = self.polygon("", coords=trainloc, fillColor=red, filled=True) + self.trg = self.polygon("", coords=triangle, fillColor=red, filled=True) + + def update(self, x, xstar): + self.x = x #*self.scale + self.xstar = xstar diff --git a/irlc/ex04/model_harmonic.py b/irlc/ex04/model_harmonic.py new file mode 100644 index 0000000..198e529 --- /dev/null +++ b/irlc/ex04/model_harmonic.py @@ -0,0 +1,113 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex04.model_linear_quadratic import LinearQuadraticModel +from irlc.ex04.discrete_control_model import DiscreteControlModel +from irlc.ex04.control_environment import ControlEnvironment +import numpy as np +from irlc.utils.graphics_util_pygame import UpgradedGraphicsUtil + +""" +Simulate a Harmonic oscillator governed by equations: + +d^2 x1 / dt^2 = -k/m x1 + u(x1, t) + +where x1 is the position and u is our externally applied force (the control) +k is the spring constant and m is the mass. See: + +https://en.wikipedia.org/wiki/Simple_harmonic_motion#Dynamics + +for more details. +In the code, we will re-write the equations as: + +dx/dt = f(x, u), u = u_fun(x, t) + +where x = [x1,x2] is now a vector and f is a function of x and the current control. +here, x1 is the position (same as x in the first equation) and x2 is the velocity. + +The function should return ts, xs, C + +where ts is the N time points t_0, ..., t_{N-1}, xs is a corresponding list [ ..., [x_1(t_k),x_2(t_k)], ...] and C is the cost. +""" + +class HarmonicOscilatorModel(LinearQuadraticModel): + metadata = { + 'render.modes': ['human', 'rgb_array'], + 'video.frames_per_second': 20 + } + """ + See: https://books.google.dk/books?id=tXZDAAAAQBAJ&pg=PA147&lpg=PA147&dq=boeing+747+flight+0.322+model+longitudinal+flight&source=bl&ots=L2RpjCAWiZ&sig=ACfU3U2m0JsiHmUorwyq5REcOj2nlxZkuA&hl=en&sa=X&ved=2ahUKEwir7L3i6o3qAhWpl4sKHQV6CdcQ6AEwAHoECAoQAQ#v=onepage&q=boeing%20747%20flight%200.322%20model%20longitudinal%20flight&f=false + """ + def __init__(self, k=1., m=1., drag=0.0, Q=None, R=None): + self.k = k + self.m = m + A = [[0, 1], + [-k/m, 0]] + + B = [[0], [1/m]] + d = [[0], [drag/m]] + + A, B, d = np.asarray(A), np.asarray(B), np.asarray(d) + if Q is None: + Q = np.eye(2) + if R is None: + R = np.eye(1) + self.viewer = None + super().__init__(A=A, B=B, Q=Q, R=R, d=d) + + def render(self, x, render_mode="human"): + """ Render the environment. You don't have to understand this code. """ + if self.viewer is None: + self.viewer = HarmonicViewer(xstar=0) # target: x=0. + self.viewer.update(x) + import time + time.sleep(0.05) + return self.viewer.blit(render_mode=render_mode) + + def close(self): + if self.viewer is not None: + self.viewer.close() + + +class DiscreteHarmonicOscilatorModel(DiscreteControlModel): + def __init__(self, dt=0.1, discretization_method=None, **kwargs): + model = HarmonicOscilatorModel(**kwargs) + super().__init__(model=model, dt=dt, discretization_method=discretization_method) + + +class HarmonicOscilatorEnvironment(ControlEnvironment): + def __init__(self, Tmax=80, supersample_trajectory=False, render_mode=None, **kwargs): + model = DiscreteHarmonicOscilatorModel(**kwargs) + self.dt = model.dt + super().__init__(discrete_model=model, Tmax=Tmax, render_mode=render_mode, supersample_trajectory=supersample_trajectory) + + def _get_initial_state(self) -> np.ndarray: + return np.asarray([1, 0]) + +class HarmonicViewer(UpgradedGraphicsUtil): + def __init__(self, xstar = 0): + self.xstar = xstar + width = 1100 + self.scale = width / 6 + self.dw = self.scale * 0.1 + super().__init__(screen_width=width, xmin=-width / 2, xmax=width / 2, ymin=-width / 5, ymax=width / 5, title='Harmonic Osscilator') + + def render(self): + self.draw_background(background_color=(255, 255, 255)) + dw = self.dw + self.rectangle(color=(0,0,0), x=-dw//2, y=-dw//2, width=dw, height=dw) + xx = np.linspace(0, 1) + y = np.sin(xx * 2 * np.pi * 5) * 0.1*self.scale * 0.5 + + for i in range(len(xx) - 1): + self.line("asfasf", here=(xx[i] * self.x[0] * self.scale, y[i]), there=(xx[i + 1] * self.x[0] * self.scale, y[i+1]), + color=(0,0,0), width=2) + self.circle("asdf", pos=( self.x[0] * self.scale, 0), r=dw, fillColor=(0,0,0)) + self.circle("asdf", pos=( self.x[0] * self.scale, 0), r=dw*0.9, fillColor=(int(.7 * 255),) * 3) + + def update(self, x): + self.x = x + +if __name__ == "__main__": + from irlc import train + env = HarmonicOscilatorEnvironment(render_mode='human') + # train(env, NullAgent(env), num_episodes=1, max_steps=200) + # env.close() diff --git a/irlc/ex04/model_linear_quadratic.py b/irlc/ex04/model_linear_quadratic.py new file mode 100644 index 0000000..912c2bb --- /dev/null +++ b/irlc/ex04/model_linear_quadratic.py @@ -0,0 +1,29 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import sympy as sym +from irlc.ex03.control_model import ControlModel +from irlc.ex03.control_cost import SymbolicQRCost +from gymnasium.spaces import Box + +class LinearQuadraticModel(ControlModel): + """ + Implements a model with update equations + + dx/dt = Ax + Bx + d + Cost = integral_0^{t_F} (1/2 x^T Q x + 1/2 u^T R u + q' x + qc) dt + """ + def __init__(self, A, B, Q, R, q=None, qc=None, d=None): + self._cost = SymbolicQRCost(R=R, Q=Q, q=q, qc=qc) + self.A, self.B, self.d = A, B, d + super().__init__() + + def sym_f(self, x, u, t=None): + xp = sym.Matrix(self.A) * sym.Matrix(x) + sym.Matrix(self.B) * sym.Matrix(u) + if self.d is not None: + xp += sym.Matrix(self.d) + return [x for xr in xp.tolist() for x in xr] + + def x0_bound(self) -> Box: + return Box(0, 0, shape=(self.state_size,)) + + def get_cost(self): + return self._cost diff --git a/irlc/ex04/model_pendulum.py b/irlc/ex04/model_pendulum.py new file mode 100644 index 0000000..2777afc --- /dev/null +++ b/irlc/ex04/model_pendulum.py @@ -0,0 +1,164 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import sympy as sym +from irlc.ex03.control_model import ControlModel +from irlc.ex03.control_cost import SymbolicQRCost +from irlc.ex04.discrete_control_model import DiscreteControlModel +import gymnasium as gym +from gymnasium.spaces.box import Box +from irlc.ex04.control_environment import ControlEnvironment +import numpy as np + +""" +SEE: https://github.com/openai/gym/blob/master/gym/envs/classic_control/cartpole.py +https://github.com/openai/gym/blob/master/gym/envs/classic_control/pendulum.py +""" +class PendulumModel(ControlModel): + state_labels= [r"$\theta$", r"$\frac{d \theta}{dt}$"] + action_labels = ['Torque $u$'] + x_upright, x_down = np.asarray([0.0, 0.0]), np.asarray([np.pi, 0.0]) + + def __init__(self, l=1., m=.8, friction=0.0, max_torque=6.0, transform_coordinates=False): + self.l, self.m, self.max_torque = l, m, max_torque + assert not transform_coordinates + super().__init__() + self.friction = friction + self._u_prev = None # For rendering + self.cp_render = {} + assert friction == 0.0 + + def sym_f(self, x, u, t=None): + l, m = self.l, self.m + g = 9.82 + theta_dot = x[1] # Parameterization: x = [theta, theta'] + theta_dot_dot = g/l * sym.sin(x[0]) + 1/(m*l**2) * u[0] + return [theta_dot, theta_dot_dot] + + def get_cost(self) -> SymbolicQRCost: + return SymbolicQRCost(R=np.ones((1, 1)), Q=np.eye(2)) + + def tF_bound(self) -> Box: + return Box(0.5, 4, shape=(1,)) + + def t0_bound(self) -> Box: + return Box(0, 0, shape=(1,)) + + def x_bound(self) -> Box: + return Box(np.asarray( [-2 * np.pi, -np.inf]), np.asarray( [2 * np.pi, np.inf]) ) + + def u_bound(self) -> Box: + return Box(np.asarray([-self.max_torque]), np.asarray([self.max_torque])) + + def x0_bound(self) -> Box: + return Box(np.asarray( [np.pi, 0] ), np.asarray( [np.pi, 0])) + + def xF_bound(self) -> Box: + return Box(np.asarray([0, 0]), np.asarray([0, 0])) + + # def close(self): + # if self.cp_render is not None: + # self.cp_render.close() + + # def render(self, x, render_mode="human"): + # if self.cp_render is None: + # self.cp_render = gym.make("Pendulum-v1", render_mode=render_mode) # environment only used for rendering + # self.cp_render.max_time_limit = 10000 + # self.cp_render.reset() + # + # self.cp_render.unwrapped.last_u = float(self._u_prev) if self._u_prev is not None else self._u_prev + # self.cp_render.unwrapped.state = np.asarray(x) + # return self.cp_render.render() + + + def close(self): + for r in self.cp_render.values(): + r.close() + + def render(self, x, render_mode="human"): + if render_mode not in self.cp_render: # is None or self.cp_render[1] != render_mode: + # if self.cp_render is not None: + # self.cp_render.close() + + self.cp_render[render_mode] = gym.make("Pendulum-v1", render_mode=render_mode) # environment only used for rendering. Change to v1 in gym 0.26. + # self.cp_render[render_mode].render_mode = render_mode + self.cp_render[render_mode].max_time_limit = 10000 + self.cp_render[render_mode].reset() + self.cp_render[render_mode].unwrapped.state = np.asarray(x) # environment is wrapped + self.cp_render[render_mode].unwrapped.last_u = self._u_prev[0] if self._u_prev is not None else None + return self.cp_render[render_mode].render() + +class SinCosPendulumModel(PendulumModel): + def phi_x(self, x): + theta, theta_dot = x[0], x[1] + return [sym.sin(theta), sym.cos(theta), theta_dot] + + def phi_x_inv(self, x): + sin_theta, cos_theta, theta_dot = x[0], x[1], x[2] + theta = sym.atan2(sin_theta, cos_theta) # Obtain angle theta from sin(theta),cos(theta) + return [theta, theta_dot] + + def phi_u(self, u): + return [sym.atanh(u[0] / self.max_torque)] + + def phi_u_inv(self, u): + return [sym.tanh(u[0]) * self.max_torque] + + def u_bound(self) -> Box: + return Box(np.asarray([-np.inf]), np.asarray([np.inf])) + +def _pendulum_cost(model): + from irlc.ex04.discrete_control_cost import DiscreteQRCost + Q = np.eye(model.state_size) + Q[0, 1] = Q[1, 0] = model.l + Q[0, 0] = Q[1, 1] = model.l ** 2 + Q[2, 2] = 0.0 + R = np.array([[0.1]]) * 10 + c0 = DiscreteQRCost(Q=np.zeros((model.state_size,model.state_size)), R=R) + c0 = c0 + c0.goal_seeking_cost(Q=Q, x_target=model.x_upright) + c0 = c0 + c0.goal_seeking_terminal_cost(xN_target=model.x_upright) * 1000 + return c0 * 2 + + +class DiscreteSinCosPendulumModel(DiscreteControlModel): + state_labels = ['$\sin(\\theta)$', '$\cos(\\theta)$', '$\\dot{\\theta}$'] # Check if this escape character works. + action_labels = ['Torque $u$'] + + def __init__(self, dt=0.02, cost=None, **kwargs): + model = SinCosPendulumModel(**kwargs) + self.max_torque = model.max_torque + # self.transform_actions = transform_actions + super().__init__(model=model, dt=dt, cost=cost) + self.x_upright = np.asarray(self.phi_x(model.x_upright)) + self.l = model.l # Pendulum length + if cost is None: + cost = _pendulum_cost(self) + self.cost = cost + + +class ThetaPendulumEnvironment(ControlEnvironment): + def __init__(self, Tmax=5, render_mode=None): + dt = 0.02 + discrete_model = DiscreteControlModel(PendulumModel(), dt=dt) + super().__init__(discrete_model, Tmax=Tmax, render_mode=render_mode) + +class GymSinCosPendulumEnvironment(ControlEnvironment): + def __init__(self, *args, Tmax=5, supersample_trajectory=False, render_mode=None, **kwargs): + discrete_model = DiscreteSinCosPendulumModel(*args, **kwargs) + self.action_space = Box(low=-np.inf, high=np.inf, shape=(discrete_model.action_size,), dtype=float) + self.observation_space = Box(low=-np.inf, high=np.inf, shape=(discrete_model.state_size,), dtype=float) + super().__init__(discrete_model, Tmax=Tmax, supersample_trajectory=supersample_trajectory, render_mode=render_mode) + +if __name__ == "__main__": + model = SinCosPendulumModel(l=1, m=1) + print(str(model)) + print(f"Pendulum with l={model.l}, m={model.m}") + x = [1,2] + u = [0] # Input state/action. + # x_dot = ... + # TODO: 1 lines missing. + raise NotImplementedError("Compute dx/dt = f(x, u, t=0) here using the model-class defined above") + # x_dot_numpy = ... + # TODO: 1 lines missing. + raise NotImplementedError("Compute dx/dt = f(x, u, t=0) here using numpy-expressions you write manually.") + + print(f"Using model-class: dx/dt = f(x, u, t) = {x_dot}") + print(f"Using numpy: dx/dt = f(x, u, t) = {x_dot_numpy}") diff --git a/irlc/ex04/pid.py b/irlc/ex04/pid.py new file mode 100644 index 0000000..440228e --- /dev/null +++ b/irlc/ex04/pid.py @@ -0,0 +1,60 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +from irlc import savepdf +import numpy as np +import matplotlib.pyplot as plt +from irlc.ex04.locomotive import LocomotiveEnvironment + +class PID: + def __init__(self, dt, Kp, Ki, Kd, target): + self.Kp = Kp + self.Ki = Ki + self.Kd = Kd + self.dt = dt # discretization time + self.target = target # target, in our case just a number. + self.I = 0 # Internal variables for integral/derivative terms; use these or define your own. + self.e_prior = 0 # Previous value of the error. Used in the derivative term. Remember to update it in the pi-function. + + def reset(self): + self.I = 0 + self.e_prior = 0 + + def pi(self, x): + """ + Policy for the PID class. x is always a scalar (float) and the output u is a scalar. + Should implement (Her24, Algorithm 19) + + :param x: Input state (float) + :return: Action to take (float) + """ + # TODO: 6 lines missing. + raise NotImplementedError("Compute u here.") + return u + + +def pid_explicit(): + env = LocomotiveEnvironment(m=70, slope=0, dt=0.05, Tmax=15) + pid = PID(dt=0.05, Kp=40, Kd=0, Ki=0, target=0) + # Compute the first action using PID control: + print(f"When x_0 = 1 then the first action is u_0 = {pid.pi(x=1)} (and should be u_0 = -40.0)") + x0, _ = env.reset() + x = [x0] + for _ in range(200): # Simulate for 200 steps, i.e. 0.05 * 200 seconds. + x_cur = x[-1] # x is the last state [position, velocity]. Note that you only need to pass position to your PID controller. + # TODO: 1 lines missing. + raise NotImplementedError("Compute action here using the pid class.") + u = np.clip(u, -100, 100) # clip actions. + xp_, reward, done, truncated, _ = env.step(u) + x.append(xp_) + + x = np.stack(x) + plt.plot(x[:,0], 'k-', label="PID state trajectory") + savepdf("pid_basic") + plt.show(block=False) + +if __name__ == "__main__": + pid_explicit() diff --git a/irlc/ex04/pid_car.py b/irlc/ex04/pid_car.py new file mode 100644 index 0000000..84627fd --- /dev/null +++ b/irlc/ex04/pid_car.py @@ -0,0 +1,61 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc import savepdf +from irlc.ex04.pid import PID +from irlc import Agent +from irlc.ex04.control_environment import ControlEnvironment + +class PIDCarAgent(Agent): + def __init__(self, env: ControlEnvironment, v_target=0.5, use_both_x5_x3=True): + """ + Define two pid controllers: One for the angle, the other for the velocity. + + self.pid_angle = PID(dt=self.discrete_model.dt, Kp=x, ...) + self.pid_velocity = PID(dt=self.discrete_model.dt, Kp=z, ...) + + I did not use Kd/Ki, however you need to think a little about the targets. + """ + # self.pid_angle = ... + ## TODO: Half of each line of code in the following 2 lines have been replaced by garbage. Make it work and remove the error. + #---------------------------------------------------------------------------------------------------------------------------- + # self.pid_angle = PID(dt=env.discrete_m?????????????????????????????????????? + # self.pid_velocity = PID(dt=env.discrete_mod??????????????????????????????????????????? + raise NotImplementedError("Define PID controllers here.") + self.use_both_x5_x3 = use_both_x5_x3 # Using both x3+x5 seems to make it a little easier to get a quick lap time, but you can just use x5 to begin with. + super().__init__(env) + + def pi(self, x, k, info=None): + """ + Call PID controller. The steering angle controller should initially just be based on + x[5] (distance to the centerline), but you can later experiment with a linear combination of x5 and x3 as input. + + Hints: + - To control the velocity, you should use x[0], the velocity of the car in the direction of the car. + - Remember to start out with a low value of v_target, then tune the controller and look at the animation. + - You can access the pid controllers as self.pid_angle(x_input) + - Remember the function must return a 2d numpy ndarray. + """ + + # TODO: 2 lines missing. + raise NotImplementedError("Compute action here. No clipping necesary.") + return u + + +if __name__ == "__main__": + from irlc.ex01.agent import train + from irlc.car.car_model import CarEnvironment + import matplotlib.pyplot as plt + + env = CarEnvironment(noise_scale=0,Tmax=30, max_laps=1, render_mode='human') + agent = PIDCarAgent(env, v_target=1, use_both_x5_x3=True) # I recommend lowering v_target to make the problem simpler. + + stats, trajectories = train(env, agent, num_episodes=1, return_trajectory=True) + env.close() + t = trajectories[0] + plt.clf() + plt.plot(t.state[:,0], label="velocity" ) + plt.plot(t.state[:,5], label="s (distance to center)" ) + plt.xlabel("Time/seconds") + plt.legend() + savepdf("pid_car_agent") + plt.show() diff --git a/irlc/ex04/pid_locomotive_agent.py b/irlc/ex04/pid_locomotive_agent.py new file mode 100644 index 0000000..bb2083c --- /dev/null +++ b/irlc/ex04/pid_locomotive_agent.py @@ -0,0 +1,70 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +import matplotlib.pyplot as plt +from irlc.ex04.locomotive import LocomotiveEnvironment +from irlc.ex04.pid_car import PID +from irlc import Agent, train +from irlc import savepdf +from irlc.ex04.control_environment import ControlEnvironment + +class PIDLocomotiveAgent(Agent): + def __init__(self, env: ControlEnvironment, dt, Kp=1.0, Ki=0.0, Kd=0.0, target=0): + # self.pid = PID(dt=...) + # TODO: 1 lines missing. + raise NotImplementedError("Make a pid instance here.") + super().__init__(env) + + def pi(self, x, k, info=None): + # TODO: 1 lines missing. + raise NotImplementedError("Get the correct action using self.pid.pi(...). Same as previous exercise") + u = np.clip(u, self.env.action_space.low[0], self.env.action_space.high[0]) # Clip actions to ensure u is in the action space + return np.asarray([u]) # Must return actions as numpy ndarrays. + +def fixplt(): + plt.legend() + plt.grid('on') + plt.box(False) + # plt.ylim([-dd, dd]) + plt.xlabel('Time/seconds') + plt.ylabel('$x(t)$') + +def pid_locomotive(): + dt = .08 + m = 70 + Tmax=15 + + env = LocomotiveEnvironment(m=m, slope=0, dt=dt, Tmax=Tmax, render_mode='human') + Kp = 40 + agent = PIDLocomotiveAgent(env, dt=dt, Kp=Kp, Ki=0, Kd=0, target=0) + stats, traj = train(env, agent, return_trajectory=True) + plt.plot(traj[0].time, traj[0].state[:, 0], '-', label=f"$K_p={40}$") + fixplt() + savepdf('pid_locomotive_Kp') + plt.show() + + # Now include a derivative term: + Kp = 40 + for Kd in [10, 50, 100]: + agent = PIDLocomotiveAgent(env, dt=dt, Kp=Kp, Ki=0, Kd=Kd, target=0) + stats, traj = train(env, agent, return_trajectory=True) + plt.plot(traj[0].time, traj[0].state[:, 0], '-', label=f"$K_p={Kp}, K_d={Kd}$") + fixplt() + savepdf('pid_locomotive_Kd') + plt.show() + env.close() + + # Derivative test: Include a slope term. For fun, let's also change the target. + env = LocomotiveEnvironment(m=m, slope=2, dt=dt, Tmax=20, target=1, render_mode='human') + for Ki in [0, 10]: + agent = PIDLocomotiveAgent(env, dt=dt, Kp=40, Ki=Ki, Kd=50, target=1) + stats, traj = train(env, agent, return_trajectory=True) + x = traj[0].state + tt = traj[0].time + plt.plot(tt, x[:, 0], '-', label=f"$K_p={Kp}, K_i={Ki}, K_d={Kd}$") + fixplt() + savepdf('pid_locomotive_Ki') + plt.show() + env.close() + +if __name__ == '__main__': + pid_locomotive() diff --git a/irlc/ex04/pid_lunar.py b/irlc/ex04/pid_lunar.py new file mode 100644 index 0000000..7af982d --- /dev/null +++ b/irlc/ex04/pid_lunar.py @@ -0,0 +1,136 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" +For information about the Apollo 11 lunar lander see: +https://eli40.com/lander/02-debrief/ + +For code for the Gym LunarLander environment see: + +https://github.com/openai/gym/blob/master/gym/envs/box2d/lunar_lander.py + +This particular controller is inspired by: + +https://github.com/wfleshman/PID_Control/blob/master/pid.py + +However, I had better success with different parameters for the PID controller. +""" +import gymnasium as gym +import matplotlib.pyplot as plt +import numpy as np +from irlc import train +from irlc.ex04.pid import PID +from irlc import Agent +from irlc.ex04 import speech +from irlc import savepdf +from gymnasium.envs.box2d.lunar_lander import FPS + +class ApolloLunarAgent(Agent): + def __init__(self, env, dt, Kp_altitude=18, Kd_altitude=13, Kp_angle=-18, Kd_angle=-18): + """ Set up PID parameters for the two controllers (one controlling the altitude, another the angle of the lander) """ + self.Kp_altitude = Kp_altitude + self.Kd_altitude = Kd_altitude + self.Kp_angle = Kp_angle + self.Kd_angle = Kd_angle + self.error_angle = [] + self.error_altitude = [] + self.dt = dt + super().__init__(env) + + def pi(self, x, k, info=None): + """ From documentation: https://github.com/openai/gym/blob/master/gym/envs/box2d/lunar_lander.py + x (list): The state. Attributes: + x[0] is the horizontal coordinate + x[1] is the vertical coordinate + x[2] is the horizontal speed + x[3] is the vertical speed + x[4] is the angle + x[5] is the angular speed + x[6] 1 if first leg has contact, else 0 + x[7] 1 if second leg has contact, else 0 + + Your implementation should follow what happens in: + + https://github.com/wfleshman/PID_Control/blob/master/pid.py + + I.e. you have to compute the target for the angle and altitude as done in the code (and explained in the documentation. + Note the target for the PID controllers is 0. + """ + if k == 0: + """ At time t=0 we set up the two PID controllers. You don't have to change these lines. """ + self.pid_alt = PID(dt=self.dt, Kp=self.Kp_altitude, Kd=self.Kd_altitude, Ki=0, target=0) + self.pid_ang = PID(dt=self.dt, Kp=self.Kp_angle, Kd=self.Kd_angle, Ki=0, target=0) + + """ Compute the PID control signals using two calls to the PID controllers such as: """ + # alt_adj = self.pid_alt.pi(...) + # ang_adj = self.pid_ang.pi(...) + """ You need to specify the inputs to the controllers. Look at the code in the link above and implement a comparable control rule. + The inputs you give to the controller will be simple functions of the coordinates of x, i.e. x[0], x[1], and so on. + """ + # TODO: 2 lines missing. + raise NotImplementedError("Compute the alt_adj and ang_adj as in the gitlab repo (see code comment).") + + u = np.array([alt_adj, ang_adj]) + u = np.clip(u, -1, +1) + + # If the legs are on the ground we made it, kill engines + if (x[6] or x[7]): + u[:] = 0 + # Record stats. + self.error_altitude.append(self.pid_alt.e_prior) + self.error_angle.append(self.pid_ang.e_prior) + return u + +def get_lunar_lander(env): + dt = 1/FPS # Get time discretization from environment. + spars = ['Kp_altitude', 'Kd_altitude', 'Kp_angle', 'Kd_angle'] + def x2pars(x2): + return {spars[i]: x2[i] for i in range(4)} + x_opt = np.asarray([52.23302414, 34.55938593, -80.68722976, -38.04571655]) + agent = ApolloLunarAgent(env, dt=dt, **x2pars(x_opt)) + return agent + +def lunar_single_mission(): + env = gym.make('LunarLanderContinuous-v2', render_mode='human') + env._max_episode_steps = 1000 # We don't want it to time out. + + agent = get_lunar_lander(env) + stats, traj = train(env, agent, return_trajectory=True, num_episodes=1) + env.close() + if traj[0].reward[-1] == 100: + print("A small step for man, a giant leap for mankind!") + elif traj[0].reward[-1] == -100: + print(speech) + else: + print("Environment timed out and the lunar module is just kind of floating around") + + states = np.stack(traj[0].state) + plt.plot(states[:, 0], label='x') + plt.plot(states[:, 1], label='y') + plt.plot(states[:, 2], label='vx') + plt.plot(states[:, 3], label='vy') + plt.plot(states[:, 4], label='theta') + plt.plot(states[:, 5], label='vtheta') + plt.legend() + plt.grid() + plt.ylim(-1.1, 1.1) + plt.title('PID Control') + plt.ylabel('Value') + plt.xlabel('Steps') + savepdf("pid_lunar_trajectory") + plt.show(block=False) + +def lunar_average_performance(): + env = gym.make('LunarLanderContinuous-v2', render_mode=None) # Set render_mode = 'human' to see what it does. + env._max_episode_steps = 1000 # To avoid the environment timing out after just 200 steps + + agent = get_lunar_lander(env) + stats, traj = train(env, agent, return_trajectory=True, num_episodes=20) + env.close() + + n_won = sum([np.sum(t.reward[-1] == 100) for t in traj]) + n_lost = sum([np.sum(t.reward[-1] == -100) for t in traj]) + print("Successfull landings: ", n_won, "of 20") + print("Unsuccessfull landings: ", n_lost, "of 20") + +if __name__ == "__main__": + lunar_single_mission() + lunar_average_performance() diff --git a/irlc/ex04/pid_pendulum.py b/irlc/ex04/pid_pendulum.py new file mode 100644 index 0000000..82e865b --- /dev/null +++ b/irlc/ex04/pid_pendulum.py @@ -0,0 +1,74 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +import matplotlib.pyplot as plt +np.random.seed(32) +from irlc import Agent, savepdf +from irlc.ex04.pid import PID +from irlc.ex01.agent import train + +class PIDPendulumAgent(Agent): + def __init__(self, env, dt, Kp=1.0, Ki=0.0, Kd=0.0, target_angle=0): + """ Balance_to_x0 = True implies the agent should also try to get the cartpole to x=0 (i.e. center). + If balance_to_x0 = False implies it is good enough for the agent to get the cart upright. + """ + self.pid = PID(dt=dt, Kp = Kp, Ki=Ki, Kd=Kd, target=target_angle) + super().__init__(env) + + def pi(self, x, k, info=None): + """ Compute action using self.pid. YCartpoleou have to think about the inputs as they will depend on + whether balance_to_x0 is true or not. """ + # TODO: 2 lines missing. + raise NotImplementedError("Implement function body") + return u + + +def get_offbalance_pendulum(waiting_steps=30): + from irlc.ex04.model_pendulum import ThetaPendulumEnvironment + env = ThetaPendulumEnvironment(Tmax=10, render_mode='human') + + env.reset() + env.state[0] = 0 + env.state[1] = 0 + for _ in range(waiting_steps): # Simulate the environment for 30 steps to get things out of balance. + env.step(1) + return env + +def plot_trajectory(trajectory): + t = trajectory + plt.plot(t.time, t.state[:,0], label="Angle $\\theta$" ) + plt.plot(t.time, t.state[:,1], label="Angular speed $\\cdot{\\theta}$") + plt.xlabel("Time") + plt.legend() + + +target_angle = np.pi/6 # The target angle for the second task in the pendulum problem. +if __name__ == "__main__": + """ + First task: Bring the balance upright from a slightly off-center position. + For this task, we do not care about the x-position, only the angle theta which should be 0 (upright) + """ + env = get_offbalance_pendulum(30) + ## TODO: Half of each line of code in the following 1 lines have been replaced by garbage. Make it work and remove the error. + #---------------------------------------------------------------------------------------------------------------------------- + # agent = PIDPendulumAgent(env, dt=env.?????????????????????????????????????? + raise NotImplementedError("Define your agent here (including parameters)") + _, trajectories = train(env, agent, num_episodes=1, return_trajectory=True, reset=False) # Note reset=False to maintain initial conditions. + env.close() + plot_trajectory(trajectories[0]) + savepdf("pid_pendulumA") + plt.show() + + """ + Second task: We will now try to get to a target angle of target_angle=np.pi/6. + """ + env = get_offbalance_pendulum(30) + ## TODO: Half of each line of code in the following 1 lines have been replaced by garbage. Make it work and remove the error. + #---------------------------------------------------------------------------------------------------------------------------- + # agent = PIDPendulumAgent(env, dt=env.dt,????????????????????????????????????????? + raise NotImplementedError("Define your agent here (include the target_angle parameter to the agent!)") + _, trajectories = train(env, agent, num_episodes=1, return_trajectory=True, reset=False) # Note reset=False to maintain initial conditions. + env.close() + plot_trajectory(trajectories[0]) + print("Final state is x(t_F) =", trajectories[0].state[-1], f"goal [{target_angle:.2f}, 0]") + savepdf("pid_pendulumB") + plt.show() diff --git a/irlc/ex05/__init__.py b/irlc/ex05/__init__.py new file mode 100644 index 0000000..23f7751 --- /dev/null +++ b/irlc/ex05/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 5.""" diff --git a/irlc/ex05/__pycache__/__init__.cpython-311.pyc b/irlc/ex05/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1b9bf1d95f19da97a2af54288ce60d0d9100ed11 GIT binary patch literal 232 zcmZ3^%ge>Uz`$UU-<$T5fq~&Mhy%lnP{wDFlIaX73{eazjKK_=OjU*<8JWcjDVas7 z$tC$kl?uuEc_oRNdBqAP8L0}X6{$tZnZ>Ea3TgR83gxM(*$Sq5ewvK8*yH0<@{{A^ zS2BDCnf%K}KO;XkRllS(BURreKe;qFHLs*tKQlK+-@wSk)S$SeGzB73l#{HVT47+S zA0MBYmst`YuUAm{i^C>2KczG$)vkz*fq?<!)?z^h28IvJjEsyA7|bugP!S6Q0|Nlw C$Uz7I literal 0 HcmV?d00001 diff --git a/irlc/ex05/__pycache__/direct.cpython-311.pyc b/irlc/ex05/__pycache__/direct.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76f0a425273c0209db1eb6913f557682f56014ee GIT binary patch literal 14745 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 Rz|aSF1{SFc%#z>~0st|%gq;8Y literal 0 HcmV?d00001 diff --git a/irlc/ex05/direct.py b/irlc/ex05/direct.py new file mode 100644 index 0000000..b38379a --- /dev/null +++ b/irlc/ex05/direct.py @@ -0,0 +1,370 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +from irlc.ex03.control_model import ControlModel +import numpy as np +import sympy as sym +import sys +from scipy.optimize import Bounds, minimize +from scipy.interpolate import interp1d +from irlc.ex03.control_model import symv +from irlc.ex04.discrete_control_model import sympy_modules_ +from irlc import Timer +from tqdm import tqdm + +def bounds2fun(t0 : float, tF : float, bounds : Bounds): + """ + Given start and end times [t0, tF] and a scipy Bounds object with upper/lower bounds on some variable x, i.e. so that: + + > bounds.lb <= x <= bounds.ub + + this function returns a new function f such that f(t0) equals bounds.lb and f(tF) = bounds.ub and + f(t) interpolates between the uppower/lower bounds linearly, i.e. + + > bounds.lb <= f(t) <= bounds.ub + + The function will return a numpy ``ndarray``. + """ + return interp1d(np.asarray([t0, tF]), np.stack([np.reshape(b, (-1,)) for b in bounds], axis=1)) + +def direct_solver(model, options): + """ + Main direct solver method, see (Her24, Algorithm 21). Given a list of options of length S, the solver performers collocation + using the settings found in the dictionary options[i], and use the result of options[i] to initialize collocation on options[i+1]. + + This iterative refinement scheme is required to obtain good overall solutions. + + :param model: A ContinuousTimeModel instance + :param options: An options-structure. This is a list of dictionaries of options for each collocation iteration + :return: A list of solutions, one for each collocation step. The last will be the 'best' solution (highest N) + + """ + if isinstance(options, dict): + options = [options] + solutions = [] # re-use result of current solutions to initialize next with a higher value of N + for i, opt in enumerate(options): + optimizer_options = opt['optimizer_options'] # to be passed along to minimize() + if i == 0 or "guess" in opt: + # No solutions-function is given. Re-calculate by linearly interpreting bounds (see (Her24, Subsection 15.3.4)) + guess = opt['guess'] + guess['u'] = bounds2fun(guess['t0'],guess['tF'],guess['u']) if isinstance(guess['u'], list) else guess['u'] + guess['x'] = bounds2fun(guess['t0'],guess['tF'],guess['x']) if isinstance(guess['x'], list) else guess['x'] + else: + """ For an iterative solver ((Her24, Subsection 15.3.4)), initialize the guess at iteration i to be the solution at iteration i-1. + The guess consists of a guess for t0, tF (just numbers) as well as x, u (state/action trajectories), + the later two being functions. The format of the guess is just a dictionary (you have seen several examples) + i.e. + + > guess = {'t0': (number), 'tF': (number), 'x': (function), 'u': (function)} + + and you can get the solution by using solutions[i - 1]['fun']. (insert a breakpoint and check the fields) + """ + # TODO: 1 lines missing. + raise NotImplementedError("Define guess = {'t0': ..., ...} here.") + N = opt['N'] + print(f"{i}> Collocation starting with grid-size N={N}") + sol = collocate(model, N=N, optimizer_options=optimizer_options, guess=guess, verbose=opt.get('verbose', False)) + solutions.append(sol) + + print("Was collocation success full at each iteration?") + for i, s in enumerate(solutions): + print(f"{i}> Success? {s['solver']['success']}") + return solutions + +def collocate(model : ControlModel, N=25, optimizer_options=None, guess : dict = None, verbose=True): + r""" + Performs collocation by discretizing the model using a grid-size of N and optimize to find the optimal solution. + The 'model' should be a ControlModel instance, optimizer_options contains options for the optimizer, and guess + is a dictionary used to initialize the optimizer containing keys:: + + guess = {'t0': Start time (float), + 'tF': Terminal time (float), + 'x': A *function* which takes time as input and return a guess for x(t), + 'u': A *function* which takes time as input and return a guess for u(t), + } + + So for instance + + .. code-block:: python + + guess['x'](0.5) + + will return the state :math:`\mathbf x(0.5)` as a numpy ndarray. + + The overall structure of the optimization procedure is as follows: + + #. Define the following variables. They will all be lists: + - ``z``: Variables to be optimized over. Each element ``z[k]`` is a symbolic variable. This will allow us to compute derivatives. + - ``z0``: A list of numbers representing the initial guess. Computed using 'guess' (above) + - ``z_lb``, ``z_ub``: Lists of numbers representting the upper/lower bounds on z. Use bound-methods in :class:`irlc.ex03.control_model.ControlModel` to get these. + #. Create a symbolic expression representing the cost-function J + This is defined using the symbolic variables similar to the toy-problem we saw last week. This allows us to compute derivatives of the cost + #. Create *symbolic* expressions representing all constraints + The lists ``Iineq`` and ``Ieq`` contains *lists* of constraints. The solver will ensure that for any i:: + + Ieq[i] == 0 + + and:: + + Iineq[i] <= 0 + + This allows us to just specify each element in 'eqC' and 'ineqC' as a single symbolic expression. Once more, we use symbolic expressions so + derivatives can be computed automatically. The most important constraints are in 'eqC', as these must include the collocation-constraints (see algorithm in notes) + #. Compile all symbolic expressions into a format useful for the optimizer + The optimizer accepts numpy functions, so we turn all symbolic expressions and derivatives into numpy (similar to the example last week). + It is then fed into the optimizer and, fingers crossed, the optimizer spits out a value 'z*', which represents the optimal values. + + #. Unpack z: + The value 'z*' then has to be unpacked and turned into function u*(t) and x*(t) (as in the notes). These functions can then be put into the + solution-dictionary and used to initialize the next guess (or assuming we terminate, these are simply our solution). + + :param model: A :class:`irlc.ex03.control_model.ControlModel` instance + :param N: The number of collocation knot points :math:`N` + :param optimizer_options: Options for the scipy optimizer. You can ignore this. + :param guess: A dictionary containing the initial guess. See the online documentation. + :param verbose: Whether to print out extra details during the run. Useful only for debugging. + :return: A dictionary containing the solution. It is compatible with the :python:`guess` datastructure . + """ + timer = Timer(start=True) + cost = model.get_cost() + t0, tF = sym.symbols("t0"), sym.symbols("tF") + ts = t0 + np.linspace(0, 1, N) * (tF-t0) # N points linearly spaced between [t0, tF] TODO: Convert this to a list. + xs, us = [], [] + for i in range(N): + xs.append(list(symv("x_%i_" % i, model.state_size))) + us.append(list(symv("u_%i_" % i, model.action_size))) + + ''' (1) Construct guess z0, all simple bounds [z_lb, z_ub] for the problem and collect all symbolic variables as z ''' + # sb = model.simple_bounds() # get simple inequality boundaries in problem (v_lb <= v <= v_ub) + z = [] # list of all *symbolic* variables in the problem + # These lists contain the guess z0 and lower/upper bounds (list-of-numbers): z_lb[k] <= z0[k] <= z_ub[k]. + # They should be lists of *numbers*. + z0, z_lb, z_ub = [], [], [] + ts_eval = sym.lambdify((t0, tF), ts.tolist(), modules='numpy') + for k in range(N): + x_low = list(model.x0_bound().low if k == 0 else (model.xF_bound().low if k == N - 1 else model.x_bound().low)) + x_high = list(model.x0_bound().high if k == 0 else (model.xF_bound().high if k == N - 1 else model.x_bound().high)) + u_low, u_high = list(model.u_bound().low), list(model.u_bound().high) + + tk = ts_eval(guess['t0'], guess['tF'])[k] + """ In these lines, update z, z0, z_lb, and z_ub with values corresponding to xs[k], us[k]. + The values are all lists; i.e. z[j] (symbolic) has guess z0[j] (float) and bounds z_lb[j], z_ub[j] (floats) """ + # TODO: 2 lines missing. + raise NotImplementedError("Updates for x_k, u_k") + + """ Update z, z0, z_lb, and z_ub with bounds/guesses corresponding to t0 and tF (same format as above). """ + # z, z0, z_lb, z_ub = z+[t0], z0+[guess['t0']], z_lb+[model.bounds['t0_low']], z_ub+[model.bounds['t0_high']] + # TODO: 2 lines missing. + raise NotImplementedError("Updates for t0, tF") + assert len(z) == len(z0) == len(z_lb) == len(z_ub) + if verbose: + print(f"z={z}\nz0={np.asarray(z0).round(1).tolist()}\nz_lb={np.asarray(z_lb).round(1).tolist()}\nz_ub={np.asarray(z_ub).round(1).tolist()}") + print(">>> Trapezoid collocation of problem") # problem in this section + fs, cs = [], [] # lists of symbolic variables corresponding to f_k and c_k, see (Her24, Algorithm 20). + for k in range(N): + """ Update both fs and cs; these are lists of symbolic expressions such that fs[k] corresponds to f_k and cs[k] to c_k in the slides. + Use the functions env.sym_f and env.sym_c """ + # fs.append( symbolic variable corresponding to f_k; see env.sym_f). similarly update cs.append(env.sym_c(...) ). + ## TODO: Half of each line of code in the following 2 lines have been replaced by garbage. Make it work and remove the error. + #---------------------------------------------------------------------------------------------------------------------------- + # fs.append(model.sym_f(x=????????????????????????? + # cs.append(cost.sym_c(x=x???????????????????????? + raise NotImplementedError("Compute f[k] and c[k] here (see slides) and add them to above lists") + + J = cost.sym_cf(x0=xs[0], t0=t0, xF=xs[-1], tF=tF) # terminal cost; you need to update this variable with all the cs[k]'s. + Ieq, Iineq = [], [] # all symbolic equality/inequality constraints are stored in these lists + for k in range(N - 1): + # Update cost function ((Her24, eq. (15.15))). Use the above defined symbolic expressions ts, hk and cs. + # TODO: 2 lines missing. + raise NotImplementedError("Update J here") + # Set up equality constraints. See (Her24, eq. (15.18)). + for j in range(model.state_size): + """Create all collocation equality-constraints here and add them to Ieq. I.e. + + xs[k+1] - xs[k] = 0.5 h_k (f_{k+1} + f_k) + + Note we have to create these coordinate-wise which is why we loop over j. + """ + ## TODO: Half of each line of code in the following 1 lines have been replaced by garbage. Make it work and remove the error. + #---------------------------------------------------------------------------------------------------------------------------- + # Ieq.append((xs[k+1][j] - xs[k][j])?????????????????????????????????? + raise NotImplementedError("Update collocation constraints here") + """ + To solve problems with dynamical path constriants like Brachiostone, update Iineq here to contain the + inequality constraint model.sym_h(...) <= 0. For the other problems this can simply be left blank """ + if hasattr(model, 'sym_h'): + # TODO: 1 lines missing. + raise NotImplementedError("Update symbolic path-dependent constraint h(x,u,t)<=0 here") + + print(">>> Creating objective and derivative...") + timer.tic("Building symbolic objective") + J_fun = sym.lambdify([z], J, modules='numpy') # create a python function from symbolic expression + # To compute the Jacobian, you can use sym.derive_by_array(J, z) to get the correct symbolic expression, then use sym.lamdify (as above) to get a numpy function. + ## TODO: Half of each line of code in the following 1 lines have been replaced by garbage. Make it work and remove the error. + #---------------------------------------------------------------------------------------------------------------------------- + # J_jac = sym.lambdify([z], sym.deri??????????????????????????????????? + raise NotImplementedError("Jacobian of J. See how this is computed for equality/inequality constratins for help.") + if verbose: + print(f"{Ieq=}\n{Iineq=}\n{J=}") + timer.toc() + print(">>> Differentiating equality constraints..."), timer.tic("Differentiating equality constraints") + constraints = [] + for eq in tqdm(Ieq, file=sys.stdout): # don't write to error output. + constraints.append(constraint2dict(eq, z, type='eq')) + timer.toc() + print(">>> Differentiating inequality constraints"), timer.tic("Differentiating inequality constraints") + constraints += [constraint2dict(ineq, z, type='ineq') for ineq in Iineq] + timer.toc() + + c_viol = sum(abs(np.minimum(z_ub - np.asarray(z0), 0))) + sum(abs(np.maximum(np.asarray(z_lb) - np.asarray(z0), 0))) + if c_viol > 0: # check if: z_lb <= z0 <= z_ub. Violations only serious if large + print(f">>> Warning! Constraint violations found of total magnitude: {c_viol:4} before optimization") + + print(">>> Running optimizer..."), timer.tic("Optimizing") + z_B = Bounds(z_lb, z_ub) + res = minimize(J_fun, x0=z0, method='SLSQP', jac=J_jac, constraints=constraints, options=optimizer_options, bounds=z_B) + # Compute value of equality constraints to check violations + timer.toc() + eqC_fun = sym.lambdify([z], Ieq) + eqC_val_ = eqC_fun(res.x) + eqC_val = np.zeros((N - 1, model.state_size)) + + x_res = np.zeros((N, model.state_size)) + u_res = np.zeros((N, model.action_size)) + t0_res = res.x[-2] + tF_res = res.x[-1] + + m = model.state_size + model.action_size + for k in range(N): + dx = res.x[k * m:(k + 1) * m] + if k < N - 1: + eqC_val[k, :] = eqC_val_[k * model.state_size:(k + 1) * model.state_size] + x_res[k, :] = dx[:model.state_size] + u_res[k, :] = dx[model.state_size:] + + # Generate solution structure + ts_numpy = ts_eval(t0_res, tF_res) + # make linear interpolation similar to (Her24, eq. (15.22)) + ufun = interp1d(ts_numpy, np.transpose(u_res), kind='linear') + # Evaluate function values fk points (useful for debugging but not much else): + f_eval = sym.lambdify((t0, tF, xs, us), fs) + fs_numpy = f_eval(t0_res, tF_res, x_res, u_res) + fs_numpy = np.asarray(fs_numpy) + + r""" Interpolate to get x(t) as described in (Her24, eq. (15.26)). The function should accept both lists and numbers for t.""" + x_fun = lambda t_new: np.stack([trapezoid_interpolant(ts_numpy, np.transpose(x_res), np.transpose(fs_numpy), t_new=t) for t in np.reshape(np.asarray(t_new), (-1,))], axis=1) + + if verbose: + newt = np.linspace(ts_numpy[0], ts_numpy[-1], len(ts_numpy)-1) + print( x_fun(newt) ) + + sol = { + 'grid': {'x': x_res, 'u': u_res, 'ts': ts_numpy, 'fs': fs_numpy}, + 'fun': {'x': x_fun, 'u': ufun, 'tF': tF_res, 't0': t0_res}, + 'solver': res, + 'eqC_val': eqC_val, + 'inputs': {'z': z, 'z0': z0, 'z_lb': z_lb, 'z_ub': z_ub}, + } + print(timer.display()) + return sol + +def trapezoid_interpolant(ts : list, xs : list, fs : list, t_new=None): + r""" + This function implements (Her24, eq. (15.26)) to evaluate :math:`\mathbf{x}(t)` at a point :math:`t =` ``t_new``. + + The other inputs represent the output of the direct optimization procedure. I.e., ``ts`` is a list of length + :math:`N+1` corresponding to :math:`t_k`, ``xs`` is a list of :math:`\mathbf x_k`, and ``fs`` is a list corresponding + to :math:`\mathbf f_k`. To implement the method, you should first determine which :math:`k` the new time point ``t_new`` + corresponds to, i.e. where :math:`t_k \leq t_\text{new} < t_{k+1}`. + + + :param ts: List of time points ``[.., t_k, ..]`` + :param xs: List of numpy ndarrays ``[.., x_k, ...]`` + :param fs: List of numpy ndarrays ``[.., f_k, ...]`` + :param t_new: The time point we should evaluate the function in. + :return: The state evaluated at time ``t_new``, i.e. :math:`\mathbf x(t_\text{new})`. + """ + # TODO: 3 lines missing. + raise NotImplementedError("Determine the time index k here so that ts[k] <= t_new < ts[k+1].") + + ts = np.asarray(ts) + tau = t_new - ts[k] + hk = ts[k + 1] - ts[k] + r""" + Make interpolation here. Should be a numpy array of dimensions [xs.shape[0], len(I)] + What the code does is that for each t in ts, we work out which knot-point interval the code falls within. I.e. + insert a breakpoint and make sure you understand what e.g. the code tau = t_new - ts[I] does. + + Given this information, we can recover the relevant (evaluated) knot-points as for instance + fs[:,I] and those at the next time step as fs[:,I]. With this information, the problem is simply an + implementation of (Her24, eq. (15.26)), i.e. + + > x_interp = xs[:,I] + tau * fs[:,I] + (...) + + """ + ## TODO: Half of each line of code in the following 1 lines have been replaced by garbage. Make it work and remove the error. + #---------------------------------------------------------------------------------------------------------------------------- + # x_interp = xs[:, k] + tau * fs[:, k] + (tau ???????????????????????????????????????????? + raise NotImplementedError("Insert your solution and remove this error.") + return x_interp + + +def constraint2dict(symb, all_vars, type='eq'): + ''' Turn constraints into a dict with type, fun, and jacobian field. ''' + if type == "ineq": symb = -1 * symb # To agree with sign convention in optimizer + + f = sym.lambdify([all_vars], symb, modules=sympy_modules_) + # np.atan = np.arctan # Monkeypatch numpy to contain atan. Passing "numpy" does not seem to fix this. + jac = sym.lambdify([all_vars], sym.derive_by_array(symb, all_vars), modules=sympy_modules_) + eq_cons = {'type': type, + 'fun': f, + 'jac': jac} + return eq_cons + +def get_opts(N, ftol=1e-6, guess=None, verbose=False): # helper function to instantiate options objet. + d = {'N': N, + 'optimizer_options': {'maxiter': 1000, + 'ftol': ftol, + 'iprint': 1, + 'disp': True, + 'eps': 1.5e-8}, # 'eps': 1.4901161193847656e-08, + 'verbose': verbose} + if guess: + d['guess'] = guess + return d + +def guess(model : ControlModel): + def mfin(z): + return [z_ if np.isfinite(z_) else 0 for z_ in z] + xL = mfin(model.x0_bound().low) + xU = mfin(model.xF_bound().high) + tF = 10 if not np.isfinite(model.tF_bound().high[0]) else model.tF_bound().high[0] + gs = {'t0': 0, + 'tF': tF, + 'x': [xL, xU], + 'u': [mfin(model.u_bound().low), mfin(model.u_bound().high)]} + return gs + + +def run_direct_small_problem(): + from irlc.ex04.model_pendulum import SinCosPendulumModel + model = SinCosPendulumModel() + """ + Test out implementation on a very small grid. The overall solution will be fairly bad, + but we can print out the various symbolic expressions + + We use verbose=True to get debug-information. + """ + print("Solving with a small grid, N=5") + options = [get_opts(N=5, ftol=1e-3, guess=guess(model), verbose=True)] + solutions = direct_solver(model, options) + return model, solutions + + +if __name__ == "__main__": + from irlc.ex05.direct_plot import plot_solutions + model, solutions = run_direct_small_problem() + plot_solutions(model, solutions, animate=False, pdf="direct_pendulum_small") diff --git a/irlc/ex05/direct_agent.py b/irlc/ex05/direct_agent.py new file mode 100644 index 0000000..e8cbca2 --- /dev/null +++ b/irlc/ex05/direct_agent.py @@ -0,0 +1,77 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex05.direct import direct_solver, get_opts, guess +from irlc.ex04.model_pendulum import SinCosPendulumModel +from irlc.ex04.discrete_control_model import DiscreteControlModel +from irlc.ex04.control_environment import ControlEnvironment +from irlc import train +from irlc import Agent +import numpy as np +import matplotlib.pyplot as plt +from irlc import savepdf +from irlc.ex05.direct_plot import plot_solutions + +class DirectAgent(Agent): + def __init__(self, env: ControlEnvironment, options=None): + cmod = env.discrete_model.continuous_model # Get the continuous-time model for planning + + if options is None: + options = [get_opts(N=10, ftol=1e-3, guess=guess(cmod), verbose=False), + get_opts(N=60, ftol=1e-6, verbose=False) + ] + solutions = direct_solver(cmod, options) + + # The next 3 lines are for plotting purposes. You can ignore them. + self.x_grid = np.stack([env.discrete_model.phi_x(x) for x in solutions[-1]['grid']['x']]) + self.u_grid = np.stack([env.discrete_model.phi_u(u) for u in solutions[-1]['grid']['u']]) + self.ts_grid = np.stack(solutions[-1]['grid']['ts']) + # set self.ufun equal to the solution (policy) function. You can get it by looking at `solutions` computed above + self.solutions = solutions + # TODO: 1 lines missing. + raise NotImplementedError("set self.ufun = solutions[....][somethingsomething] (insert a breakpoint, it should be self-explanatory).") + super().__init__(env) + + def pi(self, x, k, info=None): + """ Return the action given x and t. As a hint, you will only use t, and self.ufun computed a few lines above""" + # TODO: 7 lines missing. + raise NotImplementedError("Implement function body") + return u + +def train_direct_agent(animate=True, plot=False): + from irlc.ex04.model_pendulum import PendulumModel + model = PendulumModel() + """ + Test out implementation on a fairly small grid. Note this will work fairly terribly. + """ + guess = {'t0': 0, + 'tF': 4, + 'x': [np.asarray([0, 0]), np.asarray([np.pi, 0])], + 'u': [np.asarray([0]), np.asarray([0])]} + + options = [get_opts(N=10, ftol=1e-3, guess=guess), + get_opts(N=20, ftol=1e-3), + get_opts(N=80, ftol=1e-6) + ] + + dmod = DiscreteControlModel(model=model, dt=0.1) # Discretize the pendulum model. Used for creating the environment. + denv = ControlEnvironment(discrete_model=dmod, Tmax=4, render_mode='human' if animate else None) + agent = DirectAgent(denv, options=options) + denv.Tmax = agent.solutions[-1]['fun']['tF'] # Specify max runtime of the environment. Must be based on the Agent's solution. + stats, traj = train(denv, agent=agent, num_episodes=1, return_trajectory=True) + + if plot: + from irlc import plot_trajectory + plot_trajectory(traj[0], env=denv) + savepdf("direct_agent_pendulum") + plt.show() + + return stats, traj, agent + +if __name__ == "__main__": + stats, traj, agent = train_direct_agent(animate=True, plot=True) + print("Obtained cost", -stats[0]['Accumulated Reward']) + + # Let's try to plot the state-vectors for the two models. They are not going to agree that well. + plt.plot(agent.ts_grid, agent.x_grid, 'r-', label="Direct solver prediction") + plt.plot(traj[0].time, traj[0].state, 'k-', label='Simulation') + plt.legend() + plt.show() diff --git a/irlc/ex05/direct_brachistochrone.py b/irlc/ex05/direct_brachistochrone.py new file mode 100644 index 0000000..2aaf14e --- /dev/null +++ b/irlc/ex05/direct_brachistochrone.py @@ -0,0 +1,59 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +import matplotlib.pyplot as plt +from irlc import savepdf +from irlc.ex05.model_brachistochrone import ContiniouBrachistochrone +from irlc.ex05.direct import direct_solver, get_opts, guess +from irlc.ex05.direct_plot import plot_solutions + +def plot_brachistochrone_solutions(model, solutions, out=None): + plot_solutions(model, solutions, animate=False, pdf=out) + for index, sol in enumerate(solutions): + x_res = sol['grid']['x'] + plt.figure(figsize=(5,5)) + plt.plot( x_res[:,0], x_res[:,1]) + xF = model.bounds['xF_low'] + plt.plot([0, 0], [0, xF[1]], 'r-') + plt.plot([0, xF[0]], [xF[1], xF[1]], 'r-') + # plt.title("Curve in x/y plane") + plt.xlabel("$x$-position") + plt.ylabel("$y$-position") + if model.h is not None: + # add dynamical constraint. + xc = np.linspace(0, model.x_dist) + yc = -xc/2 - model.h + plt.plot(xc, yc, 'k-', linewidth=2) + plt.grid() + # plt.gca().invert_yaxis() + plt.gca().axis('equal') + if out: + savepdf(f"{out}_{index}") + plt.show() + pass + +def compute_unconstrained_solutions(): + model = ContiniouBrachistochrone(h=None, x_dist=1) + options = [get_opts(N=10, ftol=1e-3, guess=guess(model)), + get_opts(N=30, ftol=1e-6)] + # solve without constraints + solutions = direct_solver(model, options) + return model, solutions + +def compute_constrained_solutions(): + model_h = ContiniouBrachistochrone(h=0.1, x_dist=1) + options = [get_opts(N=10, ftol=1e-3, guess=guess(model_h)), + get_opts(N=30, ftol=1e-6)] + solutions_h = direct_solver(model_h, options) + return model_h, solutions_h + +if __name__ == "__main__": + """ + For further information see: + http://www.hep.caltech.edu/~fcp/math/variationalCalculus/variationalCalculus.pdf + """ + model, solutions = compute_unconstrained_solutions() + plot_brachistochrone_solutions(model, solutions[-1:], out="brachi") + + # solve with dynamical (sloped planc) constraint at height of h. + model_h, solutions_h = compute_constrained_solutions() + plot_brachistochrone_solutions(model_h, solutions_h[-1:], out="brachi_h") diff --git a/irlc/ex05/direct_cartpole_kelly.py b/irlc/ex05/direct_cartpole_kelly.py new file mode 100644 index 0000000..1bf0268 --- /dev/null +++ b/irlc/ex05/direct_cartpole_kelly.py @@ -0,0 +1,56 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [Kel17] Matthew Kelly. An introduction to trajectory optimization: how to do your own direct collocation. SIAM Review, 59(4):849–904, 2017. (See kelly2017.pdf). +""" +from irlc.ex05.direct import guess +from irlc.ex05.model_cartpole import CartpoleModel +from irlc.ex03.control_cost import SymbolicQRCost +from irlc.ex05.direct import direct_solver, get_opts +import numpy as np +from gymnasium.spaces import Box + +class KellyCartpoleModel(CartpoleModel): + """Completes the Cartpole swingup task in exactly 2 seconds. + + The only changes to the original cartpole model is the inclusion of a new bound on ``tf_bound(self)``, + to limit the end-time to :math:`t_F = 2`, and an updated cost function so that :math:`Q=0` and :math:`R=I`. + """ + def get_cost(self) -> SymbolicQRCost: + # TODO: 2 lines missing. + raise NotImplementedError("Construct and return a new cost-function here.") + + def tF_bound(self) -> Box: + # TODO: 2 lines missing. + raise NotImplementedError("Implement the bound on tF here") + +def make_cartpole_kelly17(): + """ + Creates Cartpole problem. Details about the cost function can be found in (Kel17, Section 6) + and details about the physical parameters can be found in (Kel17, Appendix E, table 3). + """ + # this will generate a different carpole environment with an emphasis on applying little force u. + duration = 2.0 + maxForce = 20 + model = KellyCartpoleModel(max_force=maxForce, mp=0.3, l=0.5, mc=1.0, dist=1) + guess2 = guess(model) + guess2['tF'] = duration # Our guess should match the constraints. + return model, guess2 + +def compute_solutions(): + model, guess = make_cartpole_kelly17() + options = [get_opts(N=10, ftol=1e-3, guess=guess), + get_opts(N=40, ftol=1e-6)] + solutions = direct_solver(model, options) + return model, solutions + +def direct_cartpole(): + model, solutions = compute_solutions() + from irlc.ex05.direct_plot import plot_solutions + print("Did we succeed?", solutions[-1]['solver']['success']) + plot_solutions(model, solutions, animate=True, pdf="direct_cartpole_force") + model.close() + +if __name__ == "__main__": + direct_cartpole() diff --git a/irlc/ex05/direct_cartpole_time.py b/irlc/ex05/direct_cartpole_time.py new file mode 100644 index 0000000..ccf6336 --- /dev/null +++ b/irlc/ex05/direct_cartpole_time.py @@ -0,0 +1,28 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex05.model_cartpole import CartpoleModel +from irlc.ex05.direct import direct_solver, get_opts +from irlc.ex05.direct_plot import plot_solutions +from irlc.ex05.direct import guess + +def compute_solutions(): + """ + See: https://github.com/MatthewPeterKelly/OptimTraj/blob/master/demo/cartPole/MAIN_minTime.m + """ + model = CartpoleModel(max_force=50, mp=0.5, mc=2.0, l=0.5) + guess2 = guess(model) + guess2['tF'] = 2 + guess2['u'] = [[0], [0]] + + options = [get_opts(N=8, ftol=1e-3, guess=guess2), # important. + get_opts(N=16, ftol=1e-6), # This is a hard problem and we need gradual grid-refinement. + get_opts(N=32, ftol=1e-6), + get_opts(N=70, ftol=1e-6) + ] + solutions = direct_solver(model, options) + return model, solutions + +if __name__ == "__main__": + model, solutions = compute_solutions() + x_sim, u_sim, t_sim = plot_solutions(model, solutions[:], animate=True, pdf="direct_cartpole_mintime") + model.close() + print("Did we succeed?", solutions[-1]['solver']['success']) diff --git a/irlc/ex05/direct_pendulum.py b/irlc/ex05/direct_pendulum.py new file mode 100644 index 0000000..80ae5a7 --- /dev/null +++ b/irlc/ex05/direct_pendulum.py @@ -0,0 +1,27 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex05.direct import direct_solver, get_opts +from irlc.ex04.model_pendulum import SinCosPendulumModel +from irlc.ex05.direct_plot import plot_solutions +import numpy as np + +def compute_pendulum_solutions(): + model = SinCosPendulumModel() + """ + Test out implementation on a fairly small grid. Note this will work fairly terribly. + """ + guess = {'t0': 0, + 'tF': 4, + 'x': [np.asarray([0, 0]), np.asarray([np.pi, 0])], + 'u': [np.asarray([0]), np.asarray([0])]} + + options = [get_opts(N=10, ftol=1e-3, guess=guess), + get_opts(N=20, ftol=1e-3), + get_opts(N=80, ftol=1e-6) + ] + + solutions = direct_solver(model, options) + return model, solutions + +if __name__ == "__main__": + model, solutions = compute_pendulum_solutions() + plot_solutions(model, solutions, animate=True, pdf="direct_pendulum_real") diff --git a/irlc/ex05/direct_plot.py b/irlc/ex05/direct_plot.py new file mode 100644 index 0000000..67a324a --- /dev/null +++ b/irlc/ex05/direct_plot.py @@ -0,0 +1,82 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import matplotlib.pyplot as plt +import numpy as np +from irlc.ex03.control_model import plot_trajectory +from irlc import savepdf + +""" +Helper function for plotting. +""" +def plot_solutions(model, solutions, animate=True, pdf=None, plot_defects=True, Ix=None, animate_repeats=1, animate_all=False, plot=True): + + for k, sol in enumerate(solutions): + grd = sol['grid'] + x_res = sol['grid']['x'] + u_res = sol['grid']['u'] + ts = sol['grid']['ts'] + u_fun = lambda x, t: sol['fun']['u'](t) + N = len(ts) + if pdf is not None: + pdf_out = f"{pdf}_sol{N}" + + x_sim, u_sim, t_sim = model.simulate(x0=grd['x'][0, :], u_fun=u_fun, t0=grd['ts'][0], tF=grd['ts'][-1], N_steps=1000) + if animate and (k == len(solutions)-1 or animate_all): + for _ in range(animate_repeats): + animate_rollout(model, x0=grd['x'][0, :], u_fun=u_fun, t0=grd['ts'][0], tF=grd['ts'][-1], N_steps=1000, fps=30) + + eqC_val = sol['eqC_val'] + labels = model.state_labels + + if Ix is not None: + labels = [l for k, l in enumerate(labels) if k in Ix] + x_res = x_res[:,np.asarray(Ix)] + x_sim = x_sim[:,np.asarray(Ix)] + + print("Initial State: " + ",".join(labels)) + print(x_res[0]) + print("Final State:") + print(x_res[-1]) + if plot: + ax = plot_trajectory(x_res, ts, lt='ko-', labels=labels, legend="Direct state prediction $x(t)$") + plot_trajectory(x_sim, t_sim, lt='-', ax=ax, labels=labels, legend="RK4 exact simulation") + # plt.suptitle("State", fontsize=14, y=0.98) + # make_space_above(ax, topmargin=0.5) + + if pdf is not None: + savepdf(pdf_out +"_x") + plt.show(block=False) + # print("plotting...") + plot_trajectory(u_res, ts, lt='ko-', labels=model.action_labels, legend="Direct action prediction $u(t)$") + # print("plotting... B") + # plt.suptitle("Action", fontsize=14, y=0.98) + # print("plotting... C") + # make_space_above(ax, topmargin=0.5) + # print("plotting... D") + if pdf is not None: + savepdf(pdf_out +"_u") + plt.show(block=False) + if plot_defects: + plot_trajectory(eqC_val, ts[:-1], lt='-', labels=labels) + plt.suptitle("Defects (equality constraint violations)") + if pdf is not None: + savepdf(pdf_out +"_defects") + plt.show(block=False) + return x_sim, u_sim, t_sim + + +def animate_rollout(model, x0, u_fun, t0, tF, N_steps = 1000, fps=10): + """ Helper function to animate a policy. """ + + import time + # if sys.gettrace() is not None: + # print("Not animating stuff in debugger as it crashes.") + # return + y, _, tt = model.simulate(x0, u_fun, t0, tF, N_steps=N_steps) + secs = tF-t0 + frames = int( np.ceil( secs * fps ) ) + I = np.round( np.linspace(0, N_steps-1, frames)).astype(int) + y = y[I,:] + + for i in range(frames): + model.render(x=y[i], render_mode="human") + time.sleep(1/fps) diff --git a/irlc/ex05/model_brachistochrone.py b/irlc/ex05/model_brachistochrone.py new file mode 100644 index 0000000..14c0ae7 --- /dev/null +++ b/irlc/ex05/model_brachistochrone.py @@ -0,0 +1,55 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" +The Brachistochrone problem. See +https://apmonitor.com/wiki/index.php/Apps/BrachistochroneProblem +and (Bet10) + +References: + [Bet10] John T Betts. Practical methods for optimal control and estimation using nonlinear programming. Volume 19. Siam, 2010. +""" +import sympy as sym +import numpy as np +from irlc.ex03.control_model import ControlModel +from irlc.ex03.control_cost import SymbolicQRCost +from gymnasium.spaces import Box + +class ContiniouBrachistochrone(ControlModel): + state_labels= ["$x$", "$y$", "bead speed"] + action_labels = ['Tangent angle'] + + def __init__(self, g=9.82, h=None, x_dist=1): + self.g = g + self.h = h + self.x_dist = x_dist # or x_B + super().__init__() + + def get_cost(self) -> SymbolicQRCost: + # TODO: 1 lines missing. + raise NotImplementedError("Instantiate cost=SymbolicQRCost(...) here corresponding to minimum time.") + return cost + + def x0_bound(self) -> Box: + return Box(0, 0, shape=(self.state_size,)) + + def xF_bound(self) -> Box: + return Box(np.array([self.x_dist, -np.inf, -np.inf]), np.array([self.x_dist, np.inf, np.inf])) + + def sym_f(self, x, u, t=None): + # TODO: 3 lines missing. + raise NotImplementedError("Implement function body") + return xp + + def sym_h(self, x, u, t): + r""" + Add a dynamical constraint of the form + + .. math:: + + h(x, u, t) \leq 0 + """ + if self.h is None: + return [] + else: + # compute a single dynamical constraint as in (Bet10, Example (4.10)) (Note y-axis is reversed in the example) + # TODO: 1 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") diff --git a/irlc/ex05/model_cartpole.py b/irlc/ex05/model_cartpole.py new file mode 100644 index 0000000..aea63db --- /dev/null +++ b/irlc/ex05/model_cartpole.py @@ -0,0 +1,173 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex04.discrete_control_cost import DiscreteQRCost +import sympy as sym +import numpy as np +import gymnasium as gym +from gymnasium.spaces import Box +from irlc.ex03.control_model import ControlModel +from irlc.ex03.control_cost import SymbolicQRCost +from irlc.ex04.discrete_control_model import DiscreteControlModel +from irlc.ex04.control_environment import ControlEnvironment + +class CartpoleModel(ControlModel): + state_labels = ["$x$", r"$\frac{dx}{dt}$", r"$\theta$", r"$\frac{d \theta}{dt}$"] + action_labels = ["Cart force $u$"] + + def __init__(self, mc=2, + mp=0.5, + l=0.5, + max_force=50, dist=1.0): + self.mc = mc + self.mp = mp + self.l = l + self.max_force = max_force + self.dist = dist + self.cp_render = {} + super().__init__() + + + def tF_bound(self) -> Box: + return Box(0.01, np.inf, shape=(1,)) + + def x_bound(self) -> Box: + return Box(np.asarray([-2 * self.dist, -np.inf, -2 * np.pi, -np.inf]), np.asarray([2 * self.dist, np.inf, 2 * np.pi, np.inf])) + + def x0_bound(self) -> Box: + return Box(np.asarray([0, 0, np.pi, 0]), np.asarray([0, 0, np.pi, 0])) + + def xF_bound(self) -> Box: + return Box(np.asarray([self.dist, 0, 0, 0]), np.asarray([self.dist, 0, 0, 0])) + + def u_bound(self) -> Box: + return Box(np.asarray([-self.max_force]), np.asarray([self.max_force])) + + def get_cost(self) -> SymbolicQRCost: + return SymbolicQRCost(R=np.eye(1) * 0, Q=np.eye(4) * 0, qc=1) # just minimum time + + def sym_f(self, x, u, t=None): + mp = self.mp + l = self.l + mc = self.mc + g = 9.81 # Gravity on earth. + + x_dot = x[1] + theta = x[2] + sin_theta = sym.sin(theta) + cos_theta = sym.cos(theta) + theta_dot = x[3] + F = u[0] + # Define dynamics model as per Razvan V. Florian's + # "Correct equations for the dynamics of the cart-pole system". + # Friction is neglected. + + # Eq. (23) + temp = (F + mp * l * theta_dot ** 2 * sin_theta) / (mc + mp) + numerator = g * sin_theta - cos_theta * temp + denominator = l * (4.0 / 3.0 - mp * cos_theta ** 2 / (mc + mp)) + theta_dot_dot = numerator / denominator + + # Eq. (24) + x_dot_dot = temp - mp * l * theta_dot_dot * cos_theta / (mc + mp) + xp = [x_dot, + x_dot_dot, + theta_dot, + theta_dot_dot] + return xp + + def close(self): + for r in self.cp_render.values(): + r.close() + + def render(self, x, render_mode="human"): + if render_mode not in self.cp_render: + self.cp_render[render_mode] = gym.make("CartPole-v1", render_mode=render_mode) # environment only used for rendering. Change to v1 in gym 0.26. + self.cp_render[render_mode].max_time_limit = 10000 + self.cp_render[render_mode].reset() + self.cp_render[render_mode].unwrapped.state = np.asarray(x) # environment is wrapped + return self.cp_render[render_mode].render() + +class SinCosCartpoleModel(CartpoleModel): + def phi_x(self, x): + x, dx, theta, theta_dot = x[0], x[1], x[2], x[3] + return [x, dx, sym.sin(theta), sym.cos(theta), theta_dot] + + def phi_x_inv(self, x): + x, dx, sin_theta, cos_theta, theta_dot = x[0], x[1], x[2], x[3], x[4] + theta = sym.atan2(sin_theta, cos_theta) # Obtain angle theta from sin(theta),cos(theta) + return [x, dx, theta, theta_dot] + + def phi_u(self, u): + return [sym.atanh(u[0] / self.max_force)] + + def phi_u_inv(self, u): + return [sym.tanh(u[0]) * self.max_force] + +def _cartpole_discrete_cost(model): + pole_length = model.continuous_model.l + + state_size = model.state_size + Q = np.eye(state_size) + Q[0, 0] = 1.0 + Q[1, 1] = Q[4, 4] = 0. + Q[0, 2] = Q[2, 0] = pole_length + Q[2, 2] = Q[3, 3] = pole_length ** 2 + + print("Warning: I altered the cost-matrix to prevent underflow. This is not great.") + R = np.array([[0.1]]) + Q_terminal = 1 * Q + + q = np.asarray([0,0,0,-1,0]) + # Instantaneous control cost. + c3 = DiscreteQRCost(Q=Q*0, R=R * 0.1, q=1 * q, qN=q * 1) + c3 += c3.goal_seeking_cost(Q=Q, x_target=model.x_upright) + c3 += c3.goal_seeking_terminal_cost(QN=Q_terminal, xN_target=model.x_upright) + cost = c3 + return cost + +class GymSinCosCartpoleModel(DiscreteControlModel): + state_labels = ['x', 'd_x', '$\sin(\\theta)$', '$\cos(\\theta)$', '$d\\theta/dt$'] + action_labels = ['Torque $u$'] + + def __init__(self, dt=0.02, cost=None, transform_actions=True, **kwargs): + model = SinCosCartpoleModel(**kwargs) + self.transform_actions = transform_actions + super().__init__(model=model, dt=dt, cost=cost) + self.x_upright = np.asarray(self.phi_x(model.xF_bound().low )) + if cost is None: + cost = _cartpole_discrete_cost(self) + self.cost = cost + + @property + def max_force(self): + return self.continuous_model.maxForce + + +class GymSinCosCartpoleEnvironment(ControlEnvironment): + def __init__(self, Tmax=5, transform_actions=True, supersample_trajectory=False, render_mode='human', **kwargs): + discrete_model = GymSinCosCartpoleModel(transform_actions=transform_actions, **kwargs) + self.observation_space = Box(low=-np.inf, high=np.inf, shape=(5,), dtype=float) + if transform_actions: + self.action_space = Box(low=-np.inf, high=np.inf, shape=(1,), dtype=float) + super().__init__(discrete_model, Tmax=Tmax,render_mode=render_mode, supersample_trajectory=supersample_trajectory) + + +class DiscreteCartpoleModel(DiscreteControlModel): + def __init__(self, dt=0.02, cost=None, **kwargs): + model = CartpoleModel(**kwargs) + super().__init__(model=model, dt=dt, cost=cost) + + +class CartpoleEnvironment(ControlEnvironment): + def __init__(self, Tmax=5, supersample_trajectory=False, render_mode='human', **kwargs): + discrete_model = DiscreteCartpoleModel(**kwargs) + super().__init__(discrete_model, Tmax=Tmax, supersample_trajectory=supersample_trajectory, render_mode=render_mode) + + +if __name__ == "__main__": + from irlc import train, VideoMonitor + from irlc import Agent + env = GymSinCosCartpoleEnvironment() + agent = Agent(env) + env = VideoMonitor(env) + stats, traj = train(env, agent, num_episodes=1, max_steps=100) + env.close() diff --git a/irlc/ex06/__init__.py b/irlc/ex06/__init__.py new file mode 100644 index 0000000..6e26755 --- /dev/null +++ b/irlc/ex06/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 6.""" diff --git a/irlc/ex06/__pycache__/__init__.cpython-311.pyc b/irlc/ex06/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2005a99d71b80389f53d84cdab39fae60aa41248 GIT binary patch literal 232 zcmZ3^%ge>Uz`$UU-<$T5fq~&Mhy%lnP{wDFlIaX73{eazjKK_=OjU*<8JWcjDVas7 z$tC$kl?uuEc_oRNdBqAP8L0}X6{$tZnZ>Ea3TgR83gxM(*$QTQewvK8*yH0<@{{A^ zS2BDCnf%K}KO;XkRllS(BURreKe;qFHLs*tKQlK+-@wSk)S$SeGzB73l#{HVT47+O zA0MBYmst`YuUAm{i^C>2KczG$)vkz*fq?<!)?z^h28IvJjEsyA7|bugP!S6Q0|Nlx Cgh2`b literal 0 HcmV?d00001 diff --git a/irlc/ex06/__pycache__/dlqr.cpython-311.pyc b/irlc/ex06/__pycache__/dlqr.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e3b9ef8646190a661fbefabe8b43de0c6663fce1 GIT binary patch literal 8856 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 literal 0 HcmV?d00001 diff --git a/irlc/ex06/boeing_lqr.py b/irlc/ex06/boeing_lqr.py new file mode 100644 index 0000000..e06cf3f --- /dev/null +++ b/irlc/ex06/boeing_lqr.py @@ -0,0 +1,85 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +import numpy as np +import matplotlib.pyplot as plt +from irlc import savepdf +from irlc import train +from irlc.ex06.model_boeing import BoeingEnvironment +from irlc.ex06.lqr_agent import LQRAgent +from irlc.ex03.control_model import ControlModel +import scipy + + +def boeing_simulation(): + env = BoeingEnvironment(Tmax=10) + model = env.discrete_model.continuous_model # get the model from the Boeing environment + dt = env.dt # Get the discretization time. + A, B, d = compute_A_B_d(model, dt) + # Use compute_Q_R_q to get the Q, R, and q matrices in the discretized system + # TODO: 1 lines missing. + raise NotImplementedError("Compute Q, R and q here") + ## TODO: Half of each line of code in the following 1 lines have been replaced by garbage. Make it work and remove the error. + #---------------------------------------------------------------------------------------------------------------------------- + # agent = LQRAgent(env, A=A?????????????????????????? + raise NotImplementedError("Use your LQRAgent to plan using the system matrices.") + stats, trajectories = train(env, agent, return_trajectory=True) + return stats, trajectories, env + +def compute_Q_R_q(model : ControlModel, dt : float): + cost = model.get_cost() # Get the continuous-time cost-function + # use print(cost) to see what it contains. + # Then get the discretized matrices using the techniques described in (Her24, Subsection 13.1.6). + # TODO: 3 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + return Q, R, q + +def compute_A_B_d(model : ControlModel, dt : float): + if model.d is None: + d = np.zeros((model.state_size,)) # Ensure d is set to a zero vector if it is not defined. + else: + d = model.d + + A_discrete = scipy.linalg.expm(model.A * dt) # This is the discrete A-matrix computed using the matrix exponential + # Now it is your job to define B_discrete and d_discrete. + # TODO: 2 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + return A_discrete, B_discrete, d_discrete.flatten() + +def boeing_experiment(): + _, trajectories, env = boeing_simulation() + model = env.discrete_model.continuous_model + + dt = env.dt + Q, R, q = compute_Q_R_q(model, dt) + print("Discretization time is", dt) + print("Original q-vector was:", model.get_cost().q) + print("Discretized version is:", q) + + t = trajectories[-1] + out = t.state @ model.P.T + + plt.plot(t.time, out[:, 0], '-', label=env.observation_labels[0]) + plt.plot(t.time, out[:, 1], '-', label=env.observation_labels[1]) + plt.grid() + plt.legend() + plt.xlabel("Time/seconds") + plt.ylabel("Output") + savepdf("boing_lqr_output") + plt.show(block=False) + plt.close() + + plt.plot(t.time[:-1], t.action[:, 0], '-', label=env.action_labels[0]) + plt.plot(t.time[:-1], t.action[:, 1], '-', label=env.action_labels[1]) + plt.xlabel("Time/seconds") + plt.ylabel("Control action") + plt.grid() + plt.legend() + savepdf("boing_lqr_action") + plt.show() + +if __name__ == "__main__": + boeing_experiment() diff --git a/irlc/ex06/dlqr.py b/irlc/ex06/dlqr.py new file mode 100644 index 0000000..205aa9f --- /dev/null +++ b/irlc/ex06/dlqr.py @@ -0,0 +1,207 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +import numpy as np +import matplotlib.pyplot as plt +from irlc import bmatrix +from irlc import savepdf + + + +def LQR(A : list, # Dynamic + B : list, # Dynamics + d : list =None, # Dynamics (optional) + Q : list=None, + R: list=None, + H : list=None, + q : list=None, + r : list=None, + qc : list=None, + QN : np.ndarray =None, # Terminal cost term + qN : np.ndarray=None, # Terminal cost term + qcN : np.ndarray =None, # Terminal cost term. + mu : float =0 # regularization parameter which will only be relevant next week. + ): + r""" + Implement the LQR as defined in (Her24, Algorithm 22). I recommend viewing this documentation online (documentation for week 6). + + When you solve this exercise, look at the algorithm in the book. Since the LQR problem is on the form: + + .. math:: + + x_{k+1} = A_k x_k + B_k u_k + d_k + + For :math:`k=0,\dots,N-1` this means there are :math:`N` matrices :math:`A_k`. This is implemented by assuming that + :python:`A` (i.e., the input argument) is a :python:`list` of length :math:`N` so that :python:`A[k]` corresponds + to :math:`A_k`. + + Similar conventions are used for the cost term (please see the lecture notes or the online documentation for their meaning). Recall it has the form: + + .. math:: + + c(x_k, u_k) = \frac{1}{2} \mathbf x_k^\top Q_k \mathbf x_k + \frac{1}{2} \mathbf q_k^\top \mathbf x_k + q_k + \cdots + + When the function is called, the vector :math:`\textbf{q}_k` corresponds to :python:`q` and the constant :math:`q_k` correspond to :python:`qc` (q-constant). + + .. note:: + + Only the terms :python:`A` and :python:`B` are required. The rest of the terms will default to 0-matrices. + + The LQR algorithm will ultimately compute a control law of the form: + + .. math:: + + \mathbf u_k = L_k \mathbf x_k + \mathbf l_k + + And a cost-to-go function as: + + .. math:: + + J_k(x_k) = \frac{1}{2} \mathbf x_k^\top V_k \mathbf x_k + v_k^\top \mathbf x_k + v_k + + Again there are :math:`N-1` terms. The function then return :python:`return (L, l), (V, v, vc)` so that :python:`L[k]` corresponds to :math:`L_k`. + + :param A: A list of :python:`np.ndarray` containing all terms :math:`A_k` + :param B: A list of :python:`np.ndarray` containing all terms :math:`B_k` + :param d: A list of :python:`np.ndarray` containing all terms :math:`\mathbf d_k` (optional) + :param Q: A list of :python:`np.ndarray` containing all terms :math:`Q_k` (optional) + :param R: A list of :python:`np.ndarray` containing all terms :math:`R_k` (optional) + :param H: A list of :python:`np.ndarray` containing all terms :math:`H_k` (optional) + :param q: A list of :python:`np.ndarray` containing all terms :math:`\mathbf q_k` (optional) + :param r: A list of :python:`np.ndarray` containing all terms :math:`\mathbf r_k` (optional) + :param qc: A list of :python:`float` containing all terms :math:`q_k` (i.e., constant terms) (optional) + :param QN: A :python:`np.ndarray` containing the terminal cost term :math:`Q_N` (optional) + :param qN: A :python:`np.ndarray` containing the terminal cost term :math:`\mathbf q_N` (optional) + :param qcN: A :python:`np.ndarray` containing the terminal cost term :math:`q_N` + :param mu: A regularization term which is useful for iterative-LQR (next week). Default to 0. + :return: A tuple of the form :python:`(L, l), (V, v, vc)` corresponding to the control and cost-matrices. + """ + N = len(A) + n,m = B[0].shape + # Initialize empty lists for control matrices and cost terms + L, l = [None]*N, [None]*N + V, v, vc = [None]*(N+1), [None]*(N+1), [None]*(N+1) + # Initialize constant cost-function terms to zero if not specified. + # They will be initialized to zero, meaning they have no effect on the update rules. + QN = np.zeros((n,n)) if QN is None else QN + qN = np.zeros((n,)) if qN is None else qN + qcN = 0 if qcN is None else qcN + H, q, qc, r = init_mat(H,m,n,N=N), init_mat(q,n,N=N), init_mat(qc,1,N=N), init_mat(r,m,N=N) + d = init_mat(d,n, N=N) + """ In the next line, you should initialize the last cost-term. This is similar to how we in DP had the initialization step + > J_N(x_N) = g_N(x_N) + Except that since x_N is no longer discrete, we store it as matrices/vectors representing a second-order polynomial, i.e. + > J_N(X_N) = 1/2 * x_N' V[N] x_N + v[N]' x_N + vc[N] + """ + # TODO: 1 lines missing. + raise NotImplementedError("Initialize V[N], v[N], vc[N] here") + + In = np.eye(n) + for k in range(N-1,-1,-1): + # When you update S_uu and S_ux remember to add regularization as the terms ... (V[k+1] + mu * In) ... + # Note that that to find x such that + # >>> x = A^{-1} y this + # in a numerically stable manner this should be done as + # >>> x = np.linalg.solve(A, y) + # The terms you need to update will be, in turn: + # Suu = ... + # Sux = ... + # Su = ... + # L[k] = ... + # l[k] = ... + # V[k] = ... + # V[k] = ... + # v[k] = ... + # vc[k] = ... + ## TODO: Half of each line of code in the following 4 lines have been replaced by garbage. Make it work and remove the error. + #---------------------------------------------------------------------------------------------------------------------------- + # Suu = R[k] + B[k].T @ (???????????????????????? + # Sux = H[k] + B[k].T @ (???????????????????????? + # Su = r[k] + B[k].T @ v[k + 1????????????????????????????? + # L[k] = -np.linal????????????????? + raise NotImplementedError("Insert your solution and remove this error.") + l[k] = -np.linalg.solve(Suu, Su) # You get this for free. Notice how we use np.lingalg.solve(A,x) to compute A^{-1} x + V[k] = Q[k] + A[k].T @ V[k+1] @ A[k] - L[k].T @ Suu @ L[k] + V[k] = 0.5 * (V[k] + V[k].T) # I recommend putting this here to keep V positive semidefinite + # You get these for free: Compare to the code in the algorithm. + v[k] = q[k] + A[k].T @ (v[k+1] + V[k+1] @ d[k]) + Sux.T @ l[k] + vc[k] = vc[k+1] + qc[k] + d[k].T @ v[k+1] + 1/2*( d[k].T @ V[k+1] @ d[k] ) + 1/2*l[k].T @ Su + + return (L,l), (V,v,vc) + + +def init_mat(X, a, b=None, N=None): + """ + Helper function. Check if X is None, and if so return a list + [A, A,....] + which is N long and where each A is a (a x b) zero-matrix, else returns X repeated N times: + [X, X, ...] + """ + M0 = np.zeros((a,) if b is None else (a, b)) + if X is not None: + return [m if m is not None else M0 for m in X] + else: + return [M0] * N + +def lqr_rollout(x0,A,B,d,L,l): + """ + Compute a rollout (states and actions) given solution from LQR controller function. + + x0 is a vector (starting state), and A, B, d and L, l are lists of system/control matrices. + """ + x, states,actions = x0, [x0], [] + n,m = B[0].shape + N = len(L) + d = init_mat(d,n,1,N) # Initialize as a list of zero matrices [ np.zeros((n,1)), np.zeros((n,1)), ...] + l = init_mat(l,m,1,N) # Initialize as a list of zero matrices [ np.zeros((m,1)), np.zeros((m,1)), ...] + + for k in range(N): + u = L[k] @ x + l[k] + x = A[k] @ x + B[k] @ u + d[k] + actions.append(u) + states.append(x) + return states, actions + +if __name__ == "__main__": + """ + Solve this problem (see also lecture notes for the same example) + http://cse.lab.imtlucca.it/~bemporad/teaching/ac/pdf/AC2-04-LQR-Kalman.pdf + """ + N = 20 + A = np.ones((2,2)) + A[1,0] = 0 + B = np.asarray([[0], [1]]) + Q = np.zeros((2,2)) + R = np.ones((1,1)) + + print("System matrices A, B, Q, R") + print(bmatrix(A)) + print(bmatrix(B)) + print(bmatrix(Q)) + print(bmatrix(R)) + + for rho in [0.1, 10, 100]: + Q[0,0] = 1/rho + (L,l), (V,v,vc) = LQR(A=[A]*N, B=[B]*N, d=None, Q=[Q]*N, R=[R]*N, QN=Q) + + x0 = np.asarray( [[1],[0]]) + trajectory, actions = lqr_rollout(x0,A=[A]*N, B=[B]*N, d=None,L=L,l=l) + + xs = np.concatenate(trajectory, axis=1)[0,:] + + plt.plot(xs, 'o-', label=f'rho={rho}') + + k = 10 + print(f"Control matrix in u_k = L_k x_k + l_k at k={k}:", L[k]) + for k in [N-1,N-2,0]: + print(f"L[{k}] is:", L[k].round(4)) + plt.title("Double integrator") + plt.xlabel('Steps $k$') + plt.ylabel('$x_1 = $ x[0]') + plt.legend() + plt.grid() + savepdf("dlqr_double_integrator") + plt.show() diff --git a/irlc/ex06/dlqr_check.py b/irlc/ex06/dlqr_check.py new file mode 100644 index 0000000..3d86db3 --- /dev/null +++ b/irlc/ex06/dlqr_check.py @@ -0,0 +1,40 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc.ex06.dlqr import LQR + +def urnd(sz): + return np.random.uniform(-1, 1, sz) + +def check_LQR(): + np.random.seed(42) + n,m,N = 3,2,4 + """ + Create a randomized, nonsense control problem and solve it. Since seed is fixed we can expect same solution. + """ + # system tersm + A = [urnd((n, n)) for _ in range(N)] + B = [urnd((n, m)) for _ in range(N)] + d = [urnd((n,)) for _ in range(N)] + # cost terms + Q = [urnd((n, n)) for _ in range(N)] + R = [urnd((m, m)) for _ in range(N)] + H = [urnd((m, n)) for _ in range(N)] + q = [urnd((n,)) for _ in range(N)] + qc = [urnd(()) for _ in range(N)] + r = [urnd((m,)) for _ in range(N)] + # terminal costs + QN = urnd((n, n)) + qN = urnd((n,)) + qcN = urnd(()) + return LQR(A=A, B=B, d=d, Q=Q, R=R, H=H, q=q, r=r, qc=qc, QN=QN, qN=qN, qcN=qcN, mu=0) + + +if __name__ == "__main__": + (L, l), (V, v, vc) = check_LQR() + N = len(V)-1 + print(", ".join([f"l[{k}]={l[k].round(4)}" for k in [N - 1, N - 2, 0]])) + print("\n".join([f"L[{k}]={L[k].round(4)}" for k in [N - 1, N - 2, 0]])) + + print("\n".join([f"V[{k}]={V[k].round(4)}" for k in [0]])) + print(", ".join([f"v[{k}]={v[k].round(4)}" for k in [N, N - 1, 0]])) + print(", ".join([f"vc[{k}]={vc[k].round(4)}" for k in [N, N - 1, 0]])) diff --git a/irlc/ex06/lqr_agent.py b/irlc/ex06/lqr_agent.py new file mode 100644 index 0000000..f62ec55 --- /dev/null +++ b/irlc/ex06/lqr_agent.py @@ -0,0 +1,54 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex04.locomotive import LocomotiveEnvironment +from irlc import train, plot_trajectory, savepdf, Agent +from irlc.ex06.dlqr import LQR +from irlc.ex04.control_environment import ControlEnvironment +import numpy as np +import matplotlib.pyplot as plt + +class LQRAgent(Agent): + def __init__(self, env : ControlEnvironment, A, B, Q, R, d=None, q=None): + N = int((env.Tmax / env.dt)) # Obtain the planning horizon + """ Define A, B as the list of A/B matrices here. I.e. x[t+1] = A x[t] + B x[t] + d. + You should use the function model.f to do this, which has build-in functionality to compute Jacobians which will be equal to A, B """ + """ Define self.L, self.l here as the (lists of) control matrices. """ + ## TODO: Half of each line of code in the following 1 lines have been replaced by garbage. Make it work and remove the error. + #---------------------------------------------------------------------------------------------------------------------------- + # (self.L, self.l), _ = LQR(A=[A]*N, B=[B]*N, d=[d]*N if d is not No??????????????????????????????????????????????????????????????????? + raise NotImplementedError("Insert your solution and remove this error.") + self.dt = env.dt + super().__init__(env) + + def pi(self,x, k, info=None): + """ + Compute the action here using u = L_k x + l_k. + You should use self.L, self.l to get the control matrices (i.e. L_k = self.L[k] ), + """ + # TODO: 1 lines missing. + raise NotImplementedError("Compute current action here") + return u + + +if __name__ == "__main__": + # Make a guess at the system matrices for planning. We will return on how to compute these exactly in a later exercise. + A = np.ones((2, 2)) + A[1, 0] = 0 + B = np.asarray([[0], [1]]) + Q = np.eye(2)*3 + R = np.ones((1, 1))*2 + q = np.asarray([-1.1, 0 ]) + + # Create and test our LQRAgent. + env = LocomotiveEnvironment(render_mode='human', Tmax=10, slope=1) + agent = LQRAgent(env, A=A, B=B, Q=Q, R=R, q=q) + stats, traj = train(env, agent, num_episodes=1) + + env.reset() + savepdf("locomotive_snapshot.pdf", env=env) # Make a plot for the exercise file. + env.state_labels = ["x(t)", "v(t)"] + env.action_labels = ["u(t)"] + plot_trajectory(traj[0], env) + plt.show(block=True) + savepdf("lqr_agent") + plt.show() + env.close() diff --git a/irlc/ex06/lqr_pid.py b/irlc/ex06/lqr_pid.py new file mode 100644 index 0000000..136cae2 --- /dev/null +++ b/irlc/ex06/lqr_pid.py @@ -0,0 +1,79 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import matplotlib.pyplot as plt +import numpy as np +from irlc import savepdf, train +from irlc.ex04.pid_locomotive_agent import PIDLocomotiveAgent +from irlc.ex06.lqr_agent import LQRAgent +from irlc.ex04.model_harmonic import HarmonicOscilatorEnvironment +from irlc.ex06.boeing_lqr import compute_A_B_d, compute_Q_R_q + +class ConstantLQRAgent(LQRAgent): + # TODO: 3 lines missing. + raise NotImplementedError("Complete this agent here. You need to update the policy-function: def pi(self, ..).") + +def get_Kp_Kd(L0): + # TODO: 1 lines missing. + raise NotImplementedError("Use lqr_agent.L to define Kp and Kd.") + return Kp, Kd + + +if __name__ == "__main__": + Delta = 0.06 # Time discretization constant + # Define a harmonic osscilator environment. Use .., render_mode='human' to see a visualization. + env = HarmonicOscilatorEnvironment(Tmax=8, dt=Delta, m=0.5, R=np.eye(1) * 8, render_mode=None) # set render_mode='human' to see the oscillator. + model = env.discrete_model.continuous_model # Get the ControlModel corresponding to this environment. + + + # Compute the discretized A, B and d matrices using the helper functions we defined in the Boeing problem. + # Note that these are for the discrete environment: x_{k+1} = A x_k + B u_k + d + A, B, d = compute_A_B_d(model, Delta) + Q, R, q = compute_Q_R_q(model, Delta) + + # Run the LQR agent + lqr_agent = LQRAgent(env, A=A, B=B, d=d, Q=Q, R=R, q=q) + _, traj1 = train(env, lqr_agent, return_trajectory=True) + + # Part 1. Build an agent that always takes actions u_k = L_0 x_k + l_0 + constant_agent = ConstantLQRAgent(env, A=A, B=B, d=d, Q=Q, R=R, q=q) + # Check that its policy is independent of $k$: + x0, _ = env.reset() + print(f"Initial state is {x0=}") + print(f"Action at time step k=0 {constant_agent.pi(x0, k=0)=}") + print(f"Action at time step k=5 (should be the same) {constant_agent.pi(x0, k=0)=}") + + _, traj2 = train(env, constant_agent, return_trajectory=True) + + # Part 2. Use the L and l matrices (see lqr_agent.L and lqr_agent.l) + # to select Kp and Kd in a PID agent. Then let's use the Locomotive agent to see the effect of the controller. + # Use render_mode='human' to see its effect. + # We only need to use L. + # Hint: compare the form of the LQR and PID controller and use that to select Kp and Kd. + Kp, Kd = get_Kp_Kd(lqr_agent.L[0]) # Use lqr_agent.L to define Kp and Kd. + + # Define and run the PID agent. + pid_agent = PIDLocomotiveAgent(env, env.dt, Kp=Kp, Kd=Kd) + _, traj3 = train(env, pid_agent, return_trajectory=True) + + # Plot all actions and state sequences. + plt.figure(figsize=(10,5)) + plt.grid() + plt.plot(traj1[0].time[:-1], traj1[0].action, label="Optimal LQR action sequence") + plt.plot(traj2[0].time[:-1], traj2[0].action, '.-', label="Constant LQR action sequence") + plt.plot(traj3[0].time[:-1], traj3[0].action, label="PID agent action sequence") + plt.xlabel("Time / Seconds") + plt.ylabel("Action / Newtons") + plt.ylim([-.2, .2]) + plt.legend() + savepdf("pid_lqr_actions") + plt.show(block=True) + + plt.figure(figsize=(10, 5)) + plt.grid() + plt.plot(traj1[0].time, traj1[0].state[:, 0], label="Optimal LQR states x(t)") + plt.plot(traj2[0].time, traj2[0].state[:, 0], label="Constant LQR states x(t)") + plt.plot(traj3[0].time, traj3[0].state[:, 0], label="PID agent states x(t)") + plt.xlabel("Time / Seconds") + plt.ylabel("Position x(t) / Meters") + plt.ylim([-1, 1]) + plt.legend() + savepdf("pid_lqr_states") diff --git a/irlc/ex06/model_boeing.py b/irlc/ex06/model_boeing.py new file mode 100644 index 0000000..57e0a0c --- /dev/null +++ b/irlc/ex06/model_boeing.py @@ -0,0 +1,62 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc.ex04.discrete_control_model import DiscreteControlModel +from irlc.ex04.control_environment import ControlEnvironment +from irlc.ex04.model_linear_quadratic import LinearQuadraticModel + +class BoeingModel(LinearQuadraticModel): + """ + Boeing 747 level flight example. + + See: https://books.google.dk/books?id=tXZDAAAAQBAJ&pg=PA147&lpg=PA147&dq=boeing+747+flight+0.322+model+longitudinal+flight&source=bl&ots=L2RpjCAWiZ&sig=ACfU3U2m0JsiHmUorwyq5REcOj2nlxZkuA&hl=en&sa=X&ved=2ahUKEwir7L3i6o3qAhWpl4sKHQV6CdcQ6AEwAHoECAoQAQ#v=onepage&q=boeing%20747%20flight%200.322%20model%20longitudinal%20flight&f=false + Also: https://web.stanford.edu/~boyd/vmls/vmls-slides.pdf + """ + state_labels = ["Longitudinal velocity (x) ft/sec", "Velocity in y-axis ft/sec", "Angular velocity", + "angle wrt. horizontal"] + action_labels = ['Elevator', "Throttle"] + observation_labels = ["Airspeed", "Climb rate"] + + def __init__(self, output=None): + if output is None: + output = [10, 0] + # output = [10, 0] + A = [[-0.003, 0.039, 0, -0.322], + [-0.065, -.319, 7.74, 0], + [.02, -.101, -0.429, 0], + [0, 0, 1, 0]] + B = [[.01, 1], + [-.18, -.04], + [-1.16, .598], + [0, 0]] + + A, B = np.asarray(A), np.asarray(B) + self.u0 = 7.74 # speed in hundred feet/seconds + self.P = np.asarray([[1, 0, 0, 0], [0, -1, 0, 7.74]]) # Projection of state into airspeed + + dt = 0.1 # Scale the cost by this factor. + + # Set up the cost: + self.Q_obs = np.eye(2) + Q = self.P.T @ self.Q_obs @ self.P / dt + R = np.eye(2) / dt + q = -np.asarray(output) @ self.Q_obs @ self.P / dt + super().__init__(A=A, B=B, Q=Q, R=R, q=q) + + def state2outputs(self, x): + return self.P @ x + +class DiscreteBoeingModel(DiscreteControlModel): + def __init__(self, output=None): + model = BoeingModel(output=output) + dt = 0.1 + super().__init__(model=model, dt=dt) + + +class BoeingEnvironment(ControlEnvironment): + @property + def observation_labels(self): + return self.discrete_model.continuous_model.observation_labels + + def __init__(self, Tmax=10): + model = DiscreteBoeingModel() + super().__init__(discrete_model=model, Tmax=Tmax) diff --git a/irlc/ex06/model_rendevouz.py b/irlc/ex06/model_rendevouz.py new file mode 100644 index 0000000..c6a9829 --- /dev/null +++ b/irlc/ex06/model_rendevouz.py @@ -0,0 +1,95 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc.utils.graphics_util_pygame import UpgradedGraphicsUtil +from irlc.ex04.discrete_control_model import DiscreteControlModel +from irlc.ex04.control_environment import ControlEnvironment +from irlc.ex04.model_linear_quadratic import LinearQuadraticModel +from gymnasium.spaces import Box + +""" +SEE: https://github.com/anassinator/ilqr/blob/master/examples/rendezvous.ipynb +""" +class ContiniousRendevouzModel(LinearQuadraticModel): + state_labels= ["x0", "y0", "x1", "y1", 'Vx0', "Vy0", "Vx1", "Vy1"] + action_labels = ['Fx0', 'Fy0', "Fx1", "Fy1"] + x0 = np.array([0, 0, 10, 10, 0, -5, 5, 0]) # Initial state. + + def __init__(self, m=10.0, alpha=0.1, simple_bounds=None, cost=None): + m00 = np.zeros((4,4)) + mI = np.eye(4) + A = np.block( [ [m00, mI], [m00, -alpha/m*mI] ] ) + B = np.block( [ [m00], [mI/m]] ) + state_size = len(self.x0) + action_size = 4 + self.m = m + self.alpha = alpha + Q = np.eye(state_size) + Q[0, 2] = Q[2, 0] = -1 + Q[1, 3] = Q[3, 1] = -1 + R = 0.1 * np.eye(action_size) + self.viewer = None + super().__init__(A=A, B=B, Q=Q*20, R=R*20) + + def x0_bound(self) -> Box: + return Box(self.x0, self.x0) # self.bounds['x0_low'] = self.bounds['x0_high'] = list(self.x0) + + def render(self, x, render_mode="human"): + """ Render the environment. You don't have to understand this code. """ + if self.viewer is None: + self.viewer = HarmonicViewer(xstar=0, x0=self.x0) # target: x=0. + self.viewer.update(x) + import time + time.sleep(0.05) + return self.viewer.blit(render_mode=render_mode) + + def close(self): + pass + + +class DiscreteRendevouzModel(DiscreteControlModel): + def __init__(self, dt=0.1, cost=None, transform_actions=True, **kwargs): + model = ContiniousRendevouzModel(**kwargs) + super().__init__(model=model, dt=dt, cost=cost) + +class RendevouzEnvironment(ControlEnvironment): + def __init__(self, Tmax=20, render_mode=None, **kwargs): + discrete_model = DiscreteRendevouzModel(**kwargs) + super().__init__(discrete_model, Tmax=Tmax, render_mode=render_mode) + +class HarmonicViewer(UpgradedGraphicsUtil): + def __init__(self, xstar = 0, x0=None): + self.xstar = xstar + width = 800 + self.x0 = x0 + sz = 20 + self.scale = width/(2*sz) + self.p1h = [] + self.p2h = [] + super().__init__(screen_width=width, xmin=-sz, xmax=sz, ymin=-sz, ymax=sz, title='Rendevouz environment') + + def render(self): + self.draw_background(background_color=(255, 255, 255)) + # dw = self.dw + p1 = self.x[:2] + p2 = self.x[2:4] + self.p1h.append(p1) + self.p2h.append(p2) + self.circle("asdf", pos=p1, r=.5 * self.scale, fillColor=(200, 0, 0)) + self.circle("asdf", pos=p2, r=.5 * self.scale, fillColor=(0, 0, 200) ) + if len(self.p1h) > 2: + self.polyline('...', np.stack(self.p1h)[:,0], np.stack(self.p1h)[:,1], width=1, color=(200, 0, 0)) + self.polyline('...', np.stack(self.p2h)[:,0], np.stack(self.p2h)[:,1], width=1, color=(0, 0, 200)) + + if tuple(self.x) == tuple(self.x0): + self.p1h = [] + self.p2h = [] + + + def update(self, x): + self.x = x + + +if __name__ == "__main__": + from irlc import Agent, train + env = RendevouzEnvironment(render_mode='human') + train(env, Agent(env), num_episodes=4) diff --git a/irlc/ex07/__init__.py b/irlc/ex07/__init__.py new file mode 100644 index 0000000..1e8044b --- /dev/null +++ b/irlc/ex07/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 7.""" diff --git a/irlc/ex07/__pycache__/__init__.cpython-311.pyc b/irlc/ex07/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31f12480f2dcfe61ecbfb39cae46bc4ec87cffd0 GIT binary patch literal 232 zcmZ3^%ge>Uz`$UU-<$T5fq~&Mhy%lnP{wDFlIaX73{eazjKK_=OjU*<8JWcjDVas7 z$tC$kl?uuEc_oRNdBqAP8L0}X6{$tZnZ>Ea3TgR83gxM(*$U=*ewvK8*yH0<@{{A^ zS2BDCnf%K}KO;XkRllS(BURreKe;qFHLs*tKQlK+-@wSk)S$SeGzB73l#{HVT47+W zA0MBYmst`YuUAm{i^C>2KczG$)vkz*fq?<!)?z^h28IvJjEsyA7|bugP!S6Q0|Nly CKtT)u literal 0 HcmV?d00001 diff --git a/irlc/ex07/__pycache__/ilqr.cpython-311.pyc b/irlc/ex07/__pycache__/ilqr.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7a751e7129fe8878e0d83ad2613ed7b7c560ad85 GIT binary patch literal 10002 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 literal 0 HcmV?d00001 diff --git a/irlc/ex07/ilqr.py b/irlc/ex07/ilqr.py new file mode 100644 index 0000000..8e33a8f --- /dev/null +++ b/irlc/ex07/ilqr.py @@ -0,0 +1,273 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" +This implements two methods: The basic ILQR method, described in (Her24, Algorithm 24), and the linesearch-based method +described in (Her24, Algorithm 25). + +If you are interested, you can consult (TET12) (which contains generalization to DDP) and (Har20, Alg 1). + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. + [TET12] Yuval Tassa, Tom Erez, and Emanuel Todorov. Synthesis and stabilization of complex behaviors through online trajectory optimization. In 2012 IEEE/RSJ International Conference on Intelligent Robots and Systems, 4906–4913. IEEE, 2012. (See tassa2012.pdf). + [Har20] James Harrison. Optimal and learning-based control combined course notes. (See AA203combined.pdf), 2020. +""" +import warnings +import numpy as np +from irlc.ex06.dlqr import LQR +from irlc.ex04.discrete_control_model import DiscreteControlModel + +def ilqr_basic(model : DiscreteControlModel, N, x0, us_init : list = None, n_iterations=500, verbose=True): + """ + Implements the basic ilqr algorithm, i.e. (Her24, Algorithm 24). Our notation (x_bar, etc.) will be consistent with the lecture slides + """ + mu, alpha = 1, 1 # Hyperparameters. For now, just let them have defaults and don't change them + # Create a random initial state-sequence + n, m = model.state_size, model.action_size + u_bar = [np.random.uniform(-1, 1,(model.action_size,)) for _ in range(N)] if us_init is None else us_init + x_bar = [x0] + [np.zeros(n, )] * N + """ + Initialize nominal trajectory xs, us using us and x0 (i.e. simulate system from x0 using action sequence us). + The simplest way to do this is to call forward_pass with all-zero sequence of control vector/matrix l, L. + """ + # TODO: 2 lines missing. + raise NotImplementedError("Initialize x_bar, u_bar here") + J_hist = [] + for i in range(n_iterations): + """ + Compute derivatives around trajectory and cost estimate J of trajectory. To do so, use the get_derivatives + function. Remember the functions will return lists of derivatives. + """ + # TODO: 2 lines missing. + raise NotImplementedError("Compute J and derivatives A_k = f_x, B_k = f_u, ....") + """ Backward pass: Obtain feedback law matrices l, L using the backward_pass function. + """ + # TODO: 1 lines missing. + raise NotImplementedError("Compute L, l = .... here") + """ Forward pass: Given L, l matrices computed above, simulate new (optimal) action sequence. + In the lecture slides, this is similar to how we compute u^*_k and x_k + Once they are computed, iterate the iLQR algorithm by setting x_bar, u_bar equal to these values + """ + # TODO: 1 lines missing. + raise NotImplementedError("Compute x_bar, u_bar = ...") + if verbose: + print(f"{i}> J={J:4g}, change in cost since last iteration {0 if i == 0 else J-J_hist[-1]:4g}") + J_hist.append(J) + return x_bar, u_bar, J_hist, L, l + +def ilqr_linesearch(model : DiscreteControlModel, N, x0, n_iterations, us_init=None, tol=1e-6, verbose=True): + """ + For linesearch implement method described in (Her24, Algorithm 25) (we will use regular iLQR, not DDP!) + """ + # The range of alpha-values to try out in the linesearch + # plus parameters relevant for regularization scheduling. + alphas = 1.1 ** (-np.arange(10) ** 2) # alphas = [1, 1.1^{-2}, ...] + mu_min = 1e-6 + mu_max = 1e10 + Delta_0 = 2 + mu = 1.0 + Delta = Delta_0 + + n, m = model.state_size, model.action_size + u_bar = [np.random.uniform(-1, 1, (model.action_size,)) for _ in range(N)] if us_init is None else us_init + x_bar = [x0] + [np.zeros(n, )] * (N) + # Initialize nominal trajectory xs, us (same as in basic linesearch) + # TODO: 2 lines missing. + raise NotImplementedError("Copy-paste code from previous solution") + J_hist = [] + + converged = False + for i in range(n_iterations): + alpha_was_accepted = False + """ Step 1: Compute derivatives around trajectory and cost estimate of trajectory. + (copy-paste from basic implementation). In our implementation, J_bar = J_{u^star}(x_0) """ + # TODO: 2 lines missing. + raise NotImplementedError("Obtain derivatives f_x, f_u, ... as well as cost of trajectory J_bar = ...") + try: + """ + Step 2: Backward pass to obtain control law (l, L). Same as before so more copy-paste + """ + # TODO: 1 lines missing. + raise NotImplementedError("Obtain l, L = ... in backward pass") + """ + Step 3: Forward pass and alpha scheduling. + Decrease alpha and check condition |J^new < J'|. Apply the regularization scheduling as needed. """ + for alpha in alphas: + x_hat, u_hat = forward_pass(model, x_bar, u_bar, L=L, l=l, alpha=alpha) # Simulate trajectory using this alpha + # TODO: 1 lines missing. + raise NotImplementedError("Compute J_new = ... as the cost of trajectory x_hat, u_hat") + + if J_new < J_prime: + """ Linesearch proposed trajectory accepted! Set current trajectory equal to x_hat, u_hat. """ + if np.abs((J_prime - J_new) / J_prime) < tol: + converged = True # Method does not seem to decrease J; converged. Break and return. + + J_prime = J_new + x_bar, u_bar = x_hat, u_hat + ''' + The update was accepted and you should change the regularization term mu, + and the related scheduling term Delta. + ''' + # TODO: 1 lines missing. + raise NotImplementedError("Delta, mu = ...") + alpha_was_accepted = True # accept this alpha + break + except np.linalg.LinAlgError as e: + # Matrix in dlqr was not positive-definite and this diverged + warnings.warn(str(e)) + + if not alpha_was_accepted: + ''' No alphas were accepted, which is not too hot. Regularization should change + ''' + # TODO: 1 lines missing. + raise NotImplementedError("Delta, mu = ...") + + if mu_max and mu >= mu_max: + raise Exception("Exceeded max regularization term; we are stuffed.") + + dJ = 0 if i == 0 else J_prime-J_hist[-1] + info = "converged" if converged else ("accepted" if alpha_was_accepted else "failed") + if verbose: + print(f"{i}> J={J_prime:4g}, decrease in cost {dJ:4g} ({info}).\nx[N]={x_bar[-1].round(2)}") + J_hist.append(J_prime) + if converged: + break + return x_bar, u_bar, J_hist, L, l + +def backward_pass(A : list, B : list, c_x : list, c_u : list, c_xx : list, c_ux : list, c_uu : list, mu=1): + r"""Given all derivatives, apply the LQR algorithm to get the control law. + + The input arguments are described in the online documentation and the lecture notes. You should use them to call your + implementation of the :func:`~irlc.ex06.dlqr.LQR` method. Note that you should give a value of all inputs except for the ``d``-term. + + :param A: linearization of the dynamics matrices :math:`A_k`. + :param B: linearization of the dynamics matrices :math:`B_k`. + :param c_x: Cost terms corresponding to :math:`\mathbf{q}_k` + :param c_u: Cost terms corresponding to :math:`\mathbf{r}_k` + :param c_xx: Cost terms corresponding to :math:`Q_k` + :param c_ux: Cost terms corresponding to :math:`H_k` + :param c_uu: Cost terms corresponding to :math:`R_k` + :param mu: Regularization parameter for the LQR method + :return: The control law :math:`L_k, \mathbf{l}_k` as two lists. + """ + Q, QN = c_xx[:-1], c_xx[-1] # An example. + # TODO: 4 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + # Define the inputs using the linearization inputs. + (L, l), (V, v, vc) = LQR(A=A, B=B, R=R, Q=Q, QN=QN, H=H, q=q, qN=qN, r=r, mu=mu) + return L, l + +def cost_of_trajectory(model : DiscreteControlModel, xs : list, us : list) -> float: + r"""Helper function which computes the cost of the trajectory. + + The cost is defined as: + + .. math:: + + c_N( \bar {\mathbf x}_N, \bar {\mathbf u}_) + \sum_{k=0}^{N-1} c_k(\bar {\mathbf x}_k, \bar {\mathbf u}_k) + + and to compute it, you should use the two helper methods ``model.cost.c`` and ``model.cost.cN`` + (see :func:`~irlc.ex04.discrete_control_cost.DiscreteQRCost.c` and :func:`~irlc.ex04.discrete_control_cost.DiscreteQRCost.cN`). + + :param model: The control model used to compute the cost. + :param xs: A list of length :math:`N+1` of the form :math:`\begin{bmatrix}\bar {\mathbf x}_0 & \dots & \bar {\mathbf x}_N \end{bmatrix}` + :param us: A list of length :math:`N` of the form :math:`\begin{bmatrix}\bar {\mathbf x}_0 & \dots & \bar {\mathbf x}_{N-1} \end{bmatrix}` + :return: The cost as a number. + """ + N = len(us) + JN = model.cost.cN(xs[-1]) + return sum(map(lambda args: model.cost.c(*args), zip(xs[:-1], us, range(N)))) + JN + +def get_derivatives(model : DiscreteControlModel, x_bar : list, u_bar : list): + """Compute all the derivatives used in the model. + + The return type should match the meaning in (Her24, Subequation 17.8) and in the online documentation. + + - ``c`` should be a list of length :math:`N+1` + - ``c_x`` should be a list of length :math:`N+1` + - ``c_xx`` should be a list of length :math:`N+1` + - ``c_u`` should be a list of length :math:`N` + - ``c_uu`` should be a list of length :math:`N` + - ``c_ux`` should be a list of length :math:`N` + - ``A`` should be a list of length :math:`N` + - ``B`` should be a list of length :math:`N` + + Use the model to compute these terms. For instance, this will compute the first terms ``A[0]`` and ``B[0]``:: + + A0, B0 = model.f_jacobian(x_bar[0], u_bar[0], 0) + + Meanwhile, to compute the first terms of the cost-functions you should use:: + + c[0], c_x[0], c_u[0], c_xx[0], c_ux[0], c_uu[0] = model.cost.c(x_bar[0], u_bar[0], k=0, compute_gradients=True) + + :param model: The model to use when computing the derivatives of the cost + :param x_bar: The nominal state-trajectory + :param u_bar: The nominal action-trajectory + :return: Lists of all derivatives computed around the nominal trajectory (see the lecture notes). + """ + N = len(u_bar) + """ Compute A_k, B_k (lists of matrices of length N) as the jacobians of the dynamics. To do so, + recall from the online documentation that: + x, f_x, f_u = model.f(x, u, k, compute_jacobian=True) + """ + A = [None]*N + B = [None]*N + c = [None] * (N+1) + c_x = [None] * (N + 1) + c_xx = [None] * (N + 1) + + c_u = [None] * (N+1) + c_ux = [None] * (N + 1) + c_uu = [None] * (N + 1) + # Now update each entry correctly (i.e., ensure there are no None elements left). + # TODO: 4 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + """ Compute derivatives of the cost function. For terms not including u these should be of length N+1 + (because of gN!), for the other lists of length N + recall model.cost.c has output: + c[i], c_x[i], c_u[i], c_xx[i], c_ux[i], c_uu[i] = model.cost.c(x, u, i, compute_gradients=True) + """ + # TODO: 2 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + # Concatenate the derivatives associated with the last time point N. + cN, c_xN, c_xxN = model.cost.cN(x_bar[N], compute_gradients=True) + # TODO: 3 lines missing. + raise NotImplementedError("Update c, c_x and c_xx with the terminal terms.") + return A, B, c, c_x, c_u, c_xx, c_ux, c_uu + +def forward_pass(model : DiscreteControlModel, x_bar : list, u_bar : list, L : list, l : list, alpha=1.0): + r"""Simulates the effect of the controller on the model + + We assume the system starts in :math:`\mathbf{x}_0 = \bar {\mathbf x}_0`, and then simulate the effect of + generating actions using the closed-loop policy + + .. math:: + + \mathbf{u}_k = \bar {\mathbf u}_k + \alpha \mathbf{l}_k + L_k (\mathbf{x}_k - \bar { \mathbf x}_k) + + (see (Her24, eq. (17.16))). + + :param model: The model used to compute the dynamics. + :param x_bar: A nominal list of states + :param u_bar: A nominal list of actions (not used by the method) + :param L: A list of control matrices :math:`L_k` + :param l: A list of control vectors :math:`\mathbf{l}_k` + :param alpha: The linesearch parameter. + :return: A list of length :math:`N+1` of simulated states and a list of length :math:`N` of simulated actions. + """ + N = len(u_bar) + x = [None] * (N+1) + u_star = [None] * N + x[0] = x_bar[0].copy() + + for i in range(N): + r""" Compute using (Her24, eq. (17.16)) + u_{i} = ... + """ + # TODO: 1 lines missing. + raise NotImplementedError("u_star[i] = ....") + """ Remember to compute + x_{i+1} = f_k(x_i, u_i^*) + here: + """ + # TODO: 1 lines missing. + raise NotImplementedError("x[i+1] = ...") + return x, u_star diff --git a/irlc/ex07/ilqr_agent.py b/irlc/ex07/ilqr_agent.py new file mode 100644 index 0000000..9280fc7 --- /dev/null +++ b/irlc/ex07/ilqr_agent.py @@ -0,0 +1,56 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +from irlc.ex06.model_rendevouz import RendevouzEnvironment +from irlc.ex07.ilqr_rendovouz_basic import ilqr +from irlc import train +from irlc import Agent +import numpy as np + +class ILQRAgent(Agent): + def __init__(self, env, discrete_model, N=250, ilqr_iterations=10, use_ubar=False, use_linesearch=True): + super().__init__(env) + self.dt = discrete_model.dt + # x0 = discrete_model.reset() + x0,_ = env.reset() + x0 = np.asarray(x0) # Get the initial state. We will take this from the environment. + xs, us, self.J_hist, L, l = ilqr(discrete_model, N, x0, n_iter=ilqr_iterations, use_linesearch=use_linesearch) + self.ubar = us + self.xbar = xs + self.L = L + self.l = l + self.use_ubar = use_ubar # Should policy use open-loop u-bar (suboptimal) or closed-loop L_k, l_k? + + def pi(self, x, k, info=None): + if self.use_ubar: + u = self.ubar[k] + else: + if k >= len(self.ubar): + print(k, len(self.ubar)) + k = len(self.ubar)-1 + # See (Her24, eq. (17.16)) + # TODO: 1 lines missing. + raise NotImplementedError("Generate action using the control matrices.") + return u + +def solve_rendevouz(): + env = RendevouzEnvironment() + N = int(env.Tmax / env.dt) + agent = ILQRAgent(env, env.discrete_model, N=N) + stats, trajectories = train(env, agent, num_episodes=1, return_trajectory=True) + env.close() + return stats, trajectories, agent + +if __name__ == "__main__": + from irlc.ex07.ilqr_rendovouz_basic import plot_vehicles + import matplotlib.pyplot as plt + stats, trajectories, agent = solve_rendevouz() + t =trajectories[0].state + xb = agent.xbar + plot_vehicles(t[:,0], t[:,1], t[:,2], t[:,3], linespec=':', legend=("RK4 policy simulation", "RK4 policy simulation")) + plot_vehicles(xb[:,0], xb[:,1], xb[:,2], xb[:,3], linespec='-') + plt.legend() + plt.show() diff --git a/irlc/ex07/ilqr_cartpole.py b/irlc/ex07/ilqr_cartpole.py new file mode 100644 index 0000000..d2463a5 --- /dev/null +++ b/irlc/ex07/ilqr_cartpole.py @@ -0,0 +1,83 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import matplotlib.pyplot as plt +import numpy as np +from irlc.ex05.model_cartpole import GymSinCosCartpoleEnvironment +import time +from irlc.ex07.ilqr_rendovouz_basic import ilqr +from irlc import savepdf + +# Number of steps. +N = 100 +def cartpole(use_linesearch): + env = GymSinCosCartpoleEnvironment(render_mode='human') + x0, info = env.reset() + xs, us, J_hist, L, l = ilqr(env.discrete_model, N, x0, n_iter=300, use_linesearch=use_linesearch) + plot_cartpole(env, xs, us, use_linesearch=use_linesearch) + +def plot_cartpole(env, xs, us, J_hist=None, use_linesearch=True): + animate(xs, env) + env.close() + # Transform actions/states using build-in functions. + def gapply(f, xm): + usplit = np.split(xm, len(xm)) + u2 = [f(u.flat) for u in usplit] + us = np.stack(u2) + return us + + us = gapply(env.discrete_model.phi_u_inv, us) + xs = gapply(env.discrete_model.phi_x_inv, xs) + + t = np.arange(N + 1) * env.dt + x = xs[:, 0] + theta = np.unwrap(xs[:, 2]) # Makes for smoother plots. + theta_dot = xs[:, 3] + pdf_ex = '_linesearch' if use_linesearch else '' + ev = 'cartpole_' + + plt.plot(theta, theta_dot) + plt.xlabel("theta (rad)") + plt.ylabel("theta_dot (rad/s)") + plt.title("Orientation Phase Plot") + plt.grid() + savepdf(f"{ev}theta{pdf_ex}") + plt.show() + + _ = plt.plot(t[:-1], us) + _ = plt.xlabel("time (s)") + _ = plt.ylabel("Force (N)") + _ = plt.title("Action path") + plt.grid() + savepdf(f"{ev}action{pdf_ex}") + plt.show() + + _ = plt.plot(t, x) + _ = plt.xlabel("time (s)") + _ = plt.ylabel("Position (m)") + _ = plt.title("Cart position") + plt.grid() + savepdf(f"{ev}position{pdf_ex}") + plt.show() + if J_hist is not None: + _ = plt.plot(J_hist) + _ = plt.xlabel("Iteration") + _ = plt.ylabel("Total cost") + _ = plt.title("Total cost-to-go") + plt.grid() + savepdf(f"{ev}J{pdf_ex}") + plt.show() + +def animate(xs0, env): + render = True + if render: + for i in range(2): + render_(xs0, env.discrete_model) + time.sleep(1) + # env.viewer.close() + +def render_(xs, env): + for i in range(xs.shape[0]): + x = xs[i] + env.render(x=x) + +if __name__ == "__main__": + cartpole(use_linesearch=True) diff --git a/irlc/ex07/ilqr_cartpole_agent.py b/irlc/ex07/ilqr_cartpole_agent.py new file mode 100644 index 0000000..cd82bd2 --- /dev/null +++ b/irlc/ex07/ilqr_cartpole_agent.py @@ -0,0 +1,43 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc.ex07.ilqr_agent import ILQRAgent +from irlc import train +from irlc import savepdf +import matplotlib.pyplot as plt +from irlc.ex05.model_cartpole import GymSinCosCartpoleEnvironment + +def cartpole_experiment(N=12, use_linesearch=True, figex="", animate=True): + np.random.seed(2) + Tmax = .9 + dt = Tmax/N + env = GymSinCosCartpoleEnvironment(dt=dt, Tmax=Tmax, supersample_trajectory=True, render_mode='human' if animate else None) + agent = ILQRAgent(env, env.discrete_model, N=N, ilqr_iterations=200, use_linesearch=use_linesearch) + stats, trajectories = train(env, agent, num_episodes=1, return_trajectory=True) + + agent.use_ubar = True + stats2, trajectories2 = train(env, agent, num_episodes=1, return_trajectory=True) + env.close() + + xb = agent.xbar + tb = np.arange(N+1)*dt + plt.figure(figsize=(8,6)) + F = 3 + plt.plot(trajectories[0].time, trajectories[0].state[:,F], 'k-', label='Closed-loop $\\pi$') + plt.plot(trajectories2[0].time, trajectories2[0].state[:,F], '-', label='Open-loop $\\bar{u}_k$') + + plt.plot(tb, xb[:,F], '.-', label="iLQR rediction $\\bar{x}_k$") + plt.xlabel("Time/seconds") + plt.ylabel("$\cos(\\theta)$") + plt.title(f"Cartpole environment $T={N}$") + + plt.grid() + plt.legend() + ev = "pendulum" + savepdf(f"irlc_cartpole_theta_N{N}_{use_linesearch}{figex}") + plt.show() + +def plt_cartpole(): + cartpole_experiment(N=50, use_linesearch=True, animate=True) + +if __name__ == '__main__': + plt_cartpole() diff --git a/irlc/ex07/ilqr_pendulum.py b/irlc/ex07/ilqr_pendulum.py new file mode 100644 index 0000000..5bcc82e --- /dev/null +++ b/irlc/ex07/ilqr_pendulum.py @@ -0,0 +1,68 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc.ex04.model_pendulum import DiscreteSinCosPendulumModel +import matplotlib.pyplot as plt +import time +from irlc.ex07.ilqr_rendovouz_basic import ilqr +from irlc import savepdf + +def pendulum(use_linesearch): + print("> Using iLQR to solve Pendulum swingup task. Using linesearch?", use_linesearch) + dt = 0.02 + model = DiscreteSinCosPendulumModel(dt, cost=None) + N = 250 + # This rather clunky line gets us the initial state; we transform the bound by the variable transformation. + x0 = np.asarray(model.phi_x(model.continuous_model.x0_bound().low)) + + n_iter = 200 # Use 200 iLQR iterations. + # xs, us, J_hist, L, l = ilqr(model, ...) Write a function call like this, but with the correct parametesr + # TODO: 1 lines missing. + raise NotImplementedError("Call iLQR here (see hint above).") + + render = True + if render: + for i in range(2): + render_(xs, model) + time.sleep(2) # Sleep for two seconds between simulations. + model.close() + xs = np.asarray([model.phi_x_inv(x) for x, u in zip(xs, us)]) # Convert to Radians. We use the build-in functions to change coordinates. + xs, us = np.asarray(xs), np.asarray(us) + + t = np.arange(N) * dt + theta = np.unwrap(xs[:, 0]) # Makes for smoother plots. + theta_dot = xs[:, 1] + + pdf_ex = '_linesearch' if use_linesearch else '' + stitle = "(using linesearch)" if use_linesearch else "(not using linesearch) " + ev = 'pendulum_' + _ = plt.plot(theta, theta_dot) + _ = plt.xlabel("$\\theta$ (rad)") + _ = plt.ylabel("$d\\theta/dt$ (rad/s)") + _ = plt.title(f"Phase Plot {stitle}") + plt.grid() + savepdf(f"{ev}theta{pdf_ex}") + plt.show() + + _ = plt.plot(t, us) + _ = plt.xlabel("time (s)") + _ = plt.ylabel("Force (N)") + _ = plt.title(f"Action path {stitle}") + plt.grid() + savepdf(f"{ev}action{pdf_ex}") + plt.show() + + _ = plt.plot(J_hist) + _ = plt.xlabel("Iteration") + _ = plt.ylabel("Total cost") + _ = plt.title(f"Total cost-to-go {stitle}") + plt.grid() + savepdf(f"{ev}J{pdf_ex}") + plt.show() + +def render_(xs, env): + for i in range(xs.shape[0]): + env.render(xs[i]) + +if __name__ == "__main__": + pendulum(use_linesearch=False) + pendulum(use_linesearch=True) diff --git a/irlc/ex07/ilqr_pendulum_agent.py b/irlc/ex07/ilqr_pendulum_agent.py new file mode 100644 index 0000000..a52b023 --- /dev/null +++ b/irlc/ex07/ilqr_pendulum_agent.py @@ -0,0 +1,63 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc.ex04.model_pendulum import GymSinCosPendulumEnvironment +from irlc.ex07.ilqr_agent import ILQRAgent +from irlc import train +from irlc import savepdf +import matplotlib.pyplot as plt + +Tmax = 3 +def pen_experiment(N=12, use_linesearch=True,figex="", animate=True): + dt = Tmax / N + env = GymSinCosPendulumEnvironment(dt, Tmax=Tmax, supersample_trajectory=True, render_mode="human" if animate else None) + agent = ILQRAgent(env, env.discrete_model, N=N, ilqr_iterations=200, use_linesearch=use_linesearch) + + stats, trajectories = train(env, agent, num_episodes=1, return_trajectory=True) + + agent.use_ubar = True + stats2, trajectories2 = train(env, agent, num_episodes=1, return_trajectory=True) + env.close() + + plot_pendulum_trajectory(env, trajectories[0], label='Closed-loop $\\pi$') + xb = agent.xbar + tb = np.arange(N+1)*dt + plt.figure(figsize=(12, 6)) + plt.plot(trajectories[0].time, trajectories[0].state[:,1], '-', label='Closed-loop $\\pi(x_k)$') + + plt.plot(trajectories2[0].time, trajectories2[0].state[:,1], '-', label='Open-loop $\\bar{u}_k$') + plt.plot(tb, xb[:,1], 'o-', label="iLQR prediction $\\bar{x}_k$") + plt.grid() + plt.legend() + ev = "pendulum" + savepdf(f"irlc_pendulum_theta_N{N}_{use_linesearch}{figex}") + plt.show() + + ## Plot J + plt.figure(figsize=(6, 6)) + plt.semilogy(agent.J_hist, 'k.-') + plt.xlabel("iLQR Iterations") + plt.ylabel("Cost function estimate $J$") + # plt.title("Last value: {") + plt.grid() + savepdf(f"irlc_pendulum_J_N{N}_{use_linesearch}{figex}") + plt.show() + +def plot_pendulum_trajectory(env, traj, style='k.-', label=None, action=False, **kwargs): + if action: + y = traj.action[:, 0] + y = np.clip(y, env.action_space.low[0], env.action_space.high[0]) + else: + y = traj.state[:, 1] + + plt.plot(traj.time[:-1] if action else traj.time, y, style, label=label, **kwargs) + plt.xlabel("Time/seconds") + if action: + plt.ylabel("Torque $u$") + else: + plt.ylabel("$\cos(\\theta)$") + plt.grid() + pass + +N = 50 +if __name__ == "__main__": + pen_experiment(N=N, use_linesearch=True) diff --git a/irlc/ex07/ilqr_rendevoyz.py b/irlc/ex07/ilqr_rendevoyz.py new file mode 100644 index 0000000..8cd6cdc --- /dev/null +++ b/irlc/ex07/ilqr_rendevoyz.py @@ -0,0 +1,5 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex07.ilqr_rendovouz_basic import plot_rendevouz + +if __name__ == "__main__": + plot_rendevouz(use_linesearch=True) diff --git a/irlc/ex07/ilqr_rendovouz_basic.py b/irlc/ex07/ilqr_rendovouz_basic.py new file mode 100644 index 0000000..255103b --- /dev/null +++ b/irlc/ex07/ilqr_rendovouz_basic.py @@ -0,0 +1,97 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +import matplotlib.pyplot as plt +from irlc import savepdf +from irlc.ex07.ilqr import ilqr_basic, ilqr_linesearch +from irlc.ex06.model_rendevouz import DiscreteRendevouzModel +from irlc.ex04.control_environment import ControlEnvironment +from irlc.ex04.discrete_control_model import DiscreteControlModel + + +def ilqr(model : DiscreteControlModel, N, x0, n_iter, use_linesearch, verbose=True): + if not use_linesearch: + xs, us, J_hist, L, l = ilqr_basic(model, N, x0, n_iterations=n_iter,verbose=verbose) + else: + xs, us, J_hist, L, l = ilqr_linesearch(model, N, x0, n_iterations=n_iter, tol=1e-6,verbose=verbose) + xs, us = np.stack(xs), np.stack(us) + return xs, us, J_hist, L, l + +def plot_vehicles(x_0, y_0, x_1, y_1, linespec='-', legend=("Vehicle 1", "Vehicle 2")): + _ = plt.title("Trajectory of the two omnidirectional vehicles") + _ = plt.plot(x_0, y_0, "r"+linespec, label=legend[0]) + _ = plt.plot(x_1, y_1, "b"+linespec, label=legend[1]) + +Tmax = 20 +def solve_rendovouz(use_linesearch=False): + model = DiscreteRendevouzModel() + x0 = np.asarray(model.continuous_model.x0_bound().low) # Starting position + N = int(Tmax/model.dt) + return ilqr(model, N, x0, n_iter=10, use_linesearch=use_linesearch), model + +def plot_rendevouz(use_linesearch=False): + (xs, us, J_hist, _, _), env = solve_rendovouz(use_linesearch=use_linesearch) + N = int(Tmax / env.dt) + dt = env.dt + x_0 = xs[:, 0] + y_0 = xs[:, 1] + x_1 = xs[:, 2] + y_1 = xs[:, 3] + x_0_dot = xs[:, 4] + y_0_dot = xs[:, 5] + x_1_dot = xs[:, 6] + y_1_dot = xs[:, 7] + + pdf_ex = '_linesearch' if use_linesearch else '' + ev = 'rendevouz_' + plot_vehicles(x_0, y_0, x_1, y_1, linespec='-', legend=("Vehicle 1", "Vehicle 2")) + plt.legend() + savepdf(f'{ev}trajectory{pdf_ex}') + plt.show() + + t = np.arange(N + 1) * dt + _ = plt.plot(t, x_0, "r") + _ = plt.plot(t, x_1, "b") + _ = plt.xlabel("Time (s)") + _ = plt.ylabel("x (m)") + _ = plt.title("X positional paths") + _ = plt.legend(["Vehicle 1", "Vehicle 2"]) + savepdf(f'{ev}vehicles_x_pos{pdf_ex}') + plt.show() + + _ = plt.plot(t, y_0, "r") + _ = plt.plot(t, y_1, "b") + _ = plt.xlabel("Time (s)") + _ = plt.ylabel("y (m)") + _ = plt.title("Y positional paths") + _ = plt.legend(["Vehicle 1", "Vehicle 2"]) + savepdf(f'{ev}vehicles_y_pos{pdf_ex}') + plt.show() + + _ = plt.plot(t, x_0_dot, "r") + _ = plt.plot(t, x_1_dot, "b") + _ = plt.xlabel("Time (s)") + _ = plt.ylabel("x_dot (m)") + _ = plt.title("X velocity paths") + _ = plt.legend(["Vehicle 1", "Vehicle 2"]) + savepdf(f'{ev}vehicles_vx{pdf_ex}') + plt.show() + + _ = plt.plot(t, y_0_dot, "r") + _ = plt.plot(t, y_1_dot, "b") + _ = plt.xlabel("Time (s)") + _ = plt.ylabel("y_dot (m)") + _ = plt.title("Y velocity paths") + _ = plt.legend(["Vehicle 1", "Vehicle 2"]) + savepdf(f'{ev}vehicles_vy{pdf_ex}') + plt.show() + + _ = plt.plot(J_hist) + _ = plt.xlabel("Iteration") + _ = plt.ylabel("Total cost") + _ = plt.title("Total cost-to-go") + savepdf(f'{ev}cost_to_go{pdf_ex}') + plt.show() + + +if __name__ == "__main__": + plot_rendevouz(use_linesearch=False) diff --git a/irlc/ex07/linearization_agent.py b/irlc/ex07/linearization_agent.py new file mode 100644 index 0000000..e069161 --- /dev/null +++ b/irlc/ex07/linearization_agent.py @@ -0,0 +1,67 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +from irlc.ex06.dlqr import LQR +from irlc import Agent +from irlc.ex05.model_cartpole import GymSinCosCartpoleEnvironment +from irlc import train, savepdf +import matplotlib.pyplot as plt +import numpy as np +from irlc.ex04.control_environment import ControlEnvironment +from irlc.ex04.discrete_control_model import DiscreteControlModel + +class LinearizationAgent(Agent): + """ Implement the simple linearization procedure described in (Her24, Algorithm 23) which expands around a single fixed point. """ + def __init__(self, env: ControlEnvironment, model : DiscreteControlModel, xbar=None, ubar=None): + self.model = model + N = 50 # Plan on this horizon. The control matrices will converge fairly quickly. + """ Define A, B, d as the list of A/B matrices here. I.e. x[t+1] = A x[t] + B u[t] + d. + You should use the function model.f to do this, which has build-in functionality to compute Jacobians which will be equal to A, B. + It is important that you linearize around xbar, ubar. See (Her24, Section 17.1) for further details. """ + # TODO: 4 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + Q, q, R = self.model.cost.Q, self.model.cost.q, self.model.cost.R + """ Define self.L, self.l here as the (lists of) control matrices. """ + # TODO: 1 lines missing. + raise NotImplementedError("Compute control matrices L, l here using LQR(...)") + super().__init__(env) + + def pi(self, x, k, info=None): + """ + Compute the action here using u_k = L_0 x_k + l_0. The control matrix/vector L_0 can be found as the output from LQR, i.e. + L_0 = L[0] and l_0 = l[0]. + + The reason we use L_0, l_0 (and not L_k, l_k) is because the LQR problem itself is an approximation of the true dynamics + and this controller will be able to balance the pendulum for an infinite amount of time. + """ + # TODO: 1 lines missing. + raise NotImplementedError("Compute current action here") + return u + + +def get_offbalance_cart(waiting_steps=30, sleep_time=0.1): + env = GymSinCosCartpoleEnvironment(Tmax=3, render_mode='human') + env.reset() + import time + time.sleep(sleep_time) + env.state = env.discrete_model.x_upright + env.state[-1] = 0.01 # a bit of angular speed. + for _ in range(waiting_steps): # Simulate the environment for 30 steps to get things out of balance. + env.step(1) + time.sleep(sleep_time) + return env + + +if __name__ == "__main__": + np.random.seed(42) # I don't think these results are seed-dependent but let's make sure. + from irlc import plot_trajectory + env = get_offbalance_cart(4) # Simulate for 4 seconds to get the cart off-balance. Same idea as PID control. + agent = LinearizationAgent(env, model=env.discrete_model, xbar=env.discrete_model.x_upright, ubar=env.action_space.sample()*0) + _, trajectories = train(env, agent, num_episodes=1, return_trajectory=True, reset=False) # Note reset=False to maintain initial conditions. + plot_trajectory(trajectories[0], env, xkeys=[0,2, 3], ukeys=[0]) + env.close() + savepdf("linearization_cartpole") + plt.show() diff --git a/irlc/ex08/__init__.py b/irlc/ex08/__init__.py new file mode 100644 index 0000000..2851411 --- /dev/null +++ b/irlc/ex08/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 8.""" diff --git a/irlc/ex08/__pycache__/__init__.cpython-311.pyc b/irlc/ex08/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0cf56d19154df1c345a7e784ebd4018c06211464 GIT binary patch literal 232 zcmZ3^%ge>Uz`$UU-<$T5fq~&Mhy%lnP{wDFlIaX73{eazjKK_=OjU*<8JWcjDVas7 z$tC$kl?uuEc_oRNdBqAP8L0}X6{$tZnZ>Ea3TgR83gxM(*$NhVewvK8*yH0<@{{A^ zS2BDCnf%K}KO;XkRllS(BURreKe;qFHLs*tKQlK+-@wSk)S$SeGzB73l#{HVT47+J zA0MBYmst`YuUAm{i^C>2KczG$)vkz*fq?<!)?z^h28IvJjEsyA7|bugP!S6Q0|Nly C{6P)? literal 0 HcmV?d00001 diff --git a/irlc/ex08/__pycache__/bandits.cpython-311.pyc b/irlc/ex08/__pycache__/bandits.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c02bb467c268e6303ac30d6dbf56ff684aeef2ec GIT binary patch literal 12883 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 ZASTM_#rS~%gVd8}3}gJjfR6-+F95Wp5>5aB literal 0 HcmV?d00001 diff --git a/irlc/ex08/__pycache__/simple_agents.cpython-311.pyc b/irlc/ex08/__pycache__/simple_agents.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..07b42a3efde578976cf2c50196bdb81b6934b371 GIT binary patch literal 3703 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 J0<$DI?g8_)qACCY literal 0 HcmV?d00001 diff --git a/irlc/ex08/bandit_example.py b/irlc/ex08/bandit_example.py new file mode 100644 index 0000000..fa5412b --- /dev/null +++ b/irlc/ex08/bandit_example.py @@ -0,0 +1,27 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +import matplotlib.pyplot as plt + +if __name__ == "__main__": + from irlc import Agent, train, savepdf + from irlc.ex08.bandits import StationaryBandit + bandit = StationaryBandit(k=10) # A 10-armed bandit + agent = Agent(bandit) # Recall the agent takes random actions + _, trajectories = train(bandit, agent, return_trajectory=True, num_episodes=1, max_steps=500) + plt.plot(trajectories[0].reward) + plt.xlabel("Time step") + plt.ylabel("Reward per time step") + savepdf("dumbitA") + plt.show() + + agent = Agent(bandit) # Recall the agent takes random actions + for i in range(10): + _, trajectories = train(bandit, agent, return_trajectory=True, num_episodes=1, max_steps=500) + regret = np.asarray([r['average_regret'] for r in trajectories[0].env_info[1:]]) + cum_regret = np.cumsum(regret) + plt.plot(cum_regret, label=f"Episode {i}") + plt.legend() + plt.xlabel("Time step") + plt.ylabel("Accumulated Regret") + savepdf("dumbitB") + plt.show() diff --git a/irlc/ex08/bandits.py b/irlc/ex08/bandits.py new file mode 100644 index 0000000..7b3b957 --- /dev/null +++ b/irlc/ex08/bandits.py @@ -0,0 +1,216 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import numpy as np +import matplotlib.pyplot as plt +from gymnasium import Env +from gymnasium.spaces import Discrete +from irlc import train +from tqdm import tqdm +import sys +from irlc import cache_read, cache_write, cache_exists + +class BanditEnvironment(Env): + r""" + A helper class for defining bandit problems similar to e.g. the 10-armed testbed discsused in (SB18). + We are going to implement the bandit problems as greatly simplfied gym environments, as this will allow us to + implement the bandit agents as the familiar ``Agent``. I hope this way of doing it will make it clearer that bandits + are in fact a sort of reinforcement learning method. + + The following code shows an example of how to use a bandit environment: + + .. runblock:: pycon + + >>> from irlc.ex08.bandits import StationaryBandit + >>> env = StationaryBandit(k=10) # 10-armed testbed. + >>> env.reset() # Reset env.q_star + >>> s, r, _, _, info = env.step(3) + >>> print(f"The reward we got from taking arm a=3 was {r=}") + + """ + def __init__(self, k : int): + r""" + Initialize a bandit problem. The observation space is given a dummy value since bandit problems of the sort + (SB18) discuss don't have observations. + + :param k: The number of arms. + """ + super().__init__() + self.observation_space = Discrete(1) # Dummy observation space with a single observation. + self.action_space = Discrete(k) # The arms labelled 0,1,...,k-1. + self.k = k # Number of arms + + def reset(self): + """ + Use this function to reset the all internal parameters of the environment and get ready for a new episode. + In the (SB18) 10-armed bandit testbed, this would involve resetting the expected return + + .. math:: + q^*_a + + The function must return a dummy state and info dictionary to agree with the gym ``Env`` class, but their values are + irrelevant + + :return: + - s - a state, for instance 0 + - info - the info dictionary, for instance {} + """ + raise NotImplementedError("Implement the reset method") + + def bandit_step(self, a): + """ + This helper function simplify the definition of the environments ``step``-function. + + Given an action :math:`r`, this function computes the reward obtained by taking that action :math:`r_t` + and the average regret. This is defined as the expected reward we miss out on by taking the potentially suboptimal action :math:`a` + and is defined as: + + .. math:: + \max_{a'} q^*_{a'} - q_a + + Once implemented, the reward and regret enters into the ``step`` function as follows: + + .. runblock:: pycon + + >>> from irlc.ex08.bandits import StationaryBandit + >>> env = StationaryBandit(k=4) # 4-armed testbed. + >>> env.reset() # Reset all parameters. + >>> _, r, _, _, info = env.step(2) # Take action a=2 + >>> print(f"Reward from a=2 was {r=}, the regret was {info['average_regret']=}") + + :param a: The current action we take + :return: + - r - The reward we thereby incur + - regret - The average regret incurred by taking this action (0 for an optimal action) + """ + reward = 0 # Compute the reward associated with arm a + regret = 0 # Compute the regret, by comparing to the optimal arms reward. + return reward, regret + + def step(self, action): + """ + This function is automatically defind and you do not have to edit it. + In a bandit environment, the step function is simplified greatly since there are no + states to keep track on. It should simply return the reward incurred by the action ``a`` + and (for convenience) also returns the average regret in the ``info``-dictionary. + + :param action: The current action we take :math:`a_t` + :return: + - next_state - This is always ``None`` + - reward - The reward obtained by taking the given action. In (SB18) this is defined as :math:`r_t` + - terminated - Always ``False``. Bandit problems don't terminate. + - truncated - Always ``False`` + - info - For convenience, this includes the average regret (used by the plotting methods) + + """ + reward, average_regret = self.bandit_step(action) + info = {'average_regret': average_regret} + return None, reward, False, False, info + +class StationaryBandit(BanditEnvironment): + """ + Implement the 'stationary bandit environment' which is described in (SB18, Section 2.3) + and used as a running example throughout the chapter. + + We will implement a version with a constant mean offset (q_star_mean), so that + + q* = x + q_star_mean, x ~ Normal(0,1) + + q_star_mean can just be considered to be zero at first. + """ + def __init__(self, k, q_star_mean=0): + super().__init__(k) + self.q_star_mean = q_star_mean + + def reset(self): + """ Set q^*_k = N(0,1) + mean_value. The mean_value is 0 in most examples. I.e., implement the 10-armed testbed environment. """ + self.q_star = np.random.randn(self.k) + self.q_star_mean + self.optimal_action = np.argmax(self.q_star) # Optimal action is the one with the largest q^*-value. + return 0, {} # The reset method in a gym Env must return a (dummy) state and a dictionary. + + def bandit_step(self, a): + """ Return the reward/regret for action a for the simple bandit. Use self.q_star (see reset-function above). + To implement it, implement the reward (see the description of the 10-armed testbed for more information. + How is it computed from from q^*_k?) and also compute the regret. + + As a small hint, since we are computing the average regret, it will in fact be the difference between the + value of q^* corresponding to the current arm, and the q^* value for the optimal arm. + Remember it is 0 if the optimal action is selected. + """ + # TODO: 2 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + # Actual logic goes here. Use self.q_star[a] to get mean reward and np.random.randn() to generate random numbers. + return reward, regret + + def __str__(self): + return f"{type(self).__name__}_{self.q_star_mean}" + +""" +Helper function for running a bunch of bandit experiments and plotting the results. + +The function will run the agents in 'agents' (a list of bandit agents) +on the bandit environment 'bandit' and plot the result. + +Each agent will be evaluated for num_episodes episodes, and one episode consist of 'steps' steps. +However, to speed things up you can use cache, and the bandit will not be evaluated for more than +'max_episodes' over all cache runs. + +""" +def eval_and_plot(bandit, agents, num_episodes=2000, max_episodes=2000, steps=1000, labels=None, use_cache=True): + if labels is None: + labels = [str(agent) for agent in agents] + + f, axs = plt.subplots(nrows=3, ncols=1) + f.set_size_inches(10,7) + (ax1, ax2, ax3) = axs + for i,agent in enumerate(agents): + rw, oa, regret, num_episodes = run_agent(bandit, agent, episodes=num_episodes, max_episodes=max_episodes, steps=steps, use_cache=use_cache) + ax1.plot(rw, label=labels[i]) + ax2.plot(oa, label=labels[i]) + ax3.plot(regret, label=labels[i]) + + for ax in axs: + ax.grid() + ax.set_xlabel("Steps") + + ax1.set_ylabel("Average Reward") + ax2.set_ylabel("% optimal action") + ax3.set_ylabel("Regret $L_t$") + ax3.legend() + f.suptitle(f"Evaluated on {str(bandit)} for {num_episodes} episodes") + +def run_agent(env, agent, episodes=2000, max_episodes=2000, steps=1000, use_cache=False, verbose=True): + """ + Helper function. most of the work involves the cache; the actual training is done by 'train'. + """ + C_regrets_cum_sum, C_oas_sum, C_rewards_sum, C_n_episodes = 0, 0, 0, 0 + if use_cache: + cache = f"cache/{str(env)}_{str(agent)}_{steps}.pkl" + if cache_exists(cache): + print("> Reading from cache", cache) + C_regrets_cum_sum, C_oas_sum, C_rewards_sum, C_n_episodes = cache_read(cache) + + regrets = [] + rewards = [] + cruns = max(0, min(episodes, max_episodes - C_n_episodes)) # Missing runs. + for _ in tqdm(range(cruns), file=sys.stdout, desc=str(agent),disable=not verbose): + stats, traj = train(env, agent, max_steps=steps, verbose=False, return_trajectory=True) + regret = np.asarray([r['average_regret'] for r in traj[0].env_info[1:]]) + regrets.append(regret) + rewards.append(traj[0].reward) + + regrets_cum_sum = C_regrets_cum_sum + oas_sum = C_oas_sum + rewards_sum = C_rewards_sum + episodes = C_n_episodes + if len(regrets) > 0: + regrets_cum_sum += np.cumsum(np.sum(np.stack(regrets), axis=0)) + oas_sum += np.sum(np.stack(regrets) == 0, axis=0) + rewards_sum += np.sum(np.stack(rewards), axis=0) + episodes += cruns + if use_cache and cruns > 0: + cache_write((regrets_cum_sum, oas_sum, rewards_sum, episodes), cache, protocol=4) + return rewards_sum/episodes, oas_sum/episodes, regrets_cum_sum/episodes, episodes diff --git a/irlc/ex08/gradient_agent.py b/irlc/ex08/gradient_agent.py new file mode 100644 index 0000000..34b296b --- /dev/null +++ b/irlc/ex08/gradient_agent.py @@ -0,0 +1,48 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc import savepdf +import numpy as np +import matplotlib.pyplot as plt +from irlc.ex08.bandits import eval_and_plot, StationaryBandit +from irlc import Agent + +class GradientAgent(Agent): + def __init__(self, env, alpha=None, use_baseline=True): + self.k = env.action_space.n + self.alpha = alpha + self.baseline=use_baseline + self.H = np.zeros((self.k,)) + super().__init__(env) + + def Pa(self): + """ This helper method returns the probability distribution P(A=a) of chosing the + arm a as a vector + """ + pi_a = np.exp(self.H) + return pi_a / np.sum(pi_a) + + def pi(self, s, t, info_s=None): + if t == 0: + self.R_bar = 0 # average reward baseline + self.H *= 0 # Reset H to all-zeros. + self.t = t # Sore the current time step. + return np.random.choice( self.k, p=self.Pa() ) + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + # TODO: 9 lines missing. + raise NotImplementedError("Implement function body") + + def __str__(self): + return f"{type(self).__name__}_{self.alpha}_{'baseline' if self.baseline else 'no_baseline'}" + +if __name__ == "__main__": + baseline_bandit = StationaryBandit(k=10, q_star_mean=4) + alphas = [0.1, 0.4] + agents = [GradientAgent(baseline_bandit, alpha=alpha, use_baseline=False) for alpha in alphas] + agents += [GradientAgent(baseline_bandit, alpha=alpha, use_baseline=True) for alpha in alphas] + + labels = [f'Gradient Bandit alpha={alpha}' for alpha in alphas ] + labels += [f'With baseline: Gradient Bandit alpha={alpha}' for alpha in alphas ] + use_cache = False + eval_and_plot(baseline_bandit, agents, max_episodes=2000, num_episodes=100, labels=labels, use_cache=use_cache) + savepdf("gradient_baseline") + plt.show() diff --git a/irlc/ex08/grand_bandit_race.py b/irlc/ex08/grand_bandit_race.py new file mode 100644 index 0000000..ad466aa --- /dev/null +++ b/irlc/ex08/grand_bandit_race.py @@ -0,0 +1,78 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import matplotlib.pyplot as plt +from irlc.ex08.simple_agents import BasicAgent +from irlc.ex08.bandits import StationaryBandit, eval_and_plot +from irlc.ex08.nonstationary import MovingAverageAgent, NonstationaryBandit +from irlc.ex08.gradient_agent import GradientAgent +from irlc.ex08.ucb_agent import UCBAgent +from irlc import savepdf +import time + +if __name__ == "__main__": + print("Ladies and gentlemen. It is time for the graaand bandit race") + def intro(bandit, agents): + print("We are live from the beautiful surroundings where they will compete in:") + print(bandit) + print("Who will win? who will have the most regret? we are about to find out") + print("in a minute after a brief word from our sponsors") + time.sleep(1) + print("And we are back. Let us introduce todays contestants:") + for a in agents: + print(a) + print("And they are off!") + epsilon = 0.1 + alpha = 0.1 + c = 2 + # TODO: 1 lines missing. + raise NotImplementedError("Define the bandit here: bandit1 = ...") + # TODO: 5 lines missing. + raise NotImplementedError("define agents list here") + labels = ["Basic", "Moving avg.", "gradient", "Gradient+baseline", "UCB"] + ''' + Stationary, no offset. Vanilla setting. + ''' + intro(bandit1, agents) + # TODO: 1 lines missing. + raise NotImplementedError("Call eval_and_plot here") + plt.suptitle("Stationary bandit (no offset)") + savepdf("grand_race_1") + plt.show() + ''' + Stationary, but with offset + ''' + print("Whew what a race. Let's get ready to next round:") + # TODO: 1 lines missing. + raise NotImplementedError("Define bandit2 = ... here") + intro(bandit2, agents) + # TODO: 1 lines missing. + raise NotImplementedError("Call eval_and_plot here") + plt.suptitle("Stationary bandit (with offset)") + savepdf("grand_race_2") + plt.show() + ''' + Long (nonstationary) simulations + ''' + print("Whew what a race. Let's get ready to next round which will be a long one.") + # TODO: 1 lines missing. + raise NotImplementedError("define bandit3 here") + intro(bandit3, agents) + # TODO: 1 lines missing. + raise NotImplementedError("call eval_and_plot here") + plt.suptitle("Non-stationary bandit (no offset)") + savepdf("grand_race_3") + plt.show() + + ''' + Stationary, no offset, long run. Exclude stupid bandits. + ''' + agents2 = [] + agents2 += [GradientAgent(bandit1, alpha=alpha, use_baseline=False)] + agents2 += [GradientAgent(bandit1, alpha=alpha, use_baseline=True)] + agents2 += [UCBAgent(bandit1, c=2)] + labels = ["Gradient", "Gradient+baseline", "UCB"] + intro(bandit1, agents2) + # TODO: 1 lines missing. + raise NotImplementedError("Call eval_and_plot here") + plt.suptitle("Stationary bandit (no offset)") + savepdf("grand_race_4") + plt.show() diff --git a/irlc/ex08/nonstationary.py b/irlc/ex08/nonstationary.py new file mode 100644 index 0000000..1128f0a --- /dev/null +++ b/irlc/ex08/nonstationary.py @@ -0,0 +1,62 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import numpy as np +import matplotlib.pyplot as plt +from irlc.ex08.simple_agents import BasicAgent +from irlc.ex08.bandits import StationaryBandit, eval_and_plot +from irlc import savepdf + +class NonstationaryBandit(StationaryBandit): + def __init__(self, k, q_star_mean=0, reward_change_std=0.01): + self.reward_change_std = reward_change_std + super().__init__(k, q_star_mean) + + def bandit_step(self, a): + """ Implement the non-stationary bandit environment (as described in (SB18)). + Hint: use reward_change_std * np.random.randn() to generate a single random number with the given std. + then add one to each coordinate. Remember you have to compute the regret as well, see StationaryBandit for ideas. + (remember the optimal arm will change when you add noise to q_star) """ + # TODO: 2 lines missing. + raise NotImplementedError("Implement function body") + return super().bandit_step(a) + + def __str__(self): + return f"{type(self).__name__}_{self.q_star_mean}_{self.reward_change_std}" + + +class MovingAverageAgent(BasicAgent): + """ + The simple bandit from (SB18, Section 2.4), but with moving average alpha + as described in (SB18, Eqn. (2.3)) + """ + def __init__(self, env, epsilon, alpha): + # TODO: 2 lines missing. + raise NotImplementedError("Implement function body") + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + + def __str__(self): + return f"{type(self).__name__}_{self.epsilon}_{self.alpha}" + + +if __name__ == "__main__": + plt.figure(figsize=(10, 10)) + epsilon = 0.1 + alphas = [0.15, 0.1, 0.05] + + # TODO: 4 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + + labels = [f"Basic agent, epsilon={epsilon}"] + # TODO: 1 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + use_cache = False # Set this to True to use cache (after code works!) + eval_and_plot(bandit, agents, steps=10000, num_episodes=200, labels=labels, use_cache=use_cache) + savepdf("nonstationary_bandits") + plt.show() diff --git a/irlc/ex08/simple_agents.py b/irlc/ex08/simple_agents.py new file mode 100644 index 0000000..8c51d02 --- /dev/null +++ b/irlc/ex08/simple_agents.py @@ -0,0 +1,57 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import numpy as np +import matplotlib.pyplot as plt +from irlc.ex08.bandits import StationaryBandit, eval_and_plot +from irlc import Agent +from irlc import savepdf + +class BasicAgent(Agent): + """ + Simple bandit as described on (SB18, Section 2.4). + """ + def __init__(self, env, epsilon): + super().__init__(env) + self.k = env.action_space.n + self.epsilon = epsilon + + def pi(self, s, t, info=None): + """ Since this is a bandit, s=None and can be ignored, while t refers to the time step in the current episode """ + if t == 0: + # At step 0 of episode. Re-initialize data structure. + # TODO: 2 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + # compute action here + # TODO: 1 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + """ Since this is a bandit, done, s, sp, info_s, info_sp can all be ignored. + From the input arguments you should only use a + """ + # TODO: 2 lines missing. + raise NotImplementedError("Implement function body") + + def __str__(self): + return f"BasicAgent_{self.epsilon}" + +if __name__ == "__main__": + N = 100000 + S = [np.max( np.random.randn(10) ) for _ in range(100000) ] + print( np.mean(S), np.std(S)/np.sqrt(N) ) + + use_cache = False # Set this to True to use cache (after code works!) + from irlc.utils.timer import Timer + timer = Timer(start=True) + R = 100 + steps = 1000 + env = StationaryBandit(k=10) + agents = [BasicAgent(env, epsilon=.1), BasicAgent(env, epsilon=.01), BasicAgent(env, epsilon=0) ] + eval_and_plot(env, agents, num_episodes=100, steps=1000, max_episodes=150, use_cache=use_cache) + savepdf("bandit_epsilon") + plt.show() + print(timer.display()) diff --git a/irlc/ex08/ucb_agent.py b/irlc/ex08/ucb_agent.py new file mode 100644 index 0000000..cd706ab --- /dev/null +++ b/irlc/ex08/ucb_agent.py @@ -0,0 +1,45 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import numpy as np +import matplotlib.pyplot as plt +from irlc.ex08.simple_agents import BasicAgent +from irlc import savepdf +from irlc import Agent + +class UCBAgent(Agent): + def __init__(self, env, c=2): + self.c = c + super().__init__(env) + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + # TODO: 2 lines missing. + raise NotImplementedError("Train agent here") + + def pi(self, s, k, info=None): + if k == 0: + """ Initialize the agent""" + # TODO: 3 lines missing. + raise NotImplementedError("Reset agent (i.e., make it ready to learn in a new episode with a new optimal action)") + # TODO: 1 lines missing. + raise NotImplementedError("Compute (and return) optimal action") + + def __str__(self): + return f"{type(self).__name__}_{self.c}" + +from irlc.ex08.bandits import StationaryBandit, eval_and_plot +if __name__ == "__main__": + """ Reproduce (SB18, Fig. 2.4) comparing UCB agent to epsilon greedy """ + runs, use_cache = 100, False + c = 2 + eps = 0.1 + + steps = 1000 + env = StationaryBandit(k=10) + agents = [UCBAgent(env,c=c), BasicAgent(env, epsilon=eps)] + eval_and_plot(bandit=env, agents=agents, num_episodes=runs, steps=steps, max_episodes=2000, use_cache=use_cache) + savepdf("UCB_agent") + plt.show() diff --git a/irlc/ex09/__init__.py b/irlc/ex09/__init__.py new file mode 100644 index 0000000..e753a4f --- /dev/null +++ b/irlc/ex09/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 9.""" diff --git a/irlc/ex09/__pycache__/__init__.cpython-311.pyc b/irlc/ex09/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..770ea7a94070c53deff8bab18a19af41044593a6 GIT binary patch literal 232 zcmZ3^%ge>Uz`$UU-<$T5fq~&Mhy%lnP{wDFlIaX73{eazjKK_=OjU*<8JWcjDVas7 z$tC$kl?uuEc_oRNdBqAP8L0}X6{$tZnZ>Ea3TgR83gxM(*$S3=ewvK8*yH0<@{{A^ zS2BDCnf%K}KO;XkRllS(BURreKe;qFHLs*tKQlK+-@wSk)S$SeGzB73l#{HVT47+R zA0MBYmst`YuUAm{i^C>2KczG$)vkz*fq?<!)?z^h28IvJjEsyA7|bugP!S6Q0|Nlz CxIqvA literal 0 HcmV?d00001 diff --git a/irlc/ex09/__pycache__/mdp.cpython-311.pyc b/irlc/ex09/__pycache__/mdp.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6c15cd660ced299b47841c52203bdccca264409 GIT binary patch literal 17378 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 aa0FifqYv^7EK(PkB|pe8vcil97ZU*YLraeU literal 0 HcmV?d00001 diff --git a/irlc/ex09/__pycache__/mdp_warmup.cpython-311.pyc b/irlc/ex09/__pycache__/mdp_warmup.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48b1298531f6c58a39f743d79eeb976a262d212c GIT binary patch literal 3718 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 literal 0 HcmV?d00001 diff --git a/irlc/ex09/__pycache__/rl_agent.cpython-311.pyc b/irlc/ex09/__pycache__/rl_agent.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5540d8734650d6d4c0b057b272c9ec92e443e436 GIT binary patch literal 14871 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 AC;$Ke literal 0 HcmV?d00001 diff --git a/irlc/ex09/__pycache__/value_iteration.cpython-311.pyc b/irlc/ex09/__pycache__/value_iteration.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..824c674ad5ff89eefd1e4abc43e24567ffb038f5 GIT binary patch literal 3718 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 literal 0 HcmV?d00001 diff --git a/irlc/ex09/__pycache__/value_iteration_agent.cpython-311.pyc b/irlc/ex09/__pycache__/value_iteration_agent.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2f0351567c0782f22dfae996b4cd3f6b35a9c91f GIT binary patch literal 2758 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 literal 0 HcmV?d00001 diff --git a/irlc/ex09/gambler.py b/irlc/ex09/gambler.py new file mode 100644 index 0000000..c45a7e5 --- /dev/null +++ b/irlc/ex09/gambler.py @@ -0,0 +1,81 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +from irlc import savepdf +import matplotlib.pyplot as plt +from irlc.ex09.value_iteration import value_iteration +from irlc.ex09.mdp import MDP + +class GamblerEnv(MDP): + """ + The gamler problem (see description given in (SB18, Example 4.3)) + + See the MDP class for more information about the methods. In summary: + > the state is the amount of money you have. if state = goal or state = 0 the game ends (use this for is_terminal) + > A are the available actions (a list). Note that these depends on the state; see below or example for details. + > Psr are the transitions (see MDP class for documentation) + """ + def __init__(self, goal=100, p_heads=0.4): + super().__init__(initial_state=goal//2) + self.goal = goal + self.p_heads = p_heads + + def is_terminal(self, state): + """ Implement if the state is terminal (0 or self.goal) """ + # TODO: 1 lines missing. + raise NotImplementedError("Return true only if state is terminal.") + + def A(self, s): + """ Action is the amount you choose to gamle. + You can gamble from 0 and up to the amount of money you have (state), + but not so much you will exceed the goal amount (see (SB18) for details). + In other words, return this as a list, and the number of elements should depend on the state s. """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + + def Psr(self, s, a): + """ Implement transition probabilities here. + the reward is 1 if you win (obtain goal amount) and otherwise 0. Remember the format should + return a dictionary with entries: + > { (sp, r) : probability } + + You can see the small-gridworld example (see exercise description) for an example of how to use this function, + but now you should keep in mind that since you can win (or not) the dictionary you return should have two entries: + one with a probability of self.p_heads (winning) and one with a probability of 1-self.p_heads (loosing). + """ + # TODO: 4 lines missing. + raise NotImplementedError("Implement function body") + return outcome_dict + +def gambler(): + """ + Gambler's problem from (SB18, Example 4.3) + """ + mdp = GamblerEnv(p_heads=0.4) + pi, V = value_iteration(mdp, gamma=1., theta=1e-11) + + V = [V[s] for s in mdp.states] + plt.bar(mdp.states, V) + plt.xlabel('Capital') + plt.ylabel('Value Estimates') + plt.title('Final value function (expected return) vs State (Capital)') + plt.grid() + savepdf("gambler_valuefunction") + plt.show() + + y = [pi[s] for s in mdp.nonterminal_states] + plt.bar(mdp.nonterminal_states, y, align='center', alpha=0.5) + plt.xlabel('Capital') + plt.ylabel('Final policy (stake)') + plt.title('Capital vs Final Policy') + plt.grid() + savepdf("gambler_policy") + plt.show() + + +if __name__ == "__main__": + + gambler() diff --git a/irlc/ex09/mdp.py b/irlc/ex09/mdp.py new file mode 100644 index 0000000..367ebdf --- /dev/null +++ b/irlc/ex09/mdp.py @@ -0,0 +1,303 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import numpy as np +import gymnasium as gym +from gymnasium import Env +from collections import defaultdict +from tqdm import tqdm +import sys + +class MDP: + r""" + This class represents a Markov Decision Process. It defines three main components: + + - The actions available in a given state :math:`A(s)` + - The transition probabilities :math:`p(s', r | s, a)` + - A terminal check to determine if a state :math:`s` is terminal + - A way to specify the initial state: + + - As a single state the MDP always begins in (most common) + - As a general distribution :math:`p(s_0)`. + + In addition to this it allows you to access either + - The set of all states (including terminal states) as ``mdp.states`` + - The set of all non-terminal states as ``mdp.non_terminal_states`` + + .. note:: + The ``states`` and ``non_termianl_states`` are computed lazily. This means that if you don't access them, they won't use memory. + This allows you to specify MDPs with an infinite number of states without running out of memory. + """ + def __init__(self, initial_state=None, verbose=False): + """ + Initialize the MDP. In the case where ``initial_state`` is set to a value :math:`s_0`, the initial state distribution will be + + .. math:: + p(s_0) = 1 + + :param initial_state: An optional initial state. + :param verbose: If ``True``, the class will print out debug information (useful for very large MDPs) + """ + self.verbose=verbose + self.initial_state = initial_state # Starting state s_0 of the MDP. + # The following variables that begin with _ are used to cache computations. The reason why we don't compute them + # up-front is because their computation may be time-consuming and they might not be needed. + self._states = None + self._nonterminal_states = None + self._terminal_states = None + + def is_terminal(self, state) -> bool: + r""" + Determines if a state is terminal (i.e., the environment/model is complete). In (SB18), the terminal + state is written as :math:`s_T`. + + .. runblock:: pycon + + >>> from irlc.gridworld.gridworld_environments import FrozenLake + >>> mdp = FrozenLake().mdp + >>> mdp.is_terminal(mdp.initial_state) # False, obviously. + + + :param state: The state :math:`s` to check + :return: ``True`` if the state is terminal and otherwise ``False``. + """ + return False # Return true if the given state is terminal. + + def Psr(self, state, action) -> dict: + r""" + Represents the transition probabilities: + + .. math:: + P(s', r | s, a) + + When called with state ``state`` and action ``action``, the function returns a dictionary of the form + ``{(s1, r1): p1, (s2, r2): p2, ...}``, so that ``p2`` is the probability of transitioning to ``s2`` (and obtaining + reward ``r2``) given we are in state ``state`` and take action ``action``: + + .. math:: + P(s_2, r_2 | s,a) = p_2 + + An example: + + .. runblock:: pycon + + >>> from irlc.gridworld.gridworld_environments import FrozenLake + >>> mdp = FrozenLake().mdp + >>> transitions = mdp.Psr(mdp.initial_state, 0) # P( ... | s0, a=0) + >>> for (sp, r), p in transitions.items(): + ... print(f"P(s'={sp}, r={r} | s={mdp.initial_state}, a=0) = {p}") + + :param state: The state to compute the transition probabilities in + :param action: The action to compute the transition probabilities in + :return: A dictionary where the keys are state, reward pairs we will transition to, :math:`p(s', r | ...)`, and the values are their probability. + """ + raise NotImplementedError("Return state distribution as a dictionary (see class documentation)") + + def A(self, state) -> list: + """ + Returns a list of actions available in the given state: + + .. math:: + A(s) + + An example to get the actions in the initial state: + + .. runblock:: pycon + + >>> from irlc.gridworld.gridworld_environments import FrozenLake + >>> mdp = FrozenLake().mdp + >>> mdp.A(mdp.initial_state) + + :param state: State to compute the actions in :math:`s` + :return: The list of available actions :math:`\mathcal A(s) = \{0, 1, ..., n-1\}` + """ + raise NotImplementedError("Return set/list of actions in given state A(s) = {a1, a2, ...}") + + def initial_state_distribution(self): + """ + (**Optional**) specify the initial state distribution. Should return a dictionary of the form: + ``{s0: p0, s1: p1, ..., sn: pn}``, in which case :math:`p(S_0 = s_k) = p_k`. + + You will typically not overwrite this function but just set the initial state. In that case the initial state distribution + is deterministic: + + + .. runblock:: pycon + + >>> from irlc.gridworld.gridworld_environments import FrozenLake + >>> mdp = FrozenLake().mdp + >>> mdp.initial_state_distribution() + + + + :return: An initial state distribution as a dictionary, where the keys are states, and the valuse are their probability. + """ + if self.initial_state is not None: + return {self.initial_state: 1} + else: + raise Exception("Either specify the initial state, or implement this method.") + + @property + def nonterminal_states(self): + r""" + The list of non-terminal states, i.e. :math:`\mathcal{S}` in (SB18) + + + .. runblock:: pycon + + >>> from irlc.gridworld.gridworld_environments import FrozenLake + >>> mdp = FrozenLake().mdp + >>> mdp.nonterminal_states + + :return: The list of non-terminal states :math:`\mathcal{S}` + """ + if self._nonterminal_states is None: + self._nonterminal_states = [s for s in self.states if not self.is_terminal(s)] + return self._nonterminal_states + + @property + def states(self): + r""" + The list of all states including terminal ones, i.e. :math:`\mathcal{S}^+` in (SB18). + The terminal states are those where ``is_terminal(state)`` is true. + + .. runblock:: pycon + + >>> from irlc.gridworld.gridworld_environments import FrozenLake + >>> mdp = FrozenLake().mdp + >>> mdp.states + + :return: The list all states :math:`\mathcal{S}^+` + """ + if self._states is None: + next_chunk = set(self.initial_state_distribution().keys()) + all_states = list(next_chunk) + while True: + new_states = set() + for s in tqdm(next_chunk, file=sys.stdout) if self.verbose else next_chunk: + if self.is_terminal(s): + continue + for a in self.A(s): + new_states = new_states | {sp for sp, r in self.Psr(s, a)} + + new_states = [s for s in new_states if s not in all_states] + if len(new_states) == 0: + break + all_states += new_states + next_chunk = new_states + self._states = list(set(all_states)) + + return self._states + + +def rng_from_dict(d): + """ Helper function. If d is a dictionary {x1: p1, x2: p2, ...} then this will sample an x_i with probability p_i """ + w, pw = zip(*d.items()) # seperate w and p(w) + i = np.random.choice(len(w), p=pw) # Required because numpy cast w to array (and w may contain tuples) + return w[i] + +class MDP2GymEnv(Env): + + def A(self, state): + raise Exception("Don't use this function; it is here for legacy reasons") + + def __init__(self, mdp, render_mode=None): + # We ignore this variable in this class, however, the Gridworld environment will check if + # render_mode == "human" and use it to render the environment. See: + # https://younis.dev/blog/render-api/ + self.render_mode = render_mode + self.mdp = mdp + self.state = None + # actions = set + all_actions = set.union(*[set(self.mdp.A(s)) for s in self.mdp.nonterminal_states ]) + n = max(all_actions) - min(all_actions) + 1 + assert isinstance(n, int) + self.action_space = gym.spaces.Discrete(n=n, start=min(all_actions)) + # Make observation space: + states = self.mdp.nonterminal_states + if not hasattr(self, 'observation_space'): + if isinstance(states[0], tuple): + self.observation_space = gym.spaces.Tuple([gym.spaces.Discrete(n+1) for n in np.asarray(states).max(axis=0)]) + else: + print("Could not guess observation space. Set it manually.") + + + def reset(self, seed=None, options=None): + info = {} + if seed is not None: + np.random.seed(seed) + self.action_space.seed(seed) + self.observation_space.seed(seed) + info['seed'] = seed + + ps = self.mdp.initial_state_distribution() + self.state = rng_from_dict(ps) + if self.render_mode == "human": + self.render() + info['mask'] = self._mk_mask(self.state) + return self.state, info + + def step(self, action): + ps = self.mdp.Psr(self.state, action) + self.state, reward = rng_from_dict(ps) + terminated = self.mdp.is_terminal(self.state) + if self.render_mode == "human": + self.render() + info = {'mask': self._mk_mask(self.state)} if not terminated else None + return self.state, reward, terminated, False, info + + def _mk_mask(self, state): + # self.A(state) + mask = np.zeros((self.action_space.n,), dtype=np.int8) + for a in self.mdp.A(state): + mask[a - self.action_space.start] = 1 + return mask + + +class GymEnv2MDP(MDP): + def __init__(self, env): + super().__init__() + self._states = list(range(env.observation_space.n)) + if hasattr(env, 'env'): + env = env.env + self._terminal_states = [] + for s in env.P: + for a in env.P[s]: + for (pr, sp, reward, done) in env.P[s][a]: + if done: + self._terminal_states.append(sp) + + self._terminal_states = set(self._terminal_states) + self.env = env + + def is_terminal(self, state): + return state in self._terminal_states + + def A(self, state): + return list(self.env.P[state].keys()) + + def Psr(self, state, action): + d = defaultdict(float) + for (pr, sp, reward, done) in self.env.P[state][action]: + d[ (sp, reward)] += pr + return d + +if __name__ == '__main__': + """A handful of examples of using the MDP-class in conjunction with a gym environment:""" + env = gym.make("FrozenLake-v1") + mdp = GymEnv2MDP(env) + from irlc.ex09.value_iteration import value_iteration + value_iteration(mdp) + mdp = GymEnv2MDP(gym.make("FrozenLake-v1")) + print("N = ", mdp.nonterminal_states) + print("S = ", mdp.states) + print("Is state 3 terminal?", mdp.is_terminal(3), "is state 11 terminal?", mdp.is_terminal(11)) + state = 0 + print("A(S=0) =", mdp.A(state)) + action = 2 + mdp.Psr(state, action) # Get transition probabilities + for (next_state, reward), Pr in mdp.Psr(state, action).items(): + print(f"P(S'={next_state},R={reward} | S={state}, A={action} ) = {Pr:.2f}") diff --git a/irlc/ex09/mdp_warmup.py b/irlc/ex09/mdp_warmup.py new file mode 100644 index 0000000..aab1ac6 --- /dev/null +++ b/irlc/ex09/mdp_warmup.py @@ -0,0 +1,86 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +from irlc.ex09.mdp import MDP + + +def value_function2q_function(mdp : MDP, s, gamma, v : dict) -> dict: + r"""This helper function converts a value function to an action-value function. + + Given a value-function ``v`` and a state ``s``, this function implements the update: + + .. math:: + + Q(s,a) = \mathbb{E}[r + \gamma * v(s') | s, a] = \sum_{r, s'} (r + \gamma v(s') ) p(s', r| s,a) + + as described in (SB18, ). It should return a dictionary of the form:: + + {a1: Q(s,a1), a2: Q(s,a2), ..., an: Q(s,an)} + + where the actions are keys. You can compute these using ``mdp.A(s)``. When done the following should work:: + + Qs = value_function2q_function(mdp, s, gamma, v) + Qs[a] # This is the Q-value Q(s,a) + + Hints: + + * Remember that ``v[s'] = 0`` if ``s'`` is a terminal state (this is explained in (SB18)). + + :param mdp: An MDP instance. Use this to compute :math:`p(s', r| s,a)` + :param s: A state + :param gamma: The discount factor :math:`\gamma` + :param v: The value function represented as a dictionary. + :return: A dictionary representing :math:`Q` of the form ``{a1: Q(s,a1), a2: Q(s,a2), ..., an: Q(s,an)}`` + """ + # TODO: 1 lines missing. + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + return q_dict + +def expected_reward(mdp : MDP, s, a) -> float: + # TODO: 1 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + return expected_reward + +def q_function2value_function(policy : dict, Q : dict, s) -> float: + # TODO: 1 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + return V_s + +if __name__ == "__main__": + from irlc.gridworld.gridworld_environments import FrozenLake + mdp = FrozenLake(living_reward=0.2).mdp # Get the MDP of this environment. + + ## Part 1: Expected reward + s0 = mdp.initial_state + s0 = (0, 3) # initial state + a = 3 # Go east. + print("Expected reward E[r | s0, a] =", expected_reward(mdp, s=s0, a=0), "should be 0.2") + print("Expected reward E[r | s0, a] =", expected_reward(mdp, s=(1, 2), a=0), "should be 0") + + + ## Part 2 + # First let's create a non-trivial value function + V = {} + for s in mdp.nonterminal_states: + V[s] = s[0] + 2*s[1] + print("Value function is", V) + # Compute the corresponding Q(s,a)-values in state s0: + q_ = value_function2q_function(mdp, s=s0, gamma=0.9, v=V) + print(f"Q-values in {s0=} is", q_) + + ## Part 3 + # Create a non-trivial Q-function for this problem. + Q = {} + for s in mdp.nonterminal_states: + for a in mdp.A(s): + Q[s,a] = s[0] + 2*s[1] - 10*a # The particular values are not important in this example + # Create a policy. In this case pi(a=3) = 0.4. + pi = {0: 0.2, + 1: 0.2, + 2: 0.2, + 3: 0.4} + print(f"Value-function in {s0=} is", q_function2value_function(pi, Q, s=s0)) diff --git a/irlc/ex09/policy_evaluation.py b/irlc/ex09/policy_evaluation.py new file mode 100644 index 0000000..8abbf5e --- /dev/null +++ b/irlc/ex09/policy_evaluation.py @@ -0,0 +1,68 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +from collections import defaultdict +import numpy as np +import matplotlib.pyplot as plt +from irlc.ex09.mdp_warmup import value_function2q_function +from irlc.ex09.small_gridworld import SmallGridworldMDP, plot_value_function +from irlc import savepdf + + +def policy_evaluation(pi, mdp, gamma=.99, theta=0.00001): + """ Implements the iterative policy-evaluation algorithm ((SB18, Section 4.1)). + The algorithm is given a policy pi which is represented as a dictionary so that + + > pi[s][a] = p + + is the probability p of taking action a in state s. The 'mdp' is a MDP-instance and the other terms have the same meaning as in the algorithm. + It should return a dictionary v so that + > v[s] + is the value-function evaluated in state s. I recommend using the qs_-function defined above. + """ + v = defaultdict(float) + Delta = theta #Initialize the 'Delta'-variable to a large value to make sure the first iteration of the method runs. + while Delta >= theta: # Outer loop in (SB18) + Delta = 0 # Remember to update Delta (same meaning as in (SB18)) + # Remember that 'S' in (SB18) is actually just the set of non-terminal states (NOT including terminal states!) + for s in mdp.nonterminal_states: # See the MDP class if you are curious about how this variable is defined. + """ Implement the main body of the policy evaluation algorithm here. You can do this directly, + or implement (and use) the value_function2q_function-function (consider what it does and compare to the algorithm). + If you do so, note that value_function2q_function(mdp, s, gamma, v) computes the equivalent of Q(s,a) (as a dictionary), + and in the algorithm, you then need to compute the expectation over pi: + > sum_a pi(a|s) Q(s,a) + In code it would be more akin to + q = value_function2q_function(...) + sum_a pi[s][a] * q[a] + + Don't be afraid to use a few more lines than I do. + """ + # TODO: 2 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + """ stop condition. v_ is the yafcport value of the value function (see algorithm listing in (SB18)) which you need to update. """ + Delta = max(Delta, np.abs(v_ - v[s])) + return v + + +if __name__ == "__main__": + mdp = SmallGridworldMDP() + """ + Create the random policy pi0 below. The policy is defined as a nested dict, i.e. + + > pi0[s][a] = (probability to take action a in state s) + + """ + pi0 = {s: {a: 1/len(mdp.A(s)) for a in mdp.A(s) } for s in mdp.nonterminal_states } + V = policy_evaluation(pi0, mdp, gamma=1) + plot_value_function(mdp, V) + plt.title("Value function using random policy") + savepdf("policy_eval") + plt.show() + + expected_v = np.array([0, -14, -20, -22, + -14, -18, -20, -20, + -20, -20, -18, -14, + -22, -20, -14, 0]) diff --git a/irlc/ex09/policy_iteration.py b/irlc/ex09/policy_iteration.py new file mode 100644 index 0000000..a2ab623 --- /dev/null +++ b/irlc/ex09/policy_iteration.py @@ -0,0 +1,63 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import numpy as np +from irlc.ex09.small_gridworld import SmallGridworldMDP +import matplotlib.pyplot as plt +from irlc.ex09.policy_evaluation import policy_evaluation +from irlc.ex09.mdp_warmup import value_function2q_function + +def policy_iteration(mdp, gamma=1.0): + r""" + Implement policy iteration (see (SB18, Section 4.3)). + + Note that policy iteration only considers deterministic policies. we will therefore use the shortcut by representing the policy pi + as a dictionary (similar to the DP-problem in week 2!) so that + > a = pi[s] + is the action in state s. + + """ + pi = {s: np.random.choice(mdp.A(s)) for s in mdp.nonterminal_states} + policy_stable = False + V = None # Sutton has an initialization-step, but it can actually be skipped if we intialize the policy randomly. + while not policy_stable: + # Evaluate the current policy using your code from the previous exercise. + # The main complication is that we need to transform our deterministic policy, pi[s], into a stochastic one pi[s][a]. + # It will be defined as: + # >>> pi_prob[s][a] = 1 if a = pi[s] and otherwise 0. + pi_prob = {s: {a: 1 if pi[s] == a else 0 for a in mdp.A(s)} for s in mdp.nonterminal_states} + V = policy_evaluation(pi_prob, mdp, gamma) + V = policy_evaluation( {s: {pi[s]: 1} for s in mdp.nonterminal_states}, mdp, gamma) + """ Implement the method. This is step (3) in (SB18). """ + policy_stable = True # Will be set to False if the policy pi changes + r""" Implement the steps for policy improvement here. Start by writing a for-loop over all non-terminal states + you can see the policy_evaluation function for how to do this, but + I recommend looking at the property mdp.nonterminal_states (see MDP class for more information). + Hints: + * In the algorithm in (SB18), you need to perform an argmax_a over what is actually Q-values. The function + value_function2q_function(mdp, s, gamma, V) can compute these. + * The argmax itself, assuming you follow the above procedure, involves a dictionary. It can be computed + using methods similar to those we saw in week2 of the DP problem. + It is not a coincidence these algorithms are very similar -- if you think about it, the maximization step closely resembles the DP algorithm! + """ + # TODO: 6 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + return pi, V + +if __name__ == "__main__": + mdp = SmallGridworldMDP() + pi, v = policy_iteration(mdp, gamma=0.99) + expected_v = np.array([ 0, -1, -2, -3, + -1, -2, -3, -2, + -2, -3, -2, -1, + -3, -2, -1, 0]) + + from irlc.ex09.small_gridworld import plot_value_function + plot_value_function(mdp, v) + plt.title("Value function using policy iteration to find optimal policy") + from irlc import savepdf + savepdf("policy_iteration") + plt.show() diff --git a/irlc/ex09/rl_agent.py b/irlc/ex09/rl_agent.py new file mode 100644 index 0000000..94e3c1c --- /dev/null +++ b/irlc/ex09/rl_agent.py @@ -0,0 +1,212 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc.utils.common import defaultdict2 +from irlc import Agent + +class TabularAgent(Agent): + """ + This helper class will simplify the implementation of most basic reinforcement learning. Specifically it provides: + + - A :math:`Q(s,a)`-table data structure + - An epsilon-greedy exploration method + + The code for the class is very simple, and I think it is a good idea to at least skim it. + + The Q-data structure can be used a follows: + + .. runblock:: pycon + + >>> from irlc.ex09.rl_agent import TabularAgent + >>> from irlc.gridworld.gridworld_environments import BookGridEnvironment + >>> env = BookGridEnvironment() + >>> agent = TabularAgent(env) + >>> state, info = env.reset() # Get the info-dictionary corresponding to s + >>> agent.Q[state, 1] = 2.5 # Update a Q-value; action a=1 is now optimal. + >>> agent.Q[state, 1] # Check it has indeed been updated. + >>> agent.Q[state, 0] # Q-values are 0 by default. + >>> agent.Q.get_optimal_action(state, info) # Note we pass along the info-dictionary corresopnding to this state + + .. note:: + The ``get_optimal_action``-function requires an ``info`` dictionary. This is required since the info dictionary + contains information about which actions are available. To read more about the Q-values, see :class:`~irlc.ex09.rl_agent.TabularQ`. + """ + def __init__(self, env, gamma=0.99, epsilon=0): + """ + Initialize a tabular environment. For convenience it stores the discount factor :math:`\gamma` and + exploration parameter :math:`\\varepsilon` for epsilon-greedy exploration. Access them as e.g. ``self.gamma`` + + When you implement an agent and overwrite the ``__init__``-method, you should include a call such as ``super( + ).__init__(gamma, epsilon)``. + + :param env: The gym environment + :param gamma: The discount factor :math:`\gamma` + :param epsilon: Exploration parameter :math:`\\varepsilon` for epsilon-greedy exploration + """ + super().__init__(env) + self.gamma, self.epsilon = gamma, epsilon + self.Q = TabularQ(env) + + def pi_eps(self, s, info): + """ + Performs :math:`\\varepsilon`-greedy exploration with :math:`\\varepsilon =` ``self.epsilon`` and returns the + action. Recall this means that with probability :math:`\\varepsilon` it returns a random action, and otherwise + it returns an action associated with a maximal Q-value (:math:`\\arg\\max_a Q(s,a)`). An example: + + .. runblock:: pycon + + >>> from irlc.ex09.rl_agent import TabularAgent + >>> from irlc.gridworld.gridworld_environments import BookGridEnvironment + >>> env = BookGridEnvironment() + >>> agent = TabularAgent(env) + >>> state, info = env.reset() + >>> agent.pi_eps(state, info) # Note we pass along the info-dictionary corresopnding to this state + + .. note:: + The ``info`` dictionary is used to mask (exclude) actions that are not possible in the state. + It is similar to the info dictionary in ``agent.pi(s,info)``. + + :param s: A state :math:`s_t` + :param info: The corresponding ``info``-dictionary returned by the gym environment + :return: An action computed using :math:`\\varepsilon`-greedy action selection based the Q-values stored in the ``self.Q`` class. + """ + if info is not None and 'seed' in info: # In case info contains a seed, reset the random number generator. + np.random.seed(info['seed']) + return Agent.pi(self, s, k=0, info=info) if np.random.rand() < self.epsilon else self.Q.get_optimal_action(s, info) + + +class ValueAgent(TabularAgent): + """ + This is a simple wrapper class around the Agent class above. It fixes the policy and is therefore useful for doing + value estimation. + """ + def __init__(self, env, gamma=0.95, policy=None, v_init_fun=None): + self.env = env + self.policy = policy # policy to evaluate + """ self.v holds the value estimates. + Initially v[s] = 0 unless v_init_fun is given in which case v[s] = v_init_fun(s). """ + self.v = defaultdict2(float if v_init_fun is None else v_init_fun) + super().__init__(env, gamma=gamma) + self.Q = None # Blank out the Q-values which will not be used. + + def pi(self, s, k, info=None): + return TabularAgent.pi(self, s, k, info) if self.policy is None else self.policy(s) + + def value(self, s): + return self.v[s] + +def _masked_actions(action_space, mask): + """Helper function which applies a mask to the action space.""" + from irlc.utils.common import DiscreteTextActionSpace + if isinstance(action_space, DiscreteTextActionSpace): + return [a for a in range(action_space.n) if mask[a] == 1] + else: + return [a for a in range(action_space.n) if mask[a - action_space.start] == 1] + + +class TabularQ: + """ + This is a helper class for storing Q-values. It is used by the :class:`~ircl.ex09.rl_agent.TabularAgent` to store + Q-values where it can be be accessed as ``self.Q[s,a]``. + """ + def __init__(self, env): + """ + Initialize the table. It requires a gym environment to know how many actions there are for each state. + :param env: A gym environment. + """ + self._known_masks = {} # Cache the known action masks. + + def q_default(s): + if s in self._known_masks: + return {a: 0 for a in range(self.env.action_space.n) if self._known_masks[s][a- self.env.action_space.start] == 1} + else: + return {a: 0 for a in range(self.env.action_space.n)} + + # qfun = lambda s: OrderedDict({a: 0 for a in (env.P[s] if hasattr(env, 'P') else range(env.action_space.n))}) + self.q_ = defaultdict2(lambda s: q_default(s)) + self.env = env + + def get_Qs(self, state, info_s=None): + """ + Get a list of all known Q-values for this particular state. That is, in a given state, it will return the two + lists: + + .. math:: + \\begin{bmatrix} a_1 \\\\ a_2 \\\\ \\vdots \\\\ a_k \\end{bmatrix}, \\quad + \\begin{bmatrix} Q(s,a_1) \\\\ Q(s,a_1) \\\\ \\vdots \\\\ Q(s,a_k) \\end{bmatrix} \\\\ + + the ``info_s`` parameter will ensure actions are correctly masked. An example of how to use this function from + a policy: + + .. runblock:: pycon + + >>> from irlc.ex09.rl_agent import TabularAgent + >>> class MyAgent(TabularAgent): + ... def pi(self, s, k, info=None): + ... actions, q_values = self.Q.get_Qs(s, info) + + :param state: The state to query + :param info_s: The info-dictionary returned by the environment for this state. Used for action-masking. + :return: + - actions - A tuple containing all actions available in this state ``(a_1, a_2, ..., a_k)`` + - Qs - A tuple containing all Q-values available in this state ``(Q[s,a1], Q[s, a2], ..., Q[s,ak])`` + """ + if info_s is not None and 'mask' in info_s: + if state not in self._known_masks: + self._known_masks[state] = info_s['mask'] + # Probably a good idea to check the Q-values are okay... + avail_actions = _masked_actions(self.env.action_space, info_s['mask']) + self.q_[state] = {a: self.q_[state][a] for a in avail_actions} + + (actions, Qa) = zip(*self.q_[state].items()) + return tuple(actions), tuple(Qa) + + def get_optimal_action(self, state, info_s): + """ + For a given state ``state``, this function returns the optimal action for that state. + + .. math:: + a^* = \\arg\\max_a Q(s,a) + + An example: + .. runblock:: pycon + + >>> from irlc.ex09.rl_agent import TabularAgent + >>> class MyAgent(TabularAgent): + ... def pi(self, s, k, info=None): + ... a_star = self.Q.get_optimal_action(s, info) + + + :param state: State to find the optimal action in :math:`s` + :param info_s: The ``info``-dictionary corresponding to this state + :return: The optimal action according to the Q-table :math:`a^*` + """ + actions, Qa = self.get_Qs(state, info_s) + a_ = np.argmax(np.asarray(Qa) + np.random.rand(len(Qa)) * 1e-8) + return actions[a_] + + def _chk_mask(self, s, a): + if s in self._known_masks: + mask = self._known_masks[s] + if mask[a - self.env.action_space.start] == 0: + raise Exception(f" Invalid action. You tried to access Q[{s}, {a}], however the action {a} has been previously masked and therefore cannot exist in this state. The mask for {s} is mask={mask}.") + + def __getitem__(self, state_comma_action): + s, a = state_comma_action + self._chk_mask(s, a) + return self.q_[s][a] + + def __setitem__(self, state_comma_action, q_value): + s, a = state_comma_action + self._chk_mask(s, a) + self.q_[s][a] = q_value + + def to_dict(self): + """ + This helper function converts the known Q-values to a dictionary. This function is only used for + visualization purposes in some of the examples. + + :return: A dictionary ``q`` of all known Q-values of the form ``q[s][a]`` + """ + # Convert to a regular dictionary + d = {s: {a: Q for a, Q in Qs.items() } for s,Qs in self.q_.items()} + return d diff --git a/irlc/ex09/small_gridworld.py b/irlc/ex09/small_gridworld.py new file mode 100644 index 0000000..3271171 --- /dev/null +++ b/irlc/ex09/small_gridworld.py @@ -0,0 +1,39 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc.ex09.mdp import MDP +import seaborn as sns + +# action space available to the agent +UP,RIGHT, DOWN, LEFT = 0, 1, 2, 3 +class SmallGridworldMDP(MDP): + def __init__(self, rows=4, cols=4): + self.rows, self.cols = rows, cols # Number of rows, columns. + super().__init__(initial_state=(rows//2, cols//2) ) # Initial state is in the middle of the board. + + def A(self, state): + return [UP, DOWN, RIGHT, LEFT] # All four directions available. + + def Psr(self, state, action): + row, col = state # state is in the format state = (row, col) + if action == UP: row -= 1 + if action == DOWN: row += 1 + if action == LEFT: col += 1 + if action == RIGHT: col -= 1 + + col = min(self.cols-1, max(col, 0)) # Check boundary conditions. + row = min(self.rows-1, max(row, 0)) + reward = -1 # Always get a reward of -1 + next_state = (row, col) + # Note that P(next_state, reward | state, action) = 1 because environment is deterministic + return {(next_state, reward): 1} + + def is_terminal(self, state): + row, col = state + return (row == 0 and col == 0) or (row == self.rows-1 and col == self.cols-1) + + +def plot_value_function(env, v): + A = np.zeros((env.rows, env.cols)) + for (row, col) in env.nonterminal_states: + A[row, col] = v[(row,col)] + sns.heatmap(A, cmap="YlGnBu", annot=True, cbar=False, square=True, fmt='g') diff --git a/irlc/ex09/value_iteration.py b/irlc/ex09/value_iteration.py new file mode 100644 index 0000000..9c651b6 --- /dev/null +++ b/irlc/ex09/value_iteration.py @@ -0,0 +1,73 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import matplotlib.pyplot as plt +from collections import defaultdict +import numpy as np +from irlc.ex09.mdp_warmup import value_function2q_function +from irlc import savepdf + +def value_iteration(mdp, gamma=.99, theta=0.0001, max_iters=10 ** 6, verbose=False): + """ Implement the value-iteration algorithm defined in (SB18, Section 4.4). + The inputs should be self-explanatory given the pseudo-code. + + I have also included a max_iters variable which represents an upper bound on the total number of iterations. This is useful + if you want to check what the algorithm does after a certain (e.g. 1 or 2) steps. + + The verbose-variable makes the algorithm print out the biggest change in the value-function in a single step. + This is useful if you run it on a large problem and want to know how much time remains, or simply get an idea of + how quickly it converges. + """ + V = defaultdict(lambda: 0) # value function + for i in range(max_iters): + Delta = 0 + for s in mdp.nonterminal_states: + """ Perform the update the value-function V[s] here for the given state. + Note that this has a lot of similarity to the policy-evaluation algorithm, and you can re-use + a lot of that solution, including value_function2q_function(...) (assuming you used that function). """ + # TODO: 2 lines missing. + raise NotImplementedError("Complete the algorithm here.") + if verbose: + print(i, Delta) + if Delta < theta: + break + # Turn the value-function into a policy. It implements the last line of the algorithm. + pi = values2policy(mdp, V, gamma) + return pi, V + +def values2policy(mdp, V, gamma): + r""" Turn the value-function V into a policy. The value function V is implemented as a dictionary so that + > value = V[s] + is the value-function in state s. + The procedure you implement is the very last line of the value-iteration algorithm (SB18, Section 4.4), and it should return + a policy pi as a dictionary so that + > a = pi[s] + is the action in state s. + + Note once again you can re-use the qs_-function. and the argmax -- in fact, the solution is very similar to your solution to the + policy-iteration problem in policy_iteration.py. + As you have properly noticed, even though we implement different algorithms, they are all build using the same + building-block. + """ + pi = {} + for s in mdp.nonterminal_states: + # Create the policy here. pi[s] = a is the action to be taken in state s. + # You can use the qs_ helper function to simplify things and perhaps + # re-use ideas from the dp.py problem from week 2. + # TODO: 2 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + return pi + +if __name__ == "__main__": + import seaborn as sns + from irlc.ex09.small_gridworld import SmallGridworldMDP, plot_value_function + env = SmallGridworldMDP() + policy, v = value_iteration(env, gamma=0.99, theta=1e-6) + plot_value_function(env, v) + + plt.title("Value function obtained using value iteration to find optimal policy") + savepdf("value_iteration") + plt.show() diff --git a/irlc/ex09/value_iteration_agent.py b/irlc/ex09/value_iteration_agent.py new file mode 100644 index 0000000..063fcbe --- /dev/null +++ b/irlc/ex09/value_iteration_agent.py @@ -0,0 +1,42 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex09.value_iteration import value_iteration +from irlc import TabularAgent +import numpy as np + + +class ValueIterationAgent(TabularAgent): + def __init__(self, env, mdp=None, gamma=1, epsilon=0, **kwargs): + super().__init__(env) + self.epsilon = epsilon + # TODO: 1 lines missing. + raise NotImplementedError("Call the value_iteration function and store the policy for later.") + + def pi(self, s, k, info=None): + """ With probability (1-epsilon), the take optimal action as computed using value iteration + With probability epsilon, take a random action. You can do this using return self.random_pi(s) + """ + if np.random.rand() < self.epsilon: + return super().pi(s, k, info) # Recall that by default the policy takes random actions. + else: + """ Return the optimal action here. This should be computed using value-iteration. + To speed things up, I recommend calling value-iteration from the __init__-method and store the policy. """ + # TODO: 1 lines missing. + raise NotImplementedError("Compute and return optimal action according to value-iteration.") + return action + + def __str__(self): + return f"ValueIteration(epsilon={self.epsilon})" + + +if __name__ == "__main__": + from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment + env = SuttonCornerGridEnvironment(living_reward=-1, render_mode='human') + from irlc import train, interactive + # Note you can access the MDP for a gridworld using env.mdp. The mdp will be an instance of the MDP class we have used for planning so far. + agent = ValueIterationAgent(env, mdp=env.mdp) # Make a ValueIteartion-based agent + # Visualize & interactivity. Press P or space to follow the policy. + agent.Q = None # This ensure the value function is visualized. + env, agent = interactive(env, agent) + train(env, agent, num_episodes=20) # Train for 100 episodes + env.savepdf("smallgrid.pdf") # Take a snapshot of the final configuration + env.close() # Whenever you use a VideoMonitor, call this to avoid a dumb openglwhatever error message on exit diff --git a/irlc/ex10/__init__.py b/irlc/ex10/__init__.py new file mode 100644 index 0000000..066dc00 --- /dev/null +++ b/irlc/ex10/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 10.""" diff --git a/irlc/ex10/blackjack/__init__.py b/irlc/ex10/blackjack/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/ex10/blackjack/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/ex10/blackjack/mc_agent_blackjack.py b/irlc/ex10/blackjack/mc_agent_blackjack.py new file mode 100644 index 0000000..f04c457 --- /dev/null +++ b/irlc/ex10/blackjack/mc_agent_blackjack.py @@ -0,0 +1,48 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import gym +import numpy as np +from collections import defaultdict +import matplotlib.pyplot as plt +from irlc import main_plot +from irlc import savepdf +from irlc.ex01.agent import train +from irlc.ex10.mc_evaluate_blackjack import plot_blackjack_value, plot_blackjack_policy +from irlc.ex10.mc_agent import MCAgent + +def run_experiment(episodes, first_visit=True, **kwargs): + env_name = 'Blackjack-v1' + env = gym.make(env_name) + agent = MCAgent(env, **kwargs) + lbl = "_".join(map(str, kwargs.values())) + fvl = "First" if first_visit else "Every" + title = f"MC agent ({fvl} visit)" + + expn = f"experiments/{env_name}_MCagent_{episodes}_{first_visit}_{lbl}" # Name the experiment. Pass the label to the train function to store intermediate results. See the online documentation for more information. + # TODO: 1 lines missing. + raise NotImplementedError("call the train(...) function here.") + + # Matplotlib with seaborn is for some reason very slow. + # This code re-samples the curve to just 400 points: + main_plot(expn, smoothing_window=episodes//100, resample_ticks=400) + plt.title("Estimated returns in blackjack using " + title) + plt.ylim([-0.3, 0]) + savepdf(f"blackjack_MC_agent_{episodes}_{first_visit}") + plt.show() + + V = defaultdict(lambda: 0) + A = defaultdict(lambda: 0) + for s, av in agent.Q.to_dict().items(): + A[s] = agent.pi(s, 0) + V[s] = max(av.values() ) + + plot_blackjack_value(V, title=title, pdf_out=f"blackjack_mcagent_policy{fvl}_valfun_{episodes}") + plt.show() + plot_blackjack_policy(A, title=title) + savepdf(f"blackjack_mcagent_policy{fvl}_{episodes}") + plt.show() + +if __name__ == "__main__": + episodes = 1000000 + # episodes = 1000 # Uncomment to run far fewer episodes during debugging. + run_experiment(episodes, epsilon=0.05, first_visit=True) + run_experiment(episodes, epsilon=0.05, first_visit=False) diff --git a/irlc/ex10/blackjack/mc_evaluate_blackjack.py b/irlc/ex10/blackjack/mc_evaluate_blackjack.py new file mode 100644 index 0000000..1e0cd7b --- /dev/null +++ b/irlc/ex10/blackjack/mc_evaluate_blackjack.py @@ -0,0 +1,93 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import matplotlib.pyplot as plt +import numpy as np + +def get_by_ace(V,ace=False): + dd = V.copy() + dd.clear() + for (p,d,ac),val in V.items(): + if ac == ace: + dd[ (p,d)] = val + return dd + +def plot_surface_2(X,Y,Z,fig=None, ax=None, **kwargs): + if fig is None and ax is None: + fig = plt.figure(figsize=(20, 10)) + if ax is None: + ax = fig.add_subplot(projection='3d') + surf = ax.plot_surface(X, Y, Z, cmap=plt.cm.coolwarm, linewidth=1, edgecolors='k', **kwargs) + ax.view_init(ax.elev, -120) + if fig is not None: + fig.colorbar(surf, shrink=0.5, aspect=5) + return ax + +def to_matrix(V): + min_x = min(k[0] for k in V.keys()) + max_x = max(k[0] for k in V.keys()) + min_y = min(k[1] for k in V.keys()) + max_y = max(k[1] for k in V.keys()) + + x_range = np.arange(min_x, max_x + 1) + y_range = np.arange(min_y, max_y + 1) + X, Y = np.meshgrid(x_range, y_range) + + Z_ace = np.zeros_like(X, dtype=float) + for j,(x, y) in enumerate( zip( X.flat, Y.flat)): + Z_ace.flat[j] = float(V[(x,y)]) + return X, Y, Z_ace + +def plot_blackjack_value(V, title="Value Function", pdf_out=None): + """ + Plots the value function as a surface plot. + """ + for lbl, ac in zip(["Usable ace", "No usable ace"], [True, False]): + w = get_by_ace(V,ace=ac) + X,Y,Z = to_matrix(w) + ax = plot_surface_2(X, Y, Z) + ax.set_zlabel("Value") + ax.set_title(title) + if pdf_out is not None: + savepdf(pdf_out+"_"+lbl.replace(" ", "_")) + +def plot_blackjack_policy(V, title): + plt.figure(figsize=(18, 12)) + for lbl, ac in zip(["Usable ace", "No usable ace"], [True, False]): + w = get_by_ace(V,ace=ac) + X, Y, Z = to_matrix(w) + plt.subplot(1,2,1+ac) + plt.imshow(Z.T) + plt.title(f"{title} ({lbl})") + plt.gca().invert_yaxis() + plt.ylabel('Player Sum') + plt.xlabel('Dealer Showing') + plt.colorbar() + +def policy20(s): + # TODO: 1 lines missing. + raise NotImplementedError("Implement the rule where we stick if we have a score of 20 or more.") + +if __name__ == "__main__": + from irlc.ex10.mc_evaluate import MCEvaluationAgent + from irlc.ex01.agent import train + import gym + from irlc import main_plot, savepdf + + nenv = "Blackjack-v1" + env = gym.make(nenv) + episodes = 50000 + gamma = 1 + experiment = f"experiments/{nenv}_first_{episodes}" + """ Instantiate the agent and call the training method here. Make sure to pass the policy=policy20 function to the MCEvaluationAgent + and set gamma=1. """ + # TODO: 2 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + main_plot(experiment, smoothing_window=episodes//100, resample_ticks=200) + plt.ylim([-0.5, 0]) + plt.title("Blackjack using first-visit MC") + savepdf("blackjack_stick20_first") + plt.show() + + pdf = "blackjack_stick20_valuefun" + plot_blackjack_value(agent.v, title="MC first-visit value function", pdf_out=pdf) + savepdf("blackjack_stick20_valuefun") + plt.show() diff --git a/irlc/ex10/blackjack/random_walk_example.py b/irlc/ex10/blackjack/random_walk_example.py new file mode 100644 index 0000000..0e64027 --- /dev/null +++ b/irlc/ex10/blackjack/random_walk_example.py @@ -0,0 +1,112 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import numpy as np +import matplotlib.pyplot as plt +from tqdm import tqdm +from irlc import savepdf +from irlc.ex10.td0_evaluate import TD0ValueAgent +from irlc.ex10.mc_evaluate import MCEvaluationAgent +import seaborn as sns +import pandas as pd +from irlc.ex01.agent import train +from irlc.ex09.mdp import MDP2GymEnv, MDP + +class ChainMRP(MDP): + def __init__(self, length=6): + """ + Build the "Chain MRP" yafcport from (SB18). Terminal states are [0,6], + all states are [0,1,2,3,4,5,6] and initial state is 3. (default settings). + """ + self.max_states = length + super().__init__(initial_state=length // 2) + + def is_terminal(self, state): + return state == 0 or state == self.max_states + + def A(self, s): # 0: left, 1: right. + return [0,1] + + def Psr(self, s, a): + # TODO: 1 lines missing. + raise NotImplementedError("Return the P(s', r | s,a) values here. See e.g. the gampler problem from previous week for help.") + return {(sp, 1 if sp == self.max_states else 0): 1.0} + +class ChainEnvironment(MDP2GymEnv): + def __init__(self, *args, **kwargs): + super().__init__(mdp=ChainMRP(*args, **kwargs)) + +if __name__ == "__main__": + """ plot results as in (SB18, Example 6.2) """ + env = ChainEnvironment() + V_init = np.array([0.5, 0.5, 0.5, 0.5, 0.5]) + V_true = np.array([1 / 6, 2 / 6, 3 / 6, 4 / 6, 5 / 6]) + states = range(1,6) + """ + This is a bit janky. The value-function is initialized at + 0.5 in the example, however (see (SB18)) the value function must be initialized at + 0 in terminal states. We make a function to initialize the value function + and pass it along to the ValueAgent; the ValueAgent then uses a subclassed + defaultdict which can handle a parameterized default value. """ + v_init_fun = lambda x: 0.5 + + fig, ax = plt.subplots(figsize=(15, 6), ncols=2) + """ Make TD plot """ + td_episodes = [0, 1, 10, 100] + V_current = np.copy(V_init) + xticks = ['A', 'B', 'C', 'D', 'E'] + + for i, episodes in enumerate(td_episodes): + agent = TD0ValueAgent(env, v_init_fun=v_init_fun) + train(env, agent, num_episodes=episodes,verbose=False, return_trajectory=False) + vs = [agent.value(s) for s in states] + ax[0].plot(vs, label=f"{episodes} episodes", marker='o') + + ax[0].plot(V_true, label='true values', marker='o') + ax[0].set(xlabel='State', ylabel='Estimated Value', title='Estimated Values TD(0)', + xticks=np.arange(5), xticklabels=['A','B','C','D','E']) + ax[0].legend() + + """ Make TD vs. MC plot """ + td_alphas = [0.05, 0.15, 0.1] + mc_alphas = [0.01, 0.03] + episodes = 100 + runs = 200 + + def eval_mse(agent): + errors = [] + for i in range(episodes): + V_ = [agent.value(s) for s in states] + train(env, agent, num_episodes=1, verbose=False, return_trajectory=False) + z = np.sqrt(np.sum(np.power(V_ - V_true, 2)) / 5.0) + errors.append(z) + return errors + + methods = [(TD0ValueAgent, 'TD', alpha) for alpha in td_alphas] + methods += [(MCEvaluationAgent, 'MC', alpha) for alpha in mc_alphas] + + dfs = [] + for AC,method,alpha in tqdm(methods): + TD_mse = [] + for r in range(runs): + agent = AC(env, alpha=alpha, gamma=1, v_init_fun=v_init_fun) + err_ = eval_mse(agent) + TD_mse.append( np.asarray(err_)) + + # Happy times with pandas. Let's up the production value by also plotting 1 std. + for u,mse in enumerate(TD_mse): + df = pd.DataFrame(mse, columns=['rmse']) + df.insert(len(df.columns), 'Unit', u) + df.insert(len(df.columns), 'Episodes', range(episodes)) + df.insert(len(df.columns), 'Condition', f"{method} $\\alpha$={alpha}") + dfs.append(df) + + data = pd.concat(dfs, ignore_index=True) + sns.lineplot(data=data, x='Episodes', y='rmse', hue="Condition", errorbar=('ci', 95), estimator='mean') + plt.ylabel("RMS error (averaged over states)") + plt.title("Empirical RMS error, averaged over states") + savepdf("random_walk_example") + plt.show() diff --git a/irlc/ex10/envs.py b/irlc/ex10/envs.py new file mode 100644 index 0000000..bd34125 --- /dev/null +++ b/irlc/ex10/envs.py @@ -0,0 +1,50 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import gymnasium as gym + +gym.envs.register( + id='Gambler-v0', + entry_point='irlc.ex09.gambler:GamblerEnv', +) + +gym.envs.register( + id='Tenv-v0', + entry_point='irlc.ex09.gambler:TEnv', + max_episode_steps=100, +) + +gym.envs.register( + id='JackRental4-v0', + entry_point='irlc.ex09.jacks_car_rental:RentalEnv', + max_episode_steps=1000, + kwargs={"max_cars": 4, + "poisson_truncation": 4, + "cache_str": "jack_rental_environment_4"}, +) + +gym.envs.register( + id='JackRental-v0', + entry_point='irlc.ex09.jacks_car_rental:RentalEnv', + max_episode_steps=1000, + kwargs={"cache_str": "jack_rental_environment"}, +) # "compress_tol": 0.01 + +gym.envs.register( + id='SmallGridworld-v0', + entry_point='irlc.gridworld.gridworld_environments:SuttonCornerGridEnvironment', + # max_episode_steps=100, # Stop trying to make it happen +) + +gym.envs.register( # Like MountainCar-v0, but time limit increased from 200 to 500. + id='MountainCar500-v0', + entry_point='gymnasium.envs.classic_control:MountainCarEnv', + max_episode_steps=500, + reward_threshold=-110.0, +) + + +if __name__ == "__main__": + print("Testing...") + mc = gym.make('MountainCar500-v0') + # j4 = gym.make("JackRental4-v0") + # jack = gym.make("JackRental-v0") + sg = gym.make("SmallGridworld-v0") diff --git a/irlc/ex10/mc_agent.py b/irlc/ex10/mc_agent.py new file mode 100644 index 0000000..0719f15 --- /dev/null +++ b/irlc/ex10/mc_agent.py @@ -0,0 +1,86 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from collections import defaultdict +import matplotlib.pyplot as plt +from irlc.ex09.rl_agent import TabularAgent +from irlc import main_plot, savepdf, train +from irlc import interactive +def get_MC_return_SA(episode, gamma, first_visit=True): + """ Helper method for computing the MC returns. + Given an episodes in the form [ (s0,a0,r1), (s1,a1,r2), ...] + this function computes (if first_visit=True) a new list + + > [((s,a), G) , ... ] + + consisting of the unique $(s_t,a_t)$ pairs in episode along with their return G_t (computed from their first occurance). + Alternatively, if first_visit=False, the method return a list of same length of episode + with all (s,a) pairs and their return. + """ + sa = [(s, a) for s, a, r in episode] # Get all state/action pairs. Useful for checking if we have visited a state/action before. + G = 0 + returns = [] + for t in reversed(range(len(episode))): + # TODO: 2 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + if sa_t not in sa[:t] or not first_visit: + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + return returns + +class MCAgent(TabularAgent): + def __init__(self, env, gamma=1.0, epsilon=0.05, alpha=None, first_visit=True): + if alpha is None: + self.returns_sum = defaultdict(float) + self.returns_count = defaultdict(float) + self.alpha = alpha + self.first_visit = first_visit + self.episode = [] + super().__init__(env, gamma, epsilon) + + def pi(self, s,k, info=None): + """ + Compute the policy of the MC agent. Remember the agent is epsilon-greedy. You can use the pi_eps(s,info)-function defined + in the TabularAgent class. + """ + # TODO: 1 lines missing. + raise NotImplementedError("Compute action here using the Q-values. (remember to be epsilon-greedy)") + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + """ + Consult your implementation of value estimation agent for ideas. Note you can index the Q-values as + + >> self.Q[s, a] = new_q_value + + see comments in the Agent class for more details, however for now you can consider them as simply a nested + structure where ``self.Q[s, a]`` defaults to 0 unless the Q-value has been updated. + """ + # TODO: 12 lines missing. + raise NotImplementedError("Train the agent here.") + + def __str__(self): + return f"MC_{self.gamma}_{self.epsilon}_{self.alpha}_{self.first_visit}" + +if __name__ == "__main__": + """ Load environment but make sure it is time-limited. Can you tell why? """ + envn = "SmallGridworld-v0" + + from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment, BookGridEnvironment + env = SuttonCornerGridEnvironment(uniform_initial_state=True) + # env = BookGridEnvironment(living_reward=-0.05) # Uncomment to test an alternative environment with a negative living reward. + + gamma = 1 + episodes = 20000 + experiment="experiments/mcagent_smallgrid" + agent = MCAgent(env, gamma=gamma, first_visit=True) + train(env, agent, experiment_name=experiment, num_episodes=episodes, return_trajectory=False) + main_plot(experiments=[experiment], resample_ticks=200) + plt.title("Smallgrid MC agent value function") + plt.ylim([-10, 0]) + savepdf("mcagent_smallgrid") + plt.show() + + env, agent = interactive(env, agent) + env.reset() + env.plot() + plt.title(f"MC on-policy control of {envn} using first-visit") + savepdf("MC_agent_value_smallgrid") + plt.show(block=False) diff --git a/irlc/ex10/mc_evaluate.py b/irlc/ex10/mc_evaluate.py new file mode 100644 index 0000000..973d4b1 --- /dev/null +++ b/irlc/ex10/mc_evaluate.py @@ -0,0 +1,120 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc import savepdf +import matplotlib.pyplot as plt +from irlc.ex09.rl_agent import ValueAgent +from collections import defaultdict +from irlc.ex01.agent import train +import numpy as np +import matplotlib +#matplotlib.use('qtagg') # Fix crash on linux with default backend. + +def get_MC_return_S(episode, gamma, first_visit=True): + """ Helper method for computing the MC returns. + Given an episodes in the form ``[ (s0,a0,r1), (s1,a1,r2), ...]`` + this function computes (if first_visit=True) a new list:: + + [(s0, G0), (s1, G1), ...] + + consisting of the unique s_t values in the episode along with their return G_t (computed from their first occurance). + + Alternatively, if first_visit=False, the method return a list of same length of episode + with all s values and their return. + """ + ss = [s for s, a, r in episode] + G = 0 + returns = [] + for t in reversed(range(len(episode))): + # TODO: 2 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + if s_t not in ss[:t] or not first_visit: + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + return returns +class MCEvaluationAgent(ValueAgent): + def __init__(self, env, policy=None, gamma=1, alpha=None, first_visit=True, v_init_fun=None): + self.episode = [] + self.first_visit = first_visit + self.alpha = alpha + if self.alpha is None: + self.returns_sum_S = defaultdict(float) + self.returns_count_N = defaultdict(float) + super().__init__(env, gamma, policy, v_init_fun=v_init_fun) + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + self.episode.append((s, a, r)) # Gather the episode + if done: # Only train when the episode has stopped + returns = get_MC_return_S(self.episode, self.gamma, self.first_visit) + for s, G in returns: + if self.alpha: + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + else: + # TODO: 3 lines missing. + raise NotImplementedError("Implement function body") + + self.episode = [] + + def __str__(self): + return f"MCeval_{self.gamma}_{self.alpha}_{self.first_visit}" + + +if __name__ == "__main__": + envn = "SmallGridworld-v0" + from irlc import interactive + from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment + env = SuttonCornerGridEnvironment(render_mode=None) + gamma = 1 + episodes = 200 + agent = MCEvaluationAgent(env, gamma=gamma) + train(env, agent, num_episodes=episodes) + env.render_mode = 'human' + env, agent = interactive(env, agent, autoplay=True) + env.plot() + plt.title(f"MC evaluation of {envn} using first-visit") + savepdf("MC_value_random_smallgrid") + plt.show(block=False) + env.close() + + env = SuttonCornerGridEnvironment(render_mode=None) + agent_every = MCEvaluationAgent(env, gamma=gamma, first_visit=False) + train(env, agent_every, num_episodes=episodes) + env.render_mode = 'human' + env, agent = interactive(env, agent, autoplay=True) + env.plot() + plt.title(f"MC evaluation of {envn} using every-visit") + savepdf("MC_value_random_smallgrid_every") + plt.show(block=False) + env.close() + s0 = (1, 1) + print(f"Estimated value functions v_pi(s0) for first visit {agent.v[(1,1)]:3}") + print(f"Estimated value functions v_pi(s0) for every visit {agent_every.v[(1,1)]:3}") + + ## Second part: + repeats = 5000 # increase to e.g. 20'000. + episodes = 1 + ev, fv = [], [] + env = SuttonCornerGridEnvironment() + print(f"Repeating experiment {repeats} times, this may take a while.") + for _ in range(repeats): + """ + Instantiate two agents with first_visit=True and first_visit=False. + Train the agents using the train function for episodes episodes. You might want to pass verbose=False to the + 'train'-method to suppress output. + When done, compute the mean of agent.values() and add it to the lists ev / fv; the mean of these lists + are the desired result. + """ + agent = MCEvaluationAgent(env, gamma=gamma) + # TODO: 1 lines missing. + raise NotImplementedError("Create and train an every-visit agent.") + + train(env, agent, num_episodes=episodes, verbose=False) + # TODO: 1 lines missing. + raise NotImplementedError("Create and train an every-visit agent.") + + ev.append(agent.v[(1,1)]) + fv.append(agent_every.v[(1,1)]) + + print(f"First visit: Mean of value functions E[v_pi(s0)] after {repeats} repeats {np.mean(fv):3}") + print(f"Every visit: Mean of value functions E[v_pi(s0)] after {repeats} repeats {np.mean(ev):3}") + env.close() + plt.close() diff --git a/irlc/ex10/question_td0.py b/irlc/ex10/question_td0.py new file mode 100644 index 0000000..3f31e5b --- /dev/null +++ b/irlc/ex10/question_td0.py @@ -0,0 +1,36 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +def a_compute_deltas(v: dict, states: list, rewards: list, gamma: float) -> list: + # TODO: Code has been removed from here. + raise NotImplementedError("Insert your solution and remove this error.") + return deltas + + +def b_perform_td0(v: dict, states: list, rewards: list, gamma: float, alpha: float) -> dict: + # TODO: Code has been removed from here. + raise NotImplementedError("Insert your solution and remove this error.") + return v + + +def c_perform_td0_batched(v: dict, states: list, rewards: list, gamma: float, alpha: float) -> dict: + # TODO: Code has been removed from here. + raise NotImplementedError("Insert your solution and remove this error.") + return v + + +if __name__ == "__main__": + states = [1, 0, 2, -1, 2, 4, 5, 4, 3, 2, 1, -1] + rewards = [1, 0.5, -1, 0, 1, 2, 2, 0, 0, -1, 0.5] + # In the notation of the problem: T = len(rewards). + v = {s: 0 for s in states} # Initialize the value function v. + gamma = 0.9 + alpha = 0.2 + + deltas = a_compute_deltas(v, states, rewards, gamma) + print(f"The first value of delta should be 1, your value is {deltas[0]=}") + + v = b_perform_td0(v, states, rewards, gamma, alpha) + print(f"The value function v(s=1) should be 0.25352, your value is {v[1]=}") + + v_batched = {s: 0 for s in states} # Initialize the value function anew + v_batched = c_perform_td0_batched(v_batched, states, rewards, gamma, alpha) + print(f"The batched value function in v(s=1) should be 0.3, your value is {v_batched[1]=}") diff --git a/irlc/ex10/td0_evaluate.py b/irlc/ex10/td0_evaluate.py new file mode 100644 index 0000000..98aa5fc --- /dev/null +++ b/irlc/ex10/td0_evaluate.py @@ -0,0 +1,43 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +import matplotlib.pyplot as plt +from irlc.ex09.rl_agent import ValueAgent +from irlc import savepdf +from irlc.ex01.agent import train + +class TD0ValueAgent(ValueAgent): + def __init__(self, env, policy=None, gamma=0.99, alpha=0.05, v_init_fun=None): + self.alpha = alpha + super().__init__(env, gamma=gamma, policy=policy, v_init_fun=v_init_fun) + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + # TODO: 3 lines missing. + raise NotImplementedError("Implement function body") + + def __str__(self): + return f"TD0Value_{self.gamma}_{self.alpha}" + +def value_function_test(env, agent, v_true, episodes=200): + err = [] + for t in range(episodes): + train(env, agent, num_episodes=1, verbose=False) + err.append( np.mean( [(v_true - v0) ** 2 for k, v0 in agent.v.items()] ) ) + return np.asarray(err) + +if __name__ == "__main__": + envn = "SmallGridworld-v0" + + from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment + from irlc import interactive + env = SuttonCornerGridEnvironment() # Make the gridworld environment itself + + gamma = 1 + agent = TD0ValueAgent(env, gamma=gamma, alpha=0.05) # Make a TD(0) agent + train(env, agent, num_episodes=2000, return_trajectory=False) # Train for 2000 episodes + env = SuttonCornerGridEnvironment(render_mode='human') # Re-make the gridworld to get rendering. + env, agent = interactive(env, agent) # Add a video monitor, the environment will now show an animation + train(env,agent,num_episodes=1) # Train for a (single) new episode + env.plot() # Plot the current state of the environment/agent + plt.title(f"TD0 evaluation of {envn}") + savepdf("TD_value_random_smallgrid") + plt.show(block=False) diff --git a/irlc/ex11/__init__.py b/irlc/ex11/__init__.py new file mode 100644 index 0000000..6fc0833 --- /dev/null +++ b/irlc/ex11/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 11.""" diff --git a/irlc/ex11/__pycache__/__init__.cpython-311.pyc b/irlc/ex11/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af11ce3f70498da4527edc9a5bc56e55d7a5bcca GIT binary patch literal 233 zcmZ3^%ge>Uz`$UU-<$S|fq~&Mhy%lnP{wDFlIaX73{eazjKK_=OjSl98JWcjDVas7 z$tC$kl?uuEc_oRNdBqAP8L0}X6{$tZnZ>Ea3TgR83gxM(*$Re+dVZRWx7g$3Q}UDJ z<5x0#1{wX!Mn5AzH&wr+G$U2tB|o_|H#M)MSU)p2N8iB6#MGd;q%;L0Qk0XdpITvP zs2?AnnU`4-AFo$X`HRCQH$SB`C)KWqje&sy<k(_C1_p)?%#4hT4;U;iz)%qj0|Ns9 D5PU&6 literal 0 HcmV?d00001 diff --git a/irlc/ex11/__pycache__/feature_encoder.cpython-311.pyc b/irlc/ex11/__pycache__/feature_encoder.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d8b22f7b9271cf3563787f709c9e3f17b64afa7 GIT binary patch literal 21274 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 WH%4Yg)ej7)1P?#RuQ&*BJ_Z0sIX}k$ literal 0 HcmV?d00001 diff --git a/irlc/ex11/__pycache__/q_agent.cpython-311.pyc b/irlc/ex11/__pycache__/q_agent.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e5fe50d5559fca176eeb75f5ace797e16509486 GIT binary patch literal 4605 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 TTD%&-@B=>si_`^XNa_awiH4GX literal 0 HcmV?d00001 diff --git a/irlc/ex11/feature_encoder.py b/irlc/ex11/feature_encoder.py new file mode 100644 index 0000000..79f6bb0 --- /dev/null +++ b/irlc/ex11/feature_encoder.py @@ -0,0 +1,402 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +from math import floor +from gymnasium.spaces.box import Box +import numpy as np +from irlc.ex09.rl_agent import _masked_actions +from irlc.utils.common import defaultdict2 + +class FeatureEncoder: + """ + The idea behind linear function approximation of :math:`Q`-values is that + + - We initialize (and eventually learn) a :math:`d`-dimensional weight vector :math:`w \in \mathbb{R}^d` + - We assume there exists a function to compute a :math:`d`-dimensional feature vector :math:`x(s,a) \in \mathbb{R}^d` + - The :math:`Q`-values are then represented as + + .. math:: + Q(s,a) = x(s,a)^\\top w + + Learning is therefore entirely about updating :math:`w`. + + The following example shows how you initialize the linear :math:`Q`-values and compute them in a given state: + + .. runblock:: pycon + + >>> import gymnasium as gym + >>> from irlc.ex11.feature_encoder import LinearQEncoder + >>> env = gym.make('MountainCar-v0') + >>> Q = LinearQEncoder(env, tilings=8) + >>> s, _ = env.reset() + >>> a = env.action_space.sample() + >>> Q(s,a) # Compute a Q-value. + >>> Q.d # Get the number of dimensions + >>> Q.x(s,a)[:4] # Get the first four coordinates of the x-vector + >>> Q.w[:4] # Get the first four coordinates of the w-vector + + """ + def __init__(self, env): + """ + Initialize the feature encoder. It requires an environment to know the number of actions and dimension of the state space. + + :param env: An openai Gym ``Env``. + """ + self.env = env + self.w = np.zeros((self.d, )) + self._known_masks = {} + + def q_default(s): + from irlc.utils.common import DiscreteTextActionSpace + if s in self._known_masks: + return {a: 0 for a in range(self.env.action_space.n) if + self._known_masks[s][(a - self.env.action_space.start) if not isinstance(self.env.action_space, DiscreteTextActionSpace) else a] == 1} + else: + return {a: 0 for a in range(self.env.action_space.n)} + + # qfun = lambda s: OrderedDict({a: 0 for a in (env.P[s] if hasattr(env, 'P') else range(env.action_space.n))}) + + self.q_ = defaultdict2(lambda s: q_default(s)) + + @property + def d(self): + """ Get the number of dimensions of :math:`w` + + .. runblock:: pycon + + >>> import gymnasium as gym + >>> from irlc.ex11.feature_encoder import LinearQEncoder + >>> env = gym.make('MountainCar-v0') + >>> Q = LinearQEncoder(env, tilings=8) # as in (SB18) + >>> Q.d + """ + raise NotImplementedError() + + def x(self, s, a): + """ + Computes the :math:`d`-dimensional feature vector :math:`x(s,a)` + + .. runblock:: pycon + + >>> import gymnasium as gym + >>> from irlc.ex11.feature_encoder import LinearQEncoder + >>> env = gym.make('MountainCar-v0') + >>> Q = LinearQEncoder(env, tilings=8) # as in (SB18) + >>> s, info = env.reset() + >>> x = Q.x(s, env.action_space.sample()) + + :param s: A state :math:`s` + :param a: An action :math:`a` + :return: Feature vector :math:`x(s,a)` + """ + raise NotImplementedError() + + def get_Qs(self, state, info_s=None): + """ + This is a helper function, it is only for internal use. + + :param state: + :param info_s: + :return: + """ + if info_s is not None and 'mask' in info_s and not isinstance(state, np.ndarray): + if state not in self._known_masks: + self._known_masks[state] = info_s['mask'] + # Probably a good idea to check the Q-values are okay... + avail_actions = _masked_actions(self.env.action_space, info_s['mask']) + self.q_[state] = {a: self.q_[state][a] for a in avail_actions} + # raise Exception() + # from irlc.utils.common import ExplicitActionSpace + # + # zip(*self.q_[state].items()) + from irlc.pacman.pacman_environment import PacmanEnvironment + from irlc.pacman.pacman_utils import Actions + if isinstance(state, np.ndarray): + actions = tuple(range(self.env.action_space.n)) + elif isinstance(self.env, PacmanEnvironment): + # actions = Actions + # actions = tuple(Actions._directions.keys()) + actions = _masked_actions(self.env.action_space, info_s['mask']) + actions = tuple([self.env.action_space.actions[n] for n in actions]) + else: + actions = tuple(self.q_[state].keys()) + + # if isinstance(self.env, PacmanEnvironment): + # # TODO: Make smarter masking. + # actions = [a for a in actions if a in self.env.A(state)] + # actions = + Qs = tuple([self(state,a) for a in actions]) + # TODO: Implement masking and masking-cache. + return actions, Qs + # + # actions = list( self.env.P[state].keys() if hasattr(self.env, 'P') else range(self.env.action_space.n) ) + # Qs = [self(state, a) for a in actions] + # return tuple(actions), tuple(Qs) + + def get_optimal_action(self, state, info=None): + """ + For a given state ``state``, this function returns the optimal action for that state. + + .. math:: + a^* = \\arg\\max_a Q(s,a) + + An example: + + .. runblock:: pycon + + >>> from irlc.ex09.rl_agent import TabularAgent + >>> class MyAgent(TabularAgent): + ... def pi(self, s, k, info=None): + ... a_star = self.Q.get_optimal_action(s, info) + + :param state: State to find the optimal action in :math:`s` + :param info: The ``info``-dictionary corresponding to this state + :return: The optimal action according to the Q-values :math:`a^*` + """ + actions, Qa = self.get_Qs(state, info) + if len(actions) == 0: + print("Bad actions list") + a_ = np.argmax(np.asarray(Qa) + np.random.rand(len(Qa)) * 1e-8) + return actions[a_] + + def __call__(self, s, a): + """ + Evaluate the Q-values for the given state and action. An example: + + .. runblock:: pycon + + >>> import gymnasium as gym + >>> from irlc.ex11.feature_encoder import LinearQEncoder + >>> env = gym.make('MountainCar-v0') + >>> Q = LinearQEncoder(env, tilings=8) # as in (SB18) + >>> s, info = env.reset() + >>> Q(s, env.action_space.sample()). # Compute Q(s,a) + + :param s: A state :math:`s` + :param a: An action :math:`a` + :return: Feature vector :math:`x(s,a)` + """ + return self.x(s, a) @ self.w + + def __getitem__(self, item): + raise Exception("Hi! You tried to access linear Q-values as Q[s,a]. You need to use Q(s,a). This choice signifies they are not represented as a table, but as a linear combination x(s,a)^T w") + # s,a = item + # return self.__call__(s, a) + + def __setitem__(self, key, value): + raise Exception("Oy! You tried to set a linearly encoded Q-value as in Q[s, a] = new_q_value.\n This is not possible since they are represented as x(s,a)^T w. Rewrite the expression to update Q.w.") + +class DirectEncoder(FeatureEncoder): + def __init__(self, env): + self.d_ = np.prod( env.observation_space.shape ) * env.action_space.n + # self.d_ = len(self.x(env.reset(), env.action_space.n)) + super().__init__(env) + + def x(self, s, a): + xx = np.zeros( (self.d,)) + n = s.size + xx[n * a:n*(a+1) ] = s + return xx + + ospace = self.env.observation_space.shape + simple = False + if not isinstance(ospace, tuple): + ospace = (ospace,) + simple = True + + sz = [] + for j, disc in enumerate(ospace): + sz.append(disc.n) + + total_size = sum(sz) + csum = np.cumsum(sz, ) - sz[0] + self.max_size = total_size * self.env.action_space.n + + + def fixed_sparse_representation(s, action): + if simple: + s = (s,) + s_encoded = [cs + ds + total_size * action for ds, cs in zip(s, csum)] + return s_encoded + + self.get_active_tiles = fixed_sparse_representation + + # super().__init__(env) + + @property + def d(self): + return self.d_ + return 10000*8 + x = np.zeros(self.d) + at = self.get_active_tiles(s, a) + x[at] = 1.0 + return x + + +class GridworldXYEncoder(FeatureEncoder): + def __init__(self, env): + self.env = env + self.na = self.env.action_space.n + self.ns = 2 + super().__init__(env) + + @property + def d(self): + return self.na*self.ns + + def x(self, s, a): + x,y = s + xx = [np.zeros(self.ns) for _ in range(self.na)] + xx[a][0] = x + xx[a][1] = y + # return xx[a] + xx = np.concatenate(xx) + return xx + +class SimplePacmanExtractor(FeatureEncoder): + def __init__(self, env): + self.env = env + from irlc.pacman.feature_extractor import SimpleExtractor + # from reinforcement.featureExtractors import SimpleExtractor + self._extractor = SimpleExtractor() + self.fields = ["bias", "#-of-ghosts-1-step-away", "#-of-ghosts-1-step-away", "eats-food", "closest-food"] + super().__init__(env) + + def x(self, s, a): + xx = np.zeros_like(self.w) + # ap = self.env._actions_gym2pac[a] + ap = a + for k, v in self._extractor.getFeatures(s, ap).items(): + xx[self.fields.index(k)] = v + return xx + + @property + def d(self): + return len(self.fields) + +class LinearQEncoder(FeatureEncoder): + def __init__(self, env, tilings=8, max_size=2048): + """ + Implements the tile-encoder described by (SB18) + + :param env: The openai Gym environment we wish to solve. + :param tilings: Number of tilings (translations). Typically 8. + :param max_size: Maximum number of dimensions. + """ + if isinstance(env.observation_space, Box): + os = env.observation_space + low = os.low + high = os.high + scale = tilings / (high - low) + hash_table = IHT(max_size) + self.max_size = max_size + def tile_representation(s, action): + s_ = list( (s*scale).flat ) + active_tiles = tiles(hash_table, tilings, s_, [action]) # (s * scale).tolist() + # if 0 not in active_tiles: + # active_tiles.append(0) + return active_tiles + self.get_active_tiles = tile_representation + else: + # raise Exception("Implement in new class") + # + # Use Fixed Sparse Representation. See: + # https://castlelab.princeton.edu/html/ORF544/Readings/Geramifard%20-%20Tutorial%20on%20linear%20function%20approximations%20for%20dynamic%20programming%20and%20RL.pdf + + ospace = env.observation_space + simple = False + if not isinstance(ospace, tuple): + ospace = (ospace,) + simple = True + + sz = [] + for j,disc in enumerate(ospace): + sz.append( disc.n ) + + total_size = sum(sz) + csum = np.cumsum(sz,) - sz[0] + self.max_size = total_size * env.action_space.n + + def fixed_sparse_representation(s, action): + if simple: + s = (s,) + s_encoded = [cs + ds + total_size * action for ds,cs in zip(s, csum)] + return s_encoded + self.get_active_tiles = fixed_sparse_representation + super().__init__(env) + + def x(self, s, a): + x = np.zeros(self.d) + at = self.get_active_tiles(s, a) + x[at] = 1.0 + return x + + @property + def d(self): + return self.max_size + + +""" +Following code contains the tile-coding utilities copied from: +http://incompleteideas.net/tiles/tiles3.py-remove +""" +class IHT: + """Structure to handle collisions""" + + def __init__(self, size_val): + self.size = size_val + self.overfull_count = 0 + self.dictionary = {} + + + def count(self): + return len(self.dictionary) + + def full(self): + return len(self.dictionary) >= self.size + + def get_index(self, obj, read_only=False): + d = self.dictionary + if obj in d: + return d[obj] + elif read_only: + return None + size = self.size + count = self.count() + if count >= size: + if self.overfull_count == 0: + print('IHT full, starting to allow collisions') + self.overfull_count += 1 + return hash(obj) % self.size + else: + d[obj] = count + return count + + + + +def hash_coords(coordinates, m, read_only=False): + if isinstance(m, IHT): return m.get_index(tuple(coordinates), read_only) + if isinstance(m, int): return hash(tuple(coordinates)) % m + if m is None: return coordinates + + +def tiles(iht_or_size, num_tilings, floats, ints=None, read_only=False): + """returns num-tilings tile indices corresponding to the floats and ints""" + if ints is None: + ints = [] + qfloats = [floor(f * num_tilings) for f in floats] + tiles = [] + for tiling in range(num_tilings): + tilingX2 = tiling * 2 + coords = [tiling] + b = tiling + for q in qfloats: + coords.append((q + b) // num_tilings) + b += tilingX2 + coords.extend(ints) + tiles.append(hash_coords(coords, iht_or_size, read_only)) + return tiles diff --git a/irlc/ex11/nstep_sarsa_agent.py b/irlc/ex11/nstep_sarsa_agent.py new file mode 100644 index 0000000..b1648dc --- /dev/null +++ b/irlc/ex11/nstep_sarsa_agent.py @@ -0,0 +1,84 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +from irlc.ex01.agent import train +import gymnasium as gym +from irlc import main_plot +import matplotlib.pyplot as plt +from irlc.ex11.q_agent import QAgent + +class SarsaNAgent(QAgent): + """ Implement the N-step semi-gradient sarsa agent from (SB18, Section 7.2)""" + def __init__(self, env, gamma=1, alpha=0.2, epsilon=0.1, n=1): + # Variables for TD-n + self.n = n # as in n-step sarse + # Buffer lists for previous (S_t, R_{t}, A_t) triplets + self.R, self.S, self.A = [None] * (self.n + 1), [None] * (self.n + 1), [None] * (self.n + 1) + super().__init__(env, gamma=gamma, alpha=alpha, epsilon=epsilon) + + def pi(self, s, k, info=None): + self.t = k # Save current step in episode for use in train. + if self.t == 0: # First action is epsilon-greedy. + self.A[self.t] = self.pi_eps(s, info) + return self.A[self.t % (self.n+1)] + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + # Recall we are given S_t, A_t, R_{t+1}, S_{t+1} and done is whether t=T+1. + n = self.n # n as in n-step sarsa. + t = self.t # Current time step t as in s_t. + if t == 0: # We are in the initial state. Reset buffer. + self.S[0], self.A[0] = s, a + # Store current observations in buffer. + self.S[(t+1)%(n+1)] = sp + self.R[(t+1)%(n+1)] = r + self.A[(t+1)%(n+1)] = self.pi_eps(sp, info_sp) if not done else -1 + + if done: + T = t+1 + tau_steps_to_train = range(t - n + 1, T) + else: + T = 1e10 + tau_steps_to_train = [t - n + 1] + # Tau represent the current tau-steps which are to be updated. The notation is compatible with that in Sutton. + for tau in tau_steps_to_train: + if tau >= 0: + """ + Compute the return for this tau-step and perform the relevant Q-update. + The first step is to compute the expected return G in the below section. + """ + # TODO: 4 lines missing. + raise NotImplementedError("Compute G= (expected return) here.") + + S_tau, A_tau = self.S[tau%(n+1)], self.A[tau%(n+1)] + delta = (G - self._q(S_tau, A_tau)) + if n == 1: # Check your implementation is correct when n=1 by comparing it with regular Sarsa learning. + delta_Sarsa = (r + (0 if done else self.gamma * self._q(sp,A_tau_n)) - self._q(S_tau,A_tau)) + if abs(delta-delta_Sarsa) > 1e-10: + raise Exception("n=1 agreement with Sarsa learning failed. You have at least one bug!") + self._upd_q(S_tau, A_tau, delta) + + def _q(self, s, a): return self.Q[s,a] # Using these helper methods will come in handy when we work with function approximators, but it is optional. + def _upd_q(self, s, a, delta): self.Q[s,a] += self.alpha * delta + + def __str__(self): + return f"SarsaN_{self.gamma}_{self.epsilon}_{self.alpha}_{self.n}" + + +if __name__ == "__main__": + envn = 'CliffWalking-v0' + env = gym.make(envn) + from irlc.ex11.sarsa_agent import sarsa_exp + from irlc.ex11.q_agent import q_exp + + agent = SarsaNAgent(env, n=5, epsilon=0.1,alpha=0.5) + exp = f"experiments/{envn}_{agent}" + for _ in range(10): # Train 10 times to get an idea about the average performance. + train(env, agent, exp, num_episodes=200, max_runs=10) + main_plot([q_exp, sarsa_exp, exp], smoothing_window=10) # plot with results from Q/Sarsa simulations. + plt.ylim([-100,0]) + from irlc import savepdf + savepdf("n_step_sarsa_cliff") + plt.show() diff --git a/irlc/ex11/q_agent.py b/irlc/ex11/q_agent.py new file mode 100644 index 0000000..906e873 --- /dev/null +++ b/irlc/ex11/q_agent.py @@ -0,0 +1,85 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +from irlc.ex09.mdp import GymEnv2MDP +from irlc.ex09.rl_agent import TabularAgent +from irlc import train +import gymnasium as gym +from irlc import main_plot +import matplotlib.pyplot as plt +from irlc import savepdf +from irlc.ex09.value_iteration_agent import ValueIterationAgent + +class QAgent(TabularAgent): + r""" + Implement the Q-learning agent (SB18, Section 6.5) + Note that the Q-datastructure already exist, as do helper functions useful to compute an epsilon-greedy policy. + You can access these as + + > self.Q[s,a] = 31 # Set a Q-value. + + See the TabularAgent class for more information. + """ + def __init__(self, env, gamma=1.0, alpha=0.5, epsilon=0.1): + self.alpha = alpha + super().__init__(env, gamma, epsilon) + + def pi(self, s, k, info=None): + """ + Return current action using epsilon-greedy exploration. You should look at the TabularAgent class for ideas. + """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement the epsilon-greedy policy here.") + return action + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + """ + Implement the Q-learning update rule, i.e. compute a* from the Q-values. + As a hint, note that self.Q[sp,a] corresponds to q(s_{t+1}, a) and + that what you need to update is self.Q[s, a] = ... + + You may want to look at self.Q.get_optimal_action(state) to compute a = argmax_a Q[s,a]. + """ + # TODO: 3 lines missing. + raise NotImplementedError("Update the Q[s,a]-values here.") + + def __str__(self): + return f"QLearner_{self.gamma}_{self.epsilon}_{self.alpha}" + +q_exp = f"experiments/cliffwalk_Q" +epsilon = 0.1 +max_runs = 10 +alpha = 0.5 +def cliffwalk(): + env = gym.make('CliffWalking-v0') + agent = QAgent(env, epsilon=epsilon, alpha=alpha) + train(env, agent, q_exp, num_episodes=200, max_runs=max_runs) + + # As a baseline, we set up/evaluate a value-iteration agent to get an idea about the optimal performance. + # To do so, we need an MDP object. We create an MDP object out of the gym environment below. + # You can look at the code if you like, but it is simply a helper function to convert from one datastructure to another, + # and all it does is to give a MDP object which is needed for our value-iteration implementation from the previous + # week. + mdp = GymEnv2MDP(env) + vi_exp = "experiments/cliffwalk_VI" + Vagent = ValueIterationAgent(env, mdp=mdp, epsilon=epsilon) + train(env, Vagent, vi_exp, num_episodes=200, max_runs=max_runs) + + vi_exp_opt = "experiments/cliffwalk_VI_optimal" + Vagent_opt = ValueIterationAgent(env, mdp=mdp, epsilon=0) # Same, but with epsilon=0 + train(env, Vagent_opt, vi_exp_opt, num_episodes=200, max_runs=max_runs) + + exp_names = [q_exp, vi_exp, vi_exp_opt] + return env, exp_names + +if __name__ == "__main__": + for _ in range(10): + env, exp_names = cliffwalk() + main_plot(exp_names, smoothing_window=10) + plt.ylim([-100, 0]) + plt.title("Q-learning on " + env.spec.name) + savepdf("Q_learning_cliff") + plt.show() diff --git a/irlc/ex11/sarsa_agent.py b/irlc/ex11/sarsa_agent.py new file mode 100644 index 0000000..29aa196 --- /dev/null +++ b/irlc/ex11/sarsa_agent.py @@ -0,0 +1,52 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import matplotlib.pyplot as plt +from irlc.ex11.q_agent import QAgent +from irlc import main_plot, savepdf +from irlc.ex01.agent import train +from irlc.ex11.q_agent import cliffwalk, alpha, epsilon + +class SarsaAgent(QAgent): + r""" Implement the Sarsa control method from (SB18, Section 6.4). It is recommended you complete + the Q-agent first because the two methods are very similar and the Q-agent is easier to implement. """ + def __init__(self, env, gamma=1, alpha=0.5, epsilon=0.1): + super().__init__(env, gamma=gamma, alpha=alpha, epsilon=epsilon) + + def pi(self, s, k, info=None): + if k == 0: + """ we are at the beginning of the episode. Generate a by being epsilon-greedy""" + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + else: + """ Return the action self.a you generated during the train where you know s_{t+1} """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + """ + generate A' as self.a by being epsilon-greedy. Re-use code from the Agent class. + """ + # TODO: 1 lines missing. + raise NotImplementedError("self.a = ....") + """ now that you know A' = self.a, perform the update to self.Q[s,a] here """ + # TODO: 2 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + + def __str__(self): + return f"Sarsa{self.gamma}_{self.epsilon}_{self.alpha}" + +sarsa_exp = f"experiments/cliffwalk_Sarsa" +if __name__ == "__main__": + env, q_experiments = cliffwalk() # get results from Q-learning + agent = SarsaAgent(env, epsilon=epsilon, alpha=alpha) + for _ in range(10): + train(env, agent, sarsa_exp, num_episodes=200, max_runs=10) + main_plot(q_experiments + [sarsa_exp], smoothing_window=10) + plt.ylim([-100, 0]) + plt.title("Q and Sarsa learning on " + env.spec.name) + savepdf("QSarsa_learning_cliff") + plt.show() diff --git a/irlc/ex11/semi_grad_q.py b/irlc/ex11/semi_grad_q.py new file mode 100644 index 0000000..0910717 --- /dev/null +++ b/irlc/ex11/semi_grad_q.py @@ -0,0 +1,45 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import gymnasium as gym +from irlc.ex01.agent import train +from irlc import main_plot +import matplotlib.pyplot as plt +from irlc.ex11.q_agent import QAgent +from irlc.ex11.feature_encoder import LinearQEncoder +from irlc import savepdf + +class LinearSemiGradQAgent(QAgent): + def __init__(self, env, gamma=1.0, alpha=0.5, epsilon=0.1, q_encoder=None): + """ The Q-values, as implemented using a function approximator, can now be accessed as follows: + + >> self.Q(s,a) # Compute q-value + >> self.Q.x(s,a) # Compute gradient of the above expression wrt. w + >> self.Q.w # get weight-vector. + + I would recommend inserting a breakpoint and investigating the above expressions yourself; + you can of course al check the class LinearQEncoder if you want to see how it is done in practice. + """ + super().__init__(env, gamma, epsilon=epsilon, alpha=alpha) + self.Q = LinearQEncoder(env, tilings=8) if q_encoder is None else q_encoder + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + # TODO: 4 lines missing. + raise NotImplementedError("Implement function body") + + def __str__(self): + return f"LinearSemiGradQ{self.gamma}_{self.epsilon}_{self.alpha}" + +num_of_tilings = 8 +alpha = 1 / num_of_tilings +episodes = 300 +x = "Episode" +experiment_q = "experiments/mountaincar_semigrad_q" + +if __name__ == "__main__": + from irlc.ex10 import envs + env = gym.make("MountainCar500-v0") + for _ in range(10): + agent = LinearSemiGradQAgent(env, gamma=1, alpha=alpha, epsilon=0) + train(env, agent, experiment_q, num_episodes=episodes, max_runs=10) + main_plot(experiments=[experiment_q], x_key=x, y_key='Length', smoothing_window=30, resample_ticks=100) + savepdf("semigrad_q") + plt.show() diff --git a/irlc/ex11/semi_grad_sarsa.py b/irlc/ex11/semi_grad_sarsa.py new file mode 100644 index 0000000..4c0e814 --- /dev/null +++ b/irlc/ex11/semi_grad_sarsa.py @@ -0,0 +1,52 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import matplotlib.pyplot as plt +from irlc import main_plot, savepdf +from irlc.ex01.agent import train +import numpy as np +import gymnasium as gym +from irlc.ex11.semi_grad_q import LinearSemiGradQAgent +np.seterr(all='raise') + +class LinearSemiGradSarsa(LinearSemiGradQAgent): + def __init__(self, env, gamma=0.99, epsilon=0.1, alpha=0.5, q_encoder=None): + """ Implement the Linear semi-gradient Sarsa method from (SB18, Section 10.1)""" + super().__init__(env, gamma, epsilon=epsilon, alpha=alpha, q_encoder=q_encoder) + + def pi(self, s, k, info=None): + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + return action + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + # TODO: 4 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + + if sum(np.abs(self.Q.w)) > 1e5: raise Exception("Weights diverged. Decrease alpha") + + def __str__(self): + return f"LinSemiGradSarsa{self.gamma}_{self.epsilon}_{self.alpha}" + +experiment_sarsa = "experiments/mountaincar_Sarsa" + +if __name__ == "__main__": + from irlc.ex11.semi_grad_q import experiment_q, alpha, x + from irlc.ex10 import envs + + env = gym.make("MountainCar500-v0") + for _ in range(10): + agent = LinearSemiGradSarsa(env, gamma=1, alpha=alpha, epsilon=0) + train(env, agent, experiment_sarsa, num_episodes=300, max_runs=10) + + main_plot(experiments=[experiment_q, experiment_sarsa], x_key=x, y_key='Length', smoothing_window=30) + savepdf("semigrad_q_sarsa") + plt.show() + + # Turn off averaging + main_plot(experiments=[experiment_q, experiment_sarsa], x_key=x, y_key='Length', smoothing_window=30, units="Unit", estimator=None) + savepdf("semigrad_q_sarsa_individual") + plt.show() diff --git a/irlc/ex12/__init__.py b/irlc/ex12/__init__.py new file mode 100644 index 0000000..6bf40e6 --- /dev/null +++ b/irlc/ex12/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 12.""" diff --git a/irlc/ex12/mountain_car.py b/irlc/ex12/mountain_car.py new file mode 100644 index 0000000..7483bdf --- /dev/null +++ b/irlc/ex12/mountain_car.py @@ -0,0 +1,155 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.utils.common import log_time_series +from irlc.ex10 import envs +import numpy as np +import matplotlib.pyplot as plt +from tqdm import tqdm +from irlc import savepdf +from irlc.ex01.agent import train +from irlc.ex12.semi_grad_nstep_sarsa import LinearSemiGradSarsaN +import gymnasium as gym +from irlc import main_plot +from irlc.ex12.semi_grad_sarsa_lambda import LinearSemiGradSarsa + +# Helper function for plotting the value functions. +def plot_surface_2(X,Y,Z,fig=None, ax=None, **kwargs): + if fig is None and ax is None: + fig = plt.figure(figsize=(20, 10)) + if ax is None: + ax = fig.add_subplot(projection='3d') + surf = ax.plot_surface(X, Y, Z, cmap=plt.cm.coolwarm, linewidth=1, edgecolors='k', **kwargs) + ax.view_init(ax.elev, -120) + if fig is not None: + fig.colorbar(surf, shrink=0.5, aspect=5) + return ax + + +def plot_mountaincar_value_function(env, value_function, ax): + """ + 3d plot + """ + grid_size = 40 + low = env.unwrapped.observation_space.low + high = env.unwrapped.observation_space.high + X,Y = np.meshgrid( np.linspace(low[0], high[0], grid_size), np.linspace(low[1], high[1], grid_size) ) + Z = X*0 + for i, (x,y) in enumerate(zip(X.flat, Y.flat)): + Z.flat[i] = value_function( (x,y) ) + + plot_surface_2(X,Y,Z,ax=ax) + ax.set_xlabel('Position') + ax.set_ylabel('Velocity') + ax.set_zlabel('Cost to go') + +def figure_10_1(): + episodes = 9000 + plot_episodes = [1, 99, episodes - 1] + scale = 8 + fig = plt.figure(figsize=(4*scale, scale)) + axes = [fig.add_subplot(1, len(plot_episodes), i+1, projection='3d') for i in range(len(plot_episodes))] + num_of_tilings = 8 + alpha = 0.3 + + env = gym.make("MountainCar-v0") + agent = LinearSemiGradSarsa(env, gamma=1, alpha=alpha/num_of_tilings, epsilon=0) + for ep in tqdm(range(episodes)): + train(env, agent, num_episodes=1, max_steps=np.inf, verbose=False) + if ep in plot_episodes: + v = lambda s: -max(agent.Q.get_Qs(s)[1]) + ax = axes[plot_episodes.index(ep)] + plot_mountaincar_value_function(env, v, ax=ax) + ax.set_title(f'Episode {ep+1}') + + from irlc import savepdf + savepdf("semigrad_sarsa_10-1") + plt.show() + +def figure_10_2(): + episodes = 500 + num_of_tilings = 8 + alphas = [0.1, 0.2, 0.5] + env = gym.make("MountainCar500-v0") + + experiments = [] + for alpha in alphas: + agent = LinearSemiGradSarsa(env, gamma=1, alpha=alpha / num_of_tilings, epsilon=0) + experiment = f"experiments/mountaincar_10-2_{agent}_{episodes}" + train(env, agent, experiment_name=experiment, num_episodes=episodes,max_runs=10) + experiments.append(experiment) + + main_plot(experiments=experiments, y_key="Length") + plt.xlabel('Episode') + plt.ylabel('Steps per episode') + plt.title(env.spec.name + " - Semigrad Sarsa - Figure 10.2") + savepdf("mountaincar_10-2") + plt.show() + +def figure_10_3(): + from irlc.ex12.semi_grad_sarsa_lambda import LinearSemiGradSarsaLambda + from irlc.ex11.semi_grad_q import LinearSemiGradQAgent + + max_runs = 10 + episodes = 500 + num_of_tilings = 8 + alphas = [0.5, 0.3] + n_steps = [1, 8] + + env = gym.make("MountainCar500-v0") + experiments = [] + + """ Plot results of experiments here. """ + # TODO: 16 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + + main_plot(experiments=experiments, y_key="Length") + plt.xlabel('Episode') + plt.ylabel('Steps per episode') + plt.title(env.spec.name + " - Semigrad N-step Sarsa - Figure 10.3") + savepdf("mountaincar_10-3") + plt.show() + +def figure_10_4(): + alphas = np.arange(0.25, 1.75, 0.25) + n_steps = np.power(2, np.arange(0, 5)) + episodes = 50 + env = gym.make("MountainCar500-v0") + experiments = [] + num_of_tilings = 8 + max_asteps = 500 + run = True + for n_step_index, n_step in enumerate(n_steps): + aexp = [] + did_run = False + for alpha_index, alpha in enumerate(alphas): + if not run: + continue + if (n_step == 8 and alpha > 1) or (n_step == 16 and alpha > 0.75): + # In these cases it won't converge, so ignore them + asteps = max_asteps #max_steps * episodes + else: + n = n_step + agent = LinearSemiGradSarsaN(env, gamma=1, alpha=alpha / num_of_tilings, epsilon=0, n=n) + _, stats, _ = train(env, agent, num_episodes=episodes) + asteps = np.mean( [s['Length'] for s in stats] ) + did_run = did_run or stats is not None + + aexp.append({'alpha': alpha, 'average_steps': asteps}) + + experiment = f"experiments/mc_10-4_lsgn_{n_step}" + experiments.append(experiment) + if did_run: + log_time_series(experiment, aexp) + + main_plot(experiments, x_key="alpha", y_key="average_steps", ci=None) + plt.xlabel('alpha') + plt.ylabel('Steps per episode') + plt.title("Figure 10.4: Semigrad n-step Sarsa on mountain car") + plt.ylim([150, 300]) + savepdf("mountaincar_10-4") + plt.show() + +if __name__ == '__main__': + figure_10_1() + figure_10_2() + figure_10_3() + figure_10_4() diff --git a/irlc/ex12/sarsa_lambda_agent.py b/irlc/ex12/sarsa_lambda_agent.py new file mode 100644 index 0000000..9cd7baf --- /dev/null +++ b/irlc/ex12/sarsa_lambda_agent.py @@ -0,0 +1,68 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from collections import defaultdict +import gymnasium as gym +from irlc.ex01.agent import train +from irlc import main_plot, savepdf +import matplotlib.pyplot as plt +from irlc.ex11.sarsa_agent import SarsaAgent + + +class SarsaLambdaAgent(SarsaAgent): + def __init__(self, env, gamma=0.99, epsilon=0.1, alpha=0.5, lamb=0.9): + """ + Implementation of Sarsa(Lambda) in the tabular version, see + http://incompleteideas.net/book/first/ebook/node77.html + for details. Remember to reset the + eligibility trace E after each episode, i.e. set E(s,a) = 0. + + Note 'lamb' is an abbreveation of lambda, because lambda is a reserved keyword in python. + + The constructor initializes e, the eligibility trace. Since we want to easily be able to find the non-zero + elements it will be convenient to use a dictionary. I.e. + + self.e[(s,a)] is the eligibility trace e(s,a) (or E(s,a) if you prefer). + + Note that Sarsa(Lambda) generalize Sarsa. This means that we again must generate the next action A' from S' in the train method and + store it for when we take actions in the policy method pi. I.e. we can re-use the Sarsa Agents code for the policy (self.pi). + """ + super().__init__(env, gamma=gamma, alpha=alpha, epsilon=epsilon) + self.lamb = lamb + # We use a dictionary to store the eligibility trace. It can be indexed as self.e[s,a]. + self.e = defaultdict(float) + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + # TODO: 1 lines missing. + raise NotImplementedError("a_prime = ... (get action for S'=sp using self.pi_eps; see Sarsa)") + # TODO: 1 lines missing. + raise NotImplementedError("delta = ... (The ordinary Sarsa learning signal)") + # TODO: 1 lines missing. + raise NotImplementedError("Update the eligibility trace e(s,a) += 1") + for (s,a), ee in self.e.items(): + # TODO: 2 lines missing. + raise NotImplementedError("Update Q values and eligibility trace") + if done: # Clear eligibility trace after each episode and update variables for Sarsa + self.e.clear() + else: + self.a = a_prime + + def __str__(self): + return f"SarsaLambda_{self.gamma}_{self.epsilon}_{self.alpha}_{self.lamb}" + +if __name__ == "__main__": + envn = 'CliffWalking-v0' + env = gym.make(envn) + + alpha =0.05 + sarsaLagent = SarsaLambdaAgent(env,gamma=0.99, epsilon=0.1, alpha=alpha, lamb=0.9) + sarsa = SarsaAgent(env,gamma=0.99,alpha=alpha,epsilon=0.1) + methods = [("SarsaL", sarsaLagent), ("Sarsa", sarsa)] + + experiments = [] + for k, (name,agent) in enumerate(methods): + expn = f"experiments/{envn}_{name}" + train(env, agent, expn, num_episodes=500, max_runs=10) + experiments.append(expn) + main_plot(experiments, smoothing_window=10, resample_ticks=200) + plt.ylim([-100, 0]) + savepdf("cliff_sarsa_lambda") + plt.show() diff --git a/irlc/ex12/sarsa_lambda_open.py b/irlc/ex12/sarsa_lambda_open.py new file mode 100644 index 0000000..0fe4e1c --- /dev/null +++ b/irlc/ex12/sarsa_lambda_open.py @@ -0,0 +1,35 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex12.sarsa_lambda_agent import SarsaLambdaAgent +from irlc.gridworld.gridworld_environments import OpenGridEnvironment +from irlc import train, interactive + +def keyboard_play(Agent, method_label='MC', num_episodes=1000, alpha=0.5, autoplay=False, **args): + print("Evaluating", Agent, "on the open gridworld environment.") + print("Press p to follow the agents policy or use the keyboard to input actions") + print("(Please be aware that Sarsa, N-step Sarsa, and Sarsa(Lambda) do not always make the right updates when you input actions with the keyboard)") + + env = OpenGridEnvironment(render_mode='human', frames_per_second=10) + try: + agent = Agent(env, gamma=0.99, epsilon=0.1, alpha=alpha, **args) + except Exception as e: # If it is a value agent without the epsilon. + agent = Agent(env, gamma=0.99, alpha=alpha, **args) + env, agent = interactive(env, agent, autoplay=autoplay) + train(env, agent, num_episodes=num_episodes) + env.close() + +if __name__ == "__main__": + """ + Example: Play a three episodes and save a snapshot of the Q-values as a .pdf + """ + env = OpenGridEnvironment(render_mode='human') + agent = SarsaLambdaAgent(env, gamma=0.99, epsilon=0.1, alpha=.5) + env, agent = interactive(env, agent, autoplay=True) + train(env, agent, num_episodes=3) + from irlc import savepdf + savepdf("sarsa_lambda_opengrid", env=env) + env.close() + + """ Example: Keyboard play + You can input actions manually with the keyboard, but the Q-values are not necessarily updates correctly in this mode. Can you tell why? + You can let the agent play by pressing `p`, in which case the Q-values will be updated correctly. """ + keyboard_play(SarsaLambdaAgent, method_label="Sarsa(Lambda)", lamb=0.8) diff --git a/irlc/ex12/semi_grad_nstep_sarsa.py b/irlc/ex12/semi_grad_nstep_sarsa.py new file mode 100644 index 0000000..c7f6ac2 --- /dev/null +++ b/irlc/ex12/semi_grad_nstep_sarsa.py @@ -0,0 +1,53 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex01.agent import train +import gymnasium as gym +from irlc.ex11.semi_grad_sarsa import LinearSemiGradSarsa +from irlc.ex11.nstep_sarsa_agent import SarsaNAgent + +class LinearSemiGradSarsaN(SarsaNAgent, LinearSemiGradSarsa): + def __init__(self, env, gamma=0.99, alpha=0.5, epsilon=0.1, q_encoder=None, n=1): + """ + Note you can access the super-classes as: + >> SarsaNAgent.pi(self, s) # Call the pi(s) as implemented in SarsaNAgent + Alternatively, just inherit from Agent and set up data structure as required. + """ + SarsaNAgent.__init__(self, env, gamma, alpha=alpha, epsilon=epsilon, n=n) + LinearSemiGradSarsa.__init__(self, env, gamma, alpha=alpha, epsilon=epsilon, q_encoder=q_encoder) + + def pi(self, s, k, info=None): + return SarsaNAgent.pi(self, s, k, info) + + def _q(self, s, a): + """ + Return Q(s,a) using the linear function approximator with weights self.w; i.e. use self.q + """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + + def _upd_q(self, s, a, delta): + """ + Update the weight-vector w using the appropriate rule (see exercise description). I.e. the update + should be of the form + + self.w += self.alpha * delta * (gradient of Q(s,a;w) + + where + delta = (G^n - Q(s,a;w) + """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + + def __str__(self): + return f"LinSemiGradSarsaN{self.gamma}_{self.epsilon}_{self.alpha}_{self.n}" + + +experiment_nsarsa = "experiments/mountaincar_SarsaN" +if __name__ == "__main__": + from irlc.ex12.semi_grad_sarsa_lambda import alpha, plot_including_week10, experiment_sarsaL, episodes + import irlc.ex10.envs + env = gym.make("MountainCar500-v0") + for _ in range(10): + agent = LinearSemiGradSarsaN(env, gamma=1, alpha=alpha, epsilon=0, n=4) + train(env, agent, experiment_nsarsa, num_episodes=episodes, max_runs=10) + # plot while including the results from last week for Sarsa and Q-learning + plot_including_week10([experiment_sarsaL, experiment_nsarsa],output="semigrad_sarsan") diff --git a/irlc/ex12/semi_grad_sarsa_lambda.py b/irlc/ex12/semi_grad_sarsa_lambda.py new file mode 100644 index 0000000..04644d9 --- /dev/null +++ b/irlc/ex12/semi_grad_sarsa_lambda.py @@ -0,0 +1,74 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import gymnasium as gym +import numpy as np +from irlc.ex01.agent import train +from irlc import main_plot, savepdf +import matplotlib.pyplot as plt +from irlc.ex11.semi_grad_sarsa import LinearSemiGradSarsa + +class LinearSemiGradSarsaLambda(LinearSemiGradSarsa): + def __init__(self, env, gamma=0.99, epsilon=0.1, alpha=0.5, lamb=0.9, q_encoder=None): + """ + Sarsa(Lambda) with linear feature approximators (see (SB18, Section 12.7)). + """ + super().__init__(env, gamma, alpha=alpha, epsilon=epsilon, q_encoder=q_encoder) + self.z = np.zeros(self.Q.d) # Vector to store eligibility trace (same dimension as self.w) + self.lamb = lamb # lambda in Sarsa(lambda). We cannot use the reserved keyword 'lambda'. + + def pi(self, s, k, info=None): + if k == 0: # If beginning of episode. + self.a = self.pi_eps(s, info) + self.x = self.Q.x(s,self.a) + self.Q_old = 0 + return self.a + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + a_prime = self.pi_eps(sp, info_sp) if not done else -1 + x_prime = self.Q.x(sp, a_prime) if not done else None + """ + Update the eligibility trace self.z and the weights self.w here. + Note Q-values are approximated as Q = w @ x. + We use Q_prime = w * x(s', a') to denote the new q-values for (stored for next iteration as in the pseudo code) + """ + # TODO: 5 lines missing. + raise NotImplementedError("Update z, w") + if done: # Reset eligibility trace and time step t as in Sarsa. + self.z = self.z * 0 + else: + self.Q_old, self.x, self.a = Q_prime, x_prime, a_prime + + def __str__(self): + return f"LinearSarsaLambda_{self.gamma}_{self.epsilon}_{self.alpha}_{self.lamb}" + + +from irlc.ex11.semi_grad_q import experiment_q, x, episodes +from irlc.ex11.semi_grad_sarsa import experiment_sarsa +from irlc.ex10 import envs +experiment_sarsaL = "experiments/mountaincar_sarsaL" +num_of_tilings = 8 +alpha = 1 / num_of_tilings / 2 # learning rate + +def plot_including_week10(experiments, output): + exps = ["../ex11/" + e for e in [experiment_q, experiment_sarsa]] + experiments + + main_plot(exps, x_key=x, y_key='Length', smoothing_window=30, resample_ticks=100) + savepdf(output) + plt.show() + + # Turn off averaging + main_plot(exps, x_key=x, y_key='Length', smoothing_window=30, units="Unit", estimator=None, resample_ticks=100) + savepdf(output+"_individual") + plt.show() + +if __name__ == "__main__": + env = gym.make("MountainCar500-v0") + for _ in range(5): # run experiment 10 times + agent = LinearSemiGradSarsaLambda(env, gamma=1, alpha=alpha, epsilon=0) + train(env, agent, experiment_sarsaL, num_episodes=episodes, max_runs=10) + # Make plots (we use an external function so we can re-use it for the semi-gradient n-step controller) + plot_including_week10([experiment_sarsaL], output="semigrad_sarsaL") diff --git a/irlc/ex13/__init__.py b/irlc/ex13/__init__.py new file mode 100644 index 0000000..d082cf6 --- /dev/null +++ b/irlc/ex13/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This directory contains the exercises for week 13.""" diff --git a/irlc/ex13/__pycache__/__init__.cpython-311.pyc b/irlc/ex13/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b3d045b0c7c2ba7e2f61edc2467536eae8273e1 GIT binary patch literal 233 zcmZ3^%ge>Uz`$UU-<$S|fq~&Mhy%lnP{wDFlIaX73{eazjKK_=OjSl98JWcjDVas7 z$tC$kl?uuEc_oRNdBqAP8L0}X6{$tZnZ>Ea3TgR83gxM(*$RfndVZRWx7g$3Q}UDJ z<5x0#1{wX!Mn5AzH&wr+G$U2tB|o_|H#M)MSU)p2N8iB6#MGd;q%;L0Qk0XdpITvP ztREkrnU`4-AFo$X`HRCQH$SB`C)KWqje&sy<k(_C1_p)?%#4hT4;U;iz)%qj0|Ns9 D5%fVk literal 0 HcmV?d00001 diff --git a/irlc/ex13/__pycache__/buffer.cpython-311.pyc b/irlc/ex13/__pycache__/buffer.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eefadd98930e8787a3439fd4bd00601ed4c07aa0 GIT binary patch literal 5802 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 literal 0 HcmV?d00001 diff --git a/irlc/ex13/__pycache__/dqn_network.cpython-311.pyc b/irlc/ex13/__pycache__/dqn_network.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ae0dbe1149808f291ed5478bf244e3b5a6d8334 GIT binary patch literal 3213 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 A%>V!Z literal 0 HcmV?d00001 diff --git a/irlc/ex13/__pycache__/torch_networks.cpython-311.pyc b/irlc/ex13/__pycache__/torch_networks.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..feab49d6f92ed16db97b01804a73a8c62dd2096c GIT binary patch literal 9539 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 T5xD?EA2b<Qq%JT^f^!J~7XOib literal 0 HcmV?d00001 diff --git a/irlc/ex13/buffer.py b/irlc/ex13/buffer.py new file mode 100644 index 0000000..05ef6b5 --- /dev/null +++ b/irlc/ex13/buffer.py @@ -0,0 +1,109 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +import random +from collections import deque +from irlc import cache_read, cache_write + +class BasicBuffer: + """ + The buffer class is used to keep track of past experience and sample it for learning. + """ + def __init__(self, max_size=2000): + """ + Creates a new (empty) buffer. + + :param max_size: Maximum number of elements in the buffer. This should be a large number like 100'000. + """ + self.buffer = deque(maxlen=max_size) + + def push(self, state, action, reward, next_state, done): + """ + Add information from a single step, :math:`(s_t, a_t, r_{t+1}, s_{t+1}, \\text{done})` to the buffer. + + .. runblock:: pycon + + >>> import gymnasium as gym + >>> from irlc.ex13.buffer import BasicBuffer + >>> env = gym.make("CartPole-v1") + >>> b = BasicBuffer() + >>> s, info = env.reset() + >>> a = env.action_space.sample() + >>> sp, r, done, _, info = env.step(a) + >>> b.push(s, a, r, sp, done) + >>> len(b) # Get number of elements in buffer + + :param state: A state :math:`s_t` + :param action: Action taken :math:`a_t` + :param reward: Reward obtained :math:`r_{t+1}` + :param next_state: Next state transitioned to :math:`s_{t+1}` + :param done: ``True`` if the environment terminated else ``False`` + :return: ``None`` + """ + experience = (state, action, np.array([reward]), next_state, done) + self.buffer.append(experience) + + def sample(self, batch_size): + """ + Sample ``batch_size`` elements from the buffer for use in training a deep Q-learning method. + The elements returned all be numpy ``ndarray`` where the first dimension is the batch dimension, i.e. of size + ``batch_size``. + + .. runblock:: pycon + + >>> import gymnasium as gym + >>> from irlc.ex13.buffer import BasicBuffer + >>> env = gym.make("CartPole-v1") + >>> b = BasicBuffer() + >>> s, info = env.reset() + >>> a = env.action_space.sample() + >>> sp, r, done, _, _ = env.step(a) + >>> b.push(s, a, r, sp, done) + >>> S, A, R, SP, DONE = b.sample(batch_size=32) + >>> S.shape # Dimension batch_size x n + >>> R.shape # Dimension batch_size x 1 + + :param batch_size: Number of elements to sample + :return: + - S - Matrix of size ``batch_size x n`` of sampled states + - A - Matrix of size ``batch_size x n`` of sampled actions + - R - Matrix of size ``batch_size x n`` of sampled rewards + - SP - Matrix of size ``batch_size x n`` of sampled states transitioned to + - DONE - Matrix of size ``batch_size x 1`` of bools indicating if the environment terminated + + """ + state_batch = [] + action_batch = [] + reward_batch = [] + next_state_batch = [] + done_batch = [] + assert len(self.buffer) > 0, "The replay buffer must be non-empty in order to sample a batch: Use push()" + batch = random.choices(self.buffer, k=batch_size) + for state, action, reward, next_state, done in batch: + state_batch.append(state) + action_batch.append(action) + reward_batch.append(reward) + next_state_batch.append(next_state) + done_batch.append(done) + + return map(lambda x: np.asarray(x), (state_batch, action_batch, reward_batch, next_state_batch, done_batch)) + + def __len__(self): + return len(self.buffer) + + def save(self, path): + """ + Use this to save the content of the buffer to a file + + :param path: Path where to save (use same argument with ``load``) + :return: ``None`` + """ + cache_write(self.buffer, path) + + def load(self, path): + """ + Use this to load buffer content from a file + + :param path: Path to load from (use same argument with ``save``) + :return: ``None`` + """ + self.buffer = cache_read(path) diff --git a/irlc/ex13/deepq_agent.py b/irlc/ex13/deepq_agent.py new file mode 100644 index 0000000..43facb2 --- /dev/null +++ b/irlc/ex13/deepq_agent.py @@ -0,0 +1,130 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +USE_KERAS = False # Toggle to use Keras/Pytorch +import gymnasium as gym +import numpy as np +import os +from matplotlib import pyplot as plt +from irlc.ex01.agent import train +from irlc.ex13.buffer import BasicBuffer +from irlc import cache_write, cache_read, cache_exists +from irlc.ex09.rl_agent import TabularAgent +from irlc.ex13.torch_networks import TorchNetwork as QNetwork # Torch network architechture + +class DeepQAgent(TabularAgent): + def __init__(self, env, network=None, buffer=None, gamma=0.99, epsilon=None, alpha=0.001, batch_size=32, + replay_buffer_size=2000, replay_buffer_minreplay=500): + # Ensure 'epsilon' is a function to allow gradually decreasing exploration rate + epsilon = epsilon if callable(epsilon) else lambda steps, episodes: epsilon + super().__init__(env, gamma=gamma, epsilon=epsilon) + self.memory = BasicBuffer(replay_buffer_size) if buffer is None else buffer + """ + All the 'deep' stuff is handled by a seperate class. For instance + self.Q(s) + will return a [batch_size x actions] matrix of Q-values + """ + self.Q = network(env, trainable=True) if network else QNetwork(env, trainable=True, learning_rate=alpha) + self.batch_size = batch_size + self.replay_buffer_minreplay = replay_buffer_minreplay + self.steps, self.episodes = 0, 0 + + def pi(self, s, k, info_s=None): + eps_ = self.epsilon(self.steps, self.episodes) # get the learning rate + # return action by regular epsilon-greedy exploration + return self.env.action_space.sample() if np.random.rand() < eps_ else np.argmax(self.Q(s[np.newaxis,...])) + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + self.memory.push(s, a, r, sp, done) # save current observation + if len(self.memory) > self.replay_buffer_minreplay: + self.experience_replay() # do the actual training step + self.steps, self.episodes = self.steps + 1, self.episodes + done + + def experience_replay(self): + """ + Perform the actual deep-Q learning step. + + The actual learning is handled by calling self.Q.fit(s,target) + where s is defined as below (i.e. all states from the replay buffer) + and target is the desired value of self.Q(s). + + Note that target must therefore be of size Batch x Actions. In other words fit minimize + + |Q(s) - target|^2 + + which must implement the proper cost. This can be done by setting most entries of target equal to self.Q(s) + and the other equal to y, which is Q-learning target for Q(s,a). """ + """ First we sample from replay buffer. Returns numpy Arrays of dimension + > [self.batch_size] x [...]] + for instance 'a' will be of dimension [self.batch_size x 1]. + """ + s,a,r,sp,done = self.memory.sample(self.batch_size) + # TODO: 3 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + self.Q.fit(s, target) + + def save(self, path): # allows us to save/load model + if not os.path.isdir(path): + os.makedirs(path) + self.Q.save(os.path.join(path, "Q")) + cache_write(dict(steps=self.steps, episodes=self.episodes), os.path.join(path, "agent.pkl")) + mpath = os.path.join(path, "memory.pkl") + import shutil + if os.path.isfile(mpath): + shutil.move(mpath, mpath +".backup") # shuffle file + self.memory.save(mpath) + + def load(self, path): # allows us to save/load model + if not cache_exists(os.path.join(path, "agent.pkl")): + return False + for k, v in cache_read(os.path.join(path, "agent.pkl")).items(): + self.__dict__[k] = v + self.Q.load(os.path.join(path, "Q")) + self.memory.load(os.path.join(path, "memory.pkl")) + return True + + def __str__(self): + return f"basic_DQN{self.gamma}" + +def linear_interp(maxval, minval, delay, miniter): + """ + Will return a function f(i) with the following signature: + + f(i) = maxval for i < delay + f(i) = linear interpolate between max/minval until delay+miniter + f(i) = miniter for i > delay+miniter + """ + return lambda steps, episodes: min(max([maxval- ((steps-delay)/miniter)*(maxval-minval), minval]), maxval) + +cartpole_dqn_options = dict(gamma=0.95, epsilon=linear_interp(maxval=1,minval=0.01,delay=300,miniter=5000), + replay_buffer_minreplay=300, replay_buffer_size=500000) + +def mk_cartpole(): + env = gym.make("CartPole-v0") + agent = DeepQAgent(env, **cartpole_dqn_options) + return env, agent + +if __name__ == "__main__": + env_id = "CartPole-v0" + ex = f"experiments/cartpole_dqn" + num_episodes = 200 # We train for 200 episodes + env, agent = mk_cartpole() + train(env, agent, experiment_name=ex, num_episodes=num_episodes) + from irlc import main_plot, savepdf + main_plot([ex], units="Unit", estimator=None, smoothing_window=None) + savepdf("cartpole_dqn") + plt.show() + + """ Part 2: The following code showcase how to use the save/load method to store intermediate results + and resume training. Note you have to manually remove 'bad' runs otherwise it will resume where + it left off """ + ex = f"experiments/cartpole_dqn_cache" + num_episodes = 20 # we train 20 just episodes at a time + for j in range(10): # train for a total of 200 episodes + env, agent = mk_cartpole() + """ + saveload_model=True means it will store and load intermediate results + i.e. we can resume training later. It will not be very useful for cartpole, but necesary for e.g. + the atari environment which can run for days + """ + agent.load(ex) + train(env, agent, experiment_name=ex, num_episodes=num_episodes, resume_stats=True) # Resume stat collection from last checkpoint. + agent.save(ex) diff --git a/irlc/ex13/double_deepq_agent.py b/irlc/ex13/double_deepq_agent.py new file mode 100644 index 0000000..99b624b --- /dev/null +++ b/irlc/ex13/double_deepq_agent.py @@ -0,0 +1,73 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import gymnasium as gym +import numpy as np +import os +from irlc.ex13.deepq_agent import DeepQAgent +from matplotlib import pyplot as plt +from irlc.ex13.torch_networks import TorchNetwork as QNetwork # Torch network architechture + +class DoubleQAgent(DeepQAgent): + def __init__(self, env, network=None, buffer=None, gamma=0.99, epsilon=0.2, alpha=0.001, tau=0.1, batch_size=32, + replay_buffer_size=2000, replay_buffer_minreplay=500): + super().__init__(env, network=network, buffer=buffer, gamma=gamma,epsilon=epsilon, alpha=alpha, batch_size=batch_size, + replay_buffer_size=replay_buffer_size, replay_buffer_minreplay=replay_buffer_minreplay) + # The target network play the role of q_{phi'} in the slides. + self.target = QNetwork(env, learning_rate=alpha, trainable=False) if network is None else network(env, learning_rate=alpha, trainable=False) + self.tau = tau # Rate at which the weights in the target network is updated (see slides) + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + self.memory.push(s, a, r, sp, done) + if len(self.memory) > self.replay_buffer_minreplay: + self.experience_replay() + # TODO: 1 lines missing. + raise NotImplementedError("update Phi here in the self.target network") + self.steps, self.episodes = self.steps + 1, self.episodes + done + + def experience_replay(self): + """ Update the double-Q method, i.e. make sure to select actions a' using self.Q + but evaluate the Q-values using the target network (see slides). + In other words, + > self.target(s) + is a Q-function network which evaluates + > q-hat_{\phi'}(s,:). + Asides this, the code will be nearly identical to the basic DQN agent """ + s,a,r,sp,done = self.memory.sample(self.batch_size) + # TODO: 5 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + self.Q.fit(s, target=target) + + def save(self, path): + super().save(path) + self.target.save(os.path.join(path, "Q_target")) # also save target network + + def load(self, path): + loaded = super().load(path) + if loaded: + self.Q.load(os.path.join(path, "Q_target")) # also load target network + return loaded + + + def __str__(self): + return f"doubleDQN_{self.gamma}" + +from irlc.ex13.deepq_agent import cartpole_dqn_options +cartpole_doubleq_options = {**cartpole_dqn_options, 'tau': 0.08} + +def mk_cartpole(): + env = gym.make("CartPole-v0") + agent = DoubleQAgent(env, **cartpole_doubleq_options) + return env, agent + +if __name__ == "__main__": + from irlc import main_plot, savepdf + + env_id = "CartPole-v0" + MAX_EPISODES = 200 + for j in range(1): + env, agent = mk_cartpole() + from irlc.ex01.agent import train + ex = f"experiments/cartpole_double_dqn" + train(env, agent, experiment_name=ex, num_episodes=MAX_EPISODES) + main_plot([f"experiments/cartpole_dqn", ex], estimator=None, smoothing_window=None) + savepdf("cartpole_double_dqn") + plt.show() diff --git a/irlc/ex13/dqn_network.py b/irlc/ex13/dqn_network.py new file mode 100644 index 0000000..d192099 --- /dev/null +++ b/irlc/ex13/dqn_network.py @@ -0,0 +1,63 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +class DQNNetwork: + """ + A class representing a deep Q network. + Note that this function is batched. I.e. ``s`` is assumed to be a numpy array of dimension ``batch_size x n`` + + The following example shows how you can evaluate the Q-values in a given state. An example: + + .. runblock:: pycon + + >>> from irlc.ex13.torch_networks import TorchNetwork + >>> import gymnasium as gym + >>> import numpy as np + >>> env = gym.make("CartPole-v1") + >>> Q = TorchNetwork(env, trainable=True, learning_rate=0.001) # DQN network requires an env to set network dimensions + >>> batch_size = 32 # As an example + >>> states = np.random.rand(batch_size, env.observation_space.shape[0]) # Creates some dummy input + >>> states.shape # batch_size x n + >>> qvals = Q(states) # Evaluate Q(s,a) + >>> qvals.shape # This is a tensor of dimension batch_size x actions + >>> print(qvals[0,1]) # Get Q(s_0, 1) + >>> Y = np.random.rand(batch_size, env.action_space.n) # Generate target Q-values (training data) + >>> Q.fit(states, Y) # Train the Q-network for 1 gradient descent step + """ + def update_Phi(self, source, tau=0.01): + """ + Update (adapts) the weights in this network towards those in source by a small amount. + + For each weight :math:`w_i` in (this) network, and each corresponding weight :math:`w'_i` in the ``source`` network, + the following Polyak update is performed: + + .. math:: + w_i \\leftarrow w_i + \\tau (w'_i - w_i) + + :param source: Target network to update towards + :param tau: Update rate (rate of change :math:`\\tau` + :return: ``None`` + """ + + raise NotImplementedError + + def __call__(self, s): + """ + Evaluate the Q-values in the given (batched) state. + + :param s: A matrix of size ``batch_size x n`` where :math:`n` is the state dimension. + :return: The Q-values as a ``batch_size x d`` dimensional matrix where :math:`d` is the number of actions. + """ + raise NotImplementedError + + def fit(self, s, target): + """ + Fit the network weights by minimizing + + .. math:: + \\frac{1}{B}\sum_{i=1}^B \sum_{a=1}^K \| q_\phi(s_i)_a - y_{i,a} \|^2 + + where ``target`` corresponds to :math:`y` and is a ``[batch_size x actions]`` matrix of target Q-values. + :param s: + :param target: + :return: + """ + raise NotImplementedError diff --git a/irlc/ex13/duel_deepq_agent.py b/irlc/ex13/duel_deepq_agent.py new file mode 100644 index 0000000..65491d3 --- /dev/null +++ b/irlc/ex13/duel_deepq_agent.py @@ -0,0 +1,35 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import gymnasium as gym +import matplotlib.pyplot as plt +from irlc import main_plot, savepdf +from irlc.ex01.agent import train +from irlc.ex13.double_deepq_agent import DoubleQAgent +from irlc.ex13.torch_networks import TorchDuelNetwork as DuelNetwork +from irlc.ex13.buffer import BasicBuffer +from irlc.ex13.double_deepq_agent import cartpole_doubleq_options + +class DuelQAgent(DoubleQAgent): + def __init__(self, env, network=None, buffer=None, gamma=0.99, epsilon=None, alpha=0.001, tau=0.1, batch_size=32, + replay_buffer_size=2000, replay_buffer_minreplay=500): + network = DuelNetwork if network is None else network # Only relevant change + buffer = buffer if buffer is not None else BasicBuffer(max_size=500000) + super().__init__(env, network=network, buffer=buffer, gamma=gamma,epsilon=epsilon, alpha=alpha, tau=tau,batch_size=batch_size, + replay_buffer_size=replay_buffer_size, replay_buffer_minreplay=replay_buffer_minreplay) + self.target.update_Phi(self.Q) + + def __str__(self): + return f"DuelQ_{self.gamma}" + +def mk_cartpole(): + env = gym.make("CartPole-v0") + agent = DuelQAgent(env, **cartpole_doubleq_options) + return env, agent + +if __name__ == "__main__": + env,agent = mk_cartpole() + ex = f"experiments/cartpole_duel_dqn" + train(env, agent, experiment_name=ex, num_episodes=200) + plt.close() + main_plot([f"experiments/cartpole_dqn", f"experiments/cartpole_double_dqn", ex], smoothing_window=None) + savepdf("cartpole_duel_dqn") + plt.show() diff --git a/irlc/ex13/dyna_q.py b/irlc/ex13/dyna_q.py new file mode 100644 index 0000000..a764bef --- /dev/null +++ b/irlc/ex13/dyna_q.py @@ -0,0 +1,89 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import numpy as np +from irlc.ex01.agent import train +import gymnasium as gym +from irlc import main_plot +import matplotlib.pyplot as plt +from irlc import savepdf +from irlc.ex11.sarsa_agent import SarsaAgent +from irlc.ex11.q_agent import QAgent +from irlc.ex12.sarsa_lambda_agent import SarsaLambdaAgent +from irlc.ex13.maze_dyna_environment import MazeEnvironment + +class DynaQ(QAgent): + """ + Implement the tabular dyna-Q agent (SB18, Section 8.7). + """ + def __init__(self, env, gamma=1.0, alpha=0.5, epsilon=0.1, n=5): + super().__init__(env, gamma, alpha=alpha, epsilon=epsilon) + """ + Model is a list of experience, i.e. of the form + Model = [ (s_t, a_t, r_{t+1}, s_{t+1}, done_t), ...] + """ + self.Model = [] + self.n = n # number of planning steps + + def q_update(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + """ + Update the Q-function self.Q[s,a] as in regular Q-learning + """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + self.q_update(s,a,r,sp,done, info_s, info_sp) + self.Model.append( (s,a, r,sp, done)) + for _ in range(self.n): + """ Obtain a random transition from the replay buffer. You can use np.random.randint + then call self.q_update on the random sample. """ + # TODO: 2 lines missing. + raise NotImplementedError("Implement function body") + + def __str__(self): + return f"DynaQ_{self.gamma}_{self.epsilon}_{self.alpha}_{self.n}" + + +def dyna_experiment(env, env_name='maze',num_episodes=50,epsilon=0.1, alpha=0.1, gamma=.95, runs=2): + for _ in range(runs): # Increase runs for nicer error bars + agents = [QAgent(env, epsilon=epsilon, alpha=alpha,gamma=gamma), + SarsaAgent(env, epsilon=epsilon, alpha=alpha, gamma=gamma), + SarsaLambdaAgent(env, epsilon=epsilon, alpha=alpha, gamma=gamma,lamb=0.9), + DynaQ(env, epsilon=epsilon, alpha=alpha,gamma=gamma,n=5), + DynaQ(env, epsilon=epsilon, alpha=alpha,gamma=gamma, n=50), + ] + + experiments = [] + for agent in agents: + expn = f"experiments/b{env_name}_{str(agent)}" + train(env, agent, expn, num_episodes=num_episodes, max_runs=100) + experiments.append(expn) + return experiments + +if __name__ == "__main__": + from irlc.ex09.mdp import MDP2GymEnv + """ The maze-environment is created as an MDP, and we then convert it to a Gym environment. + Alternatively, use the irlc.gridworld.gridworld_environments.py - method to specify the layout as in the other gridworld examples. """ + env = MDP2GymEnv(MazeEnvironment()) + experiments = dyna_experiment(env, env_name='maze',num_episodes=50,epsilon=0.1, alpha=0.1, gamma=.95, runs=4) + main_plot(experiments, smoothing_window=None, y_key="Length") + plt.ylim([0, 500]) + plt.title("Dyna Q on simple Maze (Figure 8.2)") + savepdf("dynaq_maze_8_2") + plt.show() + + # Part 2: Cliffwalking as reference. + env = gym.make('CliffWalking-v0') + gamma, alpha, epsilon = 1, 0.5, 0.1 + # Call the dyna_experiment(...) function here similar to the previous call but using new parameters. + # TODO: 1 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + main_plot(experiments, smoothing_window=5) + plt.ylim([-150, 0]) + plt.title("Dyna-Q learning on " + env.spec.name) + savepdf("dyna_cliff") + plt.show() diff --git a/irlc/ex13/maximization_bias_environment.py b/irlc/ex13/maximization_bias_environment.py new file mode 100644 index 0000000..9e40bc3 --- /dev/null +++ b/irlc/ex13/maximization_bias_environment.py @@ -0,0 +1,93 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import numpy as np +from irlc.ex01.agent import train +from irlc import main_plot +import matplotlib.pyplot as plt +from irlc.ex09.mdp import MDP, MDP2GymEnv +from irlc import savepdf +from irlc.ex11.sarsa_agent import SarsaAgent +from irlc.ex11.q_agent import QAgent +from irlc.ex13.tabular_double_q import TabularDoubleQ + +class MaximizationBiasEnvironment(MDP): + """ + The Maximization Bias yafcport from (SB18, Example 6.7). + For easy implementation, we fix the number of transitions from state B to terminal state to + normal_transitions. The code ensure they still have average reward 0.1, i.e. no action will be preferred. + there are B_actions possible actions from state B in this yafcport (the number is not given in the yafcport). + """ + def __init__(self, B_actions=10, normal_transitions=100, **kwargs): + self.state_A = 0 + self.state_B = 1 + self.LEFT = 0 + self.RIGHT = 1 + self.B_actions = B_actions + self.n_transitions = normal_transitions + super().__init__(initial_state=self.state_A, **kwargs) + + def is_terminal(self, state): + return state == 2 + + def A(self, s): + # define the actions pace + if s == self.state_A: + return [self.LEFT, self.RIGHT] + elif s == self.state_B: # in state B + return [n for n in range(self.B_actions)] + else: + return [0] # terminal; return a dummy action 0 which does nothing (some code is sensitive to empty action spaces) + + def Psr(self, s, a): + t = 2 # terminal state + if s == self.state_A: + if a == self.RIGHT: + # TODO: 1 lines missing. + raise NotImplementedError("Implement what the environment does in state A with a RIGHT action") + else: + # TODO: 1 lines missing. + raise NotImplementedError("Implement what the environment does in state A with a LEFT action") + else: # s is in state B + p = 1/self.n_transitions # transition probability + rewards = [np.random.randn() for _ in range(self.n_transitions)] + rewards = [r - np.mean(rewards)-0.1 for r in rewards] + return { (t, r): p for r in rewards} + +if __name__ == "__main__": + """ + The Maximization Bias from (SB18, Example 6.7). + I have fixed the number of "junk" actions in state B to 10, but it can easily be changed + in the environment. + + I don't have an easy way to get the number of 'left'-actions, so instead i plot + the trajectory length: it is 1 for a right action, and 2 for a left. + """ + env = MDP2GymEnv(MaximizationBiasEnvironment()) + + for _ in range(100): + epsilon = 0.1 + alpha = 0.1 + gamma = 1 + agents = [QAgent(env, epsilon=epsilon, alpha=alpha), + SarsaAgent(env, epsilon=epsilon, alpha=alpha), + TabularDoubleQ(env, epsilon=epsilon, alpha=alpha)] + + experiments = [] + for agent in agents: + expn = f"experiments/bias_{str(agent)}" + train(env, agent, expn, num_episodes=300, max_runs=100) + experiments.append(expn) + + main_plot(experiments, smoothing_window=10, y_key="Length") + plt.ylim([1, 2]) + plt.title("Double-Q learning on Maximization-Bias ex. (Figure 6.5)") + savepdf("maximization_bias_6_5") + plt.show() + + main_plot(experiments, smoothing_window=10) + savepdf("maximization_bias_6_5_reward") + plt.show() diff --git a/irlc/ex13/maze_dyna_environment.py b/irlc/ex13/maze_dyna_environment.py new file mode 100644 index 0000000..771af49 --- /dev/null +++ b/irlc/ex13/maze_dyna_environment.py @@ -0,0 +1,118 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" +The DynaQ Maze environment. + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" + +from irlc.ex09.mdp import MDP + +class MazeEnvironment(MDP): + """ + The Maze environment from (SB18, Example 8.1) + """ + def __init__(self, **kwargs): + self.maze_ = HiddenMaze() + super().__init__(initial_state=tuple(self.maze_.START_STATE), **kwargs) + + def is_terminal(self, state): + return state == tuple(self.maze_.GOAL_STATES[0]) + + def A(self, s): + return self.maze_.actions + + def Psr(self, s, a): + xy, r = self.maze_.step(list(s), a) + return { (tuple(xy), r): 1 } + +# A wrapper class for a maze, containing all the information about the maze. +# Basically it's initialized to DynaMaze by default, however it can be easily adapted +# to other maze +class HiddenMaze: + def __init__(self): + # maze width + self.WORLD_WIDTH = 9 + + # maze height + self.WORLD_HEIGHT = 6 + + # all possible actions + self.ACTION_UP = 0 + self.ACTION_DOWN = 1 + self.ACTION_LEFT = 2 + self.ACTION_RIGHT = 3 + self.actions = [self.ACTION_UP, self.ACTION_DOWN, self.ACTION_LEFT, self.ACTION_RIGHT] + + # start state + self.START_STATE = [2, 0] + + # goal state + self.GOAL_STATES = [[0, 8]] + + # all obstacles + self.obstacles = [[1, 2], [2, 2], [3, 2], [0, 7], [1, 7], [2, 7], [4, 5]] + self.old_obstacles = None + self.new_obstacles = None + + # time to change obstacles + self.obstacle_switch_time = None + + # initial state action pair values + # self.stateActionValues = np.zeros((self.WORLD_HEIGHT, self.WORLD_WIDTH, len(self.actions))) + + # the size of q value + self.q_size = (self.WORLD_HEIGHT, self.WORLD_WIDTH, len(self.actions)) + + # max steps + self.max_steps = float('inf') + + # track the resolution for this maze + self.resolution = 1 + + # extend a state to a higher resolution maze + # @state: state in lower resoultion maze + # @factor: extension factor, one state will become factor^2 states after extension + def extend_state(self, state, factor): + new_state = [state[0] * factor, state[1] * factor] + new_states = [] + for i in range(0, factor): + for j in range(0, factor): + new_states.append([new_state[0] + i, new_state[1] + j]) + return new_states + + # extend a state into higher resolution + # one state in original maze will become @factor^2 states in @return new maze + def extend_maze(self, factor): + new_maze = HiddenMaze() + new_maze.WORLD_WIDTH = self.WORLD_WIDTH * factor + new_maze.WORLD_HEIGHT = self.WORLD_HEIGHT * factor + new_maze.START_STATE = [self.START_STATE[0] * factor, self.START_STATE[1] * factor] + new_maze.GOAL_STATES = self.extend_state(self.GOAL_STATES[0], factor) + new_maze.obstacles = [] + for state in self.obstacles: + new_maze.obstacles.extend(self.extend_state(state, factor)) + new_maze.q_size = (new_maze.WORLD_HEIGHT, new_maze.WORLD_WIDTH, len(new_maze.actions)) + # new_maze.stateActionValues = np.zeros((new_maze.WORLD_HEIGHT, new_maze.WORLD_WIDTH, len(new_maze.actions))) + new_maze.resolution = factor + return new_maze + + # take @action in @state + # @return: [new state, reward] + def step(self, state, action): + x, y = state + if action == self.ACTION_UP: + x = max(x - 1, 0) + elif action == self.ACTION_DOWN: + x = min(x + 1, self.WORLD_HEIGHT - 1) + elif action == self.ACTION_LEFT: + y = max(y - 1, 0) + elif action == self.ACTION_RIGHT: + y = min(y + 1, self.WORLD_WIDTH - 1) + if [x, y] in self.obstacles: + x, y = state + if [x, y] in self.GOAL_STATES: + reward = 1.0 + else: + reward = 0.0 + return [x, y], reward diff --git a/irlc/ex13/tabular_double_q.py b/irlc/ex13/tabular_double_q.py new file mode 100644 index 0000000..a2280d8 --- /dev/null +++ b/irlc/ex13/tabular_double_q.py @@ -0,0 +1,78 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import numpy as np +from irlc.ex01.agent import train +import gymnasium as gym +from irlc import main_plot +import matplotlib.pyplot as plt +from irlc import savepdf +from irlc.ex11.sarsa_agent import SarsaAgent +from irlc.ex11.q_agent import QAgent +from irlc import Agent + +class TabularDoubleQ(QAgent): + """ + Implement the tabular version of the double-Q learning agent from + (SB18, Section 6.7). + + Note we will copy the Q-datastructure from the Agent class. + """ + def __init__(self, env, gamma=1.0, alpha=0.5, epsilon=0.1): + super().__init__(env, gamma, epsilon) + self.alpha = alpha + # The two Q-value functions. These are of the same type as the regular self.Q function + from irlc.ex09.rl_agent import TabularQ + self.Q1 = TabularQ(env) + self.Q2 = TabularQ(env) + self.Q = None # remove self.Q (we will not use it in double Q) + + def pi(self, s, k, info=None): + """ + Implement the epsilon-greedy action. The implementation is nearly identical to pi_eps in the Agent class + which can be used for inspiration, however we should use Q1+Q2 as the Q-value. + """ + a1, Q1 = self.Q1.get_Qs(s, info) + a2, Q2 = self.Q2.get_Qs(s, info) + Q = np.asarray(Q1) + np.asarray(Q2) + + # TODO: 1 lines missing. + raise NotImplementedError("Return epsilon-greedy action using Q") + + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + """ + Implement the double-Q learning rule, i.e. with probability np.random.rand() < 0.5 switch + the role of the two Q networks Q1 and Q2. Use the code for the regular Q-agent as inspiration. + """ + # TODO: 4 lines missing. + raise NotImplementedError("Implement function body") + + def __str__(self): + return f"TabularDoubleQ_{self.gamma}_{self.epsilon}_{self.alpha}" + +if __name__ == "__main__": + """ Part 1: Cliffwalking """ + env = gym.make('CliffWalking-v0') + epsilon = 0.1 + alpha = 0.25 + gamma = 1.0 + for _ in range(20): + agents = [QAgent(env, gamma=1, epsilon=epsilon, alpha=alpha), + SarsaAgent(env, gamma=1, epsilon=epsilon, alpha=alpha), + TabularDoubleQ(env, gamma=1, epsilon=epsilon, alpha=alpha)] + + experiments = [] + for agent in agents: + expn = f"experiments/doubleq_cliffwalk_{str(agent)}" + train(env, agent, expn, num_episodes=500, max_runs=20) + experiments.append(expn) + + main_plot(experiments, smoothing_window=10) + plt.ylim([-100, 0]) + plt.title("Double-Q learning on " + env.spec.name) + savepdf("double_Q_learning_cliff") + plt.show() diff --git a/irlc/ex13/torch_networks.py b/irlc/ex13/torch_networks.py new file mode 100644 index 0000000..9ea56b5 --- /dev/null +++ b/irlc/ex13/torch_networks.py @@ -0,0 +1,131 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +import os +from irlc.ex13.dqn_network import DQNNetwork +import torch +import torch.nn as nn +import torch.optim as optim +import torch.autograd as autograd + +# Use GPU; If the drivers give you grief you can turn GPU off without a too big hit on performance in the cartpole task +USE_CUDA = torch.cuda.is_available() + +Variable = lambda *args, **kwargs: autograd.Variable(*args, **kwargs).cuda() if USE_CUDA else autograd.Variable(*args, **kwargs) + +class TorchNetwork(nn.Module,DQNNetwork): + def __init__(self, env, trainable=True, learning_rate=0.001, hidden=30): + nn.Module.__init__(self) + DQNNetwork.__init__(self) + self.env = env + self.hidden = hidden + self.actions = env.action_space.n + self.build_model_() + if trainable: + self.optimizer = optim.Adam(self.parameters(), lr=learning_rate) + if USE_CUDA: + self.cuda() + + def build_feature_network(self): + num_observations = np.prod(self.env.observation_space.shape) + return (nn.Linear(num_observations, self.hidden), + nn.ReLU(), + nn.Linear(self.hidden, self.hidden), + nn.ReLU()) + + def build_model_(self): + num_actions = self.env.action_space.n + self.model = nn.Sequential(*self.build_feature_network(), nn.Linear(self.hidden,num_actions)) + + def forward(self, s): + s = Variable(torch.FloatTensor(s)) + s = self.model(s) + return s + + def __call__(self, s): + return self.forward(s).detach().numpy() + + def fit(self, s, target): + q_value = self.forward(s) + loss = (q_value - torch.FloatTensor(target).detach()).pow(2).sum(axis=1).mean() + self.optimizer.zero_grad() + loss.backward() + self.optimizer.step() + + def update_Phi(self, source, tau=1): + """ + Polyak adapt weights of this class given source: + I.e. tau=1 means adopt weights in one step, + tau = 0.001 means adopt very slowly, tau=1 means instant overwriting + """ + state = self.state_dict() + for k, wa in state.items(): + wb = source.state_dict()[k] + state[k] = wa*(1 - tau) + wb * tau + self.load_state_dict(state) + + def save(self, path): + if not os.path.exists(os.path.dirname(path)): + os.mkdir(os.path.dirname(path)) + torch.save(self.state_dict(), path+".torchsave") + + def load(self, path): + self.load_state_dict(torch.load(path+".torchsave")) + self.eval() # set batch norm layers, dropout, other stuff we don't use + +class TorchDuelNetwork(TorchNetwork): + def build_model_(self): + self.feature = nn.Sequential(*self.build_feature_network()) + self.advantage = nn.Sequential(nn.Linear(self.hidden, self.hidden), + nn.ReLU(), + nn.Linear(self.hidden, self.actions)) + self.value = nn.Sequential(nn.Linear(self.hidden, self.hidden), + nn.ReLU(), + nn.Linear(self.hidden, 1)) + + def forward(self, s): + """ + Return tensor corresponding to Q-values when using dueling Q-networks (see exercise description) + """ + # TODO: 4 lines missing. + raise NotImplementedError("Implement function body") + return value + advantage - advantage.mean() + +class TorchDuelNetworkAtari(TorchNetwork): + def build_feature_network(self): + hidden_size = 256 + in_channels = self.env.observation_space.shape[-1] + num_actions = self.env.action_space.n + return (nn.Conv2d(in_channels, 32, kernel_size=8, stride=4), + nn.BatchNorm2d(32), + nn.Conv2d(32, 64, kernel_size=4, stride=2), + nn.BatchNorm2d(64), + nn.Conv2d(64, 64, kernel_size=3, stride=1), + nn.BatchNorm2d(64), + nn.Linear(7 * 7 * 64, hidden_size), # has to be adjusted for other resolutionz + nn.Linear(hidden_size, num_actions) ) + +if __name__ == "__main__": + a = 234 + import gymnasium as gym + + env = gym.make("CartPole-v0") + Q = DQNNetwork(env, trainable=True, learning_rate=0.001) + + # self.Q = Network(env, trainable=True) # initialize the network + """ Assuming s has dimension [batch_dim x d] this returns a float numpy Array + array of Q-values of [batch_dim x actions], such that qvals[i,a] = Q(s_i,a) """ + batch_size = 32 # As an example + # Creates some dummy input + states = [env.reset()[0] for _ in range(batch_size)] + states.shape # batch_size x n + + qvals = Q(states) + qvals.shape # This is a tensor of dimension batch_size x actions + print(qvals[0,1]) # Get Q(s_0, 1) + + Y = np.random.rand( (batch_size, 1)) # Generate target Q-values (training data) + Q.fit(states, Y) # Train the Q-network. + + + + # Q = TorchNetwork() diff --git a/irlc/exam/__init__.py b/irlc/exam/__init__.py new file mode 100644 index 0000000..4615460 --- /dev/null +++ b/irlc/exam/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# This file is required for the test-system to find the tests in the exam. diff --git a/irlc/exam/exam2023spring/__init__.py b/irlc/exam/exam2023spring/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/exam/exam2023spring/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/exam/exam2023spring/readme.md b/irlc/exam/exam2023spring/readme.md new file mode 100644 index 0000000..c041c52 --- /dev/null +++ b/irlc/exam/exam2023spring/readme.md @@ -0,0 +1,2 @@ +This directory is purposefully left empty. During the exam, you will be given a `.zip` file with the content of this directory. +Replace this directory with the corresponding directory from the `.zip` file to begin working on the exam. diff --git a/irlc/exam/exam2023spring/solution/readme.md b/irlc/exam/exam2023spring/solution/readme.md new file mode 100644 index 0000000..8d67329 --- /dev/null +++ b/irlc/exam/exam2023spring/solution/readme.md @@ -0,0 +1 @@ +I will make the solution to the exam available in this directory. diff --git a/irlc/exam/exam2024spring/__init__.py b/irlc/exam/exam2024spring/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/exam/exam2024spring/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/exam/exam2024spring/readme.md b/irlc/exam/exam2024spring/readme.md new file mode 100644 index 0000000..c041c52 --- /dev/null +++ b/irlc/exam/exam2024spring/readme.md @@ -0,0 +1,2 @@ +This directory is purposefully left empty. During the exam, you will be given a `.zip` file with the content of this directory. +Replace this directory with the corresponding directory from the `.zip` file to begin working on the exam. diff --git a/irlc/exam/midterm2023a/__init__.py b/irlc/exam/midterm2023a/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/exam/midterm2023a/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/exam/midterm2023a/readme.md b/irlc/exam/midterm2023a/readme.md new file mode 100644 index 0000000..c041c52 --- /dev/null +++ b/irlc/exam/midterm2023a/readme.md @@ -0,0 +1,2 @@ +This directory is purposefully left empty. During the exam, you will be given a `.zip` file with the content of this directory. +Replace this directory with the corresponding directory from the `.zip` file to begin working on the exam. diff --git a/irlc/exam/midterm2023a/solution/readme.md b/irlc/exam/midterm2023a/solution/readme.md new file mode 100644 index 0000000..8d67329 --- /dev/null +++ b/irlc/exam/midterm2023a/solution/readme.md @@ -0,0 +1 @@ +I will make the solution to the exam available in this directory. diff --git a/irlc/exam/midterm2023b/__init__.py b/irlc/exam/midterm2023b/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/exam/midterm2023b/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/exam/midterm2023b/readme.md b/irlc/exam/midterm2023b/readme.md new file mode 100644 index 0000000..c041c52 --- /dev/null +++ b/irlc/exam/midterm2023b/readme.md @@ -0,0 +1,2 @@ +This directory is purposefully left empty. During the exam, you will be given a `.zip` file with the content of this directory. +Replace this directory with the corresponding directory from the `.zip` file to begin working on the exam. diff --git a/irlc/exam/midterm2023b/solution/readme.md b/irlc/exam/midterm2023b/solution/readme.md new file mode 100644 index 0000000..8d67329 --- /dev/null +++ b/irlc/exam/midterm2023b/solution/readme.md @@ -0,0 +1 @@ +I will make the solution to the exam available in this directory. diff --git a/irlc/exam/readme.md b/irlc/exam/readme.md new file mode 100644 index 0000000..c189b31 --- /dev/null +++ b/irlc/exam/readme.md @@ -0,0 +1,15 @@ +# Folder for the exam and midterms + +Before the exam: + - Ensure that the `irlc`-code generally works (you can run exercises, the packages we use such as `gymnasium` or `numpy` are installed, etc.) + - You have no problem running the various `unitgrade`-test scripts and generating `.token`-files + +During the exam: + - Download a `.zip` file with the code from the digital exam + - For the midterm, you can find the file on DTU Learn + - The `zip` file will contain the toolbox code including solutions. It will also contain a directory: + ```bash + irlc/exam/exam2024spring + ``` + - This directory contains the code you need to work on for the exam. Replace the directory on your local computer with this directory and you should be all set up + - The `.zip` file will also contain solutions to nearly all exercises. Use these if benefits you. diff --git a/irlc/exam_tabular_examples/__init__.py b/irlc/exam_tabular_examples/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/exam_tabular_examples/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/exam_tabular_examples/helper.py b/irlc/exam_tabular_examples/helper.py new file mode 100644 index 0000000..4fd09f2 --- /dev/null +++ b/irlc/exam_tabular_examples/helper.py @@ -0,0 +1,11 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc import interactive, train + + +def keyboard_play_value(env, agent, method_label='MC', q=False): + env, agent = interactive(env, agent) + agent.label = method_label + agent.label = 'MC (first visit)' + env.view_mode = 1 # Set value-function view-mode. + train(env, agent, num_episodes=100) + env.close() diff --git a/irlc/exam_tabular_examples/lecture_10_mc_value_every.py b/irlc/exam_tabular_examples/lecture_10_mc_value_every.py new file mode 100644 index 0000000..59fdeb1 --- /dev/null +++ b/irlc/exam_tabular_examples/lecture_10_mc_value_every.py @@ -0,0 +1,9 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.exam_tabular_examples.helper import keyboard_play_value +from irlc.gridworld.gridworld_environments import BookGridEnvironment +from irlc.ex10.mc_evaluate import MCEvaluationAgent + +if __name__ == "__main__": + env = BookGridEnvironment(view_mode=1, render_mode='human') + agent = MCEvaluationAgent(env, gamma=.9, alpha=0.4, first_visit=False) + keyboard_play_value(env,agent,method_label='MC every') diff --git a/irlc/exam_tabular_examples/lecture_10_mc_value_first.py b/irlc/exam_tabular_examples/lecture_10_mc_value_first.py new file mode 100644 index 0000000..0c44452 --- /dev/null +++ b/irlc/exam_tabular_examples/lecture_10_mc_value_first.py @@ -0,0 +1,13 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import BookGridEnvironment +from irlc.ex10.mc_evaluate import MCEvaluationAgent +from irlc import interactive, train + +if __name__ == "__main__": + env = BookGridEnvironment(view_mode=1, render_mode='human') + agent = MCEvaluationAgent(env, gamma=.9, alpha=0.4) + agent.label = 'MC (first visit)' + env, agent = interactive(env, agent) + env.view_mode = 1 # Automatically set value-function view-mode. + train(env, agent, num_episodes=100) + env.close() diff --git a/irlc/exam_tabular_examples/sarsa_lambda_delay.py b/irlc/exam_tabular_examples/sarsa_lambda_delay.py new file mode 100644 index 0000000..de3107f --- /dev/null +++ b/irlc/exam_tabular_examples/sarsa_lambda_delay.py @@ -0,0 +1,45 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from collections import defaultdict +from irlc.ex11.q_agent import QAgent + +class SarsaLambdaDelayAgent(QAgent): + def __init__(self, env, gamma=0.99, epsilon=0.1, alpha=0.5, lamb=0.9): + super().__init__(env, gamma=gamma, alpha=alpha, epsilon=epsilon) + self.lamb = lamb + self.method = 'Sarsa(Lambda)' + self.e = defaultdict(float) + + def pi(self, s, k, info=None): + self.t = k + action = self.pi_eps(s,info=info) + return action + + def lmb_update(self, s, a, r, sp, ap, done): + delta = r + self.gamma * (self.Q[sp,ap] if not done else 0) - self.Q[s,a] + for (s,a), ee in self.e.items(): + self.Q[s,a] += self.alpha * delta * ee + self.e[(s,a)] = self.gamma * self.lamb * ee + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + # if self.t == 0: + # self.e.clear() + + if self.t > 0: + # We have an update in the buffer and can update the states. + self.lmb_update(self.s_prev, self.a_prev, self.r_prev, s, a, done=False) + self.e[(s, a)] += 1 + + if done: + self.lmb_update(s, a, r, sp, ap=None, done=True) + self.e.clear() + + self.s_prev = s + self.a_prev = a + self.r_prev = r + + def __str__(self): + return f"SarsaLambdaDelay_{self.gamma}_{self.epsilon}_{self.alpha}_{self.lamb}" + +if __name__ == "__main__": + from irlc.ex12.sarsa_lambda_open import keyboard_play + keyboard_play(SarsaLambdaDelayAgent, method_label="Sarsa(Lambda) (delayed)") diff --git a/irlc/exam_tabular_examples/sarsa_nstep_delay.py b/irlc/exam_tabular_examples/sarsa_nstep_delay.py new file mode 100644 index 0000000..32f2aad --- /dev/null +++ b/irlc/exam_tabular_examples/sarsa_nstep_delay.py @@ -0,0 +1,77 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import gymnasium as gym +from irlc import main_plot +import matplotlib.pyplot as plt +from irlc.gridworld.gridworld_environments import OpenGridEnvironment +from irlc import train +from irlc.ex11.q_agent import QAgent + +class SarsaDelayNAgent(QAgent): + """ Implement the N-step semi-gradient sarsa agent from (SB18, Section 7.2)""" + def __init__(self, env, gamma=1, alpha=0.2, epsilon=0.1, n=1): + # Variables for TD-n + self.method = 'Sarsa' if n == 1 else f'Sarsa({n=})' + + self.n = n # as in n-step sarse + # Buffer lists for previous (S_t, R_{t}, A_t) triplets + self.R, self.S, self.A = [None] * (self.n + 1), [None] * (self.n + 1), [None] * (self.n + 1) + super().__init__(env, gamma=gamma, alpha=alpha, epsilon=epsilon) + + def pi(self, s, k, info=None): + self.t = k # Save current step in episode for use in train. + return self.pi_eps(s, info) + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + # Recall we are given S_t, A_t, R_{t+1}, S_{t+1} and done is whether t=T+1. + n, t = self.n, self.t + # Store current observations in buffer. + self.S[t%(n+1)] = s + self.A[t%(n+1)] = a # self.pi_eps(sp) if not done else -1 + self.R[(t+1)%(n+1)] = r + if done: + T = t+1 + tau_steps_to_train = range(t - n, T) + else: + T = 1e10 + tau_steps_to_train = [t - n ] if t > 0 else [] + + # Tau represent the current tau-steps which are to be updated. The notation is compatible with that in Sutton. + for tau in tau_steps_to_train: + if tau >= 0: + """ + Compute the return for this tau-step and perform the relevant Q-update. + The first step is to compute the expected return G in the below section. + """ + G = sum([self.gamma**(i-tau-1)*self.R[i%(n+1)] for i in range(tau+1, min(tau+n, T)+1)]) + S_tau_n, A_tau_n = self.S[(tau+n)%(n+1)], self.A[(tau+n)%(n+1)] + if tau+n < T: + G += self.gamma**n * self._q(S_tau_n, A_tau_n) + S_tau, A_tau = self.S[tau%(n+1)], self.A[tau%(n+1)] + delta = G - self._q(S_tau, A_tau) + + if n == 1: # Check your implementation is correct when n=1 by comparing it with regular Sarsa learning. + delta_Sarsa = (self.R[ (tau+1)%(n+1) ] + (0 if tau+n==T else self.gamma * self._q(S_tau_n,A_tau_n)) - self._q(S_tau,A_tau)) + if abs(delta-delta_Sarsa) > 1e-10: + raise Exception("n=1 agreement with Sarsa learning failed. You have at least one bug!") + self._upd_q(S_tau, A_tau, delta) + + def _q(self, s, a): return self.Q[s,a] # Using these helper methods will come in handy when we work with function approximators, but it is optional. + def _upd_q(self, s, a, delta): self.Q[s,a] += self.alpha * delta + + def __str__(self): + return f"SarsaN_{self.gamma}_{self.epsilon}_{self.alpha}_{self.n}" + +from irlc.ex11.nstep_sarsa_agent import SarsaNAgent +from irlc.lectures.lec11.lecture_10_sarsa_open import open_play +if __name__ == "__main__": + n = 8 + env = OpenGridEnvironment() + agent = SarsaDelayNAgent(env, n=n) + train(env, agent, num_episodes=100) + + open_play(SarsaDelayNAgent, method_label=f"Sarsa n={n}", n=n) diff --git a/irlc/exam_tabular_examples/tabular_examples.py b/irlc/exam_tabular_examples/tabular_examples.py new file mode 100644 index 0000000..f9932a5 --- /dev/null +++ b/irlc/exam_tabular_examples/tabular_examples.py @@ -0,0 +1,78 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex12.sarsa_lambda_agent import SarsaLambdaAgent +from irlc.gridworld.gridworld_environments import OpenGridEnvironment, BookGridEnvironment, SuttonCornerGridEnvironment, SuttonMazeEnvironment +from irlc import train, savepdf +from irlc.ex12.sarsa_lambda_open import keyboard_play +import matplotlib.pyplot as plt +from irlc.ex11.q_agent import QAgent +from irlc.ex11.sarsa_agent import SarsaAgent +from irlc.ex11.nstep_sarsa_agent import SarsaNAgent +from irlc.ex10.mc_agent import MCAgent +from irlc.ex10.mc_evaluate import MCEvaluationAgent +from irlc.exam_tabular_examples.sarsa_nstep_delay import SarsaDelayNAgent +from irlc.exam_tabular_examples.sarsa_lambda_delay import SarsaLambdaDelayAgent +from irlc import interactive + +def open_snapshop(Agent, method_label="Unknown method", file_name=None, alpha=0.5, autoplay=False, **kwargs): + env = OpenGridEnvironment(render_mode='human') + agent = Agent(env, gamma=0.99, epsilon=0.1, alpha=alpha, **kwargs) + agent.label =method_label + print("Running", agent) + env, agent = interactive(env, agent, autoplay=autoplay) + train(env, agent, num_episodes=3) + if file_name is not None: + env.plot() + plt.title(method_label) + savepdf("exam_tabular_"+file_name) + env.close() + +if __name__ == "__main__": + """ All simulations run using gamma=0.99, epsilon=0.1 and alpha=0.5 (when applicable). """ + + """ The following lines will show all the agents using automatic play. It is used to generate screenshots. + Uncomment to go to interactive play. """ + # import numpy as np + # np.random.seed(42) + # env = SuttonMazeEnvironment(living_reward=-2, render_mode='human') + # agent = MCAgent(env, alpha=0.8, epsilon=0, gamma=0.4) + # env, agent = interactive(env, agent) + # train(env, agent, num_episodes=2) + + open_snapshop(MCAgent, "Monte-Carlo control (first visit)", file_name="mc_first", alpha=None) + open_snapshop(MCAgent, "Monte-Carlo control (every visit)", file_name="mc_every", alpha=None, first_visit=False) + open_snapshop(SarsaAgent, "Sarsa", file_name="sarsa") + open_snapshop(SarsaNAgent, "n-step Sarsa (n=8)", file_name="sarsa_n8", n=8) + open_snapshop(QAgent, "Q-learning", file_name="q_learning") + open_snapshop(SarsaLambdaAgent, "Sarsa(Lambda)", file_name="sarsa_lambda") + open_snapshop(MCEvaluationAgent, "Monte-Carlo value-estimation (first visit)", file_name="mc_evaluation_first", alpha=None) + open_snapshop(MCEvaluationAgent, "Monte-Carlo value-estimation (every visit)", file_name="mc_evaluation_every", first_visit=False) + + """ MC-methods for value estimation. This is the upgraded demo which also shows the number of times + a state has been visited in the value-estimation algorithm. """ + keyboard_play(MCEvaluationAgent, "Monte-Carlo value-estimation (first visit)", alpha=None) + keyboard_play(MCEvaluationAgent, "Monte-Carlo value-estimation (every visit)", alpha=None, first_visit=False) + + """ Control methods: + Play with the agents (using keyboard input) """ + keyboard_play(MCAgent, "Monte-Carlo control (first visit)", alpha=None) + keyboard_play(MCAgent, "Monte-Carlo control (every visit)", alpha=None, first_visit=False) + keyboard_play(QAgent, "Q-learning") + + """ These agents also accept keyboard input, but they are not guaranteed to update the Q-values correctly because the next state A' (in Suttons notation) + is generated in the train() method; i.e. we cannot easily overwrite it using the keyboard. I have included them for completeness, but + be a little careful with them. """ + keyboard_play(SarsaAgent, "Sarsa") + keyboard_play(SarsaNAgent, "n-step Sarsa (n=8)", n=8) + keyboard_play(SarsaLambdaAgent, "Sarsa(Lambda)") + + """ Bonus keyboard input agents: These agents implement the same methods as their counterparts above, however they 'wait' with updating + Q(S_t, A_t) until time t+1 when the (actual) next action A_{t+1} is available. This means that when they are used in conjunction with keyboard inputs, + the Q-values will be updated correctly since we can actually set A_{t+1} equal to the keyboard input. + This also mean the updates to the Q-values appear to lag one step behind the methods above. + I have included them in the case some find it useful to test the Q-values using the keyboard, + however, the implementations/delay-idea is not part of the exam pensum: only use them if you find them useful for studying, and otherwise just rely on the + description of the methods in the lecture material. + """ + keyboard_play(SarsaDelayNAgent, "Sarsa (delayed)", n=1) # We use that Sarsa is equal to n-step sarsa with n=1. + keyboard_play(SarsaDelayNAgent, "n-step Sarsa (n=8, delayed)", n=8) + keyboard_play(SarsaLambdaDelayAgent, "Sarsa(Lambda) (delayed)") diff --git a/irlc/gridworld/__init__.py b/irlc/gridworld/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/gridworld/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/gridworld/__pycache__/__init__.cpython-311.pyc b/irlc/gridworld/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..51fdb1aad155ed02d6e2e424253ad9f79f46fc88 GIT binary patch literal 174 zcmZ3^%ge>Uz`$UU-<!6Pfq~&Mhy%lnP{wCA1_p-d3@Hr344RC7D;bKI7#J8ngCu`B z>SyHVrs|iJW~A!7<R_QrrskCt>u2WX=o=WBm>Lw9l%_yLigJ?m(~B}w%JYkIQuO2F yGxIV_;^XxSDt~d<<mRW8=A_ycu`)0)fb1;hXJBCXz|6?V_<;dN6frX}FaQ9G>MBtH literal 0 HcmV?d00001 diff --git a/irlc/gridworld/__pycache__/gridworld_environments.cpython-311.pyc b/irlc/gridworld/__pycache__/gridworld_environments.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..df934112e5c0902a93095143b4af40c837a6e60b GIT binary patch literal 20009 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 Ok%2|(0<$EzECm3g(B*sp literal 0 HcmV?d00001 diff --git a/irlc/gridworld/__pycache__/gridworld_graphics_display.cpython-311.pyc b/irlc/gridworld/__pycache__/gridworld_graphics_display.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e17825632aa1704e500dad60aa5ca905581874d GIT binary patch literal 28983 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 literal 0 HcmV?d00001 diff --git a/irlc/gridworld/__pycache__/gridworld_mdp.cpython-311.pyc b/irlc/gridworld/__pycache__/gridworld_mdp.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..402d55ea6f792f614d4f20b2f76dd75b30781609 GIT binary patch literal 4836 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 literal 0 HcmV?d00001 diff --git a/irlc/gridworld/demo_agents/__init__.py b/irlc/gridworld/demo_agents/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/gridworld/demo_agents/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/gridworld/demo_agents/hidden_agents.py b/irlc/gridworld/demo_agents/hidden_agents.py new file mode 100644 index 0000000..d831b11 --- /dev/null +++ b/irlc/gridworld/demo_agents/hidden_agents.py @@ -0,0 +1,235 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from collections import defaultdict +import numpy as np +from irlc import TabularAgent # , PlayWrapper, VideoMonitor, train +from irlc.ex09.mdp_warmup import value_function2q_function + + +class ValueIterationAgent2(TabularAgent): + def __init__(self, env, gamma=.99, epsilon=0, theta=1e-5, only_current_state=False): + self.v = defaultdict(lambda: 0) + self.steps = 0 + self.mdp = env.mdp + self.only_current_state = only_current_state + super().__init__(env, gamma, epsilon=epsilon) + + def pi(self, s, k, info=None): + # TODO: 2 lines missing. + raise NotImplementedError("Implement function body") + return self.random_pi(s) if np.random.rand() < self.epsilon else a + + @property + def label(self): + label = f"Value iteration after {self.steps} steps" + return label + + def v2Q(self, s): # used for rendering right now + return value_function2q_function(self.mdp, s, self.gamma, self.v) + + def train(self, s, a, r, sp, done=False, info_sp=None): + delta = 0 + v2 = {} + for s in self.env.P.keys(): + v, v2[s] = self.v[s], max(value_function2q_function(self.mdp, s, self.gamma, self.v).values()) if len(self.mdp.A(s)) > 0 else 0 + delta = max(delta, np.abs(v - self.v[s])) + + self.v = v2 + + for s in self.mdp.nonterminal_states: + for a in self.mdp.A(s): + self.Q[s,a] = self.v2Q(s)[a] + + self.delta = delta + self.steps += 1 + + def __str__(self): + return f"VIAgent_{self.gamma}" + + +class PolicyEvaluationAgent2(TabularAgent): + def __init__(self, env, mdp=None, gamma=0.99, steps_between_policy_improvement=10, only_update_current=False): + if mdp is None: + mdp = env.mdp + self.mdp = mdp + self.v = defaultdict(lambda: 0) + self.imp_steps = 0 + self.steps_between_policy_improvement = steps_between_policy_improvement + self.steps = 0 + self.policy = {} + self.only_update_current = only_update_current + for s in mdp.nonterminal_states: + self.policy[s] = {} + for a in mdp.A(s): + self.policy[s][a] = 1/len(mdp.A(s)) + super().__init__(env, gamma) + + + def pi(self, s,k, info=None): + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + return np.random.choice(a, p=pa) + + def v2Q(self, s): # used for rendering right now + return value_function2q_function(self.mdp, s, self.gamma, self.v) + + @property + def label(self): + if self.steps_between_policy_improvement is None: + label = f"Policy evaluation after {self.steps} steps" + else: + dd = self.steps % self.steps_between_policy_improvement == 0 + # print(dd) + label = f"PI after {self.steps} steps/{self.imp_steps-dd} policy improvements" + return label + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + if not self.only_update_current: + v2 = {} + for s in self.mdp.nonterminal_states: + q = value_function2q_function(self.mdp, s, self.gamma, self.v) + if len(q) == 0: + v2[s] = 0 + else: + v2[s] = sum( [qv * self.policy[s][a] for a, qv in q.items()] ) + + + for s in self.mdp.nonterminal_states: + for a,q in self.v2Q(s).items(): + self.Q[s,a] = q + + for k, v in v2.items(): + self.v[k] = v2[k] + + else: + # Only update Q-value in current state: + Q_ = 0 + # print(a) + + for (sp, r), p in self.mdp.Psr(s, a).items(): + Q_ += p*(r + (0 if self.mdp.is_terminal(sp) else sum([self.Q[sp, ap]*pa for ap, pa in self.policy[sp].items()]) )) + + # Q_ += p * (r + (0 if self.mdp.is_terminal(sp) else sum( + # [self.Q[sp, ap] * pa for ap, pa in self.policy[sp].items()]))) + + + self.Q[s, a] = Q_ + + v_ = 0 + for a in self.mdp.A(s): + for (sp, r), p in self.mdp.Psr(s, a).items(): + v_ += self.policy[s][a] * (self.v[sp] * self.gamma + r)*p + self.v[s] = v_ + + + if self.steps_between_policy_improvement is not None and (self.steps+1) % self.steps_between_policy_improvement == 0: + self.policy = {} + for s in self.mdp.nonterminal_states: + q = value_function2q_function(self.mdp, s, self.gamma, self.v) + if len(q) == 0: + continue + a_ = max(q, key=q.get) # optimal action + self.policy[s] = {} + for a in self.mdp.A(s): + self.policy[s][a] = 1 if q[a] == max(q.values()) else 0 #if a == a_ else 0 + + n = sum(self.policy[s].values()) + for a in self.policy[s]: + self.policy[s][a] *= 1/n + + self.imp_steps += 1 + self.steps += 1 + + def __str__(self): + return f"PIAgent_{self.gamma}" + + + +class ValueIterationAgent3(TabularAgent): + def __init__(self, env, mdp=None, epsilon=0, gamma=0.99, steps_between_policy_improvement=10, only_update_current=False): + if mdp is None: + mdp = env.mdp + self.mdp = mdp + self.v = defaultdict(lambda: 0) + self.imp_steps = 0 + self.steps_between_policy_improvement = steps_between_policy_improvement + self.steps = 0 + self.policy = {} + self.only_update_current = only_update_current + self.v = defaultdict(float) + for s in mdp.nonterminal_states: + self.policy[s] = {} + for a in mdp.A(s): + self.policy[s][a] = 1/len(mdp.A(s)) + super().__init__(env, gamma, epsilon=epsilon) + + + def pi(self, s,k, info=None): + from irlc import Agent + if np.random.rand() <self.epsilon: + return Agent.pi(self, s, k=k, info=info) + + a, pa = zip(*self.policy[s].items()) + return np.random.choice(a, p=pa) + + + def v2Q(self, s): # used for rendering right now + if not self.only_update_current: + a,q = self.Q.get_Qs(s) + return {a_: q_ for a_, q_ in zip(a,q)} + else: + return value_function2q_function(self.mdp, s, self.gamma, self.v) + + + def vi_q(self, s, a): + Q_ = 0 + for (sp, r), p in self.mdp.Psr(s, a).items(): + if self.mdp.is_terminal(sp): + QT = 0 + else: + qvals = [self.Q[sp, a_] for a_ in self.mdp.A(sp)] + QT = max(qvals) * (1-self.epsilon) + self.epsilon*np.mean(qvals) + Q_ += p * (r + self.gamma * QT) + return Q_ + + @property + def label(self): + label = f"Value Iteration after {self.steps} steps" + return label + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + s_ = s + if not self.only_update_current: + q_ = dict() + for s in self.mdp.nonterminal_states: + for a in self.mdp.A(s): + q_[s,a] = self.vi_q(s, a) + for (s,a), q in q_.items(): + self.Q[s,a] = q + else: + # Only update Q-value in current state: + # s = s_ + qq = value_function2q_function(self.mdp, s, self.gamma, self.v) + self.v[s] = max(qq.values()) + self.Q[s, a] = self.vi_q(s,a) + + + for s in self.mdp.nonterminal_states: + # q = qs_(self.mdp, s, self.gamma, self.v) + # if len(q) == 0: + # continue + # a_ = max(q, key=q.get) # optimal action + self.policy[s] = {} + qs = [self.Q[s,a] for a in self.mdp.A(s)] + + for a in self.mdp.A(s): + self.policy[s][a] = 1 if self.Q[s,a] >= max(qs)-1e-6 else 0 #if a == a_ else 0 + S = sum(self.policy[s].values()) + for a in self.mdp.A(s): + self.policy[s][a] = self.policy[s][a] / S + if not self.only_update_current: + self.v[s] = max([self.Q[s, a_] for a_ in self.mdp.A(s)]) + + self.steps += 1 + + def __str__(self): + return f"PIAgent_{self.gamma}" diff --git a/irlc/gridworld/gridworld_environments.py b/irlc/gridworld/gridworld_environments.py new file mode 100644 index 0000000..d58b21b --- /dev/null +++ b/irlc/gridworld/gridworld_environments.py @@ -0,0 +1,362 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +import numpy as np +from collections import defaultdict +from gymnasium.envs.toy_text.frozen_lake import FrozenLakeEnv +from gymnasium.spaces.discrete import Discrete +from irlc.ex09.mdp import MDP2GymEnv +from irlc.gridworld.gridworld_mdp import GridworldMDP, FrozenGridMDP +from irlc import Timer +from gymnasium.spaces.multi_discrete import MultiDiscrete +import pygame + +grid_cliff_grid = [[' ',' ',' ',' ',' ', ' ',' ',' ',' ',' ', ' '], + [' ',' ',' ',' ',' ', ' ',' ',' ',' ',' ', ' '], + ['S',-100, -100, -100, -100,-100, -100, -100, -100, -100, 0]] + +grid_cliff_grid2 = [[' ',' ',' ',' ',' '], + ['S',' ',' ',' ',' '], + [-100,-100, -100, -100, 0]] + +grid_discount_grid = [[' ',' ',' ',' ',' '], + [' ','#',' ',' ',' '], + [' ','#', 1,'#', 10], + ['S',' ',' ',' ',' '], + [-10,-10, -10, -10, -10]] + +grid_bridge_grid = [[ '#',-100, -100, -100, -100, -100, '#'], + [ 1, 'S', ' ', ' ', ' ', ' ', 10], + [ '#',-100, -100, -100, -100, -100, '#']] + +grid_book_grid = [[' ',' ',' ',+1], + [' ','#',' ',-1], + ['S',' ',' ',' ']] + +grid_maze_grid = [[' ',' ',' ', +1], + ['#','#',' ','#'], + [' ','#',' ',' '], + [' ','#','#',' '], + ['S',' ',' ',' ']] + +sutton_corner_maze = [[ 1, ' ', ' ', ' '], + [' ', ' ', ' ', ' '], + [' ', 'S', ' ', ' '], + [' ', ' ', ' ', 1]] + +# A big yafcport open maze. +grid_open_grid = [[' ']*8 for _ in range(5)] +grid_open_grid[0][0] = 'S' +grid_open_grid[-1][-1] = 1 + + +class GridworldEnvironment(MDP2GymEnv): + metadata = { + 'render.modes': ['human', 'rgb_array'], + 'video.frames_per_second': 1000, + } + def get_keys_to_action(self): + return {(pygame.K_LEFT,): GridworldMDP.WEST, (pygame.K_RIGHT,): GridworldMDP.EAST, + (pygame.K_UP,): GridworldMDP.NORTH, (pygame.K_DOWN,): GridworldMDP.SOUTH} + + # return {(key.LEFT,): GridworldMDP.WEST, (key.RIGHT,): GridworldMDP.EAST, (key.UP,): GridworldMDP.NORTH, (key.DOWN,): GridworldMDP.SOUTH} + + def _get_mdp(self, grid, uniform_initial_state=False): + return GridworldMDP(grid, living_reward=self.living_reward) + + def __init__(self, grid=None, uniform_initial_state=True, living_reward=0,zoom=1, view_mode=0, render_mode=None, print_states=False, + frames_per_second=None, + **kwargs): + self.print_states = print_states + self.living_reward = living_reward + mdp = self._get_mdp(grid) + self.render_mode = render_mode + super().__init__(mdp, render_mode=render_mode) + self.action_space = Discrete(4) + # self.observation_space = MultiDiscrete([mdp.height, mdp.width]) # N.b. the state space does not contain the terminal state. + self.render_episodes = 0 + self.render_steps = 0 + self.timer = Timer() + self.view_mode = view_mode + self.agent = None # If this is set, the environment will try to render the internal state of the agent. + # It is a little hacky, it allows us to make the visualizations etc. + # Set up rendering if required. + self.display_pygame = None + # self.screen = None + self.zoom = zoom # Save zoom level. + self.total_reward = 0 + self.frames_per_second = frames_per_second + def _step(*args, **kwargs): + s = self.state + o = type(self).step(self, *args, **kwargs) + done = o[2] + a = args[0] + self.total_reward += o[1] + self.render_steps += 1 + self.render_episodes += done + if self.print_states: + if isinstance(self, FrozenLake): + pr = f" This occurred with probability: P(s', r | s, a) = {self.mdp.Psr(s, a)[(o[0], o[1])]:.2f}." + else: + pr = "" + if done: + pt = f" Total reward for this episode was {self.total_reward}." + else: + pt = "" + print(f"s={s}, a={a} --> s'={o[0]}, r={o[1]}. {pr}{pt}") + return o + self.step = _step + + def reset(self, *args, **kwargs): + o = super().reset(*args, **kwargs) + self.total_reward = 0 + if self.print_states: + print(f"Starting in state s={o[0]}") + return o + + def keypress(self, key): + if key.unicode == 'm': + # changing mode... + self.view_mode += 1 + self.render() + return + + if key == 116: # This may easily not be used. + self.view_mode += 1 + self.render() + + + def render(self): + if self.display_pygame is None: + from irlc.gridworld.gridworld_graphics_display import GraphicsGridworldDisplay + self.display_pygame = GraphicsGridworldDisplay(self.mdp, size=int(150 * self.zoom), frames_per_second=self.frames_per_second) # last item is grid size + + agent = self.agent + label = None + method_label = agent.method if hasattr(agent, 'method') else '' + if label is None and len(method_label) > 0: + label = f"{method_label} AFTER {self.render_steps} STEPS" + + state = self.state + avail_modes = [] + if agent != None: + label = (agent.label if hasattr(agent, 'label') else label if label is not None else '') #if label is None else label + v = agent.v if hasattr(agent, 'v') else None + Q = agent.Q if hasattr(agent, 'Q') else None + # policy = agent.policy if hasattr(agent, 'policy') else None + v2Q = agent.v2Q if hasattr(agent, 'v2Q') else None + avail_modes = [] + if Q is not None: + avail_modes.append("Q") + avail_modes.append("v") + elif v is not None: + avail_modes.append("v") + + if len(avail_modes) > 0: + self.view_mode = self.view_mode % len(avail_modes) + if avail_modes[self.view_mode] == 'v': + preferred_actions = None + + if v == None: + preferred_actions = {} + v = {s: max(Q.get_Qs(s)[1]) for s in self.mdp.nonterminal_states} + + for s in self.mdp.nonterminal_states: + acts, values = Q.get_Qs(s) + preferred_actions[s] = [a for (a,w) in zip(acts, values) if np.round(w, 2) == np.round(v[s], 2)] + + if v2Q is not None: + preferred_actions = {} + for s in self.mdp.nonterminal_states: + q = v2Q(s) + mv = np.round( max( q.values() ), 2) + preferred_actions[s] = [k for k, v in q.items() if np.round(v, 2) == mv] + + if agent != None and hasattr(agent, 'policy') and agent.policy is not None and state in agent.policy and isinstance(agent.policy[state], dict): + for s in self.mdp.nonterminal_states: + preferred_actions[s] = [a for a, v in agent.policy[s].items() if v == max(agent.policy[s].values()) ] + + if hasattr(agent, 'returns_count_N'): + returns_count = agent.returns_count_N + else: + returns_count = None + if hasattr(agent, 'returns_sum_S'): + returns_sum = agent.returns_sum_S + else: + returns_sum = None + + self.display_pygame.displayValues(mdp=self.mdp, v=v, preferred_actions=preferred_actions, currentState=state, message=label, returns_count=returns_count, returns_sum=returns_sum) + + elif avail_modes[self.view_mode] == 'Q': + + if hasattr(agent, 'e') and isinstance(agent.e, defaultdict): + eligibility_trace = defaultdict(float) + for k, v in agent.e.items(): + eligibility_trace[k] = v + + else: + eligibility_trace = None + + if hasattr(agent, 'returns_count_N'): + returns_count = agent.returns_count_N + elif hasattr(agent, 'returns_count'): + returns_count = agent.returns_count + else: + returns_count = None + if hasattr(agent, 'returns_sum_S'): + returns_sum = agent.returns_sum_S + elif hasattr(agent, 'returns_sum'): + returns_sum = agent.returns_sum + else: + returns_sum = None + + self.display_pygame.displayQValues(self.mdp, Q, currentState=state, message=label, eligibility_trace=eligibility_trace, returns_count=returns_count, returns_sum=returns_sum) + else: + raise Exception("No view mode selected") + else: + # self.pygame_display = Gridworl + self.display_pygame.displayNullValues(self.mdp, currentState=state, message=label) + # self.display.displayNullValues(self.mdp, currentState=state) + + render_out2 = self.display_pygame.blit(render_mode=self.render_mode) + return render_out2 + + def close(self): + # print("Closing time...") + if self.display_pygame is not None: + self.display_pygame.close() + + +class BookGridEnvironment(GridworldEnvironment): + def __init__(self, *args, **kwargs): + super().__init__(grid_book_grid, *args, **kwargs) + +class BridgeGridEnvironment(GridworldEnvironment): + def __init__(self, *args, **kwargs): + super().__init__(grid_bridge_grid, *args, **kwargs) + +class CliffGridEnvironment(GridworldEnvironment): + def __init__(self, *args, **kwargs): + super().__init__(grid_cliff_grid, living_reward=-1, *args, **kwargs) + +class CliffGridEnvironment2(GridworldEnvironment): + def __init__(self, *args, **kwargs): + super().__init__(grid_cliff_grid2, living_reward=-1, *args, **kwargs) + + +class OpenGridEnvironment(GridworldEnvironment): + def __init__(self, *args, **kwargs): + super().__init__(grid_open_grid, *args, **kwargs) + +""" +Implement Suttons little corner-maze environment (see (SB18, Example 4.1)). +You can make an instance using: +> from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment +> env = SuttonCornerGridEnvironment() +To get access the the mdp (as a MDP-class instance, for instance to see the states env.mdp.nonterminal_states) use +> env.mdp +""" +class SuttonCornerGridEnvironment(GridworldEnvironment): + def __init__(self, *args, living_reward=-1, **kwargs): # living_reward=-1 means the agent gets a reward of -1 per step. + super().__init__(sutton_corner_maze, *args, living_reward=living_reward, **kwargs) + +class SuttonMazeEnvironment(GridworldEnvironment): + def __init__(self, *args, render_mode=None, living_reward=0, **kwargs): + sutton_maze_grid = [[' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', +1], + [' ', ' ', '#', ' ', ' ', ' ', ' ', '#', ' '], + ['S', ' ', '#', ' ', ' ', ' ', ' ', '#', ' '], + [' ', ' ', '#', ' ', ' ', ' ', ' ', ' ', ' '], + [' ', ' ', ' ', ' ', ' ', '#', ' ', ' ', ' '], + [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']] + + super().__init__(sutton_maze_grid, *args, render_mode=render_mode, living_reward=living_reward, **kwargs) + + + + +# "4x4":[ +# "SFFF", +# "FHFH", +# "FFFH", +# "HFFG" +# ] + +# "8x8": [ +# "SFFFFFFF", +# "FFFFFFFF", +# "FFFHFFFF", +# "FFFFFHFF", +# "FFFHFFFF", +# "FHHFFFHF", +# "FHFFHFHF", +# "FFFHFFFG", +# ] +# frozen_lake_4 = [['S', ' ', ' ', ' '], +# [' ', 0, ' ', 0], +# [' ', ' ', ' ', 0], +# [ 0, ' ', ' ', +1]] + +grid_book_grid_ = [[' ',' ',' ',+1], + [' ','#',' ',-1], + ['S',' ',' ',' ']] + +frozen_lake_4 = [['S',' ',' ',' '], + [' ','#',' ',-1], + [ 0 , ' ', ' ', +1]] + +class FrozenLake(GridworldEnvironment): + def _get_mdp(self, grid, uniform_initial_state=False): + return FrozenGridMDP(grid, is_slippery=self.is_slippery, living_reward=self.living_reward) + + def __init__(self, is_slippery=True, living_reward=0, *args, **kwargs): + self.is_slippery = is_slippery + menv = FrozenLakeEnv(is_slippery=is_slippery) # Load frozen-lake game layout and convert to our format 'grid' + gym2grid = dict(F=' ', G=1, H=0) + grid = [[gym2grid.get(s.decode("ascii"), s.decode("ascii")) for s in l] for l in menv.desc.tolist()] + menv.close() + super().__init__(grid=grid, *args, living_reward=living_reward, **kwargs) + +if __name__ == "__main__": + import gym + # env = gym.make('CartPole-v1', render_mode="human") + # env.reset() + # + # a = 234 gym + # env = gym.make('CartPole-v1', render_mode="human") + # env.reset() + from irlc import interactive, Agent, train + from irlc.ex11.q_agent import QAgent + from irlc.ex11.sarsa_agent import SarsaAgent + # env = SuttonMazeEnvironment(render_mode="human", zoom=0.75) + # env = OpenGridEnvironment(render_mode='human', zoom=0.75) + # env = OpenGridEnvironment() + env = CliffGridEnvironment() + agent = QAgent(env) + # env, agent = interactive(env, QAgent(env)) + # stats, trajectories = train(env, agent, num_episodes=100, experiment_name='q_learning') + stats, trajectories = train(env, SarsaAgent(env), num_episodes=100, experiment_name='sarsa') + + from irlc import main_plot + main_plot(experiments=['q_learning', 'sarsa']) + from matplotlib import pyplot as plt + plt.show() + # from irlc import VideoMonitor, train, Agent, PlayWrapper + # agent = Agent(env) + env.reset() + env.close() + + # agent = PlayWrapper(agent, env) + # env = VideoMonitor(env) + # env = Video + + # a = 234 + # for r in range(100): + # import time + # env.reset() + # time.sleep(1) + # train(env, agent, 2000) + a = 234 + # env.step(0) diff --git a/irlc/gridworld/gridworld_graphics_display.py b/irlc/gridworld/gridworld_graphics_display.py new file mode 100644 index 0000000..f8fda14 --- /dev/null +++ b/irlc/gridworld/gridworld_graphics_display.py @@ -0,0 +1,543 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# gridworld_graphics_display.py +# --------------------------- +# Licensing Information: You are free to use or extend these projects for +# educational purposes provided that (1) you do not distribute or publish +# solutions, (2) you retain this notice, and (3) you provide clear +# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. +# +# Attribution Information: The Pacman AI projects were developed at UC Berkeley. +# The core projects and autograders were primarily created by John DeNero +# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). +# Student side autograding was added by Brad Miller, Nick Hay, and +# Pieter Abbeel (pabbeel@cs.berkeley.edu). + +from irlc.utils.graphics_util_pygame import GraphicsUtilGym, formatColor +from irlc.pacman.pacman_graphics_display import PACMAN_OUTLINE_WIDTH, PACMAN_SCALE +from irlc.gridworld.gridworld_mdp import GridworldMDP +from collections import defaultdict +import math +import numpy as np + +# import sphinx_autorun + +BACKGROUND_COLOR = formatColor(0, 0, 0) +EDGE_COLOR = formatColor(1, 1, 1) +OBSTACLE_COLOR = formatColor(0.5, 0.5, 0.5) +TEXT_COLOR = formatColor(1, 1, 1) +MUTED_TEXT_COLOR = formatColor(0.7, 0.7, 0.7) +LOCATION_COLOR = formatColor(0, 0, 1) +RED_TEXT_COLOR = formatColor(.68, .93, 0.93) +from irlc.pacman.pacman_graphics_display import PACMAN_COLOR + +def getEndpoints(direction, position=(0, 0)): + x, y = position + pos = x - int(x) + y - int(y) + width = 30 + 80 * math.sin(math.pi * pos) + delta = width / 2 + if direction == 'West': + endpoints = (180 + delta, 180 - delta) + elif direction == 'North': + endpoints = (90 + delta, 90 - delta) + elif direction == 'South': + endpoints = (270 + delta, 270 - delta) + else: + endpoints = (0 + delta, 0 - delta) + return endpoints + + +class GraphicsGridworldDisplay: + time_since_last_update = 0 + key_queue = [] + def __init__(self, mdp, size=120, frames_per_second=None): + self.mdp = mdp + self.ga = GraphicsUtilGym() + self.Q_old = None + self.v_old = None + self.Null_old = None + title = "Gridworld Display" + self.GRID_SIZE = size + self.MARGIN = self.GRID_SIZE * 0.75 + screen_width = (mdp.width - 1) * self.GRID_SIZE + self.MARGIN * 2 + screen_height = (mdp.height - 0.5) * self.GRID_SIZE + self.MARGIN * 2 + self.ga.begin_graphics(screen_width, screen_height, BACKGROUND_COLOR, title=title, frames_per_second=frames_per_second) + self.annotations = [] + # function to refresh the window + + + def draw_annotation(self): + for a in self.annotations: + if a['type'] == 'text': + self.ga.text(f"adf", (a['x'], a['y']), a['color'], a['message'], "Courier", anchor='c', fontsize=a['fontsize'], bold=a['bold']) + + + def annotate_text(self, state, symbol='o', color=(200,50, 50), dx=0, dy=0, action=None, fontsize=30, bold=False): + x,y = self.to_screen(state) + x += int(dx * self.GRID_SIZE) + y += int(dy * self.GRID_SIZE) + if action is not None: + from irlc.gridworld.gridworld_mdp import GridworldMDP + dd = 0.2 + if action == GridworldMDP.NORTH: y -= int( dd * self.GRID_SIZE) + elif action == GridworldMDP.SOUTH: y += int( dd * self.GRID_SIZE) + elif action == GridworldMDP.EAST: x += int(dd * self.GRID_SIZE) + elif action == GridworldMDP.WEST: x -= int( dd * self.GRID_SIZE) + + self.annotations.append({'type': 'text', 'x': x, 'y': y, 'message': symbol, 'color': color, 'fontsize': fontsize, 'bold': bold}) + + + def close(self): + # Stop pygame and refresh thread + self.ga.close() + + def blit(self, render_mode=None): + return self.ga.blit(render_mode=render_mode) + # if render_mode == 'rgb_array': + # return np.transpose( + # np.array(pygame.surfarray.pixels3d(self.screen)), axes=(1, 0, 2) + # ) + # + # pass + + + + # def autorefresh(self, env, interval=0.1): + # raise Exception("What is this?") + # def task(env, interval): + # while True: + # env.render() + # time.sleep(interval) + # + # from threading import Thread + # thread = Thread(target=task, args=(env, interval)) + # thread.start() + + # def end_frame(self): + # self.ga.end_frame() + + def displayValues(self, mdp, v, preferred_actions=None, currentState=None, message='Agent Values', returns_count=None, returns_sum=None): + # if self.v_old == None: + # self.ga.gc.clear() + # self.v_old = {} + # else: + # pass + self.ga.draw_background() + m = [v[s] for s in mdp.nonterminal_states] + self.Q_old = None + grid = mdp.grid + minValue = min(m) + maxValue = max(m) + + for x in range(mdp.width): + for y in range(mdp.height): + name = f"V_{x}_{y}_" + state = (x, y) + gridType = grid[x, y] + isExit = str(gridType) != gridType + isCurrent = currentState == state + if gridType == '#': + self.drawSquare(name, x, y, 0, 0, 0, None, None, True, False, isCurrent) + else: + value = v[state] + value = np.round(value, 2) + valString = '%.2f' % value + if mdp.is_terminal(state): + all_actions = [] + else: + all_actions = mdp.A(state) + if preferred_actions != None: + all_actions = preferred_actions[state] + + returns_sum_ = returns_sum[state] if returns_sum is not None else None + returns_count_ = returns_count[state] if returns_count is not None else None + self.drawSquare(name, x, y, value, minValue, maxValue, valString, all_actions, False, isExit, isCurrent, + returns_sum=returns_sum_, returns_count=returns_count_) + + # print("Drawing...") + if isinstance(currentState, tuple): + # print("found pacman") + screen_x, screen_y = self.to_screen(currentState) + self.draw_player((screen_x, screen_y), 0.12 * self.GRID_SIZE) + # else: + # print("no instance found??") + + pos = self.to_screen(((mdp.width - 1.0) / 2.0, - 0.8)) + self.ga.text(f"v_text_", pos, TEXT_COLOR, message, "Courier", -32, "bold", "c") + self.draw_annotation() + + def displayNullValues(self, mdp, currentState=None, message=''): + self.ga.draw_background() + grid = mdp.grid + # self.blank() + for x in range(mdp.width): + for y in range(mdp.height): + state = (x, y) + gridType = grid[x,y] + isExit = str(gridType) != gridType + isCurrent = currentState == state + name = f"sq_{x}_{y}" + if gridType == '#': + self.drawSquare(name, x, y, 0, 0, 0, None, None, True, False, isCurrent) + else: + self.drawNullSquare(name, mdp.grid, x, y, False, isExit, isCurrent) + pos = self.to_screen(((mdp.width - 1.0) / 2.0, - 0.8)) + + if isinstance(currentState, tuple): + screen_x, screen_y = self.to_screen(currentState) + self.draw_player((screen_x, screen_y), 0.12 * self.GRID_SIZE) + else: + pass + # print("No player!") + # pos = self.to_screen(((mdp.width - 1.0) / 2.0, - 0.8)) + # self.ga.text("Q_values_text", pos, TEXT_COLOR, message, "Courier", -32, "bold", "c") + + self.ga.text("bottom_text", pos, TEXT_COLOR, message, "Courier", -32, "bold", "c") + self.draw_annotation() + + + def displayQValues(self, mdp, Q, currentState=None, message="Agent Q-Values", eligibility_trace=None, returns_count=None, returns_sum=None): + """ Eligibility trace is an optional dictionary-like object. """ + self.ga.draw_background() + if self.Q_old == None: + # self.ga.gc.clear() + + self.Q_old = {} + self.e_old = {} + else: + pass + # self.ga.gc.copy_all() + + self.v_old = None + self.Null_old = None + + m = [max(Q.get_Qs(s)[1]) for s in mdp.nonterminal_states] + mv = [min(Q.get_Qs(s)[1]) for s in mdp.nonterminal_states] + + minValue = min(mv) + maxValue = max(m) + for x in range(mdp.width): + for y in range(mdp.height): + state = (x, y) + if state not in mdp.nonterminal_states: + actions = [] + Qs = [] + else: + actions, Qs = Q.get_Qs((x, y)) + Qs = list(np.round(Qs, decimals=2)) + + # Q_same = False + if self.Q_old != None and Qs == self.Q_old.get((x, y), 0): + Q_same = True + else: + Q_same = False + Q_same = False + E_same = True + if eligibility_trace is not None: + es = [eligibility_trace[state, a] for a in actions] + if state in self.e_old and self.e_old[state] == es: + E_same = True + else: + E_same = False + + if E_same and Q_same: + continue + else: + self.Q_old[state] = Qs + if eligibility_trace is not None: + self.e_old[state] = es + + name = f"Qsqr_{x}_{y}" + gridType = mdp.grid[x, y] + isExit = (str(gridType) != gridType) + isCurrent = (currentState == state) + # actions = mdp.A(state) + if actions == None or len(actions) == 0: + actions = [None] + q = defaultdict(lambda: 0) + valStrings = {} + + if gridType == '#': + self.drawSquare(name, x, y, 0, 0, 0, None, None, True, False, isCurrent) + elif isExit: + action = actions[0] # next(iter(q.keys())) + value = Qs[0] # q[action] # q[action] + valString = '%.2f' % value + self.drawSquare(name, x, y, value, minValue, maxValue, valString, [action], False, isExit, + isCurrent) + else: + actions, Qs = Q.get_Qs(state) + de = None + rs = None # return-sum + rN = None # return-count + + for k, action in enumerate(actions): + v = Qs[k] # Get the Q-value. + # v = Q[state, action] + q[action] += v + valStrings[action] = '%.2f' % v + # etrace = None if eligibility_trace is None else eligibility_trace[] + # print(state, action, eligibility_trace[state, action]) + de = None if eligibility_trace is None else {a: eligibility_trace[state, a] for a in actions} + if returns_sum is not None: + rs = {a: returns_sum[state, a] for a in actions} + if returns_count is not None: + rN = {a: returns_count[state, a] for a in actions} + + + self.drawSquareQ(name, x, y, q, minValue, maxValue, valStrings, actions, isCurrent, eligibility_trace=de, returns_sum=rs, returns_count=rN) + pos = self.to_screen(((mdp.width - 1.0) / 2.0, - 0.8)) + self.ga.text("Q_values_text", pos, TEXT_COLOR, message, "Courier", -32, "bold", "c") + + if isinstance(currentState, tuple): + + screen_x, screen_y = self.to_screen(currentState) + self.draw_player((screen_x, screen_y), 0.12 * self.GRID_SIZE) + self.draw_annotation() + + + def drawNullSquare(self, name, grid, x, y, isObstacle, isTerminal, isCurrent): + square_color = getColor(0, -1, 1) + if isObstacle: + square_color = OBSTACLE_COLOR + (screen_x, screen_y) = self.to_screen((x, y)) + self.square(name + "_s1", (screen_x, screen_y), + 0.5 * self.GRID_SIZE, + color=square_color, + filled=1, + width=1) + self.square(name + "_s2", (screen_x, screen_y), + 0.5 * self.GRID_SIZE, + color=EDGE_COLOR, + filled=0, + width=3) + if isTerminal and not isObstacle: + self.square(name + "_s3", (screen_x, screen_y), + 0.4 * self.GRID_SIZE, + color=EDGE_COLOR, + filled=0, + width=2) + self.ga.text(name + "_text", (screen_x, screen_y), + TEXT_COLOR, + str(grid[x,y]), + "Courier", -24, "bold", "c") + self.draw_annotation() + + + def drawSquare(self, name, x, y, val, min, max, valStr, all_action, isObstacle, isTerminal, isCurrent, + returns_count=None, returns_sum=None): + square_color = getColor(val, min, max) + (screen_x, screen_y) = self.to_screen((x, y)) + if isObstacle: + square_color = OBSTACLE_COLOR + + self.square(name + "_o1", (screen_x, screen_y), 0.5 * self.GRID_SIZE, color=square_color, filled=1, width=1) + + self.square(name + "_o2", (screen_x, screen_y), 0.5 * self.GRID_SIZE, color=EDGE_COLOR, filled=0, width=3) + if isTerminal and not isObstacle: + self.square(name + "_o3", (screen_x, screen_y), 0.4 * self.GRID_SIZE, color=EDGE_COLOR, filled=0, width=2) + + if all_action is None: + all_action = [] + GRID_SIZE = self.GRID_SIZE + for action in all_action: + if action == GridworldMDP.NORTH: + self.ga.polygon(name + "_p1", [(screen_x, screen_y - 0.45 * GRID_SIZE), + (screen_x + 0.05 * GRID_SIZE, screen_y - 0.40 * GRID_SIZE), + (screen_x - 0.05 * GRID_SIZE, screen_y - 0.40 * GRID_SIZE)], EDGE_COLOR, + filled=1, smoothed=False) + if action == GridworldMDP.SOUTH: + self.ga.polygon(name + "_p2", [(screen_x, screen_y + 0.45 * GRID_SIZE), + (screen_x + 0.05 * GRID_SIZE, screen_y + 0.40 * GRID_SIZE), + (screen_x - 0.05 * GRID_SIZE, screen_y + 0.40 * GRID_SIZE)], EDGE_COLOR, + filled=1, smoothed=False) + if action == GridworldMDP.WEST: + self.ga.polygon(name + "_p3", [(screen_x - 0.45 * GRID_SIZE, screen_y), + (screen_x - 0.4 * GRID_SIZE, screen_y + 0.05 * GRID_SIZE), + (screen_x - 0.4 * GRID_SIZE, screen_y - 0.05 * GRID_SIZE)], EDGE_COLOR, + filled=1, smoothed=False) + if action == GridworldMDP.EAST: + self.ga.polygon(name + "_p4", [(screen_x + 0.45 * GRID_SIZE, screen_y), + (screen_x + 0.4 * GRID_SIZE, screen_y + 0.05 * GRID_SIZE), + (screen_x + 0.4 * GRID_SIZE, screen_y - 0.05 * GRID_SIZE)], EDGE_COLOR, + filled=1, smoothed=False) + + text_color = TEXT_COLOR + if not isObstacle: + self.ga.text(name + "_txt", (screen_x, screen_y - (GRID_SIZE/6 if isCurrent else 0) ), text_color, valStr, "Courier", -30, "bold", "c") + + if returns_count is not None: + self.ga.text(name + "_rc", (screen_x-GRID_SIZE/3, screen_y+GRID_SIZE/7), RED_TEXT_COLOR, f"N(s)={int(returns_count)}", "Courier", -20, "bold", "w") + if returns_sum is not None: + self.ga.text(name + "_rs", (screen_x-GRID_SIZE/3, screen_y+2*GRID_SIZE/7), RED_TEXT_COLOR, f"S(s)={returns_sum:.2f}", "Courier", -20, "bold", "w") + + # if returns_count is not None: + # self.ga.text(name + "_rs", (screen_x, screen_y), text_color, valStr, "Courier", -30, "bold", "c") + + + def drawSquareQ(self, name, x, y, qVals, minVal, maxVal, valStrs, bestActions, isCurrent, eligibility_trace=None, returns_sum=None, returns_count=None): + + GRID_SIZE = self.GRID_SIZE + (screen_x, screen_y) = self.to_screen((x, y)) + center = (screen_x, screen_y) + nw = (screen_x - 0.5 * GRID_SIZE, screen_y - 0.5 * GRID_SIZE) + ne = (screen_x + 0.5 * GRID_SIZE, screen_y - 0.5 * GRID_SIZE) + se = (screen_x + 0.5 * GRID_SIZE, screen_y + 0.5 * GRID_SIZE) + sw = (screen_x - 0.5 * GRID_SIZE, screen_y + 0.5 * GRID_SIZE) + + n = (screen_x, screen_y - 0.5 * GRID_SIZE + 5) + s = (screen_x, screen_y + 0.5 * GRID_SIZE - 5) + w = (screen_x - 0.5 * GRID_SIZE + 5, screen_y) + e = (screen_x + 0.5 * GRID_SIZE - 5, screen_y) + + actions = qVals.keys() + for action in actions: + wedge_color = getColor(qVals[action], minVal, maxVal) + if action == GridworldMDP.NORTH: + self.ga.polygon(name + "_s1", (center, nw, ne), wedge_color, filled=1, smoothed=False) + if action == GridworldMDP.SOUTH: + self.ga.polygon(name + "_s2", (center, sw, se), wedge_color, filled=1, smoothed=False) + if action == GridworldMDP.EAST: + self.ga.polygon(name + "_s3", (center, ne, se), wedge_color, filled=1, smoothed=False) + if action == GridworldMDP.WEST: + self.ga.polygon(name + "_s4", (center, nw, sw), wedge_color, filled=1, smoothed=False) + + self.square(name + "_base_square", (screen_x, screen_y), + 0.5 * GRID_SIZE, + color=EDGE_COLOR, + filled=0, + width=3) + + self.ga.line(name + "_l1", ne, sw, color=EDGE_COLOR) + self.ga.line(name + "_l2", nw, se, color=EDGE_COLOR) + + for action in actions: + text_color = TEXT_COLOR + if qVals[action] < max(qVals.values()): text_color = MUTED_TEXT_COLOR + valStr = "" + if action in valStrs: + valStr = valStrs[action] + h = -20 # Font size (for reasons). + if eligibility_trace is not None: + estr = f'{eligibility_trace[action]:.2f}' + dh = 0.105 * GRID_SIZE + ECOL = RED_TEXT_COLOR if eligibility_trace[action] != 0 else getColor(qVals[action], minVal, maxVal) + esize = -16 + + NCOL = RED_TEXT_COLOR + NSIZE = int(GRID_SIZE/170 * 20) + S_str = '' + N_str = '' + + rca = None + if returns_sum is not None and returns_sum[action] is not None: + rca = returns_sum[action] + + rcc = None + if returns_count is not None and returns_count[action] is not None: + rcc = returns_count[action] + + if rca is not None: + S_str = f"S(s)={returns_sum[action]:.2f}" + if rcc is not None: + N_str = f"N(s)={int(returns_count[action])}" + dh = 0.105 * GRID_SIZE + + # self.ga.text(name + "_rc", (screen_x - GRID_SIZE / 3, screen_y + GRID_SIZE / 7), RED_TEXT_COLOR, + # f"N(s)={int(returns_count)}", "Courier", -20, "bold", "w") + # if returns_sum is not None: + # self.ga.text(name + "_rs", (screen_x - GRID_SIZE / 3, screen_y + 2 * GRID_SIZE / 7), RED_TEXT_COLOR, + # f"S(s)={returns_sum:.2f}", "Courier", -20, "bold", "w") + # dw = 0.095 * GRID_SIZE + + if action == GridworldMDP.NORTH: + self.ga.text(name + "_txt1", n, text_color, valStr, "Courier", h, "bold", "n") + if eligibility_trace is not None: + self.ga.text(name + "_txt1e", (n[0], n[1]+dh), ECOL, estr, "Courier", esize, "bold", "n") + if rca is not None: + self.ga.text(f"{name}_txt_s{action}", (n[0], n[1] + dh), NCOL, S_str, "Courier", 10, "bold", "n",fontsize=NSIZE) + if rcc is not None: + self.ga.text(f"{name}_txt_n{action}", (n[0], n[1] + 2*dh), NCOL, N_str, "Courier", 2, "bold", "n",fontsize=NSIZE) + + + if action == GridworldMDP.SOUTH: + self.ga.text(name + "_txt2", s, text_color, valStr, "Courier", h, "bold", "s") + if eligibility_trace is not None: + self.ga.text(name + "_txt2e", (s[0], s[1]-dh), ECOL, estr, "Courier", esize, "bold", "s") + if rca is not None: + self.ga.text(f"{name}_txt_s{action}", (s[0], s[1] - 1.5*dh), NCOL, S_str, "Courier", 10, "bold", "n",fontsize=NSIZE) + if rcc is not None: + self.ga.text(f"{name}_txt_n{action}", (s[0], s[1] - 1.2*2*dh), NCOL, N_str, "Courier", 2, "bold", "n",fontsize=NSIZE) + + if action == GridworldMDP.EAST: + self.ga.text(name + "_txt3", e, text_color, valStr, "Courier", h, "bold", "e") + if eligibility_trace is not None: + self.ga.text(name + "_txt3e", (e[0], e[1]+dh), ECOL, estr, "Courier", esize, "bold", "e") + if rca is not None: + self.ga.text(f"{name}_txt_s{action}", (e[0]-1.4*dh, e[1] - 0.4*dh+dh), NCOL, S_str, "Courier", 10, "bold", "n",fontsize=NSIZE) + if rcc is not None: + self.ga.text(f"{name}_txt_n{action}", (e[0]-1.4*dh, e[1] + 0.4*dh+dh), NCOL, N_str, "Courier", 2, "bold", "n",fontsize=NSIZE) + + if action == GridworldMDP.WEST: + self.ga.text(name + "_txt4", w, text_color, valStr, "Courier", h, "bold", "w") + if eligibility_trace is not None: + self.ga.text(name + "_txt4e", (w[0], w[1]+dh), ECOL, estr, "Courier", esize, "bold", "w") + if rca is not None: + self.ga.text(f"{name}_txt_s{action}", (w[0]+1.6*dh, w[1] - 0.4*dh+dh), NCOL, S_str, "Courier", 10, "bold", "n",fontsize=NSIZE) + if rcc is not None: + self.ga.text(f"{name}_txt_n{action}", (w[0]+1.6*dh, w[1] + 0.4*dh+dh), NCOL, N_str, "Courier", 2, "bold", "n",fontsize=NSIZE) + + + + def square(self, name, pos, size, color, filled, width): + x, y = pos + dx, dy = size, size + return self.ga.polygon(name, [(x - dx, y - dy), (x - dx, y + dy), (x + dx, y + dy), (x + dx, y - dy)], + outlineColor=color, + fillColor=color, filled=filled, width=width, smoothed=False, closed=True) + + def draw_player(self, position, grid_size): + # PACMAN_COLOR + + self.ga.circle("pacman", position, PACMAN_SCALE * grid_size * 2, + fillColor=PACMAN_COLOR, outlineColor=PACMAN_COLOR, + endpoints=getEndpoints(0), + width=PACMAN_OUTLINE_WIDTH) + + def to_screen(self, point): + (gamex, gamey) = point + x = gamex * self.GRID_SIZE + self.MARGIN + y = (self.mdp.height - gamey - 1) * self.GRID_SIZE + self.MARGIN + return (x, y) + + +def getColor(val, min_value, max_value): + r = val * 0.65 / min_value if val < 0 and min_value < 0 else 0 + g = val * 0.65 / max_value if val > 0 and max_value > 0 else 0 + return formatColor(r, g, 0) + + +if __name__ == "__main__": + from irlc.gridworld.gridworld_environments import OpenGridEnvironment + env = OpenGridEnvironment(render_mode='human') + # env = BookGridEnvironment() + + from irlc.ex11.q_agent import QAgent + from irlc import train + + + agent = QAgent(env) + # env = VideoMonitor(env, agent=agent, fps=2000) + import time + + t = time.time() + n = 200 + train(env, agent, max_steps=n, num_episodes=10000, verbose=False) + env.close() + + print("time per step", (time.time() - t) / n) + # 0.458 + # 0.63 + # 0.61 + # Benchmark over 100 steps: everything else: 0.04 (11 %), setup: 0.25 (72 %), viewer.render: 0.06 (16 %) + +# 423, 390, 342 (cur) diff --git a/irlc/gridworld/gridworld_mdp.py b/irlc/gridworld/gridworld_mdp.py new file mode 100644 index 0000000..80c2bb6 --- /dev/null +++ b/irlc/gridworld/gridworld_mdp.py @@ -0,0 +1,71 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from collections import defaultdict +from irlc.ex09.mdp import MDP + + +class GridworldMDP(MDP): + TERMINAL = "Terminal state" + NORTH = 0 # These are the four available actions. + EAST = 1 + SOUTH = 2 + WEST = 3 + actions2labels = {NORTH: 'North', + SOUTH: 'South', + EAST: 'East', + WEST: 'West'} # This dictionary is useful for labelling purposes but otherwise serve no purpose. + + def __init__(self, grid, living_reward=0.0, noise=0.0): + self.grid = {} + self.height = len(grid) + self.width = len(grid[0]) + initial_state = None + for dy, line in enumerate(grid): + y = self.height - dy - 1 + for x, el in enumerate(line): + self.grid[x, y] = el + if el == 'S': + initial_state = (x, y) + self.noise = noise + self.living_reward = living_reward + super().__init__(initial_state=initial_state) + + def A(self, state): + """ + Returns list of valid actions available in 'state'. + + You can try to go into walls (but will state in your location) + and when you are on the exit-squares (i.e., the ones with numbers), you have a single action available + 'North' which will take you to the terminal square. + """ + return (self.NORTH,) if type(self.grid[state]) in [int, float] else (self.NORTH, self.EAST, self.SOUTH, self.WEST) + + def is_terminal(self, state): + return state == self.TERMINAL + + def Psr(self, state, action): + if type(self.grid[state]) in [float, int]: + return {(self.TERMINAL, self.grid[state]): 1.} + + probabilities = defaultdict(float) + for a, pr in [(action, 1-self.noise), ((action - 1) % 4, self.noise/2), ((action + 1) % 4, self.noise/2)]: + sp = self.f(state, a) + r = self.grid[state] if type(self.grid[state]) in [int, float] else self.living_reward + probabilities[(sp, r)] += pr + return probabilities + + def f(self, state, action): + x, y = state + nxt = {self.NORTH: (x, y+1), + self.WEST: (x-1, y), + self.EAST: (x+1, y), + self.SOUTH: (x, y-1)} + return nxt[action] if self._legal(nxt[action]) else state + + def _legal(self, state): + return state in self.grid and self.grid[state] != "#" + + +class FrozenGridMDP(GridworldMDP): + def __init__(self, grid, is_slippery=True, living_reward=0): + self.is_slippery = is_slippery + super().__init__(grid, noise=2/3 if is_slippery else 0, living_reward=living_reward) diff --git a/irlc/lectures/__init__.py b/irlc/lectures/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/lectures/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/lectures/lec01/__init__.py b/irlc/lectures/lec01/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/lectures/lec01/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/lectures/lec01/lecture_01_car_random.py b/irlc/lectures/lec01/lecture_01_car_random.py new file mode 100644 index 0000000..e1ffe55 --- /dev/null +++ b/irlc/lectures/lec01/lecture_01_car_random.py @@ -0,0 +1,10 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.car.car_model import CarEnvironment +from irlc.ex01.agent import train, Agent + +if __name__ == "__main__": + env = CarEnvironment(render_mode='human') + env.action_space.low[1] = 0 # To ensure we do not drive backwards. + agent = Agent(env) + stats, _ = train(env, agent, num_episodes=1, verbose=False) + env.close() diff --git a/irlc/lectures/lec01/lecture_01_pacman.py b/irlc/lectures/lec01/lecture_01_pacman.py new file mode 100644 index 0000000..cba2e1b --- /dev/null +++ b/irlc/lectures/lec01/lecture_01_pacman.py @@ -0,0 +1,15 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.pacman.pacman_environment import PacmanEnvironment +from irlc.ex01.agent import train, Agent +from irlc import interactive + +def ppacman(): + # smallGrid + env = PacmanEnvironment(layout='mediumClassic', render_mode='human') + env, agent = interactive(env, Agent(env)) + stats, _ = train(env, agent, num_episodes=100, verbose=False) + print("Accumulated reward", stats[-1]['Accumulated Reward']) + env.close() + +if __name__ == "__main__": + ppacman() diff --git a/irlc/lectures/lec01/lecture_01_pendulum_random.py b/irlc/lectures/lec01/lecture_01_pendulum_random.py new file mode 100644 index 0000000..a5e7fc4 --- /dev/null +++ b/irlc/lectures/lec01/lecture_01_pendulum_random.py @@ -0,0 +1,9 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex01.agent import train, Agent +from irlc.ex04.model_pendulum import GymSinCosPendulumEnvironment + +if __name__ == "__main__": + env = GymSinCosPendulumEnvironment(Tmax=100, render_mode='human') + agent = Agent(env) + stats, _ = train(env, agent, num_episodes=1, verbose=False) + env.close() diff --git a/irlc/lectures/lec02/__init__.py b/irlc/lectures/lec02/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/lectures/lec02/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/lectures/lec02/lecture_02_dp_gridworld_short.py b/irlc/lectures/lec02/lecture_02_dp_gridworld_short.py new file mode 100644 index 0000000..d2831e6 --- /dev/null +++ b/irlc/lectures/lec02/lecture_02_dp_gridworld_short.py @@ -0,0 +1,8 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.chapter1.dp_planning_agent import dp_visualization +from irlc.gridworld.gridworld_environments import FrozenLake + +if __name__ == "__main__": + env = FrozenLake(render_mode='human') + dp_visualization(env, N=4, num_episodes=10) + env.close() diff --git a/irlc/lectures/lec02/lecture_02_frozen_lake.py b/irlc/lectures/lec02/lecture_02_frozen_lake.py new file mode 100644 index 0000000..3a91f81 --- /dev/null +++ b/irlc/lectures/lec02/lecture_02_frozen_lake.py @@ -0,0 +1,13 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import FrozenLake +from gymnasium.wrappers import TimeLimit +from irlc import Agent, interactive, train + +if __name__ == "__main__": + env = FrozenLake(is_slippery=True, living_reward=-1e-4, render_mode="human") + N = 40 + env, agent = interactive(env, Agent(env)) + env = TimeLimit(env, max_episode_steps=N) + num_episodes = 100 + train(env, agent, num_episodes=num_episodes) + env.close() diff --git a/irlc/lectures/lec02/lecture_02_frozen_long_slippery.py b/irlc/lectures/lec02/lecture_02_frozen_long_slippery.py new file mode 100644 index 0000000..217929b --- /dev/null +++ b/irlc/lectures/lec02/lecture_02_frozen_long_slippery.py @@ -0,0 +1,8 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.chapter1.dp_planning_agent import dp_visualization +from irlc.gridworld.gridworld_environments import FrozenLake + +if __name__ == "__main__": + env = FrozenLake(is_slippery=True, living_reward=-1e-4, render_mode='human') + dp_visualization(env, N=40, num_episodes=100) + env.close() diff --git a/irlc/lectures/lec02/lecture_02_keyboard_pacman_g1.py b/irlc/lectures/lec02/lecture_02_keyboard_pacman_g1.py new file mode 100644 index 0000000..06aa7e9 --- /dev/null +++ b/irlc/lectures/lec02/lecture_02_keyboard_pacman_g1.py @@ -0,0 +1,23 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.pacman.pacman_environment import PacmanEnvironment +from irlc.ex01.agent import train +from irlc.ex01.agent import Agent +from irlc import interactive +from irlc.lectures.chapter3dp.dp_pacman import SS1tiny +# from irlc.pacman.layouts import S + +# from irlc import PlayWrapper +# from irlc import VideoMonitor + +def ppac(layout_str, name="pac"): + env = PacmanEnvironment(layout=None, layout_str=layout_str, animate_movement=True) + agent = Agent(env) + env, agent = interactive(env, agent) + # agent = PlayWrapper(agent, env) + # env = VideoMonitor(env) + stats, _ = train(env, agent, num_episodes=5, max_steps=8) + print("Accumulated reward for all episodes:", [s['Accumulated Reward'] for s in stats]) + env.close() + +if __name__ == "__main__": + ppac(SS1tiny) diff --git a/irlc/lectures/lec02/lecture_02_keyboard_pacman_g2.py b/irlc/lectures/lec02/lecture_02_keyboard_pacman_g2.py new file mode 100644 index 0000000..cd1f8df --- /dev/null +++ b/irlc/lectures/lec02/lecture_02_keyboard_pacman_g2.py @@ -0,0 +1,6 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex02.old.dp_pacman import SS2tiny +from irlc.lectures.lec02.lecture_02_keyboard_pacman_g1 import ppac + +if __name__ == "__main__": + ppac(SS2tiny) diff --git a/irlc/lectures/lec02/lecture_02_optimal_dp_g0.py b/irlc/lectures/lec02/lecture_02_optimal_dp_g0.py new file mode 100644 index 0000000..8c91497 --- /dev/null +++ b/irlc/lectures/lec02/lecture_02_optimal_dp_g0.py @@ -0,0 +1,38 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.pacman.pacman_environment import PacmanEnvironment +from irlc.ex02.dp_agent import DynamicalProgrammingAgent +from gymnasium.wrappers import TimeLimit +from irlc.pacman.pacman_environment import PacmanWinWrapper +from irlc.ex01.agent import train +# from irlc import VideoMonitor +# from irlc.ex02.old.dp_pacman import DPPacmanModel +from irlc.lectures.chapter3dp.dp_pacman import DPPacmanModel +# from irlc import PlayWrapper +from irlc import interactive + +def simulate_1_game(layout_str): + N = 30 + env = PacmanEnvironment(layout=None, layout_str=layout_str, render_mode='human') + + # env = VideoMonitor(env, fps=3) + model = DPPacmanModel(env, N=N, verbose=True) + agent = DynamicalProgrammingAgent(env, model=model) + # agent = PlayWrapper(agent, env) + env, agent = interactive(env, agent) + env = TimeLimit(env, max_episode_steps=N) + env = PacmanWinWrapper(env) + stats, trajectories = train(env, agent, num_episodes=100, verbose=False, return_trajectory=True) + env.close() + + +SS0 = """ +%%%%%%%%%% +% P . % +% %%%%%. % +% % +% %%% %%%% +%. .% +%%%%%%%%%% +""" +if __name__ == "__main__": + simulate_1_game(layout_str=SS0) diff --git a/irlc/lectures/lec02/lecture_02_optimal_dp_g1.py b/irlc/lectures/lec02/lecture_02_optimal_dp_g1.py new file mode 100644 index 0000000..1cd3b98 --- /dev/null +++ b/irlc/lectures/lec02/lecture_02_optimal_dp_g1.py @@ -0,0 +1,25 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# from irlc.pacman.pacman_environment import GymPacmanEnvironment +# from irlc.ex02.dp_agent import DynamicalProgrammingAgent +# from gym.wrappers import TimeLimit +# from irlc.pacman.pacman_environment import PacmanWinWrapper +# from irlc.ex01.agent import train +# # from irlc import VideoMonitor +from irlc.lectures.chapter3dp.dp_pacman import DPPacmanModel, SS1tiny +from irlc import interactive +from irlc.lectures.lec02.lecture_02_optimal_dp_g0 import simulate_1_game + +# def simulate_1_game(layout_str): +# N = 8 +# env = GymPacmanEnvironment(layout=None, layout_str=layout_str, animate_movement=True) +# env = VideoMonitor(env, fps=3) +# model = DPPacmanModel(env, N=N, verbose=True) +# agent = DynamicalProgrammingAgent(env, model=model) +# agent = PlayWrapper(agent, env) +# env = TimeLimit(env, max_episode_steps=N) +# env = PacmanWinWrapper(env) +# stats, trajectories = train(env, agent, num_episodes=100, verbose=False, return_trajectory=True) +# env.close() + +if __name__ == "__main__": + simulate_1_game(layout_str=SS1tiny) diff --git a/irlc/lectures/lec02/lecture_02_optimal_dp_g2.py b/irlc/lectures/lec02/lecture_02_optimal_dp_g2.py new file mode 100644 index 0000000..32c4b59 --- /dev/null +++ b/irlc/lectures/lec02/lecture_02_optimal_dp_g2.py @@ -0,0 +1,6 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.chapter3dp.dp_pacman import SS2tiny +from irlc.lectures.lec02.lecture_02_optimal_dp_g1 import simulate_1_game + +if __name__ == "__main__": + simulate_1_game(layout_str=SS2tiny) diff --git a/irlc/lectures/lec03/__init__.py b/irlc/lectures/lec03/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/lectures/lec03/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/lectures/lec03/ex_03_search.py b/irlc/lectures/lec03/ex_03_search.py new file mode 100644 index 0000000..7d5ce2c --- /dev/null +++ b/irlc/lectures/lec03/ex_03_search.py @@ -0,0 +1,18 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc import Agent, train, savepdf +from irlc.pacman.pacman_environment import PacmanEnvironment +from irlc.ex03.dp_forward import dp_forward +from irlc.ex03.search_problem import SearchProblem +from irlc.ex03.search_problem import EnsureTerminalSelfTransitionsWrapper +from irlc.ex03.pacman_search import layout2, layout1 + +if __name__ == "__main__": + env = PacmanEnvironment(layout_str=layout1, render_mode='human') + env.reset() + savepdf("ex03_layout1", env=env) + env.close() + + env = PacmanEnvironment(layout_str=layout1, render_mode='human') + env.reset() + savepdf("ex03_layout2", env=env) + env.close() diff --git a/irlc/lectures/lec03/lecture_03_alphab.py b/irlc/lectures/lec03/lecture_03_alphab.py new file mode 100644 index 0000000..fa81c07 --- /dev/null +++ b/irlc/lectures/lec03/lecture_03_alphab.py @@ -0,0 +1,7 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex03multisearch.multisearch_alphabeta import GymAlphaBetaAgent +from irlc.lectures.lec03.lecture_03_minimax import gminmax + +if __name__ == "__main__": + d = 3 + gminmax(Agent=GymAlphaBetaAgent,depth=d) diff --git a/irlc/lectures/lec03/lecture_03_dotsearch_astar_manhattan.py b/irlc/lectures/lec03/lecture_03_dotsearch_astar_manhattan.py new file mode 100644 index 0000000..ebea74a --- /dev/null +++ b/irlc/lectures/lec03/lecture_03_dotsearch_astar_manhattan.py @@ -0,0 +1,8 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec03.lecture_03_dotsearch_dp import singledot +from irlc.lectures.chapter4search.yield_version.pacman_yield import AStarAgentYield +from irlc.ex03multisearch.pacman_problem_positionsearch_astar import manhattanHeuristic + +if __name__ == "__main__": + agent_args = dict(heuristic=manhattanHeuristic) + singledot(SAgent=AStarAgentYield, agent_args=agent_args) diff --git a/irlc/lectures/lec03/lecture_03_dotsearch_bfs.py b/irlc/lectures/lec03/lecture_03_dotsearch_bfs.py new file mode 100644 index 0000000..2fafd77 --- /dev/null +++ b/irlc/lectures/lec03/lecture_03_dotsearch_bfs.py @@ -0,0 +1,9 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec03.lecture_03_dotsearch_dp import singledot +from irlc.lectures.chapter4search.yield_version.pacman_yield import BFSAgentYield + +if __name__ == "__main__": + # agent_args = dict(heuristic=manhattanHeuristic,N=30) + singledot(SAgent=BFSAgentYield) + + # singledot(SAgent=BFSAgentYield) diff --git a/irlc/lectures/lec03/lecture_03_dotsearch_dfs.py b/irlc/lectures/lec03/lecture_03_dotsearch_dfs.py new file mode 100644 index 0000000..276aa6b --- /dev/null +++ b/irlc/lectures/lec03/lecture_03_dotsearch_dfs.py @@ -0,0 +1,9 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec03.lecture_03_dotsearch_dp import singledot +from irlc.lectures.chapter4search.yield_version.pacman_yield import DFSAgentYield + +if __name__ == "__main__": + # agent_args = dict(heuristic=manhattanHeuristic,N=30) + singledot(SAgent=DFSAgentYield) + + # singledot(SAgent=BFSAgentYield) diff --git a/irlc/lectures/lec03/lecture_03_dotsearch_dp.py b/irlc/lectures/lec03/lecture_03_dotsearch_dp.py new file mode 100644 index 0000000..baff1ee --- /dev/null +++ b/irlc/lectures/lec03/lecture_03_dotsearch_dp.py @@ -0,0 +1,12 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.chapter4search.yield_version.pacman_yield import stest, ForwardDPSearchAgent, dargs +# from irlc.ex03.pacsearch_agents import GymPositionSearchProblem, manhattanHeuristic, GymCornersProblem, cornersHeuristic, foodHeuristic, GymFoodSearchProblem, GymAnyFoodSearchProblem +from irlc.ex03multisearch.pacman_problem_positionsearch import GymPositionSearchProblem#, manhattanHeuristic + + +def singledot(layout='smallMaze', SAgent=None, agent_args=None, layout_str=None): + stest(layout=layout, layout_str=layout_str, SAgent=SAgent, prob=GymPositionSearchProblem(), agent_args=agent_args, zoom=2, **dargs, fps=30) # part 3 + +if __name__ == "__main__": + agent_args = dict(N=30) + singledot(SAgent=ForwardDPSearchAgent, agent_args=agent_args) diff --git a/irlc/lectures/lec03/lecture_03_expectimax.py b/irlc/lectures/lec03/lecture_03_expectimax.py new file mode 100644 index 0000000..826975f --- /dev/null +++ b/irlc/lectures/lec03/lecture_03_expectimax.py @@ -0,0 +1,7 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex03multisearch.multisearch_agents import GymExpectimaxAgent +from irlc.lectures.lec03.lecture_03_minimax import gminmax + +if __name__ == "__main__": + d = 3 + gminmax(Agent=GymExpectimaxAgent,depth=d) diff --git a/irlc/lectures/lec03/lecture_03_minimax.py b/irlc/lectures/lec03/lecture_03_minimax.py new file mode 100644 index 0000000..eb8ee73 --- /dev/null +++ b/irlc/lectures/lec03/lecture_03_minimax.py @@ -0,0 +1,35 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex01.agent import train +from irlc.pacman.pacman_environment import GymPacmanEnvironment +from irlc.utils.video_monitor import VideoMonitor +from irlc.ex03multisearch.multisearch_agents import GymMinimaxAgent + + +layout_str = """ +%%%%%%%%% +% % +% %%%% % +% % +% P % +%%%% % +%%%% .G % +%%%% % +%%%%%%%%% +""".strip() + +def gminmax(layout='smallClassic', layout_str=layout_str, Agent=None, depth=3, **kwargs): + zoom = 2 + env = GymPacmanEnvironment(layout=layout, layout_str=layout_str, zoom=zoom, **kwargs) + agent = Agent(env, depth=depth) + from irlc import PlayWrapper + agent = PlayWrapper(agent, env) + + env = VideoMonitor(env, agent=agent, agent_monitor_keys=tuple(), fps=10) + train(env, agent, num_episodes=30) + env.close() + +if __name__ == "__main__": + d = 3 + gminmax(layout='minimaxClassic', layout_str=layout_str, Agent=GymMinimaxAgent,depth=d) + # gminmax(layout='minimaxClassic', layout_str=layout_str, Agent=GymAlphaBetaAgent, depth=d) + # gminmax(layout='minimaxClassic', layout_str=layout_str, Agent=GymExpectimaxAgent,depth=d) diff --git a/irlc/lectures/lec03/lecture_03_squaresearch_bfs.py b/irlc/lectures/lec03/lecture_03_squaresearch_bfs.py new file mode 100644 index 0000000..ac1e095 --- /dev/null +++ b/irlc/lectures/lec03/lecture_03_squaresearch_bfs.py @@ -0,0 +1,12 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.chapter4search.yield_version.pacman_yield import BFSAgentYield +from irlc.lectures.chapter4search.search_tables import s_large + +# def tricksearchdot(layout='trickySearch', SAgent=None, agent_args=None, layout_str=None): +# stest(layout_str=layout_str, SAgent=SAgent, prob=GymFoodSearchProblem(), agent_args=agent_args, zoom=2, **dargs, fps=1000) # part 3 + +from irlc.lectures.lec03.lecture_03_tricksearch_bfs import tricksearchdot + +if __name__ == "__main__": + # agent_args = dict(heuristic=manhattanHeuristic,N=30) + tricksearchdot(SAgent=BFSAgentYield, agent_args=None, layout_str=s_large) diff --git a/irlc/lectures/lec03/lecture_03_tricksearch_astar.py b/irlc/lectures/lec03/lecture_03_tricksearch_astar.py new file mode 100644 index 0000000..6c65849 --- /dev/null +++ b/irlc/lectures/lec03/lecture_03_tricksearch_astar.py @@ -0,0 +1,10 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# from irlc.ex03.pacsearch_agents import GymPositionSearchProblem, manhattanHeuristic, GymCornersProblem, cornersHeuristic, foodHeuristic, GymFoodSearchProblem, GymAnyFoodSearchProblem +from irlc.lectures.chapter4search.yield_version.pacman_yield import AStarAgentYield + +from irlc.lectures.lec03.lecture_03_tricksearch_bfs import tricksearchdot +from irlc.ex03multisearch.pacman_problem_foodsearch_astar import foodHeuristic + +if __name__ == "__main__": + agent_args = dict(heuristic=foodHeuristic) + tricksearchdot(SAgent=AStarAgentYield, agent_args=agent_args) diff --git a/irlc/lectures/lec03/lecture_03_tricksearch_bfs.py b/irlc/lectures/lec03/lecture_03_tricksearch_bfs.py new file mode 100644 index 0000000..89b7764 --- /dev/null +++ b/irlc/lectures/lec03/lecture_03_tricksearch_bfs.py @@ -0,0 +1,21 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.chapter4search.yield_version.pacman_yield import stest, dargs +from irlc.ex03multisearch.pacman_problem_foodsearch import GymFoodSearchProblem +from irlc.lectures.chapter4search.yield_version.pacman_yield import BFSAgentYield + +layout_str = """ +%%%%%%%%%%%% +% % % +%.%.%.%% % % +% P % % +%%%%%%%%%% % +%. % +%%%%%%%%%%%% +""".strip() + +def tricksearchdot(layout_str=layout_str, SAgent=None, agent_args=None): + stest(layout_str=layout_str, SAgent=SAgent, prob=GymFoodSearchProblem(), agent_args=agent_args, zoom=2, **dargs, fps=1000) # part 3 + +if __name__ == "__main__": + # agent_args = dict(heuristic=manhattanHeuristic,N=30) + tricksearchdot(SAgent=BFSAgentYield, agent_args=None) diff --git a/irlc/lectures/lec03/lecture_03_tricksearch_dfs.py b/irlc/lectures/lec03/lecture_03_tricksearch_dfs.py new file mode 100644 index 0000000..f3b2ac4 --- /dev/null +++ b/irlc/lectures/lec03/lecture_03_tricksearch_dfs.py @@ -0,0 +1,10 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# from irlc.ex03.pacsearch_agents import GymPositionSearchProblem, manhattanHeuristic, GymCornersProblem, cornersHeuristic, foodHeuristic, GymFoodSearchProblem, GymAnyFoodSearchProblem + +from irlc.lectures.chapter4search.yield_version.pacman_yield import DFSAgentYield +from irlc.lectures.lec03.lecture_03_tricksearch_bfs import tricksearchdot + + +if __name__ == "__main__": + # agent_args = dict(heuristic=manhattanHeuristic,N=30) + tricksearchdot(SAgent=DFSAgentYield, agent_args=None) diff --git a/irlc/lectures/lec03/snapshot_base/openaigym.video.0.8068.video000000.meta.json b/irlc/lectures/lec03/snapshot_base/openaigym.video.0.8068.video000000.meta.json new file mode 100644 index 0000000..5dc734d --- /dev/null +++ b/irlc/lectures/lec03/snapshot_base/openaigym.video.0.8068.video000000.meta.json @@ -0,0 +1 @@ +{"episode_id": 0, "content_type": "video/mp4"} \ No newline at end of file diff --git a/irlc/lectures/lec03/snapshot_base/openaigym.video.0.8068.video000000.mp4 b/irlc/lectures/lec03/snapshot_base/openaigym.video.0.8068.video000000.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..17e5e5fbd204f4f1c8bf240b166ab0a318db4744 GIT binary patch literal 48 zcmZQzU{FXasVvAW&d+6FU}6B#nZ@}=iDk)#xdkSM3=9k$X+^223=9kmxhaVy06gam A&;S4c literal 0 HcmV?d00001 diff --git a/irlc/lectures/lec04/__init__.py b/irlc/lectures/lec04/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/lectures/lec04/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/lectures/lec04/lecture_04_car_basic_pid.py b/irlc/lectures/lec04/lecture_04_car_basic_pid.py new file mode 100644 index 0000000..8ed6d96 --- /dev/null +++ b/irlc/lectures/lec04/lecture_04_car_basic_pid.py @@ -0,0 +1,20 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# from irlc.ex04.pid_lunar import lunar_single_mission, get_lunar_lander +# import gym +from irlc import train +from irlc.car.car_model import CarEnvironment +from irlc.ex04.pid_car import PIDCarAgent +from irlc import savepdf +from irlc import interactive, Agent + +if __name__ == "__main__": + env = CarEnvironment(noise_scale=0, Tmax=30, max_laps=1, render_mode='human') + agent = PIDCarAgent(env, v_target=.2, use_both_x5_x3=False) + stats, trajectories = train(env, agent, num_episodes=1, return_trajectory=True) + env.close() + + + + + # env = CarEnvironment(noise_scale=0,Tmax=30, max_laps=1, render_mode='human') + # agent = PIDCarAgent(env, v_target=1, use_both_x5_x3=True) # I recommend lowering v_target to make the problem simpler. diff --git a/irlc/lectures/lec04/lecture_04_cartpole_A.py b/irlc/lectures/lec04/lecture_04_cartpole_A.py new file mode 100644 index 0000000..3f4a289 --- /dev/null +++ b/irlc/lectures/lec04/lecture_04_cartpole_A.py @@ -0,0 +1,10 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc import train +from irlc.ex04.pid_cartpole import PIDCartpoleAgent, get_offbalance_cart + +if __name__ == "__main__": + env = get_offbalance_cart(30) + agent = PIDCartpoleAgent(env, dt=env.dt, Kp=120, Ki=0, Kd=10, balance_to_x0=False) + # agent = PlayWrapper(agent, env) + _, trajectories = train(env, agent, num_episodes=1, reset=False) + env.close() diff --git a/irlc/lectures/lec04/lecture_04_cartpole_B.py b/irlc/lectures/lec04/lecture_04_cartpole_B.py new file mode 100644 index 0000000..a57e095 --- /dev/null +++ b/irlc/lectures/lec04/lecture_04_cartpole_B.py @@ -0,0 +1,14 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc import train +from irlc.ex04.pid_cartpole import PIDCartpoleAgent, get_offbalance_cart + +if __name__ == "__main__": + """ + Second task: We will now also try to bring the cart towards x=0. + """ + env = get_offbalance_cart(30) + agent = PIDCartpoleAgent(env, env.dt, ...) + # TODO: 1 lines missing. + raise NotImplementedError("Define your agent here (including parameters)") + _, trajectories = train(env, agent, num_episodes=1, reset=False) # Note reset=False to maintain initial conditions. + env.close() diff --git a/irlc/lectures/lec04/lecture_04_harmonic.py b/irlc/lectures/lec04/lecture_04_harmonic.py new file mode 100644 index 0000000..7d74099 --- /dev/null +++ b/irlc/lectures/lec04/lecture_04_harmonic.py @@ -0,0 +1,14 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc import train +from irlc.ex04.model_harmonic import HarmonicOscilatorEnvironment +from irlc import Agent +import numpy as np + +class NullAgent(Agent): + def pi(self, x, k, info=None): + return np.asarray([0]) + +if __name__ == "__main__": + env = HarmonicOscilatorEnvironment(render_mode='human') + train(env, NullAgent(env), num_episodes=1, max_steps=200) + env.close() diff --git a/irlc/lectures/lec04/lecture_04_lunar.py b/irlc/lectures/lec04/lecture_04_lunar.py new file mode 100644 index 0000000..c68fee7 --- /dev/null +++ b/irlc/lectures/lec04/lecture_04_lunar.py @@ -0,0 +1,15 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex04.pid_lunar import lunar_single_mission, get_lunar_lander +import gymnasium +from irlc import train + +if __name__ == "__main__": + env = gymnasium.make('LunarLanderContinuous-v2', render_mode='human') + env._max_episode_steps = 1000 # We don't want it to time out. + + agent = get_lunar_lander(env) + # agent = PlayWrapper(agent, env) + # env = VideoMonitor(env) + + stats, traj = train(env, agent, return_trajectory=True, num_episodes=10) + env.close() diff --git a/irlc/lectures/lec04/lecture_04_pendulum_random.py b/irlc/lectures/lec04/lecture_04_pendulum_random.py new file mode 100644 index 0000000..58d0843 --- /dev/null +++ b/irlc/lectures/lec04/lecture_04_pendulum_random.py @@ -0,0 +1,8 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc import Agent, train +from irlc.ex04.model_pendulum import GymSinCosPendulumEnvironment + +if __name__ == "__main__": + env = GymSinCosPendulumEnvironment(Tmax=20, render_mode='human') + train(env, Agent(env), num_episodes=1) + env.close() diff --git a/irlc/lectures/lec04/lecture_04_pid_d.py b/irlc/lectures/lec04/lecture_04_pid_d.py new file mode 100644 index 0000000..8b05ff1 --- /dev/null +++ b/irlc/lectures/lec04/lecture_04_pid_d.py @@ -0,0 +1,5 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec04.lecture_04_pid_p import pidplot + +if __name__ == "__main__": + pidplot(Kp=40, Kd=100, Ki=0) diff --git a/irlc/lectures/lec04/lecture_04_pid_iA.py b/irlc/lectures/lec04/lecture_04_pid_iA.py new file mode 100644 index 0000000..fa35061 --- /dev/null +++ b/irlc/lectures/lec04/lecture_04_pid_iA.py @@ -0,0 +1,6 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec04.lecture_04_pid_p import pidplot + + +if __name__ == "__main__": + pidplot(Kp=40, Kd=50, Ki=0, slope=2, target=0) diff --git a/irlc/lectures/lec04/lecture_04_pid_iB.py b/irlc/lectures/lec04/lecture_04_pid_iB.py new file mode 100644 index 0000000..9fda178 --- /dev/null +++ b/irlc/lectures/lec04/lecture_04_pid_iB.py @@ -0,0 +1,6 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec04.lecture_04_pid_p import pidplot + + +if __name__ == "__main__": + pidplot(Kp=40, Kd=50, Ki=10, slope=2, target=0) diff --git a/irlc/lectures/lec04/lecture_04_pid_p.py b/irlc/lectures/lec04/lecture_04_pid_p.py new file mode 100644 index 0000000..ed3eb6b --- /dev/null +++ b/irlc/lectures/lec04/lecture_04_pid_p.py @@ -0,0 +1,19 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex04.locomotive import LocomotiveEnvironment +from irlc.ex04.pid_locomotive_agent import PIDLocomotiveAgent +from irlc.ex01.agent import train + +def pidplot(Kp=40, Kd=0, Ki=0, slope=0, target=0): + dt = .04 + m = 70 + Tmax=20 + env = LocomotiveEnvironment(m=m, slope=slope, dt=dt, Tmax=Tmax, render_mode='human') + # env = VideoMonitor(env) + # Kp = 40 + agent = PIDLocomotiveAgent(env, dt=dt, Kp=Kp, Ki=Ki, Kd=Kd, target=0) + # env = PlayWrapper(agent, env) + train(env, agent, num_episodes=1) + env.close() + +if __name__ == "__main__": + pidplot(Kp=40, Kd=0, Ki=0) diff --git a/irlc/lectures/lec05/__init__.py b/irlc/lectures/lec05/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/lectures/lec05/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/lectures/lec05/lecture_05_carpole_random.py b/irlc/lectures/lec05/lecture_05_carpole_random.py new file mode 100644 index 0000000..e82a89b --- /dev/null +++ b/irlc/lectures/lec05/lecture_05_carpole_random.py @@ -0,0 +1,9 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc import Agent, train +from irlc.ex05.model_cartpole import GymSinCosCartpoleEnvironment + +if __name__ == "__main__": + + env = GymSinCosCartpoleEnvironment(Tmax=20, render_mode='human') + train(env, Agent(env), num_episodes=1) + env.close() diff --git a/irlc/lectures/lec05/lecture_05_cartpole_kelly.py b/irlc/lectures/lec05/lecture_05_cartpole_kelly.py new file mode 100644 index 0000000..1bc3bcc --- /dev/null +++ b/irlc/lectures/lec05/lecture_05_cartpole_kelly.py @@ -0,0 +1,10 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex05.direct_cartpole_kelly import compute_solutions +from irlc.ex05.direct_plot import plot_solutions +import matplotlib.pyplot as plt + +if __name__ == "__main__": + env, solutions = compute_solutions() + print("Did we succeed?", solutions[-1]['solver']['success']) + plot_solutions(env, solutions, animate=True, pdf=None, animate_all=True, animate_repeats=3) + env.close() diff --git a/irlc/lectures/lec05/lecture_05_cartpole_time.py b/irlc/lectures/lec05/lecture_05_cartpole_time.py new file mode 100644 index 0000000..ebd6e87 --- /dev/null +++ b/irlc/lectures/lec05/lecture_05_cartpole_time.py @@ -0,0 +1,11 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex05.direct_cartpole_time import compute_solutions +from irlc.ex05.direct_plot import plot_solutions +import matplotlib.pyplot as plt + +if __name__ == "__main__": + env, solutions = compute_solutions() + print("Did we succeed?", solutions[-1]['solver']['success']) + plot_solutions(env, solutions, animate=True, pdf=None, animate_all=True, animate_repeats=3) + env.close() + pass diff --git a/irlc/lectures/lec06/__init__.py b/irlc/lectures/lec06/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/lectures/lec06/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/lectures/lec06/lecture6_lqr_locomotive.py b/irlc/lectures/lec06/lecture6_lqr_locomotive.py new file mode 100644 index 0000000..2c9ddf3 --- /dev/null +++ b/irlc/lectures/lec06/lecture6_lqr_locomotive.py @@ -0,0 +1,37 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import matplotlib.pyplot as plt +import numpy as np +from irlc import savepdf, train +from irlc.ex04.pid_locomotive_agent import PIDLocomotiveAgent +from irlc.ex06.lqr_agent import LQRAgent +from irlc.ex04.model_harmonic import HarmonicOscilatorEnvironment +from irlc.ex06.boeing_lqr import compute_A_B_d, compute_Q_R_q +from irlc.ex07.linearization_agent import LinearizationAgent +from irlc.ex06.lqr_pid import ConstantLQRAgent +from irlc.ex04.locomotive import LocomotiveEnvironment +from irlc.ex04.pid_locomotive_agent import PIDLocomotiveAgent +from irlc.ex01.agent import train +from irlc.ex03.control_cost import SymbolicQRCost +import matplotlib +#matplotlib.use('qtagg') +dt = .04 +m = 70 +Tmax=10 +slope = 0 + +env = LocomotiveEnvironment(m=m, slope=slope, dt=dt, Tmax=Tmax, render_mode='human') + +model = env.discrete_model +model.cost = SymbolicQRCost(Q=np.eye(2)*100, R=np.eye(1)).discretize(dt=dt) +agent = LinearizationAgent(env, model=model, xbar=env.observation_space.sample(), ubar=env.action_space.sample()) +_, traj = train(env, agent, num_episodes=1) +env.close() +if False: + from irlc import plot_trajectory, savepdf + import matplotlib.pyplot as plt + plt.figure() + plot_trajectory(trajectory=traj[0], env=env, xkeys=[0, 1], ukeys=[]) + savepdf('lqr_pid_locomotive_state.pdf') + plot_trajectory(trajectory=traj[0], env=env, ukeys=[0], xkeys=[]) + savepdf('lqr_pid_locomotive_action.pdf') + env.close() diff --git a/irlc/lectures/lec06/lecture_06_cartpole_ilqr.py b/irlc/lectures/lec06/lecture_06_cartpole_ilqr.py new file mode 100644 index 0000000..dc56335 --- /dev/null +++ b/irlc/lectures/lec06/lecture_06_cartpole_ilqr.py @@ -0,0 +1,47 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc.ex07.ilqr_agent import ILQRAgent +from irlc import train +from irlc.ex05.model_cartpole import GymSinCosCartpoleEnvironment +# from irlc import VideoMonitor + +def cartpole_experiment(N=12, use_linesearch=True, figex="", animate=True): + np.random.seed(2) + Tmax = .9 + dt = Tmax/N + + env = GymSinCosCartpoleEnvironment(dt=dt, Tmax=Tmax, supersample_trajectory=True, render_mode='human') + agent = ILQRAgent(env, env.discrete_model, N=N, ilqr_iterations=200, use_linesearch=use_linesearch) + # if animate: + # env =VideoMonitor(env) + stats, trajectories = train(env, agent, num_episodes=3, return_trajectory=True) + + # agent.use_ubar = True + # stats2, trajectories2 = train(env, agent, num_episodes=1, return_trajectory=True) + # env.close() + env.close() + +def plt_cartpole(): + cartpole_experiment(N=50, use_linesearch=True, animate=True) + +if __name__ == '__main__': + np.random.seed(42) + plt_cartpole() + + # xb = agent.xbar + # tb = np.arange(N+1)*dt + # plt.figure(figsize=(8,6)) + # F = 3 + # # plt.plot(trajectories[0].time, trajectories[0].state[:,F], 'k-', label='Closed-loop $\\pi$') + # # plt.plot(trajectories2[0].time, trajectories2[0].state[:,F], '-', label='Open-loop $\\bar{u}_k$') + # + # plt.plot(tb, xb[:,F], '.-', label="iLQR rediction $\\bar{x}_k$") + # plt.xlabel("Time/seconds") + # plt.ylabel("$\cos(\\theta)$") + # plt.title(f"Pendulum environment $T={N}$") + # + # plt.grid() + # plt.legend() + # ev = "pendulum" + # savepdf(f"irlc_cartpole_theta_N{N}_{use_linesearch}{figex}") + # plt.show() diff --git a/irlc/lectures/lec06/lecture_06_linearize.py b/irlc/lectures/lec06/lecture_06_linearize.py new file mode 100644 index 0000000..311dd27 --- /dev/null +++ b/irlc/lectures/lec06/lecture_06_linearize.py @@ -0,0 +1,6 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex07.linearization_agent import get_offbalance_cart + +if __name__ == "__main__": + env = get_offbalance_cart(waiting_steps=20, sleep_time=0.1) + env.close() diff --git a/irlc/lectures/lec06/lecture_06_linearize_b.py b/irlc/lectures/lec06/lecture_06_linearize_b.py new file mode 100644 index 0000000..b582957 --- /dev/null +++ b/irlc/lectures/lec06/lecture_06_linearize_b.py @@ -0,0 +1,18 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc import plot_trajectory, train +from irlc.ex07.linearization_agent import get_offbalance_cart, LinearizationAgent +import numpy as np +import matplotlib +matplotlib.use("tkagg") +import matplotlib.pyplot as plt + + +if __name__ == "__main__": + np.random.seed(42) # I don't think these results are seed-dependent but let's make sure. + env = get_offbalance_cart(4, sleep_time=0.08) # Simulate for a little time to get an off-balance cart. Increase 4-->10 to get failure. + agent = LinearizationAgent(env, model=env.discrete_model, xbar=env.discrete_model.x_upright, ubar=env.action_space.sample()*0) + _, trajectories = train(env, agent, num_episodes=1, return_trajectory=True, reset=False) # Note reset=False to maintain initial conditions. + plt.figure() + plot_trajectory(trajectories[0], env, xkeys=[0, 2, 3], ukeys=[0]) + plt.show() + env.close() diff --git a/irlc/lectures/lec06/lecture_06_pendulum_bilqr_L.py b/irlc/lectures/lec06/lecture_06_pendulum_bilqr_L.py new file mode 100644 index 0000000..e0cb2ca --- /dev/null +++ b/irlc/lectures/lec06/lecture_06_pendulum_bilqr_L.py @@ -0,0 +1,7 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc.lectures.lec06.lecture_06_pendulum_bilqr_ubar import pen_experiment + +if __name__ == "__main__": + np.random.seed(2) # (!) + pen_experiment(N=50, use_linesearch=False, use_ubar=False) diff --git a/irlc/lectures/lec06/lecture_06_pendulum_bilqr_ubar.py b/irlc/lectures/lec06/lecture_06_pendulum_bilqr_ubar.py new file mode 100644 index 0000000..d61a8dd --- /dev/null +++ b/irlc/lectures/lec06/lecture_06_pendulum_bilqr_ubar.py @@ -0,0 +1,66 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc.ex04.model_pendulum import GymSinCosPendulumEnvironment +from irlc.ex07.ilqr_agent import ILQRAgent +from irlc import train +from irlc import savepdf +import matplotlib.pyplot as plt + +Tmax = 3 +def pen_experiment(N=12, use_linesearch=True,figex="", animate=True, use_ubar=False): + dt = Tmax / N + env = GymSinCosPendulumEnvironment(dt, Tmax=Tmax, supersample_trajectory=True, render_mode='human' if animate else None) + agent = ILQRAgent(env, env.discrete_model, N=N, ilqr_iterations=200, use_linesearch=use_linesearch) + # if animate: + # env = VideoMonitor(env) + + if use_ubar: + agent.use_ubar = True + stats2, trajectories = train(env, agent, num_episodes=1, return_trajectory=True) + env.close() + + plot_pendulum_trajectory(trajectories[0], label=f'Use linesearch? {use_linesearch}. Use u-bar? {use_ubar}') + plt.legend() + plt.show() + + plt.figure(figsize=(6, 6)) + plt.semilogy(agent.J_hist, 'k.-') + plt.xlabel("iLQR Iterations") + plt.ylabel("Cost function estimate $J$") + # plt.title("Last value: {") + plt.grid() + # savepdf(f"irlc_pendulum_J_N{N}_{use_linesearch}{figex}") + plt.show() + # + # plt.show() + # xb = agent.xbar + # tb = np.arange(N+1)*dt + # plt.figure(figsize=(12, 6)) + # plt.plot(trajectories2[0].time, trajectories2[0].state[:,1], '-', label='Open-loop $\\bar{u}_k$') + # plt.plot(tb, xb[:,1], 'o-', label="iLQR prediction $\\bar{x}_k$") + # plt.grid() + # plt.legend() + # ev = "pendulum" + # savepdf(f"irlc_pendulum_theta_N{N}_{use_linesearch}{figex}") + # plt.show() + + ## Plot J + +# +def plot_pendulum_trajectory(traj, style='k-', label=None, action=False, **kwargs): + y = traj.state[:, 1] if not action else traj.action[:,0] + plt.plot(traj.time[:-1] if action else traj.time, y, style, label=label, **kwargs) + + plt.xlabel("Time/seconds") + if action: + plt.ylabel("Torque $u$") + else: + plt.ylabel("$\cos(\\theta)$") + plt.grid() + pass + +N = 50 + +if __name__ == "__main__": + np.random.seed(2) # (!) + pen_experiment(N=N, use_linesearch=False, use_ubar=True) diff --git a/irlc/lectures/lec06/lecture_06_pendulum_ilqr_L.py b/irlc/lectures/lec06/lecture_06_pendulum_ilqr_L.py new file mode 100644 index 0000000..6e475bf --- /dev/null +++ b/irlc/lectures/lec06/lecture_06_pendulum_ilqr_L.py @@ -0,0 +1,5 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +if __name__ == "__main__": + from irlc.lectures.lec06.lecture_06_pendulum_bilqr_ubar import pen_experiment + N = 50 + pen_experiment(N=N, use_linesearch=True, use_ubar=False) diff --git a/irlc/lectures/lec06/lecture_06_pendulum_ilqr_ubar.py b/irlc/lectures/lec06/lecture_06_pendulum_ilqr_ubar.py new file mode 100644 index 0000000..b44a35c --- /dev/null +++ b/irlc/lectures/lec06/lecture_06_pendulum_ilqr_ubar.py @@ -0,0 +1,5 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +if __name__ == "__main__": + from irlc.lectures.lec06.lecture_06_pendulum_bilqr_ubar import pen_experiment + N = 50 + pen_experiment(N=N, use_linesearch=True, use_ubar=True) diff --git a/irlc/lectures/lec07/__init__.py b/irlc/lectures/lec07/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/lectures/lec07/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/lectures/lec07/lecture_07_boing_lqr.py b/irlc/lectures/lec07/lecture_07_boing_lqr.py new file mode 100644 index 0000000..7a14075 --- /dev/null +++ b/irlc/lectures/lec07/lecture_07_boing_lqr.py @@ -0,0 +1,19 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex04.model_boeing import BoeingEnvironment +from irlc.ex07.lqr_learning_agents import learning_lqr, learning_lqr_mpc, learning_lqr_mpc_local +from irlc.ex07.learning_agent_mpc_optimize import learning_optimization_mpc_local + +if __name__ == "__main__": + env = BoeingEnvironment(output=[10, 0]) + + # Part A: LQR and global regression + learning_lqr(env) + + # Part B: LQR+MPC + # learning_lqr_mpc(env) + # + # # Part C: LQR+MPC and local regression + # learning_lqr_mpc_local(env) + # + # # Part D: Optimization+MPC and local regression + # learning_optimization_mpc_local(env) diff --git a/irlc/lectures/lec07/lecture_07_boing_lqr_mpc.py b/irlc/lectures/lec07/lecture_07_boing_lqr_mpc.py new file mode 100644 index 0000000..2c4a722 --- /dev/null +++ b/irlc/lectures/lec07/lecture_07_boing_lqr_mpc.py @@ -0,0 +1,14 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex04.model_boeing import BoeingEnvironment +from irlc.ex07.lqr_learning_agents import learning_lqr, learning_lqr_mpc, learning_lqr_mpc_local +from irlc.ex07.learning_agent_mpc_optimize import learning_optimization_mpc_local + +if __name__ == "__main__": + env = BoeingEnvironment(output=[10, 0]) + learning_lqr_mpc(env) + + # # Part C: LQR+MPC and local regression + # learning_lqr_mpc_local(env) + # + # # Part D: Optimization+MPC and local regression + # learning_optimization_mpc_local(env) diff --git a/irlc/lectures/lec07/lecture_07_boing_lqr_mpc_local.py b/irlc/lectures/lec07/lecture_07_boing_lqr_mpc_local.py new file mode 100644 index 0000000..22376d1 --- /dev/null +++ b/irlc/lectures/lec07/lecture_07_boing_lqr_mpc_local.py @@ -0,0 +1,9 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex04.model_boeing import BoeingEnvironment +from irlc.ex07.lqr_learning_agents import learning_lqr, learning_lqr_mpc, learning_lqr_mpc_local +from irlc.ex07.learning_agent_mpc_optimize import learning_optimization_mpc_local + +if __name__ == "__main__": + env = BoeingEnvironment(output=[10, 0]) + learning_lqr_mpc_local(env) + # learning_optimization_mpc_local(env) diff --git a/irlc/lectures/lec07/lecture_07_boing_lqr_mpc_optim.py b/irlc/lectures/lec07/lecture_07_boing_lqr_mpc_optim.py new file mode 100644 index 0000000..4ed3f3e --- /dev/null +++ b/irlc/lectures/lec07/lecture_07_boing_lqr_mpc_optim.py @@ -0,0 +1,8 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex04.model_boeing import BoeingEnvironment +from irlc.ex07.lqr_learning_agents import learning_lqr, learning_lqr_mpc, learning_lqr_mpc_local +from irlc.ex07.learning_agent_mpc_optimize import learning_optimization_mpc_local + +if __name__ == "__main__": + env = BoeingEnvironment(output=[10, 0]) + learning_optimization_mpc_local(env) diff --git a/irlc/lectures/lec07/lecture_07_lmpc.py b/irlc/lectures/lec07/lecture_07_lmpc.py new file mode 100644 index 0000000..5fff87c --- /dev/null +++ b/irlc/lectures/lec07/lecture_07_lmpc.py @@ -0,0 +1,5 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex07.lmpc_run import main + +if __name__ == "__main__": + main(show_episode=True) diff --git a/irlc/lectures/lec07/lecture_07_pendulum_mpc_lqr.py b/irlc/lectures/lec07/lecture_07_pendulum_mpc_lqr.py new file mode 100644 index 0000000..8867c0a --- /dev/null +++ b/irlc/lectures/lec07/lecture_07_pendulum_mpc_lqr.py @@ -0,0 +1,4 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +if __name__ == "__main__": + from irlc.ex07.mpc_pendulum_experiment_lqr import main_pendulum_lqr + main_pendulum_lqr() diff --git a/irlc/lectures/lec07/lecture_07_pendulum_mpc_optm.py b/irlc/lectures/lec07/lecture_07_pendulum_mpc_optm.py new file mode 100644 index 0000000..9eff242 --- /dev/null +++ b/irlc/lectures/lec07/lecture_07_pendulum_mpc_optm.py @@ -0,0 +1,4 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +if __name__ == "__main__": + from irlc.ex07.mpc_pendulum_experiment_optim import main_pendulum + main_pendulum() diff --git a/irlc/lectures/lec07/lecture_07_pendulum_simple.py b/irlc/lectures/lec07/lecture_07_pendulum_simple.py new file mode 100644 index 0000000..337b165 --- /dev/null +++ b/irlc/lectures/lec07/lecture_07_pendulum_simple.py @@ -0,0 +1,41 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex04.model_pendulum import GymSinCosPendulumEnvironment +from irlc.utils.video_monitor import VideoMonitor +from irlc.ex04.discrete_control_cost import goal_seeking_qr_cost, DiscreteQRCost +from irlc.ex01.agent import train +from irlc.ex07.lqr_learning_agents import MPCLocalLearningLQRAgent, MPCLearningAgent +from irlc import plot_trajectory, main_plot +import matplotlib.pyplot as plt +import numpy as np +from irlc.ex07.mpc_pendulum_experiment_lqr import mk_mpc_pendulum_env + +L = 12 +def main_pendulum_lqr_simple(Tmax=10): + + """ Run Local LQR/MPC agent using the parameters + L = 12 + neighboorhood_size = 50 + min_buffer_size = 50 + """ + env_pendulum = mk_mpc_pendulum_env() + + # agent = .... (instantiate agent here) + # TODO: 1 lines missing. + raise NotImplementedError("Instantiate your agent here") + env_pendulum = VideoMonitor(env_pendulum) + + experiment_name = f"pendulum{L}_lqr" + stats, trajectories = train(env_pendulum, agent, experiment_name=experiment_name, num_episodes=16,return_trajectory=True) + plt.show() + for k in range(len(trajectories)): + plot_trajectory(trajectories[k], env_pendulum) + plt.title(f"Trajectory {k}") + plt.show() + + env_pendulum.close() + main_plot(experiment_name) + plt.show() + +if __name__ == "__main__": + np.random.seed(1) + main_pendulum_lqr_simple() diff --git a/irlc/lectures/lec07/pendulum12/2021-03-19_08-21-20.207/log.txt b/irlc/lectures/lec07/pendulum12/2021-03-19_08-21-20.207/log.txt new file mode 100644 index 0000000..dc592cf --- /dev/null +++ b/irlc/lectures/lec07/pendulum12/2021-03-19_08-21-20.207/log.txt @@ -0,0 +1,17 @@ +Episode Accumulated Reward Average Reward Length Steps +0 -4895.647575826604 -39.165180606612836 125 125 +1 -4401.3119492497035 -35.21049559399765 125 250 +2 -2909.118791375824 -23.272950331006577 125 375 +3 -1355.8374521458716 -10.846699617166973 125 500 +4 -1392.1376132555315 -11.13710090604426 125 625 +5 -2377.229711438541 -19.017837691508326 125 750 +6 -1605.205601135333 -12.841644809082668 125 875 +7 -1142.6024308594363 -9.140819446875495 125 1000 +8 -1110.17238007953 -8.881379040636237 125 1125 +9 -1415.0153227915457 -11.320122582332363 125 1250 +10 -1084.806186007314 -8.678449488058519 125 1375 +11 -1204.58673322474 -9.636693865797913 125 1500 +12 -1582.8902992149344 -12.66312239371947 125 1625 +13 -1234.3968104401945 -9.875174483521556 125 1750 +14 -2290.3685781570866 -18.322948625256696 125 1875 +15 -1317.928485283048 -10.543427882264387 125 2000 diff --git a/irlc/lectures/lec07/pendulum12/2021-03-19_08-21-20.207/trajectories.pkl b/irlc/lectures/lec07/pendulum12/2021-03-19_08-21-20.207/trajectories.pkl new file mode 100644 index 0000000000000000000000000000000000000000..34930a77fba816ca18036b42921823ab18cefc24 GIT binary patch literal 75688 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 literal 0 HcmV?d00001 diff --git a/irlc/lectures/lec07/pendulum12/2022-03-17_14-16-10.758/log.txt b/irlc/lectures/lec07/pendulum12/2022-03-17_14-16-10.758/log.txt new file mode 100644 index 0000000..3005052 --- /dev/null +++ b/irlc/lectures/lec07/pendulum12/2022-03-17_14-16-10.758/log.txt @@ -0,0 +1,17 @@ +Episode Accumulated Reward Average Reward Length Steps +0 -5062.646915554269 -40.50117532443415 125 125 +1 -4545.443228168109 -36.36354582534487 125 250 +2 -3992.451522701582 -31.939612181612656 125 375 +3 -2660.945115772302 -21.287560926178415 125 500 +4 -1089.641113544413 -8.71712890835529 125 625 +5 -1794.3862709577143 -14.35509016766171 125 750 +6 -1599.3332228782826 -12.79466578302626 125 875 +7 -1999.3347944176303 -15.994678355341035 125 1000 +8 -1240.1770407677993 -9.921416326142396 125 1125 +9 -1128.717151496786 -9.029737211974288 125 1250 +10 -1148.8528175884883 -9.19082254070789 125 1375 +11 -1199.5840778420286 -9.596672622736232 125 1500 +12 -1147.0703774473068 -9.176563019578447 125 1625 +13 -1245.4139074019245 -9.963311259215399 125 1750 +14 -1257.9333517907346 -10.063466814325885 125 1875 +15 -1309.9607605947551 -10.479686084758042 125 2000 diff --git a/irlc/lectures/lec07/pendulum12/2022-03-17_14-16-10.758/trajectories.pkl b/irlc/lectures/lec07/pendulum12/2022-03-17_14-16-10.758/trajectories.pkl new file mode 100644 index 0000000000000000000000000000000000000000..c2b34f7154ed75b8dfa9e69bcd3de982d0cd0eb1 GIT binary patch literal 74800 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�%2YXq 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 T#^a4g(tk5CFfcH%L`DGsOfG_P literal 0 HcmV?d00001 diff --git a/irlc/lectures/lec07/pendulum12_lqr/2023-03-17_08-13-45.172/log.txt b/irlc/lectures/lec07/pendulum12_lqr/2023-03-17_08-13-45.172/log.txt new file mode 100644 index 0000000..643cee3 --- /dev/null +++ b/irlc/lectures/lec07/pendulum12_lqr/2023-03-17_08-13-45.172/log.txt @@ -0,0 +1,17 @@ +Episode Accumulated Reward Length Steps +0 -5042.020051692956 125 0 +1 -4627.801003133058 125 1 +2 -3635.9503089227105 125 2 +3 -2459.2456085370436 125 3 +4 -1142.0454750510762 125 4 +5 -1563.5408392433658 125 5 +6 -1718.6689962603696 125 6 +7 -1215.2631997008277 125 7 +8 -1172.9345344478274 125 8 +9 -1108.3729746371948 125 9 +10 -1012.6787060036193 125 10 +11 -1715.9593847985013 125 11 +12 -1009.5943996400636 125 12 +13 -1082.3121757069966 125 13 +14 -1248.0530347172762 125 14 +15 -1496.6826680867007 125 15 diff --git a/irlc/lectures/lec07/pendulum12_lqr/2023-03-17_08-13-45.172/trajectories.pkl b/irlc/lectures/lec07/pendulum12_lqr/2023-03-17_08-13-45.172/trajectories.pkl new file mode 100644 index 0000000000000000000000000000000000000000..3e9f2d19af2a1f4bdcdbc7a8922852a440795c46 GIT binary patch literal 75880 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℞WStH+hPH6nKPl+ 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 U$;I)YdGf|1>A#skk}Q!?01~=XasU7T literal 0 HcmV?d00001 diff --git a/irlc/lectures/lec07/tmp-pdfcrop-10536.tex b/irlc/lectures/lec07/tmp-pdfcrop-10536.tex new file mode 100644 index 0000000..ea5c21c --- /dev/null +++ b/irlc/lectures/lec07/tmp-pdfcrop-10536.tex @@ -0,0 +1,131 @@ +\catcode37 14 % percent +\catcode33 12 % exclam +\catcode34 12 % quote +\catcode35 6 % hash +\catcode39 12 % apostrophe +\catcode40 12 % left parenthesis +\catcode41 12 % right parenthesis +\catcode45 12 % minus +\catcode46 12 % period +\catcode60 12 % less +\catcode61 12 % equals +\catcode62 12 % greater +\catcode64 12 % at +\catcode91 12 % left square +\catcode93 12 % right square +\catcode96 12 % back tick +\catcode123 1 % left curly brace +\catcode125 2 % right curly brace +\catcode126 12 % tilde +\catcode`\#=6 % +\escapechar=92 % +\def\IfUndefined#1#2#3{% + \begingroup\expandafter\expandafter\expandafter\endgroup + \expandafter\ifx\csname#1\endcsname\relax + #2% + \else + #3% + \fi +} +\def\pdffilehex{746D702D70646663726F702D31303533362D696D672E706466} +\IfUndefined{pdfunescapehex}{% + \begingroup + \gdef\pdffile{}% + \def\do#1#2{% + \ifx\relax#2\relax + \ifx\relax#1\relax + \else + \errmessage{Invalid hex string, should not happen!}% + \fi + \else + \lccode`0="#1#2\relax + \lowercase{% + \xdef\pdffile{\pdffile0}% + }% + \expandafter\do + \fi + }% + \expandafter\do\pdffilehex\relax\relax + \endgroup +}{% + \edef\pdffile{\pdfunescapehex{\pdffilehex}}% +} +\immediate\write-1{Input file: \pdffile} +\pdfcompresslevel=9 \pdfoutput=1 % +\csname pdfmapfile\endcsname{} +\def\setpdfversion#1#2{% + \IfUndefined{pdfobjcompresslevel}{% + }{% + \ifnum#1=1 % + \ifnum#2<5 + \pdfobjcompresslevel=0 % + \else + \pdfobjcompresslevel=2 % + \fi + \fi + }% + \IfUndefined{pdfminorversion}{% + \IfUndefined{pdfoptionpdfminorversion}{% + }{% + \pdfoptionpdfminorversion=#2\relax + }% + }{% + \pdfminorversion=#2\relax + \IfUndefined{pdfmajorversion}{% + \ifnum#2=0 \pdfminorversion=5\fi} + {\pdfmajorversion=#1\relax}% + }% +} +\def\page #1 [#2 #3 #4 #5]{% + \count0=#1\relax + \setbox0=\hbox{% + \pdfximage page #1 mediabox{\pdffile}% + \pdfrefximage\pdflastximage + }% + \pdfhorigin=-#2bp\relax + \pdfvorigin=#3bp\relax + \pdfpagewidth=#4bp\relax + \advance\pdfpagewidth by -#2bp\relax + \pdfpageheight=#5bp\relax + \advance\pdfpageheight by -#3bp\relax + \ht0=\pdfpageheight + \shipout\box0\relax +} +\def\pageclip #1 [#2 #3 #4 #5][#6 #7 #8 #9]{% + \count0=#1\relax + \dimen0=#4bp\relax \advance\dimen0 by -#2bp\relax + \edef\imagewidth{\the\dimen0}% + \dimen0=#5bp\relax \advance\dimen0 by -#3bp\relax + \edef\imageheight{\the\dimen0}% + \pdfximage page #1 mediabox{\pdffile}% + \setbox0=\hbox{% + \kern -#2bp\relax + \lower #3bp\hbox{\pdfrefximage\pdflastximage}% + }% + \wd0=\imagewidth\relax + \ht0=\imageheight\relax + \dp0=0pt\relax + \pdfhorigin=#6pt\relax + \pdfvorigin=#7bp\relax + \pdfpagewidth=\imagewidth + \advance\pdfpagewidth by #6bp\relax + \advance\pdfpagewidth by #8bp\relax + \pdfpageheight=\imageheight\relax + \advance\pdfpageheight by #7bp\relax + \advance\pdfpageheight by #9bp\relax + \pdfxform0\relax + \shipout\hbox{\pdfrefxform\pdflastxform}% +}% +\def\pageinclude#1{% + \pdfhorigin=0pt\relax + \pdfvorigin=0pt\relax + \pdfximage page #1 mediabox{\pdffile}% + \setbox0=\hbox{\pdfrefximage\pdflastximage}% + \pdfpagewidth=\wd0\relax + \pdfpageheight=\ht0\relax + \advance\pdfpageheight by \dp0\relax + \shipout\hbox{% + \raise\dp0\box0\relax + }% +} +\setpdfversion{1}{4} diff --git a/irlc/lectures/lec07/tmp-pdfcrop-12592.tex b/irlc/lectures/lec07/tmp-pdfcrop-12592.tex new file mode 100644 index 0000000..479d43b --- /dev/null +++ b/irlc/lectures/lec07/tmp-pdfcrop-12592.tex @@ -0,0 +1,131 @@ +\catcode37 14 % percent +\catcode33 12 % exclam +\catcode34 12 % quote +\catcode35 6 % hash +\catcode39 12 % apostrophe +\catcode40 12 % left parenthesis +\catcode41 12 % right parenthesis +\catcode45 12 % minus +\catcode46 12 % period +\catcode60 12 % less +\catcode61 12 % equals +\catcode62 12 % greater +\catcode64 12 % at +\catcode91 12 % left square +\catcode93 12 % right square +\catcode96 12 % back tick +\catcode123 1 % left curly brace +\catcode125 2 % right curly brace +\catcode126 12 % tilde +\catcode`\#=6 % +\escapechar=92 % +\def\IfUndefined#1#2#3{% + \begingroup\expandafter\expandafter\expandafter\endgroup + \expandafter\ifx\csname#1\endcsname\relax + #2% + \else + #3% + \fi +} +\def\pdffilehex{746D702D70646663726F702D31323539322D696D672E706466} +\IfUndefined{pdfunescapehex}{% + \begingroup + \gdef\pdffile{}% + \def\do#1#2{% + \ifx\relax#2\relax + \ifx\relax#1\relax + \else + \errmessage{Invalid hex string, should not happen!}% + \fi + \else + \lccode`0="#1#2\relax + \lowercase{% + \xdef\pdffile{\pdffile0}% + }% + \expandafter\do + \fi + }% + \expandafter\do\pdffilehex\relax\relax + \endgroup +}{% + \edef\pdffile{\pdfunescapehex{\pdffilehex}}% +} +\immediate\write-1{Input file: \pdffile} +\pdfcompresslevel=9 \pdfoutput=1 % +\csname pdfmapfile\endcsname{} +\def\setpdfversion#1#2{% + \IfUndefined{pdfobjcompresslevel}{% + }{% + \ifnum#1=1 % + \ifnum#2<5 + \pdfobjcompresslevel=0 % + \else + \pdfobjcompresslevel=2 % + \fi + \fi + }% + \IfUndefined{pdfminorversion}{% + \IfUndefined{pdfoptionpdfminorversion}{% + }{% + \pdfoptionpdfminorversion=#2\relax + }% + }{% + \pdfminorversion=#2\relax + \IfUndefined{pdfmajorversion}{% + \ifnum#2=0 \pdfminorversion=5\fi} + {\pdfmajorversion=#1\relax}% + }% +} +\def\page #1 [#2 #3 #4 #5]{% + \count0=#1\relax + \setbox0=\hbox{% + \pdfximage page #1 mediabox{\pdffile}% + \pdfrefximage\pdflastximage + }% + \pdfhorigin=-#2bp\relax + \pdfvorigin=#3bp\relax + \pdfpagewidth=#4bp\relax + \advance\pdfpagewidth by -#2bp\relax + \pdfpageheight=#5bp\relax + \advance\pdfpageheight by -#3bp\relax + \ht0=\pdfpageheight + \shipout\box0\relax +} +\def\pageclip #1 [#2 #3 #4 #5][#6 #7 #8 #9]{% + \count0=#1\relax + \dimen0=#4bp\relax \advance\dimen0 by -#2bp\relax + \edef\imagewidth{\the\dimen0}% + \dimen0=#5bp\relax \advance\dimen0 by -#3bp\relax + \edef\imageheight{\the\dimen0}% + \pdfximage page #1 mediabox{\pdffile}% + \setbox0=\hbox{% + \kern -#2bp\relax + \lower #3bp\hbox{\pdfrefximage\pdflastximage}% + }% + \wd0=\imagewidth\relax + \ht0=\imageheight\relax + \dp0=0pt\relax + \pdfhorigin=#6pt\relax + \pdfvorigin=#7bp\relax + \pdfpagewidth=\imagewidth + \advance\pdfpagewidth by #6bp\relax + \advance\pdfpagewidth by #8bp\relax + \pdfpageheight=\imageheight\relax + \advance\pdfpageheight by #7bp\relax + \advance\pdfpageheight by #9bp\relax + \pdfxform0\relax + \shipout\hbox{\pdfrefxform\pdflastxform}% +}% +\def\pageinclude#1{% + \pdfhorigin=0pt\relax + \pdfvorigin=0pt\relax + \pdfximage page #1 mediabox{\pdffile}% + \setbox0=\hbox{\pdfrefximage\pdflastximage}% + \pdfpagewidth=\wd0\relax + \pdfpageheight=\ht0\relax + \advance\pdfpageheight by \dp0\relax + \shipout\hbox{% + \raise\dp0\box0\relax + }% +} +\setpdfversion{1}{4} diff --git a/irlc/lectures/lec08/__init__.py b/irlc/lectures/lec08/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/lectures/lec08/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/lectures/lec08/demo_bandit.py b/irlc/lectures/lec08/demo_bandit.py new file mode 100644 index 0000000..c1f61c3 --- /dev/null +++ b/irlc/lectures/lec08/demo_bandit.py @@ -0,0 +1,25 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex08.devel.bandit_graphics_environment import GraphicalBandit +import time +from irlc import train +from irlc.ex08.simple_agents import BasicAgent +from irlc import interactive + +def bandit_eps(autoplay=False): + env = GraphicalBandit(10, render_mode='human',frames_per_second=30) + env.reset() + #env.viewer.show_q_star = True + # env.show_q_ucb = True + agent = BasicAgent(env, epsilon=0.1) + agent.method = 'Epsilon-greedy' + env, agent = interactive(env, agent, autoplay=autoplay) + + t0 = time.time() + n = 3000 + stats, _ = train(env, agent, max_steps=n, num_episodes=10, return_trajectory=False, verbose=False) + tpf = (time.time()-t0)/ n + print("tpf", tpf, 'fps', 1/tpf) + env.close() + +if __name__ == "__main__": + bandit_eps() diff --git a/irlc/lectures/lec08/demo_bandit_ucb.py b/irlc/lectures/lec08/demo_bandit_ucb.py new file mode 100644 index 0000000..8e59632 --- /dev/null +++ b/irlc/lectures/lec08/demo_bandit_ucb.py @@ -0,0 +1,26 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex08.devel.bandit_graphics_environment import GraphicalBandit +from irlc import interactive, train +# import numpy as np +import time + +def bandit_ucb(autoplay=False): + env = GraphicalBandit(10, render_mode='human', frames_per_second=30) + env.reset() + #env.viewer.show_q_star = True + #env.viewer.show_q_ucb = True + from irlc.ex08.ucb_agent import UCBAgent + agent = UCBAgent(env, c=1) + agent.method = 'UCB' + + env, agent = interactive(env, agent, autoplay=autoplay) + t0 = time.time() + n = 500 + stats, _ = train(env, agent, max_steps=n, num_episodes=10, return_trajectory=False, verbose=False) + tpf = (time.time() - t0) / n + print("tpf", tpf, 'fps', 1 / tpf) + env.close() + + +if __name__ == "__main__": + bandit_ucb() diff --git a/irlc/lectures/lec09/__init__.py b/irlc/lectures/lec09/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/lectures/lec09/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/lectures/lec09/unf_frozenlake.py b/irlc/lectures/lec09/unf_frozenlake.py new file mode 100644 index 0000000..421bf1b --- /dev/null +++ b/irlc/lectures/lec09/unf_frozenlake.py @@ -0,0 +1,11 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex01.agent import Agent +from irlc.gridworld.gridworld_environments import BookGridEnvironment, FrozenLake, FrozenLakeEnv +from irlc import interactive, train + +if __name__ == "__main__": + env = FrozenLake(render_mode='human', print_states=True) + env, agent = interactive(env, Agent(env)) + agent.label = "Random agent" + train(env, agent, num_episodes=100, verbose=False) + env.close() diff --git a/irlc/lectures/lec09/unf_gridworld.py b/irlc/lectures/lec09/unf_gridworld.py new file mode 100644 index 0000000..e5458d9 --- /dev/null +++ b/irlc/lectures/lec09/unf_gridworld.py @@ -0,0 +1,12 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex01.agent import Agent +from irlc.gridworld.gridworld_environments import BookGridEnvironment, FrozenLakeEnv +from irlc import interactive, train + + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', print_states=True, living_reward=-0.05) + env, agent = interactive(env, Agent(env)) + agent.label = "Random agent" + train(env, agent, num_episodes=100, verbose=False) + env.close() diff --git a/irlc/lectures/lec09/unf_policy_evaluation_frozen.py b/irlc/lectures/lec09/unf_policy_evaluation_frozen.py new file mode 100644 index 0000000..9adda9f --- /dev/null +++ b/irlc/lectures/lec09/unf_policy_evaluation_frozen.py @@ -0,0 +1,20 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import FrozenLake +from irlc import interactive, train +from irlc.gridworld.demo_agents.hidden_agents import PolicyEvaluationAgent2 + +def policy_evaluation(env=None): + agent = PolicyEvaluationAgent2(env, gamma=1., steps_between_policy_improvement=None) + env, agent = interactive(env, agent) + train(env, agent, num_episodes=100) + env.close() + +def policy_improvement(env=None, q_mode=True): + agent = PolicyEvaluationAgent2(env, gamma=1.,steps_between_policy_improvement=20) + env, agent = interactive(env, agent) + train(env, agent, num_episodes=1000, verbose=False) + env.close() + +if __name__ == "__main__": + env = FrozenLake(render_mode='human', living_reward=-0.0) + policy_evaluation(env) diff --git a/irlc/lectures/lec09/unf_policy_evaluation_gridworld.py b/irlc/lectures/lec09/unf_policy_evaluation_gridworld.py new file mode 100644 index 0000000..efec411 --- /dev/null +++ b/irlc/lectures/lec09/unf_policy_evaluation_gridworld.py @@ -0,0 +1,20 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import BookGridEnvironment +from irlc import interactive, train +from irlc.gridworld.demo_agents.hidden_agents import PolicyEvaluationAgent2 + +def policy_evaluation(env=None): + agent = PolicyEvaluationAgent2(env, gamma=1., steps_between_policy_improvement=None) + env, agent = interactive(env, agent) + train(env, agent, num_episodes=100) + env.close() + +def policy_improvement(env=None, q_mode=True): + agent = PolicyEvaluationAgent2(env, gamma=1.,steps_between_policy_improvement=20) + env, agent = interactive(env, agent) + train(env, agent, num_episodes=1000) + env.close() + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', living_reward=-0.05) + policy_evaluation(env) diff --git a/irlc/lectures/lec09/unf_policy_evaluation_stepwise_gridworld.py b/irlc/lectures/lec09/unf_policy_evaluation_stepwise_gridworld.py new file mode 100644 index 0000000..a438af8 --- /dev/null +++ b/irlc/lectures/lec09/unf_policy_evaluation_stepwise_gridworld.py @@ -0,0 +1,20 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import BookGridEnvironment +from irlc import interactive, train +from irlc.gridworld.demo_agents.hidden_agents import PolicyEvaluationAgent2 + +def policy_evaluation_stepwise(env=None): + agent = PolicyEvaluationAgent2(env, gamma=1., steps_between_policy_improvement=None, only_update_current=True) + env, agent = interactive(env, agent) + train(env, agent, num_episodes=100) + env.close() + +def policy_improvement(env=None, q_mode=True): + agent = PolicyEvaluationAgent2(env, gamma=1.,steps_between_policy_improvement=20) + env, agent = interactive(env, agent) + train(env, agent, num_episodes=1000) + env.close() + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', living_reward=-0.05) + policy_evaluation_stepwise(env) diff --git a/irlc/lectures/lec09/unf_policy_improvement_frozenlake.py b/irlc/lectures/lec09/unf_policy_improvement_frozenlake.py new file mode 100644 index 0000000..7242b00 --- /dev/null +++ b/irlc/lectures/lec09/unf_policy_improvement_frozenlake.py @@ -0,0 +1,7 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import BookGridEnvironment, FrozenLake +from irlc.lectures.unf.unf_policy_evaluation_gridworld import policy_improvement + +if __name__ == "__main__": + env = FrozenLake(render_mode='human', living_reward=-0) + policy_improvement(env) diff --git a/irlc/lectures/lec09/unf_policy_improvement_gridworld.py b/irlc/lectures/lec09/unf_policy_improvement_gridworld.py new file mode 100644 index 0000000..eb6d762 --- /dev/null +++ b/irlc/lectures/lec09/unf_policy_improvement_gridworld.py @@ -0,0 +1,7 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import BookGridEnvironment +from irlc.lectures.unf.unf_policy_evaluation_gridworld import policy_improvement + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', living_reward=-0.05) + policy_improvement(env) diff --git a/irlc/lectures/lec09/unf_vi_frozenlake.py b/irlc/lectures/lec09/unf_vi_frozenlake.py new file mode 100644 index 0000000..4ece4f2 --- /dev/null +++ b/irlc/lectures/lec09/unf_vi_frozenlake.py @@ -0,0 +1,17 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import FrozenLake +from irlc.ex01.agent import train +from irlc.gridworld.demo_agents.hidden_agents import ValueIterationAgent3 +from irlc import interactive + +def q1_vi(env): + agent = ValueIterationAgent3(env, epsilon=0, gamma=1, only_update_current=False) + env, agent = interactive(env, agent) + env.reset() + train(env, agent, num_episodes=100) + env.close() + + +if __name__ == "__main__": + env = FrozenLake(render_mode='human', living_reward=-0) + q1_vi(env) diff --git a/irlc/lectures/lec09/unf_vi_gridworld.py b/irlc/lectures/lec09/unf_vi_gridworld.py new file mode 100644 index 0000000..56319af --- /dev/null +++ b/irlc/lectures/lec09/unf_vi_gridworld.py @@ -0,0 +1,19 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import BookGridEnvironment +# from irlc.utils.video_monitor import VideoMonitor +from irlc.ex01.agent import train +from irlc.gridworld.demo_agents.hidden_agents import ValueIterationAgent3 +from irlc import interactive + +def q1_vi(env): + agent = ValueIterationAgent3(env, epsilon=0, gamma=1, only_update_current=False) + env, agent = interactive(env, agent) + # experiment = "experiments/q1_value_iteration" + # env = VideoMonitor(env, agent=agent, fps=100, continious_recording=True, agent_monitor_keys=('v', 'v2Q'), render_kwargs={'method_label': 'VI'}) + env.reset() + train(env, agent, num_episodes=100) + env.close() + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', living_reward=-0.05) + q1_vi(env) diff --git a/irlc/lectures/lec09/unf_vi_gridworld_stepwise.py b/irlc/lectures/lec09/unf_vi_gridworld_stepwise.py new file mode 100644 index 0000000..152a91b --- /dev/null +++ b/irlc/lectures/lec09/unf_vi_gridworld_stepwise.py @@ -0,0 +1,16 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import BookGridEnvironment +from irlc.ex01.agent import train +from irlc.gridworld.demo_agents.hidden_agents import ValueIterationAgent3 +from irlc import interactive + +def q1_vi(env): + agent = ValueIterationAgent3(env, epsilon=0, gamma=1, only_update_current=True) + env, agent = interactive(env, agent) + env.reset() + train(env, agent, num_episodes=100) + env.close() + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', living_reward=-0.05, print_states=False) + q1_vi(env) diff --git a/irlc/lectures/lec10/__init__.py b/irlc/lectures/lec10/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/lectures/lec10/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/lectures/lec10/lecture_10_mc_action_value_first_one_state.py b/irlc/lectures/lec10/lecture_10_mc_action_value_first_one_state.py new file mode 100644 index 0000000..a55be35 --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_mc_action_value_first_one_state.py @@ -0,0 +1,60 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment, BookGridEnvironment +from irlc.ex10.mc_agent import MCAgent + +from irlc.ex10.mc_evaluate import MCEvaluationAgent +import numpy as np +from irlc import interactive, train + +class MCControlAgentOneState(MCAgent): + def __init__(self, *args, state_action=None, **kwargs): + a = 34 + super().__init__(*args, **kwargs) + if state_action is None: + state_action = (self.env.mdp.initial_state, self.env.mdp.A(self.env.mdp.initial_state)[0]) + + self.state_action = state_action + self._clear_states() + + def _clear_states(self, val=None): + for s in self.env.mdp.nonterminal_states: + for a in self.env.mdp.A(s): + # self.Q[s,a] = 0 + if (s,a) != self.state_action: + self.returns_sum[s,a] = val + self.returns_count[s,a] = val + + # if s in self.Q.q_: + k = next(self.env.mdp.Psr(s, self.env.mdp.A(s)[0]).keys().__iter__() )[0] + if not self.env.mdp.is_terminal(k): + self.Q[s,a] = 0 + + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + # self.episode = [e for e in self.episode if e[0] == self.state] + self._clear_states(0) + super().train(s, a, r, sp, done) + # Clear out many of the state, actions: + self._clear_states(None) + # for s in self.env.mdp.nonterminal_states: + # if s != self.state: + # self.v[s] = None + + pass + + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', living_reward=-0.05, print_states=True, zoom=2) + agent = MCControlAgentOneState(env, gamma=1, alpha=None, first_visit=True) + method_label = 'MC (gamma=1)' + agent.label = method_label + autoplay = False + env, agent = interactive(env, agent, autoplay=autoplay) + # agent = PlayWrapper(agent, env,autoplay=autoplay) + # env = VideoMonitor(env, agent=agent, fps=100, agent_monitor_keys=('pi', 'Q'), render_kwargs={'method_label': method_label}) + num_episodes = 1000 + train(env, agent, num_episodes=num_episodes) + env.close() + + # keyboard_play(env,agent,method_label='MC (alpha=0.5)') diff --git a/irlc/lectures/lec10/lecture_10_mc_action_value_first_one_state_b.py b/irlc/lectures/lec10/lecture_10_mc_action_value_first_one_state_b.py new file mode 100644 index 0000000..f0f705b --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_mc_action_value_first_one_state_b.py @@ -0,0 +1,21 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment, BookGridEnvironment +from irlc.ex10.mc_agent import MCAgent +from irlc.lectures.lec10.lecture_10_mc_action_value_first_one_state import MCControlAgentOneState +from irlc.ex10.mc_evaluate import MCEvaluationAgent +import numpy as np +from irlc import interactive, train + + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', living_reward=-0.05, print_states=True, zoom=2) + agent = MCControlAgentOneState(env, gamma=1, alpha=None, first_visit=True, state_action=( (0,2), 2)) + method_label = 'MC control (gamma=1)' + agent.label = method_label + autoplay = False + env, agent = interactive(env, agent, autoplay=autoplay) + num_episodes = 1000 + train(env, agent, num_episodes=num_episodes) + env.close() + # keyboard_play(env,agent,method_label='MC (alpha=0.5)') diff --git a/irlc/lectures/lec10/lecture_10_mc_control.py b/irlc/lectures/lec10/lecture_10_mc_control.py new file mode 100644 index 0000000..e286478 --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_mc_control.py @@ -0,0 +1,13 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.gridworld.gridworld_environments import BookGridEnvironment +from irlc.ex10.mc_agent import MCAgent +import numpy as np + +if __name__ == "__main__": + np.random.seed(433) + env = BookGridEnvironment(render_mode='human',zoom=2) + # agent = MCAgent(env, gamma=0.9, epsilon=0.15, alpha=0.1, first_visit=True) + agent = MCAgent(env, gamma=1.0, epsilon=0.15, alpha=None, first_visit=True) + # env, agent = interactive(env, agent) + keyboard_play(env,agent,method_label='MC control') diff --git a/irlc/lectures/lec10/lecture_10_mc_corner.py b/irlc/lectures/lec10/lecture_10_mc_corner.py new file mode 100644 index 0000000..a1ec3e1 --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_mc_corner.py @@ -0,0 +1,10 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment +from irlc.ex10.mc_agent import MCAgent +import numpy as np + +if __name__ == "__main__": + env = SuttonCornerGridEnvironment(render_mode='human') + agent = MCAgent(env, gamma=1, epsilon=1, alpha=.5, first_visit=False) + keyboard_play(env,agent,method_label='MC (alpha=0.5)') diff --git a/irlc/lectures/lec10/lecture_10_mc_onestate_every.py b/irlc/lectures/lec10/lecture_10_mc_onestate_every.py new file mode 100644 index 0000000..710532e --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_mc_onestate_every.py @@ -0,0 +1,12 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.exam_tabular_examples.helper import keyboard_play_value +# from irlc.gridworld_pyglet.gridworld_environments import BookGridEnvironment +from irlc.ex10.mc_evaluate import MCEvaluationAgent +# from irlc.gridworld_pyglet.gridworld_environments import GridworldEnvironment +from irlc.lectures.lec10.lecture_10_mc_onestate_first import CaughtGrid + + +if __name__ == "__main__": + env = CaughtGrid(view_mode=1, render_mode='humanp') + agent = MCEvaluationAgent(env, gamma=1, alpha=None, first_visit=False) + keyboard_play_value(env,agent,method_label='MC (every visit)') diff --git a/irlc/lectures/lec10/lecture_10_mc_onestate_first.py b/irlc/lectures/lec10/lecture_10_mc_onestate_first.py new file mode 100644 index 0000000..c111aa6 --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_mc_onestate_first.py @@ -0,0 +1,18 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.exam_tabular_examples.helper import keyboard_play_value +# from irlc.gridworld_pyglet.gridworld_environments import BookGridEnvironment +from irlc.ex10.mc_evaluate import MCEvaluationAgent +from irlc.gridworld.gridworld_environments import GridworldEnvironment + +map = [['#', '#', '#', '#'], + ['#','S',0,'#'], + ['#','#','#','#']] + +class CaughtGrid(GridworldEnvironment): + def __init__(self, **kwargs): + super().__init__(map, living_reward=1, zoom=1.5, **kwargs) + +if __name__ == "__main__": + env = CaughtGrid(view_mode=1, render_mode='human') + agent = MCEvaluationAgent(env, gamma=1, alpha=None) + keyboard_play_value(env,agent,method_label='MC (first visit)') diff --git a/irlc/lectures/lec10/lecture_10_mc_q_estimation.py b/irlc/lectures/lec10/lecture_10_mc_q_estimation.py new file mode 100644 index 0000000..4b6ef32 --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_mc_q_estimation.py @@ -0,0 +1,40 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# from irlc.berkley.rl.feature_encoder import SimplePacmanExtractor +# from irlc.utils.player_wrapper_pyglet import PlayWrapper +# from irlc.gridworld.gridworld import BerkleyBookGridEnvironment +from irlc.gridworld.gridworld_environments import BookGridEnvironment +# from irlc.utils.video_monitor import VideoMonitor +from irlc import train, interactive +# from irlc import interactive + +def keyboard_play(env, agent, method_label='MC',autoplay=False, num_episodes=1000): + agent.label = method_label + env, agent = interactive(env, agent, autoplay=autoplay) + # agent = PlayWrapper(agent, env,autoplay=autoplay) + # env = VideoMonitor(env, agent=agent, fps=100, agent_monitor_keys=('pi', 'Q'), render_kwargs={'method_label': method_label}) + train(env, agent, num_episodes=num_episodes) + env.close() + + +def automatic_play(env, agent, method_label='MC'): + # agent = PlayWrapper(agent, env) + env = VideoMonitor(env, agent=agent, fps=40, continious_recording=True, agent_monitor_keys=('pi', 'Q'), render_kwargs={'method_label': method_label}) + train(env, agent, num_episodes=1000) + env.close() + +def automatic_play_value(env, agent, method_label='MC'): + agent.label = method_label + env, agent = interactive(env, agent) + + # env = VideoMonitor(env, agent=agent, fps=40, continious_recording=True, agent_monitor_keys=('v'), render_kwargs={'method_label': method_label}) + # agent = PlayWrapper(agent, env) + train(env, agent, num_episodes=1000) + env.close() + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', zoom=2, living_reward=-0.05) + from irlc.ex10.mc_agent import MCAgent + agent = MCAgent(env, gamma=0.9, epsilon=1., first_visit=True, alpha=None) + # agent.label = + # env, agent = interactive(env, agent) + keyboard_play(env, agent, method_label='MC Q-estimation (First visit)') diff --git a/irlc/lectures/lec10/lecture_10_mc_value_every.py b/irlc/lectures/lec10/lecture_10_mc_value_every.py new file mode 100644 index 0000000..8598fa5 --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_mc_value_every.py @@ -0,0 +1,11 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.exam_tabular_examples.helper import keyboard_play_value +# from irlc.berkley.rl.feature_encoder import SimplePacmanExtractor +from irlc.gridworld.gridworld_environments import BookGridEnvironment +from irlc.ex10.mc_evaluate import MCEvaluationAgent + +if __name__ == "__main__": + env = BookGridEnvironment(view_mode=1, render_mode='human', living_reward=-0.05) + agent = MCEvaluationAgent(env, gamma=.9, alpha=None, first_visit=False) + + keyboard_play_value(env,agent,method_label='MC every') diff --git a/irlc/lectures/lec10/lecture_10_mc_value_every_one_state.py b/irlc/lectures/lec10/lecture_10_mc_value_every_one_state.py new file mode 100644 index 0000000..bd86faf --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_mc_value_every_one_state.py @@ -0,0 +1,58 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment, BookGridEnvironment +from irlc.lectures.lec10.lecture_10_mc_value_first_one_state import MCAgentOneState +from irlc.ex10.mc_agent import MCAgent +from irlc.ex10.mc_evaluate import MCEvaluationAgent +import numpy as np +from irlc import interactive, train + +# class MCAgentOneState(MCEvaluationAgent): +# def __init__(self, *args, state=None, **kwargs): +# a = 34 +# super().__init__(*args, **kwargs) +# if state is None: +# state = self.env.mdp.initial_state +# self.state = state +# self._clear_states() +# +# def _clear_states(self, val=None): +# for s in self.env.mdp.nonterminal_states: +# # for a in self.env.mdp.A(s): +# # self.Q[s,a] = 0 +# if s != self.state: +# self.returns_sum_S[s] = val +# self.returns_count_N[s] = val +# +# if s in self.v: +# k = next(self.env.mdp.Psr(s, self.env.mdp.A(s)[0]).keys().__iter__() )[0] +# if not self.env.mdp.is_terminal(k): +# +# del self.v[s] +# +# +# def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): +# # self.episode = [e for e in self.episode if e[0] == self.state] +# self._clear_states(0) +# super().train(s, a, r, sp, done) +# # Clear out many of the state, actions: +# self._clear_states(None) +# # for s in self.env.mdp.nonterminal_states: +# # if s != self.state: +# # self.v[s] = None +# pass + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', living_reward=-0.05, print_states=True) + agent = MCAgentOneState(env, gamma=1, alpha=None, first_visit=False) + method_label = 'MC (gamma=1)' + agent.label = method_label + autoplay = False + env, agent = interactive(env, agent, autoplay=autoplay) + # agent = PlayWrapper(agent, env,autoplay=autoplay) + # env = VideoMonitor(env, agent=agent, fps=100, agent_monitor_keys=('pi', 'Q'), render_kwargs={'method_label': method_label}) + num_episodes = 1000 + train(env, agent, num_episodes=num_episodes) + env.close() + + # keyboard_play(env,agent,method_label='MC (alpha=0.5)') diff --git a/irlc/lectures/lec10/lecture_10_mc_value_first.py b/irlc/lectures/lec10/lecture_10_mc_value_first.py new file mode 100644 index 0000000..549b797 --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_mc_value_first.py @@ -0,0 +1,32 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import BookGridEnvironment, BridgeGridEnvironment, GridworldEnvironment +from irlc.ex10.mc_evaluate import MCEvaluationAgent +from irlc import interactive, train + +class BridgeGridEnvironment2(GridworldEnvironment): + def __init__(self, *args, **kwargs): + super().__init__(grid_bridge_grid, *args, **kwargs) + + +grid_bridge_grid = [[ '#',-100, -100, -100, -100, -100, '#'], + [ 1, ' ', 'S', ' ', ' ', ' ', 2], + [ '#',-100, -100, -100, -100, -100, '#']] + + +if __name__ == "__main__": + + # env = BridgeGridEnvironment2(view_mode=1, render_mode='human', living_reward=0) + # agent = MCEvaluationAgent(env, gamma=.8, alpha=None, first_visit=False) + # env, agent = interactive(env, agent) + # train(env, agent, num_episodes=1000) + # env.close() + + env = BookGridEnvironment(view_mode=1, render_mode='human', living_reward=-0.05) + agent = MCEvaluationAgent(env, gamma=1, alpha=None) + # agent = PlayWrapper(agent, env) + agent.label = 'MC First (gamma=1)' + env, agent = interactive(env, agent) + env.view_mode = 1 # Automatically set value-function view-mode. + # env = VideoMonitor(env, agent=agent, fps=200, render_kwargs={'method_label': 'MC first'}) + train(env, agent, num_episodes=1000) + env.close() diff --git a/irlc/lectures/lec10/lecture_10_mc_value_first_one_state.py b/irlc/lectures/lec10/lecture_10_mc_value_first_one_state.py new file mode 100644 index 0000000..c998543 --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_mc_value_first_one_state.py @@ -0,0 +1,64 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment, BookGridEnvironment +from irlc.ex10.mc_agent import MCAgent +from irlc.ex10.mc_evaluate import MCEvaluationAgent +import numpy as np +from irlc import interactive, train + +class MCAgentOneState(MCEvaluationAgent): + def __init__(self, *args, state=None, **kwargs): + a = 34 + super().__init__(*args, **kwargs) + if state is None: + state = self.env.mdp.initial_state + self.state = state + self._clear_states() + + def _clear_states(self, val=None): + for s in self.env.mdp.nonterminal_states: + # for a in self.env.mdp.A(s): + # self.Q[s,a] = 0 + if s != self.state: + self.returns_sum_S[s] = val + self.returns_count_N[s] = val + + if s in self.v: + k = next(self.env.mdp.Psr(s, self.env.mdp.A(s)[0]).keys().__iter__() )[0] + if not self.env.mdp.is_terminal(k): + + del self.v[s] + + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + # self.episode = [e for e in self.episode if e[0] == self.state] + self._clear_states(0) + super().train(s, a, r, sp, done) + self._clear_states(None) + + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', living_reward=-0.05, print_states=True, zoom=2) + agent = MCAgentOneState(env, gamma=1, alpha=None, first_visit=True) + method_label = 'MC (gamma=1)' + agent.label = method_label + autoplay = False + env, agent = interactive(env, agent, autoplay=autoplay) + # agent = PlayWrapper(agent, env,autoplay=autoplay) + # env = VideoMonitor(env, agent=agent, fps=100, agent_monitor_keys=('pi', 'Q'), render_kwargs={'method_label': method_label}) + num_episodes = 1000 + train(env, agent, num_episodes=num_episodes) + env.close() + + import matplotlib.pyplot as plt + import numpy as np + + import matplotlib.pyplot as plt + import numpy as np + + lt = np.linspace(np.log(1000), np.log(2000) + 0*5000) + plt.plot(lt, 5 + 2 * np.sqrt(lt / 500), 'k-') + plt.plot(lt, 10 + 2 * np.sqrt(lt / (np.exp(lt) - 500)), 'r-') + plt.xlabel('log(t)') + plt.show() + # keyboard_play(env,agent,method_label='MC (alpha=0.5)') diff --git a/irlc/lectures/lec10/lecture_10_mc_value_first_one_state_b.py b/irlc/lectures/lec10/lecture_10_mc_value_first_one_state_b.py new file mode 100644 index 0000000..6567221 --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_mc_value_first_one_state_b.py @@ -0,0 +1,58 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment, BookGridEnvironment +from irlc.lectures.lec10.lecture_10_mc_value_first_one_state import MCAgentOneState +from irlc.ex10.mc_agent import MCAgent +from irlc.ex10.mc_evaluate import MCEvaluationAgent +import numpy as np +from irlc import interactive, train + +# class MCAgentOneState(MCEvaluationAgent): +# def __init__(self, *args, state=None, **kwargs): +# a = 34 +# super().__init__(*args, **kwargs) +# if state is None: +# state = self.env.mdp.initial_state +# self.state = state +# self._clear_states() +# +# def _clear_states(self, val=None): +# for s in self.env.mdp.nonterminal_states: +# # for a in self.env.mdp.A(s): +# # self.Q[s,a] = 0 +# if s != self.state: +# self.returns_sum_S[s] = val +# self.returns_count_N[s] = val +# if s in self.v: +# k = next(self.env.mdp.Psr(s, self.env.mdp.A(s)[0]).keys().__iter__() )[0] +# if not self.env.mdp.is_terminal(k): +# +# del self.v[s] +# +# def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): +# # self.episode = [e for e in self.episode if e[0] == self.state] +# self._clear_states(0) +# super().train(s, a, r, sp, done) +# # Clear out many of the state, actions: +# self._clear_states(None) +# # for s in self.env.mdp.nonterminal_states: +# # if s != self.state: +# # self.v[s] = None +# +# pass + + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', living_reward=-0.05) + agent = MCAgentOneState(env, gamma=1, alpha=None, first_visit=True, state=(0,2)) + method_label = 'MC (gamma=1)' + agent.label = method_label + autoplay = False + env, agent = interactive(env, agent, autoplay=autoplay) + # agent = PlayWrapper(agent, env,autoplay=autoplay) + # env = VideoMonitor(env, agent=agent, fps=100, agent_monitor_keys=('pi', 'Q'), render_kwargs={'method_label': method_label}) + num_episodes = 1000 + train(env, agent, num_episodes=num_episodes) + env.close() + + # keyboard_play(env,agent,method_label='MC (alpha=0.5)') diff --git a/irlc/lectures/lec10/lecture_10_td_corner.py b/irlc/lectures/lec10/lecture_10_td_corner.py new file mode 100644 index 0000000..e2aa0cd --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_td_corner.py @@ -0,0 +1,9 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment +from irlc.ex10.td0_evaluate import TD0ValueAgent + +if __name__ == "__main__": + env = SuttonCornerGridEnvironment() + agent = TD0ValueAgent(env, gamma=1, alpha=0.5) + keyboard_play(env,agent,method_label='TD(0) (alpha=0.5)') diff --git a/irlc/lectures/lec10/lecture_10_td_keyboard.py b/irlc/lectures/lec10/lecture_10_td_keyboard.py new file mode 100644 index 0000000..8787900 --- /dev/null +++ b/irlc/lectures/lec10/lecture_10_td_keyboard.py @@ -0,0 +1,9 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec10.lecture_10_mc_q_estimation import automatic_play_value +from irlc.gridworld.gridworld_environments import BookGridEnvironment +from irlc.ex10.td0_evaluate import TD0ValueAgent + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', living_reward=-0.05) + agent = TD0ValueAgent(env, gamma=1.0, alpha=0.2) + automatic_play_value(env,agent,method_label='TD(0)') diff --git a/irlc/lectures/lec10/unf_gridworld_action_value.py b/irlc/lectures/lec10/unf_gridworld_action_value.py new file mode 100644 index 0000000..67d3ad9 --- /dev/null +++ b/irlc/lectures/lec10/unf_gridworld_action_value.py @@ -0,0 +1,42 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex01.agent import Agent +from irlc.gridworld.gridworld_environments import BookGridEnvironment, FrozenLakeEnv +# from irlc.utils.video_monitor import VideoMonitor +from irlc import interactive, train +# from irlc.ex01.agent import train +# from irlc import PlayWrapper + +from irlc.ex10.mc_agent import MCAgent + +class SingleActionValueAgent(MCAgent): + def __init__(self, env, gamma=1.0, epsilon=0.05, alpha=None, first_visit=True): + super().__init__(env, gamma=1., epsilon=1, alpha=None, first_visit=True) + + def pi(self, s, k, info=None): + if k == 0: + return 1 + else: + return super().pi_eps(s, info=None) + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + super().train(s, a, r, sp, done, info_s, info_sp) + for s in self.env.mdp.nonterminal_states: + for a in self.env.mdp.A(s): + if s == (0,0) and a == 1: + pass + elif len(self.env.mdp.A(s)) == 1: + pass + else: + self.Q[s,a] = 0 + a = 234 + + + + + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', print_states=True, living_reward=-0.05) + env, agent = interactive(env, SingleActionValueAgent(env)) + agent.label = "Random agent" + train(env, agent, num_episodes=100, verbose=False) + env.close() diff --git a/irlc/lectures/lec10/unf_gridworld_value.py b/irlc/lectures/lec10/unf_gridworld_value.py new file mode 100644 index 0000000..7286e1d --- /dev/null +++ b/irlc/lectures/lec10/unf_gridworld_value.py @@ -0,0 +1,42 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex01.agent import Agent +from irlc.gridworld.gridworld_environments import BookGridEnvironment, FrozenLakeEnv +# from irlc.utils.video_monitor import VideoMonitor +from irlc import interactive, train +# from irlc.ex01.agent import train +# from irlc import PlayWrapper +from irlc.ex10.mc_agent import MCAgent +from irlc.ex10.mc_evaluate import MCEvaluationAgent + +class SingleActionValueAgent(MCEvaluationAgent): + def __init__(self, env, gamma=1.0, epsilon=0.05, alpha=None, first_visit=True): + super().__init__(env, gamma=1., alpha=None, first_visit=True) + + # def pi(self, s, k, info=None): + # if k == 0: + # return 1 + # else: + # return super().pi_eps(s, info=None) + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + super().train(s, a, r, sp, done, info_s, info_sp) + for s in self.env.mdp.nonterminal_states: + # for a in self.env.mdp.A(s): + if s == (0,0):# and a == 1: + pass + elif len(self.env.mdp.A(s)) == 1: + pass + else: + self.v[s] = 0 + a = 234 + + + + + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human', print_states=True, living_reward=-0.05) + env, agent = interactive(env, SingleActionValueAgent(env)) + agent.label = "Random agent" + train(env, agent, num_episodes=100, verbose=False) + env.close() diff --git a/irlc/lectures/lec11/__init__.py b/irlc/lectures/lec11/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/lectures/lec11/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/lectures/lec11/exam_sol.py b/irlc/lectures/lec11/exam_sol.py new file mode 100644 index 0000000..7687d17 --- /dev/null +++ b/irlc/lectures/lec11/exam_sol.py @@ -0,0 +1,11 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import BookGridEnvironment +from irlc.exam_tabular_examples.sarsa_nstep_delay import SarsaDelayNAgent +from irlc import interactive, train + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human') + agent = SarsaDelayNAgent(env, gamma=1, epsilon=0.1, alpha=0.9, n=1) # Exam problem. + # agent = SarsaDelayNAgent(env, gamma=0.95, epsilon=0.1, alpha=.2, n=1) + env, agent = interactive(env, agent) + train(env, agent, num_episodes=10) diff --git a/irlc/lectures/lec11/lecture_10_grid_lin_q.py b/irlc/lectures/lec11/lecture_10_grid_lin_q.py new file mode 100644 index 0000000..659201d --- /dev/null +++ b/irlc/lectures/lec11/lecture_10_grid_lin_q.py @@ -0,0 +1,10 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.berkley.rl.semi_grad_q import LinearSemiGradQAgent +from irlc.ex11.feature_encoder import GridworldXYEncoder +from irlc.gridworld.gridworld_environments import BookGridEnvironment +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human') + agent = LinearSemiGradQAgent(env, gamma=0.95, epsilon=0.1, alpha=.01, q_encoder=GridworldXYEncoder(env)) + keyboard_play(env, agent, method_label="Q-lin-xy") diff --git a/irlc/lectures/lec11/lecture_10_sarsa_open.py b/irlc/lectures/lec11/lecture_10_sarsa_open.py new file mode 100644 index 0000000..4e1ca8c --- /dev/null +++ b/irlc/lectures/lec11/lecture_10_sarsa_open.py @@ -0,0 +1,12 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import OpenGridEnvironment +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.ex11.sarsa_agent import SarsaAgent + +def open_play(Agent, method_label, frames_per_second=30, **args): + env = OpenGridEnvironment(render_mode='human', frames_per_second=frames_per_second) + agent = Agent(env, gamma=0.99, epsilon=0.1, alpha=.5, **args) + keyboard_play(env, agent, method_label=method_label) + +if __name__ == "__main__": + open_play(SarsaAgent, method_label="Sarsa") diff --git a/irlc/lectures/lec11/lecture_11_nstep_open.py b/irlc/lectures/lec11/lecture_11_nstep_open.py new file mode 100644 index 0000000..fc5e285 --- /dev/null +++ b/irlc/lectures/lec11/lecture_11_nstep_open.py @@ -0,0 +1,11 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# from irlc.berkley.rl.feature_encoder import SimplePacmanExtractor + +from irlc.ex11.nstep_sarsa_agent import SarsaNAgent +from irlc.exam_tabular_examples.sarsa_nstep_delay import SarsaDelayNAgent + +from irlc.lectures.lec11.lecture_10_sarsa_open import open_play +if __name__ == "__main__": + # env = OpenGridEnvironment() + # agent = (env, gamma=0.95, epsilon=0.1, alpha=.5) + open_play(SarsaDelayNAgent, method_label="Sarsa n=8", n=8) diff --git a/irlc/lectures/lec11/lecture_11_pacman_lin_q.py b/irlc/lectures/lec11/lecture_11_pacman_lin_q.py new file mode 100644 index 0000000..3b7e121 --- /dev/null +++ b/irlc/lectures/lec11/lecture_11_pacman_lin_q.py @@ -0,0 +1,32 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex11.semi_grad_q import LinearSemiGradQAgent +from irlc.pacman.pacman_environment import PacmanEnvironment, PacmanWinWrapper +from irlc.ex11.feature_encoder import SimplePacmanExtractor +import matplotlib.pyplot as plt +# from irlc.utils.video_monitor import VideoMonitor +from irlc.ex01.agent import train +# from irlc import PlayWrapper +from irlc import interactive + +def play_pacman(env, agent, layout = 'smallGrid'): + train(env, agent, num_episodes=100) + + env2 = PacmanWinWrapper(env) + + # env2 = Monitor(env2, directory="experiments/randomdir", force=True) + # env2 = VideoMonitor(env2) + env2, agent = interactive(env, agent) + agent.epsilon = 0 + agent.alpha = 0 + # agent = PlayWrapper(agent, env2) + train(env2, agent, num_episodes=100) + plt.show() + env.close() + +if __name__ == "__main__": + layout = 'smallGrid' + env = PacmanEnvironment(animate_movement=True, layout=layout, render_mode='human', frames_per_second=100) + qex = SimplePacmanExtractor(env) + agent = LinearSemiGradQAgent(env, epsilon=0.05, alpha=0.1, gamma=0.8, q_encoder=qex) + play_pacman(env, agent, layout = 'smallGrid') + # main_plot('experiments/q_lin') diff --git a/irlc/lectures/lec11/lecture_11_pacman_q.py b/irlc/lectures/lec11/lecture_11_pacman_q.py new file mode 100644 index 0000000..7a51a06 --- /dev/null +++ b/irlc/lectures/lec11/lecture_11_pacman_q.py @@ -0,0 +1,35 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.pacman.pacman_environment import PacmanEnvironment, PacmanWinWrapper +# from irlc.berkley.rl.feature_encoder import SimplePacmanExtractor +# from irlc.utils.player_wrapper_pyglet import PlayWrapper +from irlc import main_plot +import matplotlib.pyplot as plt +# from irlc.utils.video_monitor import VideoMonitor +from irlc.ex01.agent import train +# from irlc.lectures.lecture_09_mc import keyboard_play +from irlc.ex11.q_agent import QAgent +from irlc import interactive + + +def play_pacman(env, agent, layout = 'smallGrid'): + + train(env, agent, num_episodes=100) + env2 = PacmanWinWrapper(env) + # env2 = Monitor(env2, directory="experiments/randomdir", force=True) + # env2 = VideoMonitor(env2) + env2, agent = interactive(env2, agent) + agent.epsilon = 0 + agent.alpha = 0 + # agent = PlayWrapper(agent, env2) + train(env2, agent, num_episodes=100) + plt.show() + env.close() + +if __name__ == "__main__": + layout = 'smallGrid' + env = PacmanEnvironment(animate_movement=False, layout=layout, render_mode='human') + agent = QAgent(env, epsilon=0.05, alpha=0.1, gamma=0.8) + # from irlc import PlayWrapper + # agent = PlayWrapper(agent, env) + play_pacman(env, agent, layout = 'smallGrid') + # main_plot('experiments/q_lin') diff --git a/irlc/lectures/lec11/lecture_11_q.py b/irlc/lectures/lec11/lecture_11_q.py new file mode 100644 index 0000000..d3df9db --- /dev/null +++ b/irlc/lectures/lec11/lecture_11_q.py @@ -0,0 +1,10 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# from irlc.berkley.rl.feature_encoder import SimplePacmanExtractor +from irlc.gridworld.gridworld_environments import BookGridEnvironment +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.ex11.q_agent import QAgent + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human') + agent = QAgent(env, gamma=0.95, epsilon=0.1, alpha=.2) + keyboard_play(env, agent, method_label="Q-learning") diff --git a/irlc/lectures/lec11/lecture_11_q_cliff.py b/irlc/lectures/lec11/lecture_11_q_cliff.py new file mode 100644 index 0000000..421db1f --- /dev/null +++ b/irlc/lectures/lec11/lecture_11_q_cliff.py @@ -0,0 +1,18 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import CliffGridEnvironment, CliffGridEnvironment2 +from irlc.ex11.q_agent import QAgent + + +# def cliffwalk(env, agent, method_label="method"): +# agent = PlayWrapper(agent, env) + # env = VideoMonitor(env, agent=agent, fps=100, continious_recording=True, agent_monitor_keys=('pi', 'Q'), render_kwargs={'method_label': method_label}) + # train(env, agent, num_episodes=200) + # env.close() + +from irlc.lectures.lec11.lecture_11_sarsa_cliff import cliffwalk, gamma, alpha, epsi +if __name__ == "__main__": + import numpy as np + np.random.seed(1) + env = CliffGridEnvironment2(zoom=.8, render_mode='human') + agent = QAgent(env, gamma=gamma, epsilon=epsi, alpha=alpha) + cliffwalk(env, agent, method_label="Q-learning") diff --git a/irlc/lectures/lec11/lecture_11_q_open.py b/irlc/lectures/lec11/lecture_11_q_open.py new file mode 100644 index 0000000..f0a35a5 --- /dev/null +++ b/irlc/lectures/lec11/lecture_11_q_open.py @@ -0,0 +1,12 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld_pyglet.gridworld_environments import OpenGridEnvironment +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.ex11.q_agent import QAgent + +def open_play(Agent, method_label, **args): + env = OpenGridEnvironment() + agent = Agent(env, gamma=0.99, epsilon=0.1, alpha=.5, **args) + keyboard_play(env, agent, method_label=method_label) + +if __name__ == "__main__": + open_play(QAgent, method_label="Q-learning") diff --git a/irlc/lectures/lec11/lecture_11_sarsa.py b/irlc/lectures/lec11/lecture_11_sarsa.py new file mode 100644 index 0000000..7dfb39d --- /dev/null +++ b/irlc/lectures/lec11/lecture_11_sarsa.py @@ -0,0 +1,10 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import BookGridEnvironment +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.exam_tabular_examples.sarsa_nstep_delay import SarsaDelayNAgent + +if __name__ == "__main__": + env = BookGridEnvironment(render_mode='human') + # agent = SarsaDelayNAgent(env, gamma=1, epsilon=0.1, alpha=0.9, n=1) # Exam problem. + agent = SarsaDelayNAgent(env, gamma=0.95, epsilon=0.1, alpha=.2, n=1) + keyboard_play(env, agent, method_label="Sarsa") diff --git a/irlc/lectures/lec11/lecture_11_sarsa_cliff.py b/irlc/lectures/lec11/lecture_11_sarsa_cliff.py new file mode 100644 index 0000000..3d250fa --- /dev/null +++ b/irlc/lectures/lec11/lecture_11_sarsa_cliff.py @@ -0,0 +1,33 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# from irlc.utils.player_wrapper_pyglet import PlayWrapper +from irlc.gridworld.gridworld_environments import CliffGridEnvironment, CliffGridEnvironment2 +# from irlc.utils.video_monitor import VideoMonitor +from irlc.ex01.agent import train +from irlc import interactive +from irlc.ex11.sarsa_agent import SarsaAgent + + +def cliffwalk(env, agent, method_label="method"): + # agent = PlayWrapper(agent, env) + env.label = method_label + agent.method_label = method_label + agent.label = method_label + agent.method = method_label + + + env, agent = interactive(env, agent) + # env = VideoMonitor(env, agent=agent, fps=200, continious_recording=True, agent_monitor_keys=('pi', 'Q'), render_kwargs={'method_label': method_label}) + train(env, agent, num_episodes=1000) + env.close() + +epsi = 0.5 +gamma = 1.0 +alpha = .3 + +if __name__ == "__main__": + import numpy as np + np.random.seed(1) + env = CliffGridEnvironment2(zoom=.8, render_mode='human') + agent = SarsaAgent(env, gamma=gamma, epsilon=epsi, alpha=alpha) + # agent = QAgent(env, gamma=0.95, epsilon=0.5, alpha=.2) + cliffwalk(env, agent, method_label="Sarsa") diff --git a/irlc/lectures/lec12/__init__.py b/irlc/lectures/lec12/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/lectures/lec12/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/lectures/lec12/lecture_12_mc_open.py b/irlc/lectures/lec12/lecture_12_mc_open.py new file mode 100644 index 0000000..e0adf31 --- /dev/null +++ b/irlc/lectures/lec12/lecture_12_mc_open.py @@ -0,0 +1,19 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# from irlc.berkley.rl.feature_encoder import SimplePacmanExtractor +# from irlc.lectures.lecture_09_mc import keyboard_play + +# alpha = 0.5 +# gamma = + +# def open_play(Agent, method_label, **args): +# env = OpenGridEnvironment() +# agent = Agent(env, gamma=0.95, epsilon=0.1, alpha=.5, **args) +# keyboard_play(env, agent, method_label=method_label) + +from irlc.lectures.lec11.lecture_10_sarsa_open import open_play +from irlc.ex10.mc_agent import MCAgent +if __name__ == "__main__": + # env = OpenGridEnvironment() + # agent = (env, gamma=0.95, epsilon=0.1, alpha=.5) + open_play(MCAgent, method_label="MC agent") + # diff --git a/irlc/lectures/lec12/lecture_12_pacman.py b/irlc/lectures/lec12/lecture_12_pacman.py new file mode 100644 index 0000000..3e3f9fb --- /dev/null +++ b/irlc/lectures/lec12/lecture_12_pacman.py @@ -0,0 +1,21 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex11.semi_grad_q import LinearSemiGradQAgent +from irlc.pacman.pacman_environment import PacmanEnvironment +from irlc.ex01.agent import train +from irlc import interactive +from irlc.lectures.chapter14lectures.lecture11pacman import layout, rns +# from irlc import VideoMonitor + +if __name__ == "__main__": + env = PacmanEnvironment(animate_movement=False, layout=layout) + + n, agent = rns[-1] + agent = agent(env) + # env, agent = interactive(env, agent) + + train(env, agent, num_episodes=100, max_runs=20) + env2 = PacmanEnvironment(animate_movement=True, layout=layout, render_mode='human') + # agent.env = env2 + env2, agent = interactive(env2, agent) + train(env2, agent, num_episodes=100, max_runs=20) + env2.close() diff --git a/irlc/lectures/lec12/lecture_12_sarsa_lamda_open.py b/irlc/lectures/lec12/lecture_12_sarsa_lamda_open.py new file mode 100644 index 0000000..0e1a233 --- /dev/null +++ b/irlc/lectures/lec12/lecture_12_sarsa_lamda_open.py @@ -0,0 +1,6 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec11.lecture_10_sarsa_open import open_play +from irlc.exam_tabular_examples.sarsa_lambda_delay import SarsaLambdaDelayAgent + +if __name__ == "__main__": + open_play(SarsaLambdaDelayAgent, method_label="Sarsa(Lambda)", lamb=0.8) diff --git a/irlc/lectures/lec12/lecture_12_sarsa_nstep.py b/irlc/lectures/lec12/lecture_12_sarsa_nstep.py new file mode 100644 index 0000000..0f04c1a --- /dev/null +++ b/irlc/lectures/lec12/lecture_12_sarsa_nstep.py @@ -0,0 +1,13 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.gridworld.gridworld_environments import OpenGridEnvironment +from irlc import train +from irlc.lectures.lec11.lecture_10_sarsa_open import open_play +from irlc.exam_tabular_examples.sarsa_nstep_delay import SarsaDelayNAgent + +if __name__ == "__main__": + n = 8 + env = OpenGridEnvironment() + agent = SarsaDelayNAgent(env, n=n) + train(env, agent, num_episodes=100) + + open_play(SarsaDelayNAgent, method_label=f"Sarsa n={n}", n=n) diff --git a/irlc/lectures/lec12/lecture_12_sarsa_open.py b/irlc/lectures/lec12/lecture_12_sarsa_open.py new file mode 100644 index 0000000..dfba5b0 --- /dev/null +++ b/irlc/lectures/lec12/lecture_12_sarsa_open.py @@ -0,0 +1,11 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc import train +from irlc.gridworld.gridworld_environments import OpenGridEnvironment +from irlc.lectures.lec11.lecture_10_sarsa_open import open_play +from irlc.exam_tabular_examples.sarsa_nstep_delay import SarsaDelayNAgent + +if __name__ == "__main__": + env = OpenGridEnvironment() + agent = SarsaDelayNAgent(env, n=1) + train(env, agent, num_episodes=100) + open_play(SarsaDelayNAgent, method_label=f"Sarsa") diff --git a/irlc/lectures/lec13/double_q_viz.py b/irlc/lectures/lec13/double_q_viz.py new file mode 100644 index 0000000..cca339d --- /dev/null +++ b/irlc/lectures/lec13/double_q_viz.py @@ -0,0 +1,71 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc.ex01.agent import train +import gymnasium as gym +from irlc import main_plot +import matplotlib.pyplot as plt +from irlc import savepdf +from irlc.ex11.sarsa_agent import SarsaAgent +from irlc.ex11.q_agent import QAgent +from irlc.ex13.tabular_double_q import TabularDoubleQ +from irlc.ex09.rl_agent import TabularQ +from irlc.gridworld.gridworld_environments import CliffGridEnvironment + +class DoubleQVizAgent(TabularDoubleQ): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.Q = TabularQ(self.env) + + def train(self, s, a, r, sp, done=False, info_s=None, info_sp=None): + super().train(s, a, r, sp, done, info_s,info_sp) + self.Q[s,a] = (self.Q1[s,a] + self.Q2[s,a] )/2 + +def train_cliff(runs=4, extension="long", save_pdf=False, alpha=0.02, num_episodes=5000): + """ Part 1: Cliffwalking """ + # env = gym.make('CliffWalking-v0') + + env = CliffGridEnvironment(zoom=1) + epsilon = 0.1 + # alpha = 0.02 + for _ in range(runs): + agents = [QAgent(env, gamma=1, epsilon=epsilon, alpha=alpha), + SarsaAgent(env, gamma=1, epsilon=epsilon, alpha=alpha), + DoubleQVizAgent(env, gamma=1, epsilon=epsilon, alpha=alpha)] + + experiments = [] + for agent in agents: + expn = f"experiments/doubleq_cliffwalk_{extension}_{str(agent)}" + train(env, agent, expn, num_episodes=num_episodes, max_runs=1e6) + experiments.append(expn) + if save_pdf: + main_plot(experiments, smoothing_window=20, resample_ticks=500) + plt.ylim([-100, 50]) + plt.title(f"Double-Q learning on Cliffwalk ({extension})") + savepdf(f"double_Q_learning_cliff_{extension}") + plt.show() + return agents, env + + +def grid_experiment(runs=20, extension="long", alpha=0.02, num_episodes=5000): + from irlc.gridworld.gridworld_environments import CliffGridEnvironment + # from irlc import VideoMonitor, PlayWrapper + from irlc import interactive + + agents, env = train_cliff(runs=runs, extension=extension, save_pdf=True, alpha=alpha, num_episodes=num_episodes) + labels = ["Q-learning", "Sarsa", "Double Q-learning"] + for na in range(len(agents)): + env2 = CliffGridEnvironment(zoom=1, view_mode='human') + env2, agent = interactive(env2, agent=agents[na])# , agent_monitor_keys=('Q',), render_kwargs={'method_label': labels[na]}) + # agent = PlayWrapper(agents[na], env) + env2.savepdf(f"doubleq_cliff_{extension}_agent_{na}") + env2.close() + + env.close() + pass + +if __name__ == "__main__": + """ + Test cliffwalk in both the long and short version + """ + grid_experiment(runs=1, extension="long", alpha=0.02, num_episodes=5000) + grid_experiment(runs=1, extension="short", alpha=0.25, num_episodes=500) diff --git a/irlc/lectures/lec13/lecture_13_Q_maze.py b/irlc/lectures/lec13/lecture_13_Q_maze.py new file mode 100644 index 0000000..c1b0582 --- /dev/null +++ b/irlc/lectures/lec13/lecture_13_Q_maze.py @@ -0,0 +1,14 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec11.lecture_10_sarsa_open import open_play +from irlc.ex11.q_agent import QAgent +from irlc.ex13.dyna_q import DynaQ +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.gridworld.gridworld_environments import SuttonMazeEnvironment + +def sutton_maze_play(Agent, method_label="Q-learning agent", **kwargs): + env = SuttonMazeEnvironment(render_mode='human') + agent = Agent(env, gamma=0.98, epsilon=0.1, alpha=.5, **kwargs) + keyboard_play(env, agent, method_label=method_label) + +if __name__ == "__main__": + sutton_maze_play(DynaQ, method_label="Q-learning agent", n=0) diff --git a/irlc/lectures/lec13/lecture_13_Q_open.py b/irlc/lectures/lec13/lecture_13_Q_open.py new file mode 100644 index 0000000..b45e069 --- /dev/null +++ b/irlc/lectures/lec13/lecture_13_Q_open.py @@ -0,0 +1,6 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec11.lecture_10_sarsa_open import open_play +from irlc.ex11.q_agent import QAgent + +if __name__ == "__main__": + open_play(QAgent, method_label="Q-learning agent") diff --git a/irlc/lectures/lec13/lecture_13_dyna_q_5_maze.py b/irlc/lectures/lec13/lecture_13_dyna_q_5_maze.py new file mode 100644 index 0000000..293771d --- /dev/null +++ b/irlc/lectures/lec13/lecture_13_dyna_q_5_maze.py @@ -0,0 +1,10 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec11.lecture_10_sarsa_open import open_play +from irlc.ex11.q_agent import QAgent +from irlc.ex13.dyna_q import DynaQ +from irlc.lectures.lec10.lecture_10_mc_q_estimation import keyboard_play +from irlc.gridworld.gridworld_environments import SuttonMazeEnvironment +from irlc.lectures.lec13.lecture_13_Q_maze import sutton_maze_play + +if __name__ == "__main__": + sutton_maze_play(DynaQ, method_label="DynaQ (n=5)", n=5) diff --git a/irlc/lectures/lec13/lecture_13_sarsa_lambda_maze.py b/irlc/lectures/lec13/lecture_13_sarsa_lambda_maze.py new file mode 100644 index 0000000..4336879 --- /dev/null +++ b/irlc/lectures/lec13/lecture_13_sarsa_lambda_maze.py @@ -0,0 +1,6 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.lectures.lec13.lecture_13_Q_maze import sutton_maze_play +from irlc.ex12.sarsa_lambda_agent import SarsaLambdaAgent + +if __name__ == "__main__": + sutton_maze_play(SarsaLambdaAgent, method_label="Sarsa(Lambda=0.9)", lamb=0.9) diff --git a/irlc/lectures/readme.md b/irlc/lectures/readme.md new file mode 100644 index 0000000..1d3ccdb --- /dev/null +++ b/irlc/lectures/readme.md @@ -0,0 +1,6 @@ +# In-class examples + +This folder contains various examples used throughout class. You should be able to run most of the examples +if you find it helpful (and many of the examples are simply running the exercise code), however, +in some instances I have made small changes to the exercises to provide additional visualizations etc. Also note that the code is sometimes not +well organized -- in other words, the folder is provided "as is" for those who find it helpful, and you are free to ignore it. diff --git a/irlc/pacman/__init__.py b/irlc/pacman/__init__.py new file mode 100644 index 0000000..9916664 --- /dev/null +++ b/irlc/pacman/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.pacman.pacman_environment import PacmanEnvironment diff --git a/irlc/pacman/__pycache__/__init__.cpython-311.pyc b/irlc/pacman/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59a1fd223427c1d692a1f9db502ea71573779c82 GIT binary patch literal 257 zcmZ3^%ge>Uz`$UU-<$T1fq~&Mhy%k+P{wB=1_p-d3@HpLj5!Rsj8Tk?3@J>(44TX@ zK?*b(ZwUq@Cg&#Rx#pE+7Uk#VrskFSX)@iC%Ph)C)++!@L8<sugpwj=1_p+e44*+} z{Ib)}$j?pHFDcDP)pyBHE(MuUte=^iqi<kjVro!aQks&QS5mAGGEyI6q<(ySW?p7V xe7s&k<u4AK-29Z%oK(9a4h9AWMg|6kVp#?Th7Zh)jEoN$Y%X9!MQjWV3;;Q@N8A7a literal 0 HcmV?d00001 diff --git a/irlc/pacman/__pycache__/gamestate.cpython-311.pyc b/irlc/pacman/__pycache__/gamestate.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9aa794223cbc54858e8d02ec80d33c6986577e08 GIT binary patch literal 33196 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 H0LL2u-89e~ literal 0 HcmV?d00001 diff --git a/irlc/pacman/__pycache__/layout.cpython-311.pyc b/irlc/pacman/__pycache__/layout.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..03091d715903d53e6e467e17b514095681882ca2 GIT binary patch literal 8491 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 literal 0 HcmV?d00001 diff --git a/irlc/pacman/__pycache__/pacman_environment.cpython-311.pyc b/irlc/pacman/__pycache__/pacman_environment.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b601df57ba77d362482407b7d03491083d23a656 GIT binary patch literal 11293 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 L)CFcqaP9{HPgT;W literal 0 HcmV?d00001 diff --git a/irlc/pacman/__pycache__/pacman_graphics_display.cpython-311.pyc b/irlc/pacman/__pycache__/pacman_graphics_display.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b583f2ce171807c07a0c845e957334a277a79ec GIT binary patch literal 45736 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 B7Z?Bl literal 0 HcmV?d00001 diff --git a/irlc/pacman/__pycache__/pacman_text_display.cpython-311.pyc b/irlc/pacman/__pycache__/pacman_text_display.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3cf59db02dff7911114b3da4081c6965dc0c4f08 GIT binary patch literal 3505 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 literal 0 HcmV?d00001 diff --git a/irlc/pacman/__pycache__/pacman_utils.cpython-311.pyc b/irlc/pacman/__pycache__/pacman_utils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a7be403248e32e151ccbef8ab4ac2bfd4a8ff9b GIT binary patch literal 35617 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 P#^z|taL|^;iJ2JyNaxy+ literal 0 HcmV?d00001 diff --git a/irlc/pacman/feature_extractor.py b/irlc/pacman/feature_extractor.py new file mode 100644 index 0000000..7a40946 --- /dev/null +++ b/irlc/pacman/feature_extractor.py @@ -0,0 +1,109 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# feature_extractor.py +# -------------------- +# Licensing Information: You are free to use or extend these projects for +# educational purposes provided that (1) you do not distribute or publish +# solutions, (2) you retain this notice, and (3) you provide clear +# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. +# +# Attribution Information: The Pacman AI projects were developed at UC Berkeley. +# The core projects and autograders were primarily created by John DeNero +# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). +# Student side autograding was added by Brad Miller, Nick Hay, and +# Pieter Abbeel (pabbeel@cs.berkeley.edu). +from irlc.pacman.pacman_utils import Actions + +## Other classes +class FeatureExtractor: + def getFeatures(self, state, action): + """ + Returns a dict from features to counts + Usually, the count will just be 1.0 for + indicator functions. + """ + raise NotImplementedError() + # util.raiseNotDefined() + +class IdentityExtractor(FeatureExtractor): + def getFeatures(self, state, action): + from collections import defaultdict + feats = defaultdict(lambda: 0) + # feats = util.Counter() + feats[(state,action)] = 1.0 + return feats + +class CoordinateExtractor(FeatureExtractor): + def getFeatures(self, state, action): + from collections import defaultdict + feats = defaultdict(lambda: 0) + # feats = util.Counter() + feats[state] = 1.0 + feats['x=%d' % state[0]] = 1.0 + feats['y=%d' % state[0]] = 1.0 + feats['action=%s' % action] = 1.0 + return feats + +def closestFood(pos, food, walls): + """ + closestFood -- this is similar to the function that we have + worked on in the search project; here its all in one place + """ + fringe = [(pos[0], pos[1], 0)] + expanded = set() + while fringe: + pos_x, pos_y, dist = fringe.pop(0) + if (pos_x, pos_y) in expanded: + continue + expanded.add((pos_x, pos_y)) + # if we find a food at this location then exit + if food[pos_x][pos_y]: + return dist + # otherwise spread out from the location to its neighbours + nbrs = Actions.getLegalNeighbors((pos_x, pos_y), walls) + for nbr_x, nbr_y in nbrs: + fringe.append((nbr_x, nbr_y, dist+1)) + # no food found + return None + +class SimpleExtractor(FeatureExtractor): + """ + Returns simple features for a basic reflex Pacman: + - whether food will be eaten + - how far away the next food is + - whether a ghost collision is imminent + - whether a ghost is one step away + """ + + def getFeatures(self, state, action): + # extract the grid of food and wall locations and get the ghost locations + food = state.getFood() + walls = state.getWalls() + ghosts = state.getGhostPositions() + + from collections import defaultdict + features = defaultdict(lambda: 0) + + # features = util.Counter() + + features["bias"] = 1.0 + + # compute the location of pacman after he takes the action + x, y = state.getPacmanPosition() + dx, dy = Actions.directionToVector(action) + next_x, next_y = int(x + dx), int(y + dy) + + # count the number of ghosts 1-step away + features["#-of-ghosts-1-step-away"] = sum((next_x, next_y) in Actions.getLegalNeighbors(g, walls) for g in ghosts) + + # if there is no danger of ghosts then add the food feature + if not features["#-of-ghosts-1-step-away"] and food[next_x][next_y]: + features["eats-food"] = 1.0 + + dist = closestFood((next_x, next_y), food, walls) + if dist is not None: + # make the distance a number less than one otherwise the update + # will diverge wildly + features["closest-food"] = float(dist) / (walls.width * walls.height) + # features.divideAll(10.0) + features = {k: v/10.0 for k, v in features.items() } + return features diff --git a/irlc/pacman/gamestate.py b/irlc/pacman/gamestate.py new file mode 100644 index 0000000..c75db5f --- /dev/null +++ b/irlc/pacman/gamestate.py @@ -0,0 +1,812 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# gamestate.py +# --------- +# Licensing Information: You are free to use or extend these projects for +# educational purposes provided that (1) you do not distribute or publish +# solutions, (2) you retain this notice, and (3) you provide clear +# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. +# +# Attribution Information: The Pacman AI projects were developed at UC Berkeley. +# The core projects and autograders were primarily created by John DeNero +# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). +# Student side autograding was added by Brad Miller, Nick Hay, and +# Pieter Abbeel (pabbeel@cs.berkeley.edu). + + +""" +Pacman.py holds the logic for the classic pacman game along with the main +code to run a game. This file is divided into three sections: + + (i) Your interface to the pacman world: + Pacman is a complex environment. You probably don't want to + read through all of the code we wrote to make the game runs + correctly. This section contains the parts of the code + that you will need to understand in order to complete the + project. There is also some code in pacman_utils.py that you should + understand. + + (ii) The hidden secrets of pacman: + This section contains all of the logic code that the pacman + environment uses to decide who can move where, who dies when + things collide, etc. You shouldn't need to read this section + of code, but you can if you want. + + (iii) Framework to start a game: + The final section contains the code for reading the command + you use to set up the game, then starting up a new game, along with + linking in all the external parts (agent functions, graphics). + Check this section out to see all the options available to you. + +To play your first game, type 'python gamestate.py' from the command line. +The keys are 'a', 's', 'd', and 'w' to move (or arrow keys). Have fun! +""" +import irlc.pacman.pacman_utils +from irlc.pacman.pacman_utils import GameStateData +from irlc.pacman.pacman_utils import Game +from irlc.pacman.pacman_utils import Directions +from irlc.pacman.pacman_utils import Actions + + +################################################### +# YOUR INTERFACE TO THE PACMAN WORLD: A GameState # +################################################### + +class GameState: + r""" + A `GameState` specifies the full game state, including the food, capsules, + agent configurations and score changes. + + `GameState`\ s are used by the Game object to capture the actual state of the game and + can be used by agents to reason about the game. + + Much of the information in a GameState is stored in a `GameStateData` object. We + strongly suggest that you access that data via the accessor methods below rather + than referring to the `GameStateData` object directly. + + Note that in classic Pacman, Pacman is always agent 0. + + To get you started, here are some examples. + + .. runblock:: pycon + + >>> from irlc.pacman.pacman_environment import PacmanEnvironment, very_small_haunted_maze + >>> env = PacmanEnvironment(layout_str=very_small_haunted_maze) + >>> state, _ = env.reset() # Get starting state + >>> print(state) + + In the above code, `state` is a `GameState` instance -- i.e. has all the methods found in + *this* class. So for instance to know if the game is won or lost you can do: + + .. runblock:: pycon + + >>> from irlc.pacman.pacman_environment import PacmanEnvironment, very_small_haunted_maze + >>> env = PacmanEnvironment(layout_str=very_small_haunted_maze) + >>> state, _ = env.reset() # Get starting state + >>> print("Did we win?", state.is_won(), "did we loose?", state.is_lost()) + + Or to get the available actions, and then the *next* state representing what occurs when you take an action `a`: + + .. runblock:: pycon + + >>> from irlc.pacman.pacman_environment import PacmanEnvironment, very_small_haunted_maze + >>> env = PacmanEnvironment(layout_str=very_small_haunted_maze) + >>> state, _ = env.reset() # Get starting state + >>> actions = state.A() + >>> print("Available actions are", actions) + >>> next_state = state.f(actions[0]) # Take the first action + >>> print(next_state) # Result of taking the first of the available actions. + + When a ghost move, it will select randomly between the available actions. Thus, the chance of a single move is :python:`1/len(state.A())`. + """ + ##################################################### + # 02465-relevant stuff: These methods allows you to # + # interact with the game-state. See comments above. # + ##################################################### + + def player(self) -> int: + """Return the current player. + + The players take turns. Initially ``player=0``, meaning it is Pacman (your) turn, and in case there are ghosts + player will then increment until all ghosts have moved at which point ``player = 0`` again and the game is ready + for the next step. + + :return: The id of the player who will make the next move. + """ + return self._player + + def players(self): + """Return the total number of players. + + :return: Return the number of ghosts + 1 (pacman). + """ + return self.getNumAgents() + + def A(self): + """Return the available actions for the current player in this state. + + If the state is won/lost, the actions will be just the stop-action: ``["Stop"]``. + + :return: Available actions as a list. + """ + if self.is_won() or self.is_lost(): + return [Directions.STOP] + else: + return self.getLegalActions(self.player()) + + def f(self, a : str) -> object: + """Let the current player take action ``a``. + + This will return a new GameState corresponding to the current player taking an action. + + :param a: The action to take. + :return: The next GameState. + """ + if self.is_won() or self.is_lost(): + return self + + suc = self.generateSuccessor(self.player(), a) + suc._player = (self.player() + 1) % self.getNumAgents() + return suc + + def is_lost(self): + """Determine if this is a lost game. + + :return: ``True`` if this GameState corresponds to a lost game (a ghost ate pacman) + """ + return self.data._lose + + def is_won(self): + """Determine if this is a won game. + + :return: ``True`` if this GameState corresponds to a won game (all pellets eaten) + """ + return self.data._win + + ################################################################################################## + # End of 02465-related stuff. These methods are internal to the game and should **not** be used. # + ################################################################################################## + + # static variable keeps track of which states have had getLegalActions called + explored = set() + def getAndResetExplored(): + tmp = GameState.explored.copy() + GameState.explored = set() + return tmp + getAndResetExplored = staticmethod(getAndResetExplored) + + def getLegalActions( self, agentIndex=0 ): + # """ + # Returns the legal actions for the agent specified. + # """ +# GameState.explored.add(self) + if self.is_won() or self.is_lost(): return [] + + if agentIndex == 0: # Pacman is moving + return PacmanRules.getLegalActions( self ) + else: + return GhostRules.getLegalActions( self, agentIndex ) + + def generateSuccessor( self, agentIndex, action): + # """ + # Returns the successor state after the specified agent takes the action. + # """ + # Check that successors exist + if self.is_won() or self.is_lost(): raise Exception('Can\'t generate a successor of a terminal state.') + + # Copy current state + state = GameState(self) + + # Let agent's logic deal with its action's effects on the board + if agentIndex == 0: # Pacman is moving + state.data._eaten = [False for i in range(state.getNumAgents())] + PacmanRules.applyAction( state, action ) + else: # A ghost is moving + GhostRules.applyAction( state, action, agentIndex ) + + # Time passes + if agentIndex == 0: + state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around + else: + GhostRules.decrementTimer( state.data.agentStates[agentIndex] ) + + # Resolve multi-agent effects + GhostRules.checkDeath( state, agentIndex ) + + # Book keeping + state.data._agentMoved = agentIndex + state.data.score += state.data.scoreChange + GameState.explored.add(self) + GameState.explored.add(state) + return state + + + def getLegalPacmanActions( self ): + return self.getLegalActions( 0 ) + + def generatePacmanSuccessor( self, action ): + # """ + # Generates the successor state after the specified pacman move + # """ + return self.generateSuccessor( 0, action ) + + def getPacmanState( self ): + # """ + # Returns an AgentState object for pacman (in pacman_utils.py) + # + # state.pos gives the current position + # state.direction gives the travel vector + # """ + return self.data.agentStates[0].copy() + + def getPacmanPosition( self ): + return self.data.agentStates[0].getPosition() + + def getGhostStates( self ): + return self.data.agentStates[1:] + + def getGhostState( self, agentIndex ): + if agentIndex == 0 or agentIndex >= self.getNumAgents(): + raise Exception("Invalid index passed to getGhostState") + return self.data.agentStates[agentIndex] + + def getGhostPosition( self, agentIndex ): + if agentIndex == 0: + raise Exception("Pacman's index passed to getGhostPosition") + return self.data.agentStates[agentIndex].getPosition() + + def getGhostPositions(self): + return [s.getPosition() for s in self.getGhostStates()] + + def getNumAgents( self ): + return len( self.data.agentStates ) + + def getScore( self ): + return float(self.data.score) + + def getCapsules(self): + # """ + # Returns a list of positions (x,y) of the remaining capsules. + # """ + return self.data.capsules + + def getNumFood( self ): + return self.data.food.count() + + def getFood(self): + # """ + # Returns a Grid of boolean food indicator variables. + # + # Grids can be accessed via list notation, so to check + # if there is food at (x,y), just call + # + # currentFood = state.getFood() + # if currentFood[x][y] == True: ... + # """ + return self.data.food + + def getWalls(self): + # """ + # Returns a Grid of boolean wall indicator variables. + # + # Grids can be accessed via list notation, so to check + # if there is a wall at (x,y), just call + # + # walls = state.getWalls() + # if walls[x][y] == True: ... + # """ + return self.data.layout.walls + + def hasFood(self, x, y): + return self.data.food[x][y] + + def hasWall(self, x, y): + return self.data.layout.walls[x][y] + + + ############################################# + # Helper methods: # + # You shouldn't need to call these directly # + ############################################# + + def __init__( self, prevState = None): + # """ + # Generates a new state by copying information from its predecessor. + # """ + if prevState != None: # Initial state + self.data = GameStateData(prevState.data) + else: + self.data = GameStateData() + self._player = 0 + + def deepCopy( self ): + state = GameState( self ) + state.data = self.data.deepCopy() + return state + + def __eq__( self, other ): + # """ + # Allows two states to be compared. + # """ + return hasattr(other, 'data') and self.data == other.data + + def __hash__( self ): + # """ + # Allows states to be keys of dictionaries. + # """ + return hash( self.data ) + + def __str__( self ): + return str(self.data) + + def initialize( self, layout, numGhostAgents=1000 ): + # """ + # Creates an initial game state from a layout array (see layout.py). + # """ + self.data.initialize(layout, numGhostAgents) + +############################################################################ +# THE HIDDEN SECRETS OF PACMAN # +# # +# You shouldn't need to look through the code in this section of the file. # +############################################################################ + +SCARED_TIME = 40 # Moves ghosts are scared +COLLISION_TOLERANCE = 0.7 # How close ghosts must be to Pacman to kill +TIME_PENALTY = 1 # Number of points lost each round + +class ClassicGameRules: + """ + These game rules manage the control flow of a game, deciding when + and how the game starts and ends. + """ + def __init__(self, timeout=30): + self.timeout = timeout + + def newGame( self, layout, pacmanAgent, ghostAgents, quiet = False, catchExceptions=False, time_penalty=TIME_PENALTY): + agents = [pacmanAgent] + ghostAgents[:layout.getNumGhosts()] + initState = GameState() # Time penalty is my idea + initState.initialize( layout, len(ghostAgents) ) + game = Game(agents=agents, rules=self, catchExceptions=catchExceptions) + game.state = initState + self.initialState = initState.deepCopy() + self.quiet = quiet + return game + + def process(self, state, game): + """ + Checks to see whether it is time to end the game. + """ + if state.is_won(): self.win(state, game) + if state.is_lost(): self.lose(state, game) + + def win( self, state, game ): + if not self.quiet: print("Pacman emerges victorious! Score: %d" % state.data.score) + game.gameOver = True + + def lose( self, state, game ): + if not self.quiet: print("Pacman died! Score: %d" % state.data.score) + game.gameOver = True + + def getProgress(self, game): + return float(game.state.getNumFood()) / self.initialState.getNumFood() + + def agentCrash(self, game, agentIndex): + if agentIndex == 0: + print("Pacman crashed") + else: + print("A ghost crashed") + + def getMaxTotalTime(self, agentIndex): + return self.timeout + + def getMaxStartupTime(self, agentIndex): + return self.timeout + + def getMoveWarningTime(self, agentIndex): + return self.timeout + + def getMoveTimeout(self, agentIndex): + return self.timeout + + def getMaxTimeWarnings(self, agentIndex): + return 0 + +class PacmanRules: + """ + These functions govern how pacman interacts with his environment under + the classic game rules. + """ + PACMAN_SPEED=1 + + def getLegalActions( state ): + """ + Returns a list of possible actions. + """ + return Actions.getPossibleActions( state.getPacmanState().configuration, state.data.layout.walls ) + getLegalActions = staticmethod( getLegalActions ) + + def applyAction( state, action ): + """ + Edits the state to reflect the results of the action. + """ + legal = PacmanRules.getLegalActions( state ) + if action not in legal: + raise Exception("Illegal action " + str(action)) + + pacmanState = state.data.agentStates[0] + + # Update Configuration + vector = Actions.directionToVector( action, PacmanRules.PACMAN_SPEED ) + pacmanState.configuration = pacmanState.configuration.generateSuccessor( vector ) + + # Eat + next = pacmanState.configuration.getPosition() + nearest = nearestPoint( next ) + if manhattanDistance( nearest, next ) <= 0.5 : + # Remove food + PacmanRules.consume( nearest, state ) + applyAction = staticmethod( applyAction ) + + def consume( position, state ): + x,y = position + # Eat food + if state.data.food[x][y]: + state.data.scoreChange += 10 + state.data.food = state.data.food.copy() + state.data.food[x][y] = False + state.data._foodEaten = position + # TODO: cache numFood? + numFood = state.getNumFood() + if numFood == 0 and not state.data._lose: + state.data.scoreChange += 500 + state.data._win = True + # Eat capsule + if( position in state.getCapsules() ): + state.data.capsules.remove( position ) + state.data._capsuleEaten = position + # Reset all ghosts' scared timers + for index in range( 1, len( state.data.agentStates ) ): + state.data.agentStates[index].scaredTimer = SCARED_TIME + consume = staticmethod( consume ) + +class GhostRules: + """ + These functions dictate how ghosts interact with their environment. + """ + GHOST_SPEED=1.0 + def getLegalActions( state, ghostIndex ): + """ + Ghosts cannot stop, and cannot turn around unless they + reach a dead end, but can turn 90 degrees at intersections. + """ + conf = state.getGhostState( ghostIndex ).configuration + possibleActions = Actions.getPossibleActions( conf, state.data.layout.walls ) + reverse = Actions.reverseDirection( conf.direction ) + if Directions.STOP in possibleActions: + possibleActions.remove( Directions.STOP ) + if reverse in possibleActions and len( possibleActions ) > 1: + possibleActions.remove( reverse ) + return possibleActions + getLegalActions = staticmethod( getLegalActions ) + + def applyAction( state, action, ghostIndex): + + legal = GhostRules.getLegalActions( state, ghostIndex ) + if action not in legal: + raise Exception("Illegal ghost action " + str(action)) + + ghostState = state.data.agentStates[ghostIndex] + speed = GhostRules.GHOST_SPEED + if ghostState.scaredTimer > 0: speed /= 2.0 + vector = Actions.directionToVector( action, speed ) + ghostState.configuration = ghostState.configuration.generateSuccessor( vector ) + applyAction = staticmethod( applyAction ) + + def decrementTimer( ghostState): + timer = ghostState.scaredTimer + if timer == 1: + ghostState.configuration.pos = nearestPoint( ghostState.configuration.pos ) + ghostState.scaredTimer = max( 0, timer - 1 ) + decrementTimer = staticmethod( decrementTimer ) + + def checkDeath( state, agentIndex): + pacmanPosition = state.getPacmanPosition() + if agentIndex == 0: # Pacman just moved; Anyone can kill him + for index in range( 1, len( state.data.agentStates ) ): + ghostState = state.data.agentStates[index] + ghostPosition = ghostState.configuration.getPosition() + if GhostRules.canKill( pacmanPosition, ghostPosition ): + GhostRules.collide( state, ghostState, index ) + else: + ghostState = state.data.agentStates[agentIndex] + ghostPosition = ghostState.configuration.getPosition() + if GhostRules.canKill( pacmanPosition, ghostPosition ): + GhostRules.collide( state, ghostState, agentIndex ) + checkDeath = staticmethod( checkDeath ) + + def collide( state, ghostState, agentIndex): + if ghostState.scaredTimer > 0: + state.data.scoreChange += 200 + GhostRules.placeGhost(state, ghostState) + ghostState.scaredTimer = 0 + # Added for first-person + state.data._eaten[agentIndex] = True + else: + if not state.data._win: + state.data.scoreChange -= 500 + state.data._lose = True + collide = staticmethod( collide ) + + def canKill( pacmanPosition, ghostPosition ): + return manhattanDistance( ghostPosition, pacmanPosition ) <= COLLISION_TOLERANCE + canKill = staticmethod( canKill ) + + def placeGhost(state, ghostState): + ghostState.configuration = ghostState.start + placeGhost = staticmethod( placeGhost ) + +############################# +# FRAMEWORK TO START A GAME # +############################# + +def default(str): + return str + ' [Default: %default]' + +def parseAgentArgs(str): + if str == None: return {} + pieces = str.split(',') + opts = {} + for p in pieces: + if '=' in p: + key, val = p.split('=') + else: + key,val = p, 1 + opts[key] = val + return opts + +# def readCommand( argv ): +# """ +# Processes the command used to run pacman from the command line. +# """ +# from optparse import OptionParser +# usageStr = """ +# USAGE: python gamestate.py <options> +# EXAMPLES: (1) python gamestate.py +# - starts an interactive game +# (2) python gamestate.py --layout smallClassic --zoom 2 +# OR python gamestate.py -l smallClassic -z 2 +# - starts an interactive game on a smaller board, zoomed in +# """ +# parser = OptionParser(usageStr) +# +# parser.add_option('-n', '--numGames', dest='numGames', type='int', +# help=default('the number of GAMES to play'), metavar='GAMES', default=1) +# parser.add_option('-l', '--layout', dest='layout', +# help=default('the LAYOUT_FILE from which to load the map layout'), +# metavar='LAYOUT_FILE', default='mediumClassic') +# parser.add_option('-p', '--pacman', dest='pacman', +# help=default('the agent TYPE in the pacmanAgents module to use'), +# metavar='TYPE', default='KeyboardAgent') +# parser.add_option('-t', '--textGraphics', action='store_true', dest='textGraphics', +# help='Display output as text only', default=False) +# parser.add_option('-q', '--quietTextGraphics', action='store_true', dest='quietGraphics', +# help='Generate minimal output and no graphics', default=False) +# parser.add_option('-g', '--ghosts', dest='ghost', +# help=default('the ghost agent TYPE in the ghostAgents module to use'), +# metavar = 'TYPE', default='RandomGhost') +# parser.add_option('-k', '--numghosts', type='int', dest='numGhosts', +# help=default('The maximum number of ghosts to use'), default=4) +# parser.add_option('-z', '--zoom', type='float', dest='zoom', +# help=default('Zoom the size of the graphics window'), default=1.0) +# parser.add_option('-f', '--fixRandomSeed', action='store_true', dest='fixRandomSeed', +# help='Fixes the random seed to always play the same game', default=False) +# parser.add_option('-r', '--recordActions', action='store_true', dest='record', +# help='Writes game histories to a file (named by the time they were played)', default=False) +# parser.add_option('--replay', dest='gameToReplay', +# help='A recorded game file (pickle) to replay', default=None) +# parser.add_option('-a','--agentArgs',dest='agentArgs', +# help='Comma separated values sent to agent. e.g. "opt1=val1,opt2,opt3=val3"') +# parser.add_option('-x', '--numTraining', dest='numTraining', type='int', +# help=default('How many episodes are training (suppresses output)'), default=0) +# parser.add_option('--frameTime', dest='frameTime', type='float', +# help=default('Time to delay between frames; <0 means keyboard'), default=0.1) +# parser.add_option('-c', '--catchExceptions', action='store_true', dest='catchExceptions', +# help='Turns on exception handling and timeouts during games', default=False) +# parser.add_option('--timeout', dest='timeout', type='int', +# help=default('Maximum length of time an agent can spend computing in a single game'), default=30) +# +# options, otherjunk = parser.parse_args(argv) +# if len(otherjunk) != 0: +# raise Exception('Command line input not understood: ' + str(otherjunk)) +# args = dict() +# +# # Fix the random seed +# if options.fixRandomSeed: random.seed('cs188') +# +# # Choose a layout +# args['layout'] = layout.getLayout( options.layout ) +# if args['layout'] == None: raise Exception("The layout " + options.layout + " cannot be found") +# +# # Choose a Pacman agent +# noKeyboard = options.gameToReplay == None and (options.textGraphics or options.quietGraphics) +# pacmanType = loadAgent(options.pacman, noKeyboard) +# agentOpts = parseAgentArgs(options.agentArgs) +# if options.numTraining > 0: +# args['numTraining'] = options.numTraining +# if 'numTraining' not in agentOpts: agentOpts['numTraining'] = options.numTraining +# pacman = pacmanType(**agentOpts) # Instantiate Pacman with agentArgs +# args['pacman'] = pacman +# +# # Don't display training games +# if 'numTrain' in agentOpts: +# options.numQuiet = int(agentOpts['numTrain']) +# options.numIgnore = int(agentOpts['numTrain']) +# +# # Choose a ghost agent +# ghostType = loadAgent(options.ghost, noKeyboard) +# args['ghosts'] = [ghostType( i+1 ) for i in range( options.numGhosts )] +# +# # Choose a display format +# if options.quietGraphics: +# import text_display_pacman +# args['display'] = text_display_pacman.NullGraphics() +# elif options.textGraphics: +# import text_display_pacman +# text_display_pacman.SLEEP_TIME = options.frameTime +# args['display'] = text_display_pacman.PacmanGraphics() +# else: +# pass +# # from gympackman import ggraphicsDisplay +# # args['display'] = ggraphicsDisplay.PacmanGraphics(options.zoom, frameTime = options.frameTime) +# args['numGames'] = options.numGames +# args['record'] = options.record +# args['catchExceptions'] = options.catchExceptions +# args['timeout'] = options.timeout +# +# # Special case: recorded games don't use the runGames method or args structure +# if options.gameToReplay != None: +# print('Replaying recorded game %s.' % options.gameToReplay) +# import cPickle +# f = open(options.gameToReplay) +# try: recorded = cPickle.load(f) +# finally: f.close() +# recorded['display'] = args['display'] +# replayGame(**recorded) +# sys.exit(0) +# +# args['options'] = options +# return args + +# def loadAgent(pacman, nographics): +# # Looks through all pythonPath Directories for the right module, +# pythonPathStr = os.path.expandvars("$PYTHONPATH") +# if pythonPathStr.find(';') == -1: +# pythonPathDirs = pythonPathStr.split(':') +# else: +# pythonPathDirs = pythonPathStr.split(';') +# pythonPathDirs.append('.') +# from irlc.berkley import pacman as pcman +# pythonPathDirs.append(os.path.dirname(pcman.__file__)) +# if pacman == 'PacmanQAgent': +# from irlc.berkley.pacman.qlearningAgents import QLearningAgent +# return QLearningAgent +# if pacman == 'RandomGhost': +# from irlc.berkley.pacman.ghostAgents import RandomGhost +# return RandomGhost +# +# for moduleDir in pythonPathDirs: +# if not os.path.isdir(moduleDir): continue +# moduleNames = [f for f in os.listdir(moduleDir) if f.endswith('gents.py')] +# print(moduleNames) +# for modulename in moduleNames: +# try: +# module = __import__(modulename[:-3]) +# except ImportError: +# continue +# print(module) +# if pacman in dir(module): +# if nographics and modulename == 'keyboardAgents.py': +# raise Exception('Using the keyboard requires graphics (not text display)') +# return getattr(module, pacman) +# raise Exception('The agent ' + pacman + ' is not specified in any *Agents.py.') + +def replayGame( layout, actions, display ): + import ghostAgents + from irlc.berkley import pacmanAgents + rules = ClassicGameRules() + agents = [pacmanAgents.GreedyAgent()] + [irlc.pacman.pacman_utils.RandomGhost(i + 1) for i in range(layout.getNumGhosts())] + game = rules.newGame( layout, agents[0], agents[1:], display ) + state = game.state + display.initialize(state.data) + + for action in actions: + # Execute the action + state = state.generateSuccessor( *action ) + # Change the display + display.update( state.data ) + # Allow for game specific conditions (winning, losing, etc.) + rules.process(state, game) + + display.finish() + +def runGames( layout, pacman, ghosts, display, numGames, record, numTraining = 0, catchExceptions=False, timeout=30 ): + # import __main__ + # global __main__ + # __main__.__dict__['_display'] = display + + rules = ClassicGameRules(timeout) + games = [] + + for i in range( numGames ): + beQuiet = i < numTraining + if beQuiet: + # Suppress output and graphics + import text_display_pacman + gameDisplay = text_display_pacman.NullGraphics() + rules.quiet = True + else: + gameDisplay = display + rules.quiet = False + game = rules.newGame( layout, pacman, ghosts, gameDisplay, beQuiet, catchExceptions) + game.run() + if not beQuiet: games.append(game) + + if record: + import time, cPickle + fname = ('recorded-game-%d' % (i + 1)) + '-'.join([str(t) for t in time.localtime()[1:6]]) + with open(fname, "w") as f: + # f = file(fname, 'w') + components = {'layout': layout, 'actions': game.moveHistory} + cPickle.dump(components, f) + # f.close() + + if (numGames-numTraining) > 0: + scores = [game.state.getScore() for game in games] + wins = [game.state.is_won() for game in games] + winRate = wins.count(True)/ float(len(wins)) + print('Average Score:', sum(scores) / float(len(scores))) + print('Scores: ', ', '.join([str(score) for score in scores])) + print('Win Rate: %d/%d (%.2f)' % (wins.count(True), len(wins), winRate)) + print('Record: ', ', '.join([ ['Loss', 'Win'][int(w)] for w in wins])) + + return games + +# if __name__ == '__main__': +# """ +# The main function called when gamestate.py is run +# from the command line: +# +# > python gamestate.py +# +# See the usage string for more details. +# +# > python gamestate.py --help +# """ +# import sys +# +# sys.adaptor = 'tk' +# # sys.adaptor = 'gym' +# ss = "-p PacmanQAgent -n 1 -l mediumGrid -a numTraining=100" +# +# sys.argv.extend(ss.split()) +# args = readCommand( sys.argv[1:] ) # Get game components based on input +# runGames( **args ) +# +# # import cProfile +# # cProfile.run("runGames( **args )") +# pass + + +def nearestPoint( pos ): + """ + Finds the nearest grid point to a position (discretizes). + """ + ( current_row, current_col ) = pos + + grid_row = int( current_row + 0.5 ) + grid_col = int( current_col + 0.5 ) + return ( grid_row, grid_col ) + +def manhattanDistance( xy1, xy2 ): + "Returns the Manhattan distance between points xy1 and xy2" + return abs( xy1[0] - xy2[0] ) + abs( xy1[1] - xy2[1] ) diff --git a/irlc/pacman/layout.py b/irlc/pacman/layout.py new file mode 100644 index 0000000..92413e0 --- /dev/null +++ b/irlc/pacman/layout.py @@ -0,0 +1,157 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# layout.py +# --------- +# Licensing Information: You are free to use or extend these projects for +# educational purposes provided that (1) you do not distribute or publish +# solutions, (2) you retain this notice, and (3) you provide clear +# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. +# +# Attribution Information: The Pacman AI projects were developed at UC Berkeley. +# The core projects and autograders were primarily created by John DeNero +# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). +# Student side autograding was added by Brad Miller, Nick Hay, and +# Pieter Abbeel (pabbeel@cs.berkeley.edu). + + +# from irlc.berkley.util import manhattanDistance +from irlc.pacman.pacman_utils import Grid +import os +import random + +VISIBILITY_MATRIX_CACHE = {} + +def manhattanDistance( xy1, xy2 ): + "Returns the Manhattan distance between points xy1 and xy2" + return abs( xy1[0] - xy2[0] ) + abs( xy1[1] - xy2[1] ) + +class Layout: + """ + A Layout manages the static information about the game board. + """ + + def __init__(self, layoutText): + self.width = len(layoutText[0]) + self.height= len(layoutText) + self.walls = Grid(self.width, self.height, False) + self.food = Grid(self.width, self.height, False) + self.capsules = [] + self.agentPositions = [] + self.numGhosts = 0 + self.processLayoutText(layoutText) + self.layoutText = layoutText + self.totalFood = len(self.food.asList()) + # self.initializeVisibilityMatrix() + + def getNumGhosts(self): + return self.numGhosts + + # def initializeVisibilityMatrix(self): + # global VISIBILITY_MATRIX_CACHE + # if reduce(str.__add__, self.layoutText) not in VISIBILITY_MATRIX_CACHE: + # from game import Directions + # vecs = [(-0.5,0), (0.5,0),(0,-0.5),(0,0.5)] + # dirs = [Directions.NORTH, Directions.SOUTH, Directions.WEST, Directions.EAST] + # vis = Grid(self.width, self.height, {Directions.NORTH:set(), Directions.SOUTH:set(), Directions.EAST:set(), Directions.WEST:set(), Directions.STOP:set()}) + # for x in range(self.width): + # for y in range(self.height): + # if self.walls[x][y] == False: + # for vec, direction in zip(vecs, dirs): + # dx, dy = vec + # nextx, nexty = x + dx, y + dy + # while (nextx + nexty) != int(nextx) + int(nexty) or not self.walls[int(nextx)][int(nexty)] : + # vis[x][y][direction].add((nextx, nexty)) + # nextx, nexty = x + dx, y + dy + # self.visibility = vis + # VISIBILITY_MATRIX_CACHE[reduce(str.__add__, self.layoutText)] = vis + # else: + # self.visibility = VISIBILITY_MATRIX_CACHE[reduce(str.__add__, self.layoutText)] + + def isWall(self, pos): + x, col = pos + return self.walls[x][col] + + def getRandomLegalPosition(self): + x = random.choice(range(self.width)) + y = random.choice(range(self.height)) + while self.isWall( (x, y) ): + x = random.choice(range(self.width)) + y = random.choice(range(self.height)) + return (x,y) + + def getRandomCorner(self): + poses = [(1,1), (1, self.height - 2), (self.width - 2, 1), (self.width - 2, self.height - 2)] + return random.choice(poses) + + def getFurthestCorner(self, pacPos): + poses = [(1,1), (1, self.height - 2), (self.width - 2, 1), (self.width - 2, self.height - 2)] + dist, pos = max([(manhattanDistance(p, pacPos), p) for p in poses]) + return pos + + # def isVisibleFrom(self, ghostPos, pacPos, pacDirection): + # row, col = [int(x) for x in pacPos] + # return ghostPos in self.visibility[row][col][pacDirection] + + def __str__(self): + return "\n".join(self.layoutText) + + def deepCopy(self): + return Layout(self.layoutText[:]) + + def processLayoutText(self, layoutText): + """ + Coordinates are flipped from the input format to the (x,y) convention here + + The shape of the maze. Each character + represents a different type of object. + % - Wall + . - Food + o - Capsule + G - Ghost + P - Pacman + Other characters are ignored. + """ + maxY = self.height - 1 + for y in range(self.height): + for x in range(self.width): + layoutChar = layoutText[maxY - y][x] + self.processLayoutChar(x, y, layoutChar) + self.agentPositions.sort() + self.agentPositions = [ ( i == 0, pos) for i, pos in self.agentPositions] + + def processLayoutChar(self, x, y, layoutChar): + if layoutChar == '%': + self.walls[x][y] = True + elif layoutChar == '.': + self.food[x][y] = True + elif layoutChar == 'o': + self.capsules.append((x, y)) + elif layoutChar == 'P': + self.agentPositions.append( (0, (x, y) ) ) + elif layoutChar in ['G']: + self.agentPositions.append( (1, (x, y) ) ) + self.numGhosts += 1 + elif layoutChar in ['1', '2', '3', '4']: + self.agentPositions.append( (int(layoutChar), (x,y))) + self.numGhosts += 1 +def getLayout(name, back = 2): + if name.endswith('.lay'): + layout = tryToLoad('layouts/' + name) + if layout == None: layout = tryToLoad(name) + else: + layout = tryToLoad('layouts/' + name + '.lay') + if layout == None: layout = tryToLoad(name + '.lay') + if layout == None and back >= 0: + curdir = os.path.abspath('.') + os.chdir('..') + layout = getLayout(name, back -1) + os.chdir(curdir) + return layout + +def tryToLoad(fullname): + import pathlib + fullname = os.path.join(fullname, pathlib.Path(__file__).parent.absolute(), fullname) + if(not os.path.exists(fullname)): return None + # os.path.abspath(fullname) + f = open(fullname) + try: return Layout([line.strip() for line in f]) + finally: f.close() diff --git a/irlc/pacman/layouts/bigCorners.lay b/irlc/pacman/layouts/bigCorners.lay new file mode 100644 index 0000000..4d89d7b --- /dev/null +++ b/irlc/pacman/layouts/bigCorners.lay @@ -0,0 +1,37 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%. % %.% +% %%%%% % %%% %%% %%%%%%% % % +% % % % % % % % +%%%%% %%%%% %%% % % % %%% %%%%% % %%% +% % % % % % % % % % % % % +% %%% % % % %%% %%%%% %%% % %%% %%% % +% % % % % % % % % +%%% %%%%%%%%% %%%%%%% %%% %%% % % % % +% % % % % % % +% % %%%%% % %%% % % %%% % %%% %%% % % +% % % % % % % % % % % % % % +% % % %%%%%%% % %%%%%%%%% %%% % %%% % +% % % % % % % % % % +%%% %%% % %%%%% %%%%% %%% %%% %%%%% % +% % % % % % % % % +% % % % % % %%% %%% %%% % % % % % % +% % % % % %% % % % % % % % % % +% % %%%%% % %%% %%% % %%% %%% %%%%% +% % % % % % % % % % % +% %%% % % % %%% %%% %%%%%%%%% % %%% +% % % % % % % +% %%% %%%%%%%%%%%%%%%%%%%%% % % %%% % +% % % % +% % % %%%%% %%% % % % % %%%%%%%%%%%%% +% % % % % % % % % % % % +% % %%% %%% % % % %%%%%%%%% %%% % % % +% % % % % % %P % % % % % % +% %%% %%% %%% % %%% % % %%%%% % %%%%% +% % % % % % % % +%%% % %%%%% %%%%% %%% %%% % %%% % %%% +% % % % % % % % % % % % % % % +% % %%% % % % % %%%%%%%%% % % % % % % +% % % % +% % % %%% %%% %%%%%%% %%% %%% %%% % +%.% % % % % .% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/irlc/pacman/layouts/bigHunt.lay b/irlc/pacman/layouts/bigHunt.lay new file mode 100644 index 0000000..48ccd0c --- /dev/null +++ b/irlc/pacman/layouts/bigHunt.lay @@ -0,0 +1,20 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%% +%P % +% %%%%%%%%%%%% %%% % +% %% % +% %% % +% % % % +% %%%%%% %%% %% % %G% +% %%%%%% +% %%%%%% % % % +% % % % % +% % G % % %%%%%%%% % +% % % % % +% % % % %%%%%%%% % +% % G % +% %% % %% %% % +% %% % % +% G% % +%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % % % %%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/irlc/pacman/layouts/bigMaze.lay b/irlc/pacman/layouts/bigMaze.lay new file mode 100644 index 0000000..e11fade --- /dev/null +++ b/irlc/pacman/layouts/bigMaze.lay @@ -0,0 +1,37 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % % % % % % % +% %%%%%%% % %%% % %%% %%% %%%%%%% % % +% % % % % % % % +%%%%% %%%%% %%% % % % %%% %%%%% % %%% +% % % % % % % % % % % % % % +% %%% % % % %%% %%%%% %%% % %%% %%% % +% % % % % % % % % +%%% %%%%%%%%% %%%%%%% %%% %%% % % % % +% % % % % % % +% % %%%%% % %%% % % %%% % %%% %%% % % +% % % % % % % % % % % % % % +% % % %%%%%%% % %%%%%%%%% %%% % %%% % +% % % % % % % % % % +%%% %%% % %%%%% %%%%% %%% %%% %%%%% % +% % % % % % % % % % % % +% % % % % %%% %%% %%% %%% % % % % % % +% % % % % % % % % +%%% %%%%%%% % % %%%%% %%% % %%% %%%%% +% % % % % % % % % % +%%%%% % % %%%%%%%%% %%%%%%%%%%% % %%% +% % % % % % % % % +% %%% %%%%% %%%%%%%%% %%%%% % % %%% % +% % % % % % % +% % % %%%%% %%% % % % % %%%%%%%%%%%%% +% % % % % % % % % % % % +% % %%% %%% % % % %%%%%%%%% %%% % % % +% % % % % % % % % % % % % +% %%% %%% %%%%% %%% % % %%%%% % %%%%% +% % % % % % % % % +%%% % %%%%% %%%%% %%% %%% % %%% % %%% +% % % % % % % % % % % % % % % +% % %%% % % % % %%%%%%%%% % % % % % % +% % % % % % +% % % % %%% %%% %%%%%%% %%% %%% %%% % +%.% % % % % % % % P% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/irlc/pacman/layouts/bigSafeSearch.lay b/irlc/pacman/layouts/bigSafeSearch.lay new file mode 100644 index 0000000..b5fd414 --- /dev/null +++ b/irlc/pacman/layouts/bigSafeSearch.lay @@ -0,0 +1,8 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%.%.........%% G % o%%%%.....% +%.%.%%%%%%%.%%%%%% %%%%%%%.%%.% +%............%...%............% +%%%%%...%%%.. ..%.%...%.%%% +%o%%%.%%%%%.%%%%%%%.%%%.%.%%%%% +% ..........Po...%...%. o% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/bigSearch.lay b/irlc/pacman/layouts/bigSearch.lay new file mode 100644 index 0000000..bb59eb8 --- /dev/null +++ b/irlc/pacman/layouts/bigSearch.lay @@ -0,0 +1,15 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%.....%.................%.....% +%.%%%.%.%%%.%%%%%%%.%%%.%.....% +%.%...%.%......%......%.%.....% +%...%%%.%.%%%%.%.%%%%...%%%...% +%%%.%.%.%.%......%..%.%...%.%%% +%...%.%%%.%.%%% %%%.%.%%%.%...% +%.%%%.......% %.......%%%.% +%...%.%%%%%.%%%%%%%.%.%%%.%...% +%%%.%...%.%....%....%.%...%.%%% +%...%%%.%.%%%%.%.%%%%.%.%%%...% +%.......%......%......%.....%.% +%.....%.%%%.%%%%%%%.%%%.%.%%%.% +%.....%........P....%...%.....% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/boxSearch.lay b/irlc/pacman/layouts/boxSearch.lay new file mode 100644 index 0000000..4a113fc --- /dev/null +++ b/irlc/pacman/layouts/boxSearch.lay @@ -0,0 +1,14 @@ +%%%%%%%%%%%%%% +%. . . . . % % +% % % +%. . . . . %G% +% % % +%. . . . . % % +% % % +%. . . . . % % +% P %G% +%. . . . . % % +% % % +%. . . . . % % +% % % +%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/capsuleClassic.lay b/irlc/pacman/layouts/capsuleClassic.lay new file mode 100644 index 0000000..06a5c51 --- /dev/null +++ b/irlc/pacman/layouts/capsuleClassic.lay @@ -0,0 +1,7 @@ +%%%%%%%%%%%%%%%%%%% +%G. G ....% +%.% % %%%%%% %.%%.% +%.%o% % o% %.o%.% +%.%%%.% %%% %..%.% +%..... P %..%G% +%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/contestClassic.lay b/irlc/pacman/layouts/contestClassic.lay new file mode 100644 index 0000000..84c8733 --- /dev/null +++ b/irlc/pacman/layouts/contestClassic.lay @@ -0,0 +1,9 @@ +%%%%%%%%%%%%%%%%%%%% +%o...%........%...o% +%.%%.%.%%..%%.%.%%.% +%...... G GG%......% +%.%.%%.%% %%%.%%.%.% +%.%....% ooo%.%..%.% +%.%.%%.% %% %.%.%%.% +%o%......P....%....% +%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/contoursMaze.lay b/irlc/pacman/layouts/contoursMaze.lay new file mode 100644 index 0000000..a068956 --- /dev/null +++ b/irlc/pacman/layouts/contoursMaze.lay @@ -0,0 +1,11 @@ +%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% % +% P % +% % +% % +% % +%. % +%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/irlc/pacman/layouts/greedySearch.lay b/irlc/pacman/layouts/greedySearch.lay new file mode 100644 index 0000000..4072363 --- /dev/null +++ b/irlc/pacman/layouts/greedySearch.lay @@ -0,0 +1,8 @@ +%%%%%% +%....% +% %%.% +% %%.% +%.P .% +%.%%%% +%....% +%%%%%% \ No newline at end of file diff --git a/irlc/pacman/layouts/mediumClassic.lay b/irlc/pacman/layouts/mediumClassic.lay new file mode 100644 index 0000000..33c5db8 --- /dev/null +++ b/irlc/pacman/layouts/mediumClassic.lay @@ -0,0 +1,11 @@ +%%%%%%%%%%%%%%%%%%%% +%o...%........%....% +%.%%.%.%%%%%%.%.%%.% +%.%..............%.% +%.%.%%.%% %%.%%.%.% +%......%G G%......% +%.%.%%.%%%%%%.%%.%.% +%.%..............%.% +%.%%.%.%%%%%%.%.%%.% +%....%...P....%...o% +%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/mediumCorners.lay b/irlc/pacman/layouts/mediumCorners.lay new file mode 100644 index 0000000..6a39756 --- /dev/null +++ b/irlc/pacman/layouts/mediumCorners.lay @@ -0,0 +1,14 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%. % % % %.% +% % % %%%%%% %%%%%%% % % +% % % % % % +%%%%% %%%%% %%% %% %%%%% % %%% +% % % % % % % % % +% %%% % % % %%%%%%%% %%% %%% % +% % %% % % % % +%%% % %%%%%%% %%%% %%% % % % % +% % %% % % % +% % %%%%% % %%%% % %%% %%% % % +% % % % % % %%% % +%. %P%%%%% % %%% % .% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/irlc/pacman/layouts/mediumDottedMaze.lay b/irlc/pacman/layouts/mediumDottedMaze.lay new file mode 100644 index 0000000..103f818 --- /dev/null +++ b/irlc/pacman/layouts/mediumDottedMaze.lay @@ -0,0 +1,18 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% P% +% %%%%%%%%%%%%%%%%%%% %%% %%%%%%%% % +% %% % % %%% %%% %% ... % +% %% % % % % %%%% %%%%%%%%% %% %%%%% +% %% % % % % % %% %% %% ... % +% %% % % % % % %%%% %%% %%%%%% % +% % % % % % %% %%%%%%%% ... % +% %% % % %%%%%%%% %% %% %%%%% +% %% % %% %%%%%%%%% %% ... % +% %%%%%% %%%%%%% %% %%%%%% % +%%%%%% % %%%% %% % ... % +% %%%%%% %%%%% % %% %% %%%%% +% %%%%%% % %%%%% %% % +% %%%%%% %%%%%%%%%%% %% %% % +%%%%%%%%%% %%%%%% % +%. %%%%%%%%%%%%%%%% ...... % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/irlc/pacman/layouts/mediumGrid.lay b/irlc/pacman/layouts/mediumGrid.lay new file mode 100644 index 0000000..52b2707 --- /dev/null +++ b/irlc/pacman/layouts/mediumGrid.lay @@ -0,0 +1,7 @@ +%%%%%%%% +%P % +% .% . % +% % % +% .% . % +% G% +%%%%%%%% diff --git a/irlc/pacman/layouts/mediumMaze.lay b/irlc/pacman/layouts/mediumMaze.lay new file mode 100644 index 0000000..55c1236 --- /dev/null +++ b/irlc/pacman/layouts/mediumMaze.lay @@ -0,0 +1,18 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% P% +% %%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% % +% %% % % %%%%%%% %% % +% %% % % % % %%%% %%%%%%%%% %% %%%%% +% %% % % % % %% %% % +% %% % % % % % %%%% %%% %%%%%% % +% % % % % % %% %%%%%%%% % +% %% % % %%%%%%%% %% %% %%%%% +% %% % %% %%%%%%%%% %% % +% %%%%%% %%%%%%% %% %%%%%% % +%%%%%% % %%%% %% % % +% %%%%%% %%%%% % %% %% %%%%% +% %%%%%% % %%%%% %% % +% %%%%%% %%%%%%%%%%% %% %% % +%%%%%%%%%% %%%%%% % +%. %%%%%%%%%%%%%%%% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/irlc/pacman/layouts/mediumSafeSearch.lay b/irlc/pacman/layouts/mediumSafeSearch.lay new file mode 100644 index 0000000..e7d6b1c --- /dev/null +++ b/irlc/pacman/layouts/mediumSafeSearch.lay @@ -0,0 +1,6 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%.% ....%% G %%%%%% o%%.% +%.%o%%%%%%%.%%%%%%% %%%%%.% +% %%%.%%%%%.%%%%%%%.%%%.%.%%%.% +% ..........Po...%.........% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/mediumScaryMaze.lay b/irlc/pacman/layouts/mediumScaryMaze.lay new file mode 100644 index 0000000..65d4c33 --- /dev/null +++ b/irlc/pacman/layouts/mediumScaryMaze.lay @@ -0,0 +1,18 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% P% +% %%%%%%%%%%%%%%%%%%% %%% %%%%%%%% % +% %% % % %%% %%% %%GG % +% %% % % % % %%%% %%%%%%%%% %% %%%%% +% %% % % % % % %%GG %% % +% %% % % % % % %%%%% %%% %%%%%% % +% %% % % % % %% %%%%%%%%% % +% %% % % %%%%%%%% %% %% %%%%% +% %% % %% %%%%%%%%% %% % +% %%% %% %%%%%%% %% %%%%%% % +%%%%%% % % %% %% % +% %%%%%% %% %% %% %% %%%%% +% %%%%%% % %%%%% %% % +% %%%% %%%%% %%%%%% % +%%%%%%%% % %%%%%% % +%. %%%%%%%%%%%%%%%% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/irlc/pacman/layouts/mediumSearch.lay b/irlc/pacman/layouts/mediumSearch.lay new file mode 100644 index 0000000..2f8af42 --- /dev/null +++ b/irlc/pacman/layouts/mediumSearch.lay @@ -0,0 +1,8 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%............%%%%%............% +%%%.%...%%%.........%.%...%.%%% +%...%%%.%.%%%%.%.%%%%%%.%%%...% +%.%.....%......%......%.....%.% +%.%%%.%%%%%.%%%%%%%.%%%.%.%%%%% +%.....%........P....%...%.....% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/minimaxClassic.lay b/irlc/pacman/layouts/minimaxClassic.lay new file mode 100644 index 0000000..a547397 --- /dev/null +++ b/irlc/pacman/layouts/minimaxClassic.lay @@ -0,0 +1,5 @@ +%%%%%%%%% +%.P G% +% %.%G%%% +%G %%% +%%%%%%%%% diff --git a/irlc/pacman/layouts/oddSearch.lay b/irlc/pacman/layouts/oddSearch.lay new file mode 100644 index 0000000..2ddbc9a --- /dev/null +++ b/irlc/pacman/layouts/oddSearch.lay @@ -0,0 +1,7 @@ +%%%%%%%%%%%%%%%%%%%% +%...%.........%%...% +%.%.%.%%%%%%%%%%.%.% +%..................% +%%%%%%%%.%.%%%%%%%P% +%%%%%%%%....... % +%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/oneHunt.lay b/irlc/pacman/layouts/oneHunt.lay new file mode 100644 index 0000000..45291a9 --- /dev/null +++ b/irlc/pacman/layouts/oneHunt.lay @@ -0,0 +1,16 @@ +%%%%%%%%%%%%%%%%%%%% +% % +% % +% G G % +% % +% P % +% % +% % +% % +% G G % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%% +% % % % %%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/irlc/pacman/layouts/openClassic.lay b/irlc/pacman/layouts/openClassic.lay new file mode 100644 index 0000000..6760b42 --- /dev/null +++ b/irlc/pacman/layouts/openClassic.lay @@ -0,0 +1,9 @@ +%%%%%%%%%%%%%%%%%%%%%%%%% +%.. P .... .... % +%.. ... ... ... ... % +%.. ... ... ... ... % +%.. .... .... G % +%.. ... ... ... ... % +%.. ... ... ... ... % +%.. .... .... o% +%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/openHunt.lay b/irlc/pacman/layouts/openHunt.lay new file mode 100644 index 0000000..45d3388 --- /dev/null +++ b/irlc/pacman/layouts/openHunt.lay @@ -0,0 +1,13 @@ +%%%%%%%%%%%%%%%%%%%% +%P G % +% %%% %%% %% %%% % +% G % +% % % +% % % +% %%%%%% %%%G%%% % +% G % +% % % +% % % +%%%%%%%%%%%%%%%%%%%% +% % % % %%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/openMaze.lay b/irlc/pacman/layouts/openMaze.lay new file mode 100644 index 0000000..5dee689 --- /dev/null +++ b/irlc/pacman/layouts/openMaze.lay @@ -0,0 +1,23 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% P% +% % % +% % % +% % % +% % % +% % % +% % % % +% % % % +% % % % +% % % % +% % % % +% % % % +% % % % +%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%% +% % % +% % % +% % % +% % +% % +% % +%. % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/irlc/pacman/layouts/openSearch.lay b/irlc/pacman/layouts/openSearch.lay new file mode 100644 index 0000000..f02d21d --- /dev/null +++ b/irlc/pacman/layouts/openSearch.lay @@ -0,0 +1,7 @@ +%%%%%%%%%%%%%%%%%%%% +%..................% +%..................% +%........P.........% +%..................% +%..................% +%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/originalClassic.lay b/irlc/pacman/layouts/originalClassic.lay new file mode 100644 index 0000000..b2770c5 --- /dev/null +++ b/irlc/pacman/layouts/originalClassic.lay @@ -0,0 +1,27 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%............%%............% +%.%%%%.%%%%%.%%.%%%%%.%%%%.% +%o%%%%.%%%%%.%%.%%%%%.%%%%o% +%.%%%%.%%%%%.%%.%%%%%.%%%%.% +%..........................% +%.%%%%.%%.%%%%%%%%.%%.%%%%.% +%.%%%%.%%.%%%%%%%%.%%.%%%%.% +%......%%....%%....%%......% +%%%%%%.%%%%% %% %%%%%.%%%%%% +%%%%%%.%%%%% %% %%%%%.%%%%%% +%%%%%%.% %.%%%%%% +%%%%%%.% %%%% %%%% %.%%%%%% +% . %G GG G% . % +%%%%%%.% %%%%%%%%%% %.%%%%%% +%%%%%%.% %.%%%%%% +%%%%%%.% %%%%%%%%%% %.%%%%%% +%............%%............% +%.%%%%.%%%%%.%%.%%%%%.%%%%.% +%.%%%%.%%%%%.%%.%%%%%.%%%%.% +%o..%%....... .......%%..o% +%%%.%%.%%.%%%%%%%%.%%.%%.%%% +%%%.%%.%%.%%%%%%%%.%%.%%.%%% +%......%%....%%....%%......% +%.%%%%%%%%%%.%%.%%%%%%%%%%.% +%.............P............% +%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/powerClassic.lay b/irlc/pacman/layouts/powerClassic.lay new file mode 100644 index 0000000..3f3d983 --- /dev/null +++ b/irlc/pacman/layouts/powerClassic.lay @@ -0,0 +1,7 @@ +%%%%%%%%%%%%%%%%%%%% +%o....o%GGGG%o....o% +%..%...%% %%...%..% +%.%o.%........%.o%.% +%.o%.%.%%%%%%.%.%o.% +%........P.........% +%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/smallClassic.lay b/irlc/pacman/layouts/smallClassic.lay new file mode 100644 index 0000000..ce6c1d9 --- /dev/null +++ b/irlc/pacman/layouts/smallClassic.lay @@ -0,0 +1,7 @@ +%%%%%%%%%%%%%%%%%%%% +%......%G G%......% +%.%%...%% %%...%%.% +%.%o.%........%.o%.% +%.%%.%.%%%%%%.%.%%.% +%........P.........% +%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/smallGrid.lay b/irlc/pacman/layouts/smallGrid.lay new file mode 100644 index 0000000..4bbe2b6 --- /dev/null +++ b/irlc/pacman/layouts/smallGrid.lay @@ -0,0 +1,7 @@ +%%%%%%% +% P % +% %%% % +% %. % +% %%% % +%. G % +%%%%%%% diff --git a/irlc/pacman/layouts/smallHunt.lay b/irlc/pacman/layouts/smallHunt.lay new file mode 100644 index 0000000..ef9059a --- /dev/null +++ b/irlc/pacman/layouts/smallHunt.lay @@ -0,0 +1,8 @@ +%%%%%%%%%%%%%%%%%%%% +%P G G % +% %%%%% %%%%%% % % % +% G % +% G % +%%%%%%%%%%%%%%%%%%%% +% % % % %%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/smallMaze.lay b/irlc/pacman/layouts/smallMaze.lay new file mode 100644 index 0000000..72d3ffc --- /dev/null +++ b/irlc/pacman/layouts/smallMaze.lay @@ -0,0 +1,10 @@ +%%%%%%%%%%%%%%%%%%%%%% +% %% % % % +% %%%%%% % %%%%%% % +%%%%%% P % % +% % %%%%%% %% %%%%% +% %%%% % % % +% %%% %%% % % +%%%%%%%%%% %%%%%% % +%. %% % +%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/irlc/pacman/layouts/smallSafeSearch.lay b/irlc/pacman/layouts/smallSafeSearch.lay new file mode 100644 index 0000000..b97feaa --- /dev/null +++ b/irlc/pacman/layouts/smallSafeSearch.lay @@ -0,0 +1,15 @@ +%%%%%%%%% +%.. % G % +%%% %%%%% +% % +%%%%%%% % +% % +% %%%%% % +% % % +%%%%% % % +% %o% +% %%%%%%% +% .% +%%%%%%%.% +%Po .% +%%%%%%%%% diff --git a/irlc/pacman/layouts/smallSearch.lay b/irlc/pacman/layouts/smallSearch.lay new file mode 100644 index 0000000..c2321d4 --- /dev/null +++ b/irlc/pacman/layouts/smallSearch.lay @@ -0,0 +1,5 @@ +%%%%%%%%%%%%%%%%%%%% +%. ...P .% +%.%%.%%.%%.%%.%% %.% +% %% %..... %.% +%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/testClassic.lay b/irlc/pacman/layouts/testClassic.lay new file mode 100644 index 0000000..4b3ffca --- /dev/null +++ b/irlc/pacman/layouts/testClassic.lay @@ -0,0 +1,10 @@ +%%%%% +% . % +%.G.% +% . % +%. .% +% % +% .% +% % +%P .% +%%%%% diff --git a/irlc/pacman/layouts/testMaze.lay b/irlc/pacman/layouts/testMaze.lay new file mode 100644 index 0000000..4d259a4 --- /dev/null +++ b/irlc/pacman/layouts/testMaze.lay @@ -0,0 +1,3 @@ +%%%%%%%%%% +%. P% +%%%%%%%%%% diff --git a/irlc/pacman/layouts/testSearch.lay b/irlc/pacman/layouts/testSearch.lay new file mode 100644 index 0000000..25bad23 --- /dev/null +++ b/irlc/pacman/layouts/testSearch.lay @@ -0,0 +1,5 @@ +%%%%% +%.P % +%%% % +%. % +%%%%% diff --git a/irlc/pacman/layouts/tinyCorners.lay b/irlc/pacman/layouts/tinyCorners.lay new file mode 100644 index 0000000..526c880 --- /dev/null +++ b/irlc/pacman/layouts/tinyCorners.lay @@ -0,0 +1,8 @@ +%%%%%%%% +%. .% +% P % +% %%%% % +% % % +% % %%%% +%.% .% +%%%%%%%% diff --git a/irlc/pacman/layouts/tinyMaze.lay b/irlc/pacman/layouts/tinyMaze.lay new file mode 100644 index 0000000..f7035a5 --- /dev/null +++ b/irlc/pacman/layouts/tinyMaze.lay @@ -0,0 +1,7 @@ +%%%%%%% +% P% +% %%% % +% % % +%% %% +%. %%%% +%%%%%%% diff --git a/irlc/pacman/layouts/tinySafeSearch.lay b/irlc/pacman/layouts/tinySafeSearch.lay new file mode 100644 index 0000000..fea6860 --- /dev/null +++ b/irlc/pacman/layouts/tinySafeSearch.lay @@ -0,0 +1,7 @@ +%%%%%%%%% +% G %...% +%%%%%%% % +%Po % +%.%%.%%.% +%.%%....% +%%%%%%%%% diff --git a/irlc/pacman/layouts/tinySearch.lay b/irlc/pacman/layouts/tinySearch.lay new file mode 100644 index 0000000..c51f4b0 --- /dev/null +++ b/irlc/pacman/layouts/tinySearch.lay @@ -0,0 +1,7 @@ +%%%%%%%%% +%.. ..% +%%%%.%% % +% P % +%.%% %%.% +%.%. .% +%%%%%%%%% diff --git a/irlc/pacman/layouts/trappedClassic.lay b/irlc/pacman/layouts/trappedClassic.lay new file mode 100644 index 0000000..289557f --- /dev/null +++ b/irlc/pacman/layouts/trappedClassic.lay @@ -0,0 +1,5 @@ +%%%%%%%% +% P G% +%G%%%%%% +%.... % +%%%%%%%% diff --git a/irlc/pacman/layouts/trickyClassic.lay b/irlc/pacman/layouts/trickyClassic.lay new file mode 100644 index 0000000..ffa156c --- /dev/null +++ b/irlc/pacman/layouts/trickyClassic.lay @@ -0,0 +1,13 @@ +%%%%%%%%%%%%%%%%%%%% +%o...%........%...o% +%.%%.%.%%..%%.%.%%.% +%.%.....%..%.....%.% +%.%.%%.%% %%.%%.%.% +%...... GGGG%.%....% +%.%....%%%%%%.%..%.% +%.%....% oo%.%..%.% +%.%....% %%%%.%..%.% +%.%...........%..%.% +%.%%.%.%%%%%%.%.%%.% +%o...%...P....%...o% +%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/layouts/trickySearch.lay b/irlc/pacman/layouts/trickySearch.lay new file mode 100644 index 0000000..4a607e6 --- /dev/null +++ b/irlc/pacman/layouts/trickySearch.lay @@ -0,0 +1,7 @@ +%%%%%%%%%%%%%%%%%%%% +%. ..% % +%.%%.%%.%%.%%.%% % % +% P % % +%%%%%%%%%%%%%%%%%% % +%..... % +%%%%%%%%%%%%%%%%%%%% diff --git a/irlc/pacman/pacman_environment.py b/irlc/pacman/pacman_environment.py new file mode 100644 index 0000000..cc75de1 --- /dev/null +++ b/irlc/pacman/pacman_environment.py @@ -0,0 +1,243 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import pygame +from irlc.pacman.gamestate import Directions, ClassicGameRules +from irlc.pacman.layout import getLayout +from irlc.pacman.pacman_text_display import PacmanTextDisplay +from irlc.pacman.pacman_graphics_display import PacmanGraphics, FirstPersonPacmanGraphics +from irlc.pacman.pacman_utils import PacAgent, RandomGhost +from irlc.pacman.layout import Layout +import gymnasium as gym +from gymnasium import RewardWrapper +from irlc.utils.common import ExplicitActionSpace, DiscreteTextActionSpace + +datadiscs = """ +%%%%%%% +% .% +%.P%% % +%. .% +%%%%%%% +""" + +very_small_maze = """ +%%%%%% +%P. .% +% %%% +%%%%%% +""" + +very_small_haunted_maze = """ +%%%%%% +%P. .% +% %%%% +% G% +%%%%%% +""" + + +class PacmanEnvironment(gym.Env): + _unpack_search_state = True # A hacky fix to set the search state. + """ + A fairly messy pacman environment class. I do not recommend reading this code. + """ + metadata = { + 'render.modes': ['human', 'rgb_array'], + 'video.frames_per_second': 20 + } + + # def A(self, state): + # """ + # Return a list of actions available in the given state. This function should be considered deprecated. + # """ + # raise Exception("HArd deprecation.") + # return state.A() + + def __init__(self, layout_str=None, render_mode=None, animate_movement=None, layout='mediumGrid', zoom=2.0, num_ghosts=4, frames_per_second=30, ghost_agent=None, + method_str='', allow_all_actions=False, verbose=False): + self.metadata['video_frames_per_second'] = frames_per_second + self.ghosts = [ghost_agent(i+1) if ghost_agent is not None else RandomGhost(i+1) for i in range(num_ghosts)] + if animate_movement is None: + animate_movement = render_mode =='human' + if animate_movement: + render_mode = 'human' + + # from irlc.utils. + # self.action_space = ExplicitActionSpace(self) # Wrapper environments copy the action space. + + from irlc.pacman.gamestate import Directions + self.action_space = DiscreteTextActionSpace(seed=None, actions=[Directions.NORTH, Directions.EAST, Directions.SOUTH, Directions.WEST, Directions.STOP]) + + + # Load level layout + if layout_str is not None: + self.layout = Layout([line.strip() for line in layout_str.strip().splitlines()]) + else: + self.layout = getLayout(layout) + if self.layout is None: + raise Exception("Layout file not found", layout) + self.rules = ClassicGameRules(30) + self.options_frametime = 1/frames_per_second + self.game = None + + # Setup displays. + self.first_person_graphics = False + self.animate_movement = animate_movement + self.options_zoom = zoom + self.text_display = PacmanTextDisplay(1 / frames_per_second) + self.graphics_display = None + + # temporary variables for animation/visualization. Don't remove. + self.visitedlist = None + self.ghostbeliefs = None + self.path = None + self.render_mode = render_mode + self.method = method_str + + def reset(self, seed=None, options=None): + """ + Reset the environment. + + :param seed: + :param options: + :return: + """ + self.game = self.rules.newGame(self.layout, PacAgent(index=0), self.ghosts, quiet=True, catchExceptions=False) + self.game.numMoves = 0 + if self.render_mode == 'human': + self.render() + return self.state, {'mask': self.action_space._make_mask(self.state.A()) } + + + def close(self): + if self.graphics_display is not None: + self.graphics_display.close() + return + + @property + def state(self): + if self.game is None: + return None + return self.game.state.deepCopy() + + def get_keys_to_action(self): + return {(pygame.K_LEFT,): Directions.WEST, + (pygame.K_RIGHT,): Directions.EAST, + (pygame.K_UP,): Directions.NORTH, + (pygame.K_DOWN,): Directions.SOUTH, + (pygame.K_s,): Directions.STOP, + } + + def step(self, action): + r_ = self.game.state.getScore() + done = False + + if action not in self.state.A(): + # if action not in self.A(self.state): + raise Exception(f"Agent tried {action=} available actions {self.state.A()}") + + # Let player play `action`, then let the ghosts play their moves in sequence. + for agent_index in range(len(self.game.agents)): + a = self.game.agents[agent_index].getAction(self.game.state) if agent_index > 0 else action + self.game.state = self.game.state.f(a) + self.game.rules.process(self.game.state, self.game) + + if self.graphics_display is not None and self.animate_movement and agent_index == 0: + self.graphics_display.update(self.game.state, animate=self.animate_movement, ghostbeliefs=self.ghostbeliefs, path=self.path, visitedlist=self.visitedlist) + + done = self.game.gameOver or self.game.state.is_won() or self.game.state.is_lost() + if done: + break + reward = self.game.state.getScore() - r_ + return self.state, reward, done, False, {'mask': self.action_space._make_mask(self.state.A())} + + def render(self): + if hasattr(self, 'agent'): + path = self.agent.__dict__.get('path', None) + ghostbeliefs = self.agent.__dict__.get('ghostbeliefs', None) + visitedlist = self.agent.__dict__.get('visitedlist', None) + else: + path, ghostbeliefs, visitedlist = None, None, None + + # Initialize graphics adaptor. + if self.graphics_display is None and self.render_mode in ["human", 'rgb_array']: + if self.first_person_graphics: + self.graphics_display = FirstPersonPacmanGraphics(self.game.state, self.options_zoom, showGhosts=True, frameTime=self.options_frametime, ghostbeliefs=self.ghostbeliefs) + # self.graphics_display.ghostbeliefs = self.ghostbeliefs + else: + self.graphics_display = PacmanGraphics(self.game.state, self.options_zoom, frameTime=self.options_frametime, method=self.method) + + if self.render_mode in ["human", 'rgb_array']: + # if self.graphics_display is None: + # if self.first_person_graphics: + # self.graphics_display = FirstPersonPacmanGraphics(self.options_zoom, showGhosts=True, + # frameTime=self.options_frametime) + # self.graphics_display.ghostbeliefs = self.ghostbeliefs + # else: + # self.graphics_display = PacmanGraphics(self.options_zoom, frameTime=self.options_frametime) + + if not hasattr(self.graphics_display, 'viewer'): + self.graphics_display.initialize(self.game.state.data) + + # We save these because the animation code may need it in step() + self.visitedlist = visitedlist + self.path = path + self.ghostbeliefs = ghostbeliefs + self.graphics_display.master_render(self.game.state, ghostbeliefs=ghostbeliefs, path=path, visitedlist=visitedlist) + + return self.graphics_display.blit(render_mode=self.render_mode) + # return self.graphics_display.viewer.render(return_rgb_array=self.render_mode == "rgb_array") + + elif self.render_mode in ['ascii']: + return self.text_display.draw(self.game.state) + else: + raise Exception("Bad video mode", self.render_mode) + + @property + def viewer(self): + if self.graphics_display is not None and hasattr(self.graphics_display, 'viewer'): + return self.graphics_display.viewer + else: + return None + + +class PacmanWinWrapper(RewardWrapper): + def step(self, action): + observation, reward, done, truncated, info = self.env.step(action) + if self.env.game.state.is_won(): + reward = 1 + else: + reward = 0 + return observation, reward, done, truncated, info + + +if __name__ == "__main__": + # from irlc import VideoMonitor + import time + # from irlc.utils.player_wrapper_pygame import PlayWrapperPygame + # from irlc.utils.player_wrapper import PlayWrapper + from irlc.ex01.agent import Agent, train + from irlc import interactive + + # from irlc.pacman.pacman_environment import PacmanEnvironment + # from irlc import Agent + # env = PacmanEnvironment() + # s, info = env.reset() + # agent = Agent(env) + # agent.pi(s, k=0, info=info) # get a random action + # agent.pi(s, k=0) # If info is not specified, all actions are assumed permissible. + + + env = PacmanEnvironment(layout='mediumClassic', animate_movement=True, render_mode='human') + agent = Agent(env) + # agent = PlayWrapperPygame(agent, env) + env, agent = interactive(env, agent) + + # env = VideoMonitor(env) + # experiment = "experiments/pacman_q" + # if True: + # agent = Agent(env) + # agent = PlayWrapper(agent, env) + train(env, agent, num_episodes=1) + # env.unwrapped.close() + time.sleep(0.1) + env.close() +# 230 174, 159 diff --git a/irlc/pacman/pacman_graphics_display.py b/irlc/pacman/pacman_graphics_display.py new file mode 100644 index 0000000..d01f7ec --- /dev/null +++ b/irlc/pacman/pacman_graphics_display.py @@ -0,0 +1,700 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# graphicsDisplay.py +# ------------------ +# Licensing Information: You are free to use or extend these projects for +# educational purposes provided that (1) you do not distribute or publish +# solutions, (2) you retain this notice, and (3) you provide clear +# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. +# +# Attribution Information: The Pacman AI projects were developed at UC Berkeley. +# The core projects and autograders were primarily created by John DeNero +# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). +# Student side autograding was added by Brad Miller, Nick Hay, and +# Pieter Abbeel (pabbeel@cs.berkeley.edu). + +# Most code by Dan Klein and John Denero written or rewritten for cs188, UC Berkeley. +# Some code from a Pacman implementation by LiveWires, and used / modified with permission. + +# from irlc.utils.gym_graphics_utils import formatColor, GraphicsUtilGym, colorToVector +# from irlc.utils.gym_graphics_utils import formatColor, GraphicsUtilGym, colorToVector +from irlc.utils.graphics_util_pygame import formatColor, GraphicsUtilGym, colorToVector +from irlc.pacman.pacman_utils import Directions +import math +import time + +DEFAULT_GRID_SIZE = 30.0 +INFO_PANE_HEIGHT = 35 +BACKGROUND_COLOR = formatColor(0,0,0) +WALL_COLOR = formatColor(0.0/255.0, 51.0/255.0, 255.0/255.0) +INFO_PANE_COLOR = formatColor(.4,.4,0) +SCORE_COLOR = formatColor(.9, .9, .9) +PACMAN_OUTLINE_WIDTH = 2 +PACMAN_CAPTURE_OUTLINE_WIDTH = 4 + +GHOST_COLORS = [] +GHOST_COLORS.append(formatColor(.9,0,0)) # Red +GHOST_COLORS.append(formatColor(0,.3,.9)) # Blue +GHOST_COLORS.append(formatColor(.98,.41,.07)) # Orange +GHOST_COLORS.append(formatColor(.1,.75,.7)) # Green +GHOST_COLORS.append(formatColor(1.0,0.6,0.0)) # Yellow +GHOST_COLORS.append(formatColor(.4,0.13,0.91)) # Purple + +TEAM_COLORS = GHOST_COLORS[:2] + +GHOST_SHAPE = [ + ( 0, 0.3 ), + ( 0.25, 0.75 ), + ( 0.5, 0.3 ), + ( 0.75, 0.75 ), + ( 0.75, -0.5 ), + ( 0.5, -0.75 ), + (-0.5, -0.75 ), + (-0.75, -0.5 ), + (-0.75, 0.75 ), + (-0.5, 0.3 ), + (-0.25, 0.75 ) + ] +GHOST_SIZE = 0.65 +SCARED_COLOR = formatColor(1,1,1) + +GHOST_VEC_COLORS = [colorToVector(gc) for gc in GHOST_COLORS] + +PACMAN_COLOR = formatColor(255.0/255.0, 255.0/255.0, 61.0/255) +PACMAN_SCALE = 0.5 + +# Food +FOOD_COLOR = formatColor(1,1,1) +FOOD_SIZE = 0.1 + +# Laser +LASER_COLOR = formatColor(1,0,0) +LASER_SIZE = 0.02 + +# Capsule graphics +CAPSULE_COLOR = formatColor(1,1,1) +CAPSULE_SIZE = 0.25 +# Drawing walls +WALL_RADIUS = 0.15 + +class InfoPane: + def __init__(self, ga, layout, gridSize): + self.gridSize = gridSize + self.width = (layout.width) * gridSize + self.base = (layout.height + 1) * gridSize + self.height = INFO_PANE_HEIGHT + self.fontSize = 24 + self.textColor = PACMAN_COLOR + self.drawPane() + self.ga = ga + + + def toScreen(self, pos, y = None): + """ + Translates a point relative from the bottom left of the info pane. + """ + if y == None: + x,y = pos + else: + x = pos + x = self.gridSize + x # Margin + y = self.base + y + return x,y + + def drawPane(self): + self.scoreText = {'pos':self.toScreen(0, 0), + 'color':self.textColor, + 'contents': "SCORE: 0", + 'font': "Times", + 'size': self.fontSize, + 'style': "bold"} + + def initializeGhostDistances(self, distances): + self.ghostDistanceText = [] + size = 20 + if self.width < 240: + size = 12 + if self.width < 160: + size = 10 + + for i, d in enumerate(distances): + t = {'pos': self.toScreen(self.width/2 + self.width/8 * i, 0), + 'color': GHOST_COLORS[i+1], + 'contents': str(d), + 'font': "Times", + 'size':size, + 'style': "bold"} + self.ghostDistanceText.append(t) + + def updateScore(self, score, method=''): + self.scoreText['contents'] = "SCORE: % 4d %s" %(score, method) + + def setTeam(self, isBlue): + txt = "RED TEAM" + if isBlue: txt = "BLUE TEAM" + self.teamText = {'pos': self.toScreen(300, 0 ), + 'color': self.textColor, + 'contents': txt, + 'font': "Times", + 'size': self.fontSize, + 'style': "bold"} + + def updateGhostDistances(self, distances): + if len(distances) == 0: return + self.initializeGhostDistances(distances) + + def master_render(self): + self.ga.text("master_test", **self.scoreText) + if hasattr(self, 'teamText'): + self.ga.text("team_test", **self.teamText) + if hasattr(self, 'ghostDistanceText'): + for d in self.ghostDistanceText: + self.ga.text(f"ghost_distance_text_{d}_", **d) + + def drawGhost(self): + pass + + def drawPacman(self): + pass + + def drawWarning(self): + pass + + def clearIcon(self): + pass + + def updateMessage(self, message): + pass + + def clearMessage(self): + pass + + +class PacmanGraphics: + def __init__(self, state, zoom=1.0, frameTime=0.0, capture=False, isBlue=False, method=''): + self.have_window = 0 + self.currentGhostImages = {} + self.pacmanImage = None + self.zoom = zoom + self.gridSize = DEFAULT_GRID_SIZE * zoom + self.capture = capture + self.frameTime = frameTime + # self.visitedlist = None + # self.ghostbeliefs = None # for the ghost distributions + self.ga = GraphicsUtilGym() + # Used to be initialize. + self.isBlue = isBlue + self.startGraphics(state) + self.distributionImages = None # Initialized lazily + self.previousState = state + self.method = method + + # def initialize(self, state, isBlue = False): + + def master_render(self, state, ghostbeliefs=None, visitedlist=None, path=None): + # self.viewer.geoms = [] + # self.ga.gc. + # assert False + # state = state.data + # This is completely needless. Just update the things that need to be updated and let everything else be. + + # self.ga.gc.clear() + self.ga.draw_background() + if visitedlist is not None: + self.drawExpandedCells(cells=visitedlist) + + if path is not None: + # draw the given path. + path = [self.to_screen(p) for p in path] + x, y = zip(*path) + # name = f"render_path" + for k in range(len(x)-1): + self.ga.line('asdfasdf', here=(x[k], y[k]), there=(x[k+1], y[k+1]), width=4, color= formatColor(0.5, 0.95, 0.5) ) + + # if len(path) > 1: + # self.ga.plot(name, x, y, width=4, color=formatColor(0.5, 0.95, 0.5) ) + + if ghostbeliefs is not None: + self.drawDistributions(state.data, ghostbeliefs=ghostbeliefs) + + self.drawStaticObjects(state.data) + self.drawAgentObjects(state.data) + self.infoPane.updateScore(state.data.score, self.method) + + if 'ghostDistances' in dir(state.data): + self.infoPane.updateGhostDistances(state.data.ghostDistances) + self.infoPane.master_render() + # self.ga.gc.prune_frame() + # self.viewer.render() + + def blit(self, render_mode=None): + return self.ga.blit(render_mode=render_mode) + + + + def close(self): + self.ga.close() + + def startGraphics(self, state): + self.layout = state.data.layout + # layout = self.layout + self.width = self.layout.width + self.height = self.layout.height + self.make_window(self.width, self.height) + self.ga.draw_background() + self.infoPane = InfoPane(ga=self.ga, layout=self.layout, gridSize=self.gridSize) + self.currentState = self.layout # Unclear. + + def drawDistributions(self, state, ghostbeliefs=None): + ghostbeliefs = [gb.copy() for gb in ghostbeliefs] # uses a default dict. + if ghostbeliefs is None or len(ghostbeliefs) == 0: + return + walls = state.layout.walls + for x in range(walls.width): + for y in range(walls.height): + weights = [gb[(x,y)] for gb in ghostbeliefs] + color = [0.0, 0.0, 0.0] + colors = list(GHOST_VEC_COLORS)[1:] # With Pacman + if self.capture: colors = GHOST_VEC_COLORS + + for weight, gcolor in zip(weights, colors): + color = [min(1.0, c + 0.95 * g * weight ** .3) for c, g in zip(color, gcolor)] + color = formatColor(*color) + ( screen_x, screen_y ) = self.to_screen( (x, y) ) + self.ga.square(f"_belif_{x}_{y}_", (screen_x, screen_y), + 0.5 * self.gridSize, + color = color, # BACKGROUND_COLOR, + filled = 1, behind=2) + + def drawStaticObjects(self, state): + layout = self.layout + self.drawWalls(layout.walls) + self.food = self.drawFood(state.food) + self.capsules = self.drawCapsules(state.capsules) + + def drawAgentObjects(self, state): + self.agentImages = [] # (agentState, image) + for index, agent in enumerate(state.agentStates): + if agent.isPacman: + image = self.drawPacman(agent, index) + self.agentImages.append( (agent, image) ) + else: + image = self.drawGhost(agent, index) + self.agentImages.append( (agent, image) ) + + + def update(self, newState, animate=False, ghostbeliefs=None, path=None, visitedlist=None): + # newState = newState.data + agentIndex = newState.data._agentMoved + agentState = newState.data.agentStates[agentIndex] + # assert False + if self.agentImages[agentIndex][0].isPacman != agentState.isPacman: self.swapImages(agentIndex, agentState) + prevState, prevImage = self.agentImages[agentIndex] + if animate: + if agentState.isPacman: + self.animatePacman(agentState, prevState, prevImage, state=newState, ghostbeliefs=ghostbeliefs, path=path, visitedlist=visitedlist) + else: + self.moveGhost(agentState, agentIndex, prevState, prevImage) + + self.agentImages[agentIndex] = (agentState, prevImage) + + if newState.data._foodEaten != None: + self.removeFood(newState.data._foodEaten, self.food) + if newState.data._capsuleEaten != None: + self.removeCapsule(newState.data._capsuleEaten, self.capsules) + + if 'ghostDistances' in dir(newState): + self.infoPane.updateGhostDistances(newState.data.ghostDistances) + self.master_render(newState, ghostbeliefs=ghostbeliefs, path=path, visitedlist=visitedlist) + + def make_window(self, width, height): + grid_width = (width-1) * self.gridSize + grid_height = (height-1) * self.gridSize + screen_width = 2*self.gridSize + grid_width + screen_height = 2*self.gridSize + grid_height + INFO_PANE_HEIGHT + self.viewer = self.ga.begin_graphics(screen_width, screen_height, BACKGROUND_COLOR, "Pacman") + + def drawPacman(self, pacman, index): + position = self.getPosition(pacman) + d = pacman.draw_extra['delta_xy'] + position = (position[0] + d[0], position[1]+d[1]) + screen_point = self.to_screen(position) + + if 'endpoints' in pacman.draw_extra: + endpoints = pacman.draw_extra['endpoints'] + else: + endpoints = self.getEndpoints(self.getDirection(pacman)) + + width = PACMAN_OUTLINE_WIDTH + outlineColor = PACMAN_COLOR + fillColor = PACMAN_COLOR + + if self.capture: + outlineColor = TEAM_COLORS[index % 2] + fillColor = GHOST_COLORS[index] + width = PACMAN_CAPTURE_OUTLINE_WIDTH + + return [self.ga.circle("pacman", screen_point, PACMAN_SCALE * self.gridSize, + fillColor = fillColor, outlineColor = outlineColor, + endpoints = endpoints, + width = width)] + + def getEndpoints(self, direction, position=(0,0)): + x, y = position + pos = x - int(x) + y - int(y) + width = 30 + 80 * math.sin(math.pi* pos) + + delta = width / 2 + if (direction == 'West'): + endpoints = (180+delta, 180-delta) + elif (direction == 'North'): + endpoints = (90+delta, 90-delta) + elif (direction == 'South'): + endpoints = (270+delta, 270-delta) + else: + endpoints = (0+delta, 0-delta) + return endpoints + + def movePacman(self, position, direction, image,pacman): + # screenPosition = self.to_screen(position) + endpoints = self.getEndpoints( direction, position ) + # r = PACMAN_SCALE * self.gridSize + pacman.draw_extra['endpoints'] = endpoints + + def animatePacman(self, pacman, prevPacman, image, nframe=1, frames=4, state=None, ghostbeliefs=None, path=None, visitedlist=None): + if self.frameTime < 0: + print('Press any key to step forward, "q" to play') + if self.frameTime > 0.01 or self.frameTime < 0: + fx, fy = self.getPosition(prevPacman) + px, py = self.getPosition(pacman) + for nframe in range(1,int(frames) + 1): + pos = px*nframe/frames + fx*(frames-nframe)/frames, py*nframe/frames + fy*(frames-nframe)/frames + self.movePacman(pos, self.getDirection(pacman), image, pacman=pacman) + pacman.draw_extra['delta_xy'] = (pos[0]-px, pos[1]-py) + time.sleep(self.frameTime/frames) + self.master_render(state, ghostbeliefs=ghostbeliefs, path=path, visitedlist=visitedlist) + self.blit(render_mode='human') + else: + self.movePacman(self.getPosition(pacman), self.getDirection(pacman), image, pacman=pacman) + + + def getGhostColor(self, ghost, ghostIndex): + if ghost.scaredTimer > 0: + return SCARED_COLOR + else: + return GHOST_COLORS[ghostIndex] + + def drawGhost(self, ghost, agentIndex): + pos = self.getPosition(ghost) + dir = self.getDirection(ghost) + (screen_x, screen_y) = (self.to_screen(pos) ) + coords = [] + for (x, y) in GHOST_SHAPE: + coords.append((x*self.gridSize*GHOST_SIZE + screen_x, y*self.gridSize*GHOST_SIZE + screen_y)) + + colour = self.getGhostColor(ghost, agentIndex) + name = f"ghost_{agentIndex}_" + body = self.ga.polygon(name, coords, colour, filled = 1) + WHITE = formatColor(1.0, 1.0, 1.0) + BLACK = formatColor(0.0, 0.0, 0.0) + + dx = 0 + dy = 0 + if dir == 'North': + dy = -0.2 + if dir == 'South': + dy = 0.2 + if dir == 'East': + dx = 0.2 + if dir == 'West': + dx = -0.2 + leftEye = self.ga.circle(name +"_s1", (screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx/1.5), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2, WHITE, WHITE) + rightEye = self.ga.circle(name +"_s2",(screen_x+self.gridSize*GHOST_SIZE*(0.3+dx/1.5), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2, WHITE, WHITE) + leftPupil = self.ga.circle(name +"_s3",(screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08, BLACK, BLACK) + rightPupil = self.ga.circle(name +"_s4",(screen_x+self.gridSize*GHOST_SIZE*(0.3+dx), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08, BLACK, BLACK) + ghostImageParts = [] + ghostImageParts.append(body) + ghostImageParts.append(leftEye) + ghostImageParts.append(rightEye) + ghostImageParts.append(leftPupil) + ghostImageParts.append(rightPupil) + return ghostImageParts + + def moveEyes(self, pos, dir, eyes): # does this do anything? + (screen_x, screen_y) = (self.to_screen(pos) ) + dx = 0 + dy = 0 + if dir == 'North': + dy = -0.2 + if dir == 'South': + dy = 0.2 + if dir == 'East': + dx = 0.2 + if dir == 'West': + dx = -0.2 + self.ga.moveCircle(eyes[0],(screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx/1.5), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2) + self.ga.moveCircle(eyes[1],(screen_x+self.gridSize*GHOST_SIZE*(0.3+dx/1.5), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy/1.5)), self.gridSize*GHOST_SIZE*0.2) + self.ga.moveCircle(eyes[2],(screen_x+self.gridSize*GHOST_SIZE*(-0.3+dx), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08) + self.ga.moveCircle(eyes[3],(screen_x+self.gridSize*GHOST_SIZE*(0.3+dx), screen_y-self.gridSize*GHOST_SIZE*(0.3-dy)), self.gridSize*GHOST_SIZE*0.08) + + def moveGhost(self, ghost, ghostIndex, prevGhost, ghostImageParts): + old_x, old_y = self.to_screen(self.getPosition(prevGhost)) + new_x, new_y = self.to_screen(self.getPosition(ghost)) + delta = new_x - old_x, new_y - old_y + + if ghost.scaredTimer > 0: + color = SCARED_COLOR + else: + color = GHOST_COLORS[ghostIndex] + self.ga.edit(ghostImageParts[0], ('fill', color), ('outline', color)) + self.moveEyes(self.getPosition(ghost), self.getDirection(ghost), ghostImageParts[-4:]) + + + def getPosition(self, agentState): + if agentState.configuration == None: return (-1000, -1000) + return agentState.getPosition() + + def getDirection(self, agentState): + if agentState.configuration == None: return Directions.STOP + return agentState.configuration.getDirection() + + def to_screen(self, point): + ( x, y ) = point + x = (x + 1)*self.gridSize + y = (self.height - y)*self.gridSize + return ( x, y ) + + # Fixes some TK issue with off-center circles + def to_screen2(self, point): + ( x, y ) = point + #y = self.height - y + x = (x + 1)*self.gridSize + y = (self.height - y)*self.gridSize + return ( x, y ) + + def drawWalls(self, wallMatrix): + wallColor = WALL_COLOR + + for xNum, x in enumerate(wallMatrix): + if self.capture and (xNum * 2) < wallMatrix.width: wallColor = TEAM_COLORS[0] + if self.capture and (xNum * 2) >= wallMatrix.width: wallColor = TEAM_COLORS[1] + + for yNum, cell in enumerate(x): + name = f"{xNum}_{yNum}_" + if cell: # There's a wall here + pos = (xNum, yNum) + screen = self.to_screen(pos) + screen2 = self.to_screen2(pos) + + # draw each quadrant of the square based on adjacent walls + wIsWall = self.isWall(xNum-1, yNum, wallMatrix) + eIsWall = self.isWall(xNum+1, yNum, wallMatrix) + nIsWall = self.isWall(xNum, yNum+1, wallMatrix) + sIsWall = self.isWall(xNum, yNum-1, wallMatrix) + nwIsWall = self.isWall(xNum-1, yNum+1, wallMatrix) + swIsWall = self.isWall(xNum-1, yNum-1, wallMatrix) + neIsWall = self.isWall(xNum+1, yNum+1, wallMatrix) + seIsWall = self.isWall(xNum+1, yNum-1, wallMatrix) + + # NE quadrant + if (not nIsWall) and (not eIsWall): + # inner circle + # self.ga.circle(name + "s1", screen2, WALL_RADIUS * self.gridSize, wallColor, wallColor, (0,91), 'arc') + self.ga.centered_arc(wallColor, screen2, WALL_RADIUS * self.gridSize, 0,90, width=2) + + if (nIsWall) and (not eIsWall): + # vertical line + self.ga.line(name + "s2", add(screen, (self.gridSize*WALL_RADIUS, 0)), add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(-0.5)-0)), wallColor) + if (not nIsWall) and (eIsWall): + # horizontal line + self.ga.line(name + "s3", add(screen, (0, self.gridSize*(-1)*WALL_RADIUS)), add(screen, (self.gridSize*0.5+0, self.gridSize*(-1)*WALL_RADIUS)), wallColor) + if (nIsWall) and (eIsWall) and (not neIsWall): + # outer circle + # self.ga.circle(name + "s4", add(screen2, (self.gridSize*2*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (180,271), 'arc') + self.ga.centered_arc(wallColor, add(screen2, (self.gridSize * 2 * WALL_RADIUS, self.gridSize * (-2) * WALL_RADIUS)), WALL_RADIUS * self.gridSize- 0, 180, 270, width=2) + # centered_arc(self, color, pos, r, start_angle, stop_angle, width=1) + self.ga.line(name + "s5", add(screen, (self.gridSize*2*WALL_RADIUS-0, self.gridSize*(-1)*WALL_RADIUS)), add(screen, (self.gridSize*0.5+0, self.gridSize*(-1)*WALL_RADIUS)), wallColor) + self.ga.line(name + "s6", add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS+0)), add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(-0.5))), wallColor) + + # NW quadrant + if (not nIsWall) and (not wIsWall): + # inner circle + # self.ga.circle(name + "s8", screen2, WALL_RADIUS * self.gridSize, wallColor, wallColor, (90,181), 'arc') + self.ga.centered_arc(wallColor, screen2, WALL_RADIUS * self.gridSize, 90,180, width=2) + + if (nIsWall) and (not wIsWall): + # vertical line + self.ga.line(name + "s10", add(screen, (self.gridSize*(-1)*WALL_RADIUS, 0)), add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(-0.5)-0)), wallColor) + if (not nIsWall) and (wIsWall): + # horizontal line + self.ga.line(name + "s11", add(screen, (0, self.gridSize*(-1)*WALL_RADIUS)), add(screen, (self.gridSize*(-0.5)-0, self.gridSize*(-1)*WALL_RADIUS)), wallColor) + if (nIsWall) and (wIsWall) and (not nwIsWall): + # outer circle + # self.ga.circle(name + "s12", add(screen2, (self.gridSize*(-2)*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (270,361), 'arc') + self.ga.centered_arc(wallColor, add(screen2, (self.gridSize*(-2)*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize, 270,360, width=2) + + self.ga.line(name + "s13", add(screen, (self.gridSize*(-2)*WALL_RADIUS+0, self.gridSize*(-1)*WALL_RADIUS)), add(screen, (self.gridSize*(-0.5), self.gridSize*(-1)*WALL_RADIUS)), wallColor) + self.ga.line(name + "s14", add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(-2)*WALL_RADIUS+1)), add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(-0.5))), wallColor) + + # SE quadrant + if (not sIsWall) and (not eIsWall): + # inner circle + # self.ga.circle(name + "s18", screen2, WALL_RADIUS * self.gridSize, wallColor, wallColor, (270,361), 'arc') + self.ga.centered_arc(wallColor, screen2, WALL_RADIUS * self.gridSize, 270,360, width=2) + + if (sIsWall) and (not eIsWall): + # vertical line + self.ga.line(name + "s20", add(screen, (self.gridSize*WALL_RADIUS, 0)), add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(0.5)+0)), wallColor) + if (not sIsWall) and (eIsWall): + # horizontal line + self.ga.line(name + "s21", add(screen, (0, self.gridSize*(1)*WALL_RADIUS)), add(screen, (self.gridSize*0.5+1, self.gridSize*(1)*WALL_RADIUS)), wallColor) + if (sIsWall) and (eIsWall) and (not seIsWall): + # outer circle + # self.ga.circle(name + "s22", add(screen2, (self.gridSize*2*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (90,181), 'arc') + self.ga.centered_arc(wallColor, add(screen2, (self.gridSize*2*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-0, 90,180, width=2) + self.ga.line(name + "s23", add(screen, (self.gridSize*2*WALL_RADIUS-0, self.gridSize*(1)*WALL_RADIUS)), add(screen, (self.gridSize*0.5, self.gridSize*(1)*WALL_RADIUS)), wallColor) + self.ga.line(name + "s24", add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS-0)), add(screen, (self.gridSize*WALL_RADIUS, self.gridSize*(0.5))), wallColor) + + # SW quadrant + if (not sIsWall) and (not wIsWall): + # inner circle + # self.ga.circle(name + "s30", screen2, WALL_RADIUS * self.gridSize, wallColor, wallColor, (180,271), 'arc') + self.ga.centered_arc(wallColor, screen2, WALL_RADIUS * self.gridSize, 180,270, width=2) + if (sIsWall) and (not wIsWall): + # vertical line + self.ga.line(name + "s31", add(screen, (self.gridSize*(-1)*WALL_RADIUS, 0)), add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(0.5)+1)), wallColor) + if (not sIsWall) and (wIsWall): + # horizontal line + self.ga.line(name + "s32", add(screen, (0, self.gridSize*(1)*WALL_RADIUS)), add(screen, (self.gridSize*(-0.5)-0, self.gridSize*(1)*WALL_RADIUS)), wallColor) + if (sIsWall) and (wIsWall) and (not swIsWall): + # outer circle + # self.ga.circle(name + "s33", add(screen2, (self.gridSize*(-2)*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-1, wallColor, wallColor, (0,91), 'arc') + self.ga.centered_arc(wallColor, add(screen2, (self.gridSize*(-2)*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS)), WALL_RADIUS * self.gridSize-0, 0, 90, width=2) + self.ga.line(name + "s34", add(screen, (self.gridSize*(-2)*WALL_RADIUS+0, self.gridSize*(1)*WALL_RADIUS)), add(screen, (self.gridSize*(-0.5), self.gridSize*(1)*WALL_RADIUS)), wallColor) + self.ga.line(name + "s35", add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(2)*WALL_RADIUS-0)), add(screen, (self.gridSize*(-1)*WALL_RADIUS, self.gridSize*(0.5))), wallColor) + + def isWall(self, x, y, walls): + if x < 0 or y < 0: + return False + if x >= walls.width or y >= walls.height: + return False + return walls[x][y] + + def drawFood(self, foodMatrix ): + foodImages = [] + color = FOOD_COLOR + for xNum, x in enumerate(foodMatrix): + if self.capture and (xNum * 2) <= foodMatrix.width: color = TEAM_COLORS[0] + if self.capture and (xNum * 2) > foodMatrix.width: color = TEAM_COLORS[1] + imageRow = [] + foodImages.append(imageRow) + for yNum, cell in enumerate(x): + name = f"food_{xNum}_{yNum}_" + if cell: # There's food here + screen = self.to_screen((xNum, yNum )) + dot = self.ga.circle(name, screen, + FOOD_SIZE * self.gridSize, + outlineColor = color, fillColor = color, + width = 1) + imageRow.append(dot) + else: + imageRow.append(None) + return foodImages + + def drawCapsules(self, capsules ): + capsuleImages = {} + for capsule in capsules: + ( screen_x, screen_y ) = self.to_screen(capsule) + name = f"capsule_{screen_y}_{screen_x}_" + dot = self.ga.circle(name, (screen_x, screen_y), + CAPSULE_SIZE * self.gridSize, + outlineColor = CAPSULE_COLOR, + fillColor = CAPSULE_COLOR, + width = 1) + capsuleImages[capsule] = dot + return capsuleImages + + def removeFood(self, cell, foodImages ): + x, y = cell + + # remove_from_screen(foodImages[x][y]) + + def removeCapsule(self, cell, capsuleImages ): + x, y = cell + # remove_from_screen(capsuleImages[(x, y)]) + + def drawExpandedCells(self, cells): + """ + Draws an overlay of expanded grid positions for search agents + """ + n = float(len(cells)) + baseColor = [1.0, 0.0, 0.0] + self.clearExpandedCells() + self.expandedCells = [] + for k, cell in enumerate(cells): + screenPos = self.to_screen( cell) + cellColor = formatColor(*[(n-k) * c * .5 / n + .25 for c in baseColor]) + name = f"exp_cell_{screenPos}_" + block = self.ga.square(name, screenPos, + 0.5 * self.gridSize, + color = cellColor, + filled = 1, behind=2) + self.expandedCells.append(block) + # if self.frameTime < 0: + # refresh() + + def clearExpandedCells(self): + if 'expandedCells' in dir(self) and len(self.expandedCells) > 0: + for cell in self.expandedCells: + pass + +class FirstPersonPacmanGraphics(PacmanGraphics): + def __init__(self, state, zoom = 1.0, showGhosts = True, capture = False, frameTime=0, ghostbeliefs=None): + PacmanGraphics.__init__(self, state, zoom=zoom, frameTime=frameTime) + self.showGhosts = showGhosts + self.capture = capture + self.ghostbeliefs = ghostbeliefs + + + def initialize(self, state, isBlue = False): + self.isBlue = isBlue + PacmanGraphics.startGraphics(self, state) + self.layout = state.layout + self.previousState = state + + def lookAhead(self, config, state): + if config.getDirection() == 'Stop': + return + else: + pass + # Draw relevant ghosts + allGhosts = state.getGhostStates() + visibleGhosts = state.getVisibleGhosts() + for i, ghost in enumerate(allGhosts): + if ghost in visibleGhosts: + self.drawGhost(ghost, i) + else: + self.currentGhostImages[i] = None + + def getGhostColor(self, ghost, ghostIndex): + return GHOST_COLORS[ghostIndex] + + def getPosition(self, ghostState): + if not self.showGhosts and not ghostState.isPacman and ghostState.getPosition()[1] > 1: + return (-1000, -1000) + else: + return PacmanGraphics.getPosition(self, ghostState) + +def add(x, y): + return x[0] + y[0], x[1] + y[1] + +# 790 + +if __name__ == '__main__': + from irlc.pacman.pacman_environment import GymPacmanEnvironment + env = GymPacmanEnvironment(animate_movement=True, layout='mediumClassic', frame_time=0.0001) + # env = GymPacmanEnvironment(animate_movement=True, layout='smallClassic') + from irlc import VideoMonitor, train, Agent + env = VideoMonitor(env) + n = 100 + train(env, Agent(env), max_steps=n, num_episodes=1000) + # everything else: 0.20 (61 %), set up graphics: 0.03 (10 %), rendering: 0.09 (27 %) diff --git a/irlc/pacman/pacman_resources.py b/irlc/pacman/pacman_resources.py new file mode 100644 index 0000000..6b5660e --- /dev/null +++ b/irlc/pacman/pacman_resources.py @@ -0,0 +1,266 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import math +import numpy as np +import pygame +from PIL import ImageColor +# from pyglet.shapes import Circle, Rectangle, Polygon, Sector +# from irlc.utils.pyglet_rendering import GroupedElement +from irlc.pacman.pacman_graphics_display import GHOST_COLORS, GHOST_SHAPE + +WHITE = (255, 255, 255) +BLACK = (0, 0, 0) + + +# class Eye(GroupedElement): +# normal, cross = None, None +# +# def render(self): +# self.normal = [Circle(0, 0, .2, color=WHITE, batch=self.batch, group=self.group), +# Circle(0, 0, 0.1, color=BLACK, batch=self.batch, group=self.group)] # radius was 0.08 +# ew = 0.6 +# rw = ew/6 +# self.cross = [Rectangle(x=-ew/2, y=-rw/2, width=ew, height=rw, color=BLACK, group=self.group, batch=self.batch), +# Rectangle(x=-rw/2, y=-ew/2, width=rw, height=ew, color=BLACK, group=self.group, batch=self.batch)] +# self.set_eye_dir('stop') +# +# def set_eye_dir(self, direction='stop'): +# dead = direction.lower() == 'dead' +# for n in self.normal: +# n.visible = not dead +# pp = (0, 0) +# if direction.lower() == 'stop': +# pass +# dd = 0.1 +# if direction.lower() == 'east': +# pp = (dd, 0) +# # self.group.translate(dd, 0) +# +# if direction.lower() == 'west': +# pp = (-dd, 0) +# # self.group.translate(-dd, 0) +# if direction.lower() == 'south': +# pp = (0, -dd) +# # self.group.translate(0, -dd) +# if direction.lower() == 'north': +# # self.group.translate(0, dd) +# pp = (0, dd) +# self.normal[1].x = pp[0] +# self.normal[1].y = pp[1] +# +# for e in self.cross: +# e.visible = dead +# self.group.rotate(np.pi/4 if dead else 0) + +from irlc.utils.graphics_util_pygame import rotate_around + +class Ghost: + body_, eyes_ = None, None + def __init__(self, graphics_adaptor, agent_index=1, order=1, scale=10.): + self.agentIndex = agent_index + + # GS = [(x*scale, y*scale) for x,y in GHOST_SHAPE] + # self.GS = GS + # xx, yy = zip(*GS) + # xmin, xmax = min(xx), max(xx) + # ymin, ymax = min(yy), max(yy) + # this creates a surface + # self.GS = GS + # self.surf = pygame.Surface( (int(xmax-xmin), int(ymax-ymin)) ) + # Write ghost to this surface, then turn it to make it lie down. + self.ga = graphics_adaptor + # self.xmin = xmin + # self.ymin = ymin + # self.rect = self.surf.get_rect() + self.x = 0 + self.y = 0 + self.angle = 0 + self.scale = scale + + self.direction = 'stop' + # super().__init__(order=order) + + + def set_scared(self, scared): + return + from irlc.pacman.devel.pyglet_pacman_graphics import SCARED_COLOR, GHOST_COLORS + self.body_.color = SCARED_COLOR if scared else GHOST_COLORS[self.agentIndex] + + def eyes(self, direction): + return + for e in self.eyes_: + e.set_eye_dir(direction) + + def set_position(self, x, y): + # print("setting position", x,y) + # self.group.x = x + # self.group.y = y + # self.group.translate(x, y) + self.x = x + self.y = y + pass + + def rand_eyes(self): + return ['stop', 'east', 'west', 'north', 'south'][np.random.randint(0, 5)] + + + def set_direction(self, direction): + self.direction = direction + + return + self.eyes(direction) + + def kill(self): + self.set_direction('dead') + return + # return + # self.eyes('dead') + self.body_color = ImageColor.getcolor(GHOST_COLORS[3], "RGB") + # self.group.rotate(-np.pi/2) + + def resurrect(self): + self.set_direction(self.rand_eyes()) + # return + # self.eyes('straight') + return + self.body_.color = ImageColor.getcolor(GHOST_COLORS[self.agentIndex], "RGB") + self.group.rotate(0) + + def render(self): + # ghost_shape = tuple((x, -y) for (x, y) in GHOST_SHAPE) + dead = self.direction.lower() == 'dead' + angle = 0 + if dead: + angle = -90 + + ghost_shape = tuple((x*self.scale+self.x, -y*self.scale+self.y) for (x, y) in GHOST_SHAPE) + + # self.ga.polygon() + # print(ghost_shape) + xy0 = (self.x, self.y) + self.ga.polygon("asdfasf", [rotate_around(c, xy0, angle) for c in ghost_shape], GHOST_COLORS[self.agentIndex] if not dead else GHOST_COLORS[3], filled=1) + dx = 0.3 + dy = 0.3 + + # pdx = 0.2 + # pdy = 0.2 + + for k in range(2): + pos = (self.x + (-1 if k == 0 else 1)*dx*self.scale, self.y + dy*self.scale) + self.ga.circle("asdfsF", rotate_around(pos, xy0, angle), 0.15*self.scale, None, WHITE) + # Eyes: + # continue + + direction = self.direction + + + # for n in self.normal: + # n.visible = not dead + pp = (0, 0) + if direction.lower() == 'stop': + pass + dd = 0.1 + if direction.lower() == 'east': + pp = (dd, 0) + # self.group.translate(dd, 0) + if direction.lower() == 'west': + pp = (-dd, 0) + # self.group.translate(-dd, 0) + if direction.lower() == 'south': + pp = (0, -dd) + # self.group.translate(0, -dd) + if direction.lower() == 'north': + # self.group.translate(0, dd) + pp = (0, dd) + # self.normal[1].x = pp[0] + # self.normal[1].y = pp[1] + if not dead: + self.ga.circle("asdfsF", rotate_around( (pos[0] + pp[0]*self.scale, pos[1] + pp[1]*self.scale), xy0, self.angle), + 0.05 * self.scale, None, BLACK) + else: + ew = 0.6 + rw = ew / 6 + for k in range(2): + cross = [(-rw/2, ew/2), + (rw / 2, ew / 2), + (rw / 2, -ew / 2), + (-rw / 2, -ew / 2), + ] + cross = cross + [cross[0]] + cross = [rotate_around(c, (0,0), 45 + 90*k) for c in cross] + cc = [rotate_around( (pos[0]+x *self.scale+ pp[0], pos[1]+y *self.scale+ pp[1]), xy0, angle) for (x,y) in cross] + self.ga.polygon("asdfasf", cc, None, filled=True, fillColor=BLACK) + + + + + + + # self.cross = [ + # Rectangle(x=-ew / 2, y=-rw / 2, width=ew, height=rw, color=BLACK, group=self.group, batch=self.batch), + # Rectangle(x=-rw / 2, y=-ew / 2, width=rw, height=ew, color=BLACK, group=self.group, batch=self.batch)] + + + pass + # Circle(0, 0, .2, color=WHITE, batch=self.batch, group=self.group) + # + # self.normal = [Circle(0, 0, .2, color=WHITE, batch=self.batch, group=self.group), + # Circle(0, 0, 0.1, color=BLACK, batch=self.batch, group=self.group)] # radius was 0.08 + # ew = 0.6 + # rw = ew / 6 + # self.cross = [ + # Rectangle(x=-ew / 2, y=-rw / 2, width=ew, height=rw, color=BLACK, group=self.group, batch=self.batch), + # Rectangle(x=-rw / 2, y=-ew / 2, width=rw, height=ew, color=BLACK, group=self.group, batch=self.batch)] + # + # for e in self.cross: + # e.visible = dead + # return + # self.ga.polygon() + # colour = ImageColor.getcolor(GHOST_COLORS[self.agentIndex], "RGB") + # self.body_ = Polygon(*ghost_shape, color=colour, batch=self.batch, group=self.group) + # self.eyes_ = [Eye(order=self.group.order+1+k, pg=self.group, batch=self.batch) for k in range(2)] + # for k, e in enumerate(self.eyes_): + # e.group.translate(-.3 if k == 0 else .3, .3) + + +PACMAN_COLOR = (255, 255, 61) + + +# class Pacman(GroupedElement): +# body = None +# +# def __init__(self, grid_size, batch, pg=None, parent=None, order=0): +# self.delta = 0 +# self.GRID_SIZE = grid_size +# super().__init__(batch, pg=pg, parent=parent, order=order) +# self.set_animation(0, 4) +# +# def set_animation(self, frame, frames): +# pos = frame/frames +# width = 30 + 80 * math.sin(math.pi * pos) +# delta = width / 2 +# self.delta = delta * np.pi / 180 +# self.body._angle = 2*np.pi-2*self.delta +# self.body._start_angle = self.delta +# self.body._update_position() +# +# def set_direction(self, direction): +# if direction == 'Stop': +# pass +# else: +# angle = 0 +# if direction == 'East': +# angle = 0 +# elif direction == 'North': +# angle = np.pi/2 +# elif direction == 'West': +# angle = np.pi +# elif direction == 'South': +# angle = np.pi*1.5 +# self.group.rotate(angle) +# +# def render(self): +# width = 30 +# delta = width/2 +# delta = delta/180 * np.pi +# self.body = Sector(0, 0, self.GRID_SIZE/2, angle=2*np.pi-2*delta, start_angle=delta, +# color=PACMAN_COLOR, batch=self.batch, group=self.group) diff --git a/irlc/pacman/pacman_text_display.py b/irlc/pacman/pacman_text_display.py new file mode 100644 index 0000000..72d4b10 --- /dev/null +++ b/irlc/pacman/pacman_text_display.py @@ -0,0 +1,64 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# pacman_text_display.py +# -------------- +# Licensing Information: You are free to use or extend these projects for +# educational purposes provided that (1) you do not distribute or publish +# solutions, (2) you retain this notice, and (3) you provide clear +# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. +# +# Attribution Information: The Pacman AI projects were developed at UC Berkeley. +# The core projects and autograders were primarily created by John DeNero +# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). +# Student side autograding was added by Brad Miller, Nick Hay, and +# Pieter Abbeel (pabbeel@cs.berkeley.edu). +import time + +DRAW_EVERY = 1 +SLEEP_TIME = 0 # This can be overwritten by __init__ +DISPLAY_MOVES = False +QUIET = False # Supresses output + +class PacmanTextDisplay: + def __init__(self, speed=None): + if speed != None: + global SLEEP_TIME + SLEEP_TIME = speed + + def initialize(self, state, isBlue = False): + self.draw(state) + self.pause() + self.turn = 0 + self.agentCounter = 0 + + def update(self, state): + numAgents = len(state.agentStates) + self.agentCounter = (self.agentCounter + 1) % numAgents + if self.agentCounter == 0: + self.turn += 1 + if DISPLAY_MOVES: + ghosts = [nearestPoint(state.getGhostPosition(i)) for i in range(1, numAgents)] + print("%4d) P: %-8s" % (self.turn, str(nearestPoint(state.getPacmanPosition()))),'| Score: %-5d' % state.score,'| Ghosts:', ghosts) + if self.turn % DRAW_EVERY == 0: + self.draw(state) + self.pause() + if state._win or state._lose: + self.draw(state) + + def pause(self): + time.sleep(SLEEP_TIME) + + def draw(self, state): + print(state) + + def finish(self): + pass + +def nearestPoint( pos ): + """ + Finds the nearest grid point to a position (discretizes). + """ + ( current_row, current_col ) = pos + + grid_row = int( current_row + 0.5 ) + grid_col = int( current_col + 0.5 ) + return ( grid_row, grid_col ) diff --git a/irlc/pacman/pacman_utils.py b/irlc/pacman/pacman_utils.py new file mode 100644 index 0000000..1c55dfb --- /dev/null +++ b/irlc/pacman/pacman_utils.py @@ -0,0 +1,680 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# pacman_utils.py +# ------- +# Licensing Information: You are free to use or extend these projects for +# educational purposes provided that (1) you do not distribute or publish +# solutions, (2) you retain this notice, and (3) you provide clear +# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. +# +# Attribution Information: The Pacman AI projects were developed at UC Berkeley. +# The core projects and autograders were primarily created by John DeNero +# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). +# Student side autograding was added by Brad Miller, Nick Hay, and +# Pieter Abbeel (pabbeel@cs.berkeley.edu). + + +# pacman_utils.py +# ------- +# Licensing Information: Please do not distribute or publish solutions to this +# project. You are free to use and extend these projects for educational +# purposes. The Pacman AI projects were developed at UC Berkeley, primarily by +# John DeNero (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). +# For more info, see http://inst.eecs.berkeley.edu/~cs188/sp09/pacman.html + +import traceback +import sys +from collections import defaultdict +import io +import numpy as np +# from irlc.berkley.util import manhattanDistance + + +class PacAgent: + """ + An agent must define a getAction method, but may also define the + following methods which will be called if they exist: + + def registerInitialState(self, state): # inspects the starting state + """ + def __init__(self, index=0): + self.index = index + + def getAction(self, state): + """ + The Agent will receive a GameState (from either {pacman, capture, sonar}.py) and + must return an action from Directions.{North, South, East, West, Stop} + """ + raise NotImplementedError() + +class Directions: + NORTH = 'North' + SOUTH = 'South' + EAST = 'East' + WEST = 'West' + STOP = 'Stop' + + LEFT = {NORTH: WEST, + SOUTH: EAST, + EAST: NORTH, + WEST: SOUTH, + STOP: STOP} + + RIGHT = dict([(y,x) for x, y in LEFT.items()]) + + REVERSE = {NORTH: SOUTH, + SOUTH: NORTH, + EAST: WEST, + WEST: EAST, + STOP: STOP} + +class Configuration: + """ + A Configuration holds the (x,y) coordinate of a character, along with its + traveling direction. + + The convention for positions, like a graph, is that (0,0) is the lower left corner, x increases + horizontally and y increases vertically. Therefore, north is the direction of increasing y, or (0,1). + """ + + def __init__(self, pos, direction): + self.pos = pos + self.direction = direction + + def getPosition(self): + return (self.pos) + + def getDirection(self): + return self.direction + + def isInteger(self): + x,y = self.pos + return x == int(x) and y == int(y) + + def __eq__(self, other): + if other == None: return False + return (self.pos == other.pos and self.direction == other.direction) + + def __hash__(self): + x = hash(self.pos) + y = hash(self.direction) + return hash(x + 13 * y) + + def __str__(self): + return "(x,y)="+str(self.pos)+", "+str(self.direction) + + def generateSuccessor(self, vector): + """ + Generates a new configuration reached by translating the current + configuration by the action vector. This is a low-level call and does + not attempt to respect the legality of the movement. + + Actions are movement vectors. + """ + x, y= self.pos + dx, dy = vector + direction = Actions.vectorToDirection(vector) + if direction == Directions.STOP: + direction = self.direction # There is no stop direction + return Configuration((x + dx, y+dy), direction) + +class AgentState: + """ + AgentStates hold the state of an agent (configuration, speed, scared, etc). + """ + + def __init__( self, startConfiguration, isPacman ): + self.start = startConfiguration + self.configuration = startConfiguration + self.isPacman = isPacman + self.scaredTimer = 0 + self.numCarrying = 0 + self.numReturned = 0 + # Tue + # self.draw_delta_xy = (0,0) + # for instance, pacman endpoints, mid-animation movement, etc. + self.draw_extra = {'delta_xy': (0,0)} + + + def __str__( self ): + if self.isPacman: + return "Pacman: " + str( self.configuration ) + else: + return "Ghost: " + str( self.configuration ) + + def __eq__( self, other ): + if other == None: + return False + return self.configuration == other.configuration and self.scaredTimer == other.scaredTimer + + def __hash__(self): + return hash(hash(self.configuration) + 13 * hash(self.scaredTimer)) + + def copy( self ): + state = AgentState( self.start, self.isPacman ) + state.configuration = self.configuration + state.scaredTimer = self.scaredTimer + state.numCarrying = self.numCarrying + state.numReturned = self.numReturned + return state + + def getPosition(self): + if self.configuration == None: return None + return self.configuration.getPosition() + + def getDirection(self): + return self.configuration.getDirection() + +class Grid: + """ + A 2-dimensional array of objects backed by a list of lists. Data is accessed + via grid[x][y] where (x,y) are positions on a Pacman map with x horizontal, + y vertical and the origin (0,0) in the bottom left corner. + + The __str__ method constructs an output that is oriented like a pacman board. + """ + def __init__(self, width, height, initialValue=False, bitRepresentation=None): + if initialValue not in [False, True]: + raise Exception('Grids can only contain booleans') + self.CELLS_PER_INT = 30 + + self.width = width + self.height = height + self.data = [[initialValue for y in range(height)] for x in range(width)] + if bitRepresentation: + self._unpackBits(bitRepresentation) + + def __getitem__(self, i): + return self.data[i] + + def __setitem__(self, key, item): + self.data[key] = item + + def __str__(self): + out = [[str(self.data[x][y])[0] for x in range(self.width)] for y in range(self.height)] + out.reverse() + return '\n'.join([''.join(x) for x in out]) + + def __eq__(self, other): + if other == None: return False + return self.data == other.data + + def __hash__(self): + # return hash(str(self)) + base = 1 + h = 0 + for l in self.data: + for i in l: + if i: + h += base + base *= 2 + return hash(h) + + def copy(self): + g = Grid(self.width, self.height) + g.data = [x[:] for x in self.data] + return g + + def deepCopy(self): + return self.copy() + + def shallowCopy(self): + g = Grid(self.width, self.height) + g.data = self.data + return g + + def count(self, item =True ): + return sum([x.count(item) for x in self.data]) + + def asList(self, key = True): + list = [] + for x in range(self.width): + for y in range(self.height): + if self[x][y] == key: list.append( (x,y) ) + return list + + def packBits(self): + """ + Returns an efficient int list representation + + (width, height, bitPackedInts...) + """ + bits = [self.width, self.height] + currentInt = 0 + for i in range(self.height * self.width): + bit = self.CELLS_PER_INT - (i % self.CELLS_PER_INT) - 1 + x, y = self._cellIndexToPosition(i) + if self[x][y]: + currentInt += 2 ** bit + if (i + 1) % self.CELLS_PER_INT == 0: + bits.append(currentInt) + currentInt = 0 + bits.append(currentInt) + return tuple(bits) + + def _cellIndexToPosition(self, index): + x = index / self.height + y = index % self.height + return x, y + + def _unpackBits(self, bits): + """ + Fills in data from a bit-level representation + """ + cell = 0 + for packed in bits: + for bit in self._unpackInt(packed, self.CELLS_PER_INT): + if cell == self.width * self.height: break + x, y = self._cellIndexToPosition(cell) + self[x][y] = bit + cell += 1 + + def _unpackInt(self, packed, size): + bools = [] + if packed < 0: raise ValueError("must be a positive integer") + for i in range(size): + n = 2 ** (self.CELLS_PER_INT - i - 1) + if packed >= n: + bools.append(True) + packed -= n + else: + bools.append(False) + return bools + +def reconstituteGrid(bitRep): + if type(bitRep) is not type((1,2)): + return bitRep + width, height = bitRep[:2] + return Grid(width, height, bitRepresentation= bitRep[2:]) + +#################################### +# Parts you shouldn't have to read # +#################################### + +class Actions: + """ + A collection of static methods for manipulating move actions. + """ + # Directions + _directions = {Directions.NORTH: (0, 1), + Directions.SOUTH: (0, -1), + Directions.EAST: (1, 0), + Directions.WEST: (-1, 0), + Directions.STOP: (0, 0)} + + _directionsAsList = _directions.items() + + TOLERANCE = .001 + + def reverseDirection(action): + if action == Directions.NORTH: + return Directions.SOUTH + if action == Directions.SOUTH: + return Directions.NORTH + if action == Directions.EAST: + return Directions.WEST + if action == Directions.WEST: + return Directions.EAST + return action + reverseDirection = staticmethod(reverseDirection) + + def vectorToDirection(vector): + dx, dy = vector + if dy > 0: + return Directions.NORTH + if dy < 0: + return Directions.SOUTH + if dx < 0: + return Directions.WEST + if dx > 0: + return Directions.EAST + return Directions.STOP + vectorToDirection = staticmethod(vectorToDirection) + + def directionToVector(direction, speed = 1.0): + # print(direction) + dx, dy = Actions._directions[direction] + # dx, dy = list(Actions._directions.values())[direction] + + return (dx * speed, dy * speed) + directionToVector = staticmethod(directionToVector) + + def getPossibleActions(config, walls): + possible = [] + x, y = config.pos + x_int, y_int = int(x + 0.5), int(y + 0.5) + + # In between grid points, all agents must continue straight + if (abs(x - x_int) + abs(y - y_int) > Actions.TOLERANCE): + return [config.getDirection()] + + for dir, vec in Actions._directionsAsList: + dx, dy = vec + next_y = y_int + dy + next_x = x_int + dx + if not walls[next_x][next_y]: possible.append(dir) + + return possible + + getPossibleActions = staticmethod(getPossibleActions) + + def getLegalNeighbors(position, walls): + x,y = position + x_int, y_int = int(x + 0.5), int(y + 0.5) + neighbors = [] + for dir, vec in Actions._directionsAsList: + dx, dy = vec + next_x = x_int + dx + if next_x < 0 or next_x == walls.width: continue + next_y = y_int + dy + if next_y < 0 or next_y == walls.height: continue + if not walls[next_x][next_y]: neighbors.append((next_x, next_y)) + return neighbors + getLegalNeighbors = staticmethod(getLegalNeighbors) + + def getSuccessor(position, action): + dx, dy = Actions.directionToVector(action) + x, y = position + return (x + dx, y + dy) + getSuccessor = staticmethod(getSuccessor) + +class GameStateData: + """ + + """ + def __init__( self, prevState = None ): + """ + Generates a new data packet by copying information from its predecessor. + """ + if prevState != None: + self.food = prevState.food.shallowCopy() + self.capsules = prevState.capsules[:] + self.agentStates = self.copyAgentStates( prevState.agentStates ) + self.layout = prevState.layout + self._eaten = prevState._eaten + self.score = prevState.score + + self._foodEaten = None + self._foodAdded = None + self._capsuleEaten = None + self._agentMoved = None + self._lose = False + self._win = False + self.scoreChange = 0 + + def deepCopy( self ): + state = GameStateData( self ) + state.food = self.food.deepCopy() + state.layout = self.layout.deepCopy() + state._agentMoved = self._agentMoved + state._foodEaten = self._foodEaten + state._foodAdded = self._foodAdded + state._capsuleEaten = self._capsuleEaten + + # Tue: I added these. I got no idea if this will screw things up. But why should they not be deep copied? + state._win = self._win + state._lose = self._lose + return state + + def copyAgentStates( self, agentStates ): + copiedStates = [] + for agentState in agentStates: + copiedStates.append( agentState.copy() ) + return copiedStates + + def __eq__( self, other ): + """ + Allows two states to be compared. + """ + if other == None: return False + # TODO Check for type of other + if not self.agentStates == other.agentStates: return False + if not self.food == other.food: return False + if not self.capsules == other.capsules: return False + # if not self.score == other.score: return False # This i am very unsure about. + return True + + def __hash__( self ): + """ + Allows states to be keys of dictionaries. + """ + for i, state in enumerate( self.agentStates ): + try: + int(hash(state)) + except TypeError as e: + print(e) + #hash(state) + return int((hash(tuple(self.agentStates)) + 13*hash(self.food) + 113* hash(tuple(self.capsules)) + 0 * hash(self.score)) % 1048575 ) + + def __str__( self ): + width, height = self.layout.width, self.layout.height + map = Grid(width, height) + if type(self.food) == type((1,2)): + self.food = reconstituteGrid(self.food) + for x in range(width): + for y in range(height): + food, walls = self.food, self.layout.walls + map[x][y] = self._foodWallStr(food[x][y], walls[x][y]) + + for agentState in self.agentStates: + if agentState == None: continue + if agentState.configuration == None: continue + x,y = [int( i ) for i in nearestPoint( agentState.configuration.pos )] + agent_dir = agentState.configuration.direction + if agentState.isPacman: + map[x][y] = self._pacStr( agent_dir ) + else: + map[x][y] = self._ghostStr( agent_dir ) + + for x, y in self.capsules: + map[x][y] = 'o' + + return str(map) + ("\nScore: %d\n" % self.score) + + # def str_no_score(self): # + # return "\n".join(str(self).splitlines()[:-1]) + + def _foodWallStr( self, hasFood, hasWall ): + if hasFood: + return '.' + elif hasWall: + return '%' + else: + return ' ' + + def _pacStr( self, dir ): + if dir == Directions.NORTH: + return 'v' + if dir == Directions.SOUTH: + return '^' + if dir == Directions.WEST: + return '>' + return '<' + + def _ghostStr( self, dir ): + return 'G' + if dir == Directions.NORTH: + return 'M' + if dir == Directions.SOUTH: + return 'W' + if dir == Directions.WEST: + return '3' + return 'E' + + def initialize( self, layout, numGhostAgents ): + """ + Creates an initial game state from a layout array (see layout.py). + """ + self.food = layout.food.copy() + #self.capsules = [] + self.capsules = layout.capsules[:] + self.layout = layout + self.score = 0 + self.scoreChange = 0 + + self.agentStates = [] + numGhosts = 0 + for isPacman, pos in layout.agentPositions: + if not isPacman: + if numGhosts == numGhostAgents: continue # Max ghosts reached already + else: numGhosts += 1 + self.agentStates.append( AgentState( Configuration( pos, Directions.STOP), isPacman) ) + self._eaten = [False for a in self.agentStates] + +try: + import boinc + _BOINC_ENABLED = True +except: + _BOINC_ENABLED = False + +class Game: + """ + The Game manages the control flow, soliciting actions from agents. + """ + + def __init__( self, agents, rules, display=None, startingIndex=0, muteAgents=False, catchExceptions=False ): + self.agentCrashed = False + self.agents = agents + # self.display = display + self.rules = rules + self.startingIndex = startingIndex + self.gameOver = False + self.muteAgents = muteAgents + self.catchExceptions = catchExceptions + self.moveHistory = [] + self.totalAgentTimes = [0 for agent in agents] + self.totalAgentTimeWarnings = [0 for agent in agents] + self.agentTimeout = False + # import cStringIO + + self.agentOutput = [io.StringIO() for agent in agents] + + def getProgress(self): + if self.gameOver: + return 1.0 + else: + return self.rules.getProgress(self) + + def _agentCrash( self, agentIndex, quiet=False): + "Helper method for handling agent crashes" + if not quiet: traceback.print_exc() + self.gameOver = True + self.agentCrashed = True + self.rules.agentCrash(self, agentIndex) + + OLD_STDOUT = None + OLD_STDERR = None + + def mute(self, agentIndex): + if not self.muteAgents: return + global OLD_STDOUT, OLD_STDERR + # import cStringIO + OLD_STDOUT = sys.stdout + OLD_STDERR = sys.stderr + sys.stdout = self.agentOutput[agentIndex] + sys.stderr = self.agentOutput[agentIndex] + + def unmute(self): + if not self.muteAgents: return + global OLD_STDOUT, OLD_STDERR + # Revert stdout/stderr to originals + sys.stdout = OLD_STDOUT + sys.stderr = OLD_STDERR + + +def nearestPoint( pos ): + """ + Finds the nearest grid point to a position (discretizes). + """ + ( current_row, current_col ) = pos + grid_row = int( current_row + 0.5 ) + grid_col = int( current_col + 0.5 ) + return ( grid_row, grid_col ) + + +def chooseFromDistribution( distribution ): + "Takes either a counter or a list of (prob, key) pairs and samples" + # k, v = zip( distribution.items() ) + k, v = zip(*distribution.items()) + sel = np.random.choice( list(k), 1, replace=True, p=list(v) ) + return sel[0] + + +class GhostAgent( PacAgent ): + # def __init__( self, index ): + # self.index = index + + def getAction( self, state ): + dist = self.getDistribution(state) + if len(dist) == 0: + return Directions.STOP + else: + return chooseFromDistribution(dist) + # return util.chooseFromDistribution( dist ) + + def getDistribution(self, state): + "Returns a Counter encoding a distribution over actions from the provided state." + raise NotImplementedError() + # util.raiseNotDefined() + + +class RandomGhost( GhostAgent ): + "A ghost that chooses a legal action uniformly at random." + def getDistribution( self, state ): + # dist = util.Counter() + dist = {} + for a in state.getLegalActions( self.index ): + dist[a] = 1.0 + sm = sum(dist.values()) + for a in dist: + dist[a] = dist[a]/sm + + # dist.normalize() + return dist + + +class DirectionalGhost( GhostAgent ): + "A ghost that prefers to rush Pacman, or flee when scared." + def __init__( self, index, prob_attack=0.8, prob_scaredFlee=0.8 ): + self.index = index + self.prob_attack = prob_attack + self.prob_scaredFlee = prob_scaredFlee + + def getDistribution( self, state ): + # Read variables from state + ghostState = state.getGhostState( self.index ) + legalActions = state.getLegalActions( self.index ) + pos = state.getGhostPosition( self.index ) + isScared = ghostState.scaredTimer > 0 + + speed = 1 + if isScared: speed = 0.5 + + actionVectors = [Actions.directionToVector( a, speed ) for a in legalActions] + newPositions = [( pos[0]+a[0], pos[1]+a[1] ) for a in actionVectors] + pacmanPosition = state.getPacmanPosition() + + # Select best actions given the state + distancesToPacman = [manhattanDistance( pos, pacmanPosition ) for pos in newPositions] + if isScared: + bestScore = max( distancesToPacman ) + bestProb = self.prob_scaredFlee + else: + bestScore = min( distancesToPacman ) + bestProb = self.prob_attack + bestActions = [action for action, distance in zip( legalActions, distancesToPacman ) if distance == bestScore] + + # Construct distribution + # dist = util.Counter() + + + dist = defaultdict(lambda: 0) + + for a in bestActions: dist[a] = bestProb / len(bestActions) + for a in legalActions: dist[a] += ( 1-bestProb ) / len(legalActions) + + sm = sum(dist.values()) + for k, v in dist.items(): + dist[k] = v /sm + # dist = {k: v/sm for k, v in dist.items() } + # dist.normalize() + return dist diff --git a/irlc/project0/__init__.py b/irlc/project0/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/project0/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/project0/__pycache__/__init__.cpython-311.pyc b/irlc/project0/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cc28450a2987c5790bd8ac7792fb3e66f490d636 GIT binary patch literal 173 zcmZ3^%ge>Uz`$Uc-<!6Pfq~&Mhy%lnP{wCA1_p-d3@Hr344RC7D;bKI7#J8ngCu`B z=x5~Trs|iJW~A!7<R_QrrskCt>u2WX=o=WBm>Lw9l%_yLigJ?m3ySiyQj<#z^yA|* x^D;}~<Mj$Ee{tC4=BJeAq}mm+GB7ZJtSshdU|{&b%*e?2fdNJoF*7hQ002nxDXIVf literal 0 HcmV?d00001 diff --git a/irlc/project0/fruit_project_grade.py b/irlc/project0/fruit_project_grade.py new file mode 100644 index 0000000..1207c3a --- /dev/null +++ b/irlc/project0/fruit_project_grade.py @@ -0,0 +1,4 @@ +# irlc/project0/fruit_project_tests.py +''' WARNING: Modifying, decompiling or otherwise tampering with this script, it's data or the resulting .token file will be investigated as a cheating attempt. ''' +import bz2, base64 +exec(bz2.decompress(base64.b64decode('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'))) \ No newline at end of file diff --git a/irlc/project0/fruit_project_tests.py b/irlc/project0/fruit_project_tests.py new file mode 100644 index 0000000..331949c --- /dev/null +++ b/irlc/project0/fruit_project_tests.py @@ -0,0 +1,121 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import UTestCase, Report +from irlc.ex00.fruit_homework import add, misterfy, mean_value, fruits_ordered, BasicFruitShop, OnlineFruitShop, shop_smart +from unitgrade import hide + +class AdditionQuestion(UTestCase): + """ Problem 1: Adding two numbers """ + def test_add(self): + """ Adding two numbers together """ + self.assertEqual(add(2, 3), 5) # Test the add-function. + self.assertEqual(add(2, -917), -915) # Test the add-function. + + + +class MisterfyQuestion(UTestCase): + """ Problem 2: Misterfy a list """ + def test_misterfy(self): + """ Add 'mr' in front of each item in a string """ + self.assertEqualC(misterfy(['dog', 'cat', 'lion'])) + self.assertEqualC(misterfy(['giraffe'])) + self.assertEqualC(misterfy([])) + + + +class MeanOfDie(UTestCase): + """ Problem 3: Mean of die """ + def test_mean_value(self): + """ Compute mean of two dice """ + p_die = {1: 0.20, + 2: 0.10, + 3: 0.15, + 4: 0.05, + 5: 0.10, + 6: 0.40} + self.assertL2(mean_value(p_die), tol=0.0001) + self.assertL2(mean_value({-1: 0.5, 1: 0.5}), tol=0.0001) + + + +class FruitsOrdered(UTestCase): + """ Problem 4: The fruits_ordered function """ + def test_fruits_ordered(self): + """ fruits_ordered """ + order = {'apples': 1.0, + 'oranges': 3.0} + self.assertEqualC(list(sorted(fruits_ordered(order)))) + order2 = {'banana': 4, + 'apples': 1.0, + 'oranges': 3.0, + 'pears': 4} + self.assertEqualC(list(sorted(fruits_ordered(order2)))) + + +class BasicClass(UTestCase): + """ Problem 5: The BasicFruitShop """ + def test_cost(self): + """ Testing cost function """ + price1 = {"apple": 4, "pear": 8, 'orange': 10} + shop1 = BasicFruitShop("Alis Funky Fruits", price1) + self.assertEqualC(shop1.cost("apple")) + self.assertEqualC(shop1.cost("pear")) + + price2 = {'banana': 9, "apple": 5, "pear": 7, 'orange': 11} + shop2 = BasicFruitShop("Hansen Fruit Emporium", price2) + self.assertEqualC(shop2.cost("orange")) + self.assertEqualC(shop2.cost("banana")) + + +class Inheritance(UTestCase): + title = "Problem 6: Inheritance" + + def test_price_of_order(self): + """ Testing the price_of_order function """ + price_of_fruits = {'apples': 2, 'oranges': 1, 'pears': 1.5, 'mellon': 10, 'banana': 1.5} + shopA = OnlineFruitShop('shopA', price_of_fruits) + + order1 = {'apples': 1.0, + 'oranges': 3.0} + self.assertL2(shopA.price_of_order(order1), tol=1e-8) + order2 = {'banana': 4, + 'apples': 1.0, + 'oranges': 3.0, + 'pears': 4} + self.assertL2(shopA.price_of_order(order2), tol=1e-8) + + +class ClassUse(UTestCase): + title = "Problem 7: Using classes" + + def test_shop_smarter(self): + """ Testing the shop_smarter function """ + price_of_fruits = {'apples': 2, 'oranges': 1, 'pears': 1.5, 'mellon': 10} + shopA = OnlineFruitShop('shopA', price_of_fruits) + shopB = OnlineFruitShop('shopB', {'apples': 1.0, 'oranges': 5.0}) + + shops = [shopA, shopB] + order = {'apples': 1.0, + 'oranges': 3.0} + self.assertEqualC(shop_smart(order, shops).name) + order = {'apples': 3.0} # test with a new order. + self.assertEqualC(shop_smart(order, shops).name) + + +class FruitReport(Report): + title = "Fruit example report" + abbreviate_questions = True + questions = [(AdditionQuestion, 10), + (MisterfyQuestion, 10), + (MeanOfDie, 10), + (FruitsOrdered, 10), + (BasicClass, 10), + (Inheritance, 10), + (ClassUse, 10)] + + import irlc + pack_imports = [irlc] + + +if __name__ == "__main__": + from unitgrade import evaluate_report_student + evaluate_report_student(FruitReport()) diff --git a/irlc/project0/fruit_project_tests_complete_grade.py b/irlc/project0/fruit_project_tests_complete_grade.py new file mode 100644 index 0000000..b76bbb3 --- /dev/null +++ b/irlc/project0/fruit_project_tests_complete_grade.py @@ -0,0 +1,4 @@ +# irlc/project0/fruit_project_tests_complete.py +''' WARNING: Modifying, decompiling or otherwise tampering with this script, it's data or the resulting .token file will be investigated as a cheating attempt. ''' +import bz2, base64 +exec(bz2.decompress(base64.b64decode('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'))) \ No newline at end of file diff --git a/irlc/project0/unitgrade_data/AdditionQuestion.pkl b/irlc/project0/unitgrade_data/AdditionQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..11c0af9d431d3f61b3f2af0fba319cf8b8bb1958 GIT binary patch literal 161 zcmZo*nL3RD0&1sd^awbnq-2(4=H~^LrWS+fDLq`psU@KW&N+$2#Z%g*^stm<=B7?* zo8oRS>HyZ4!Pvu5l3H96pO}&YQovf0S&{=%(IX8qEH7Q5q�CuQWF)wWwI3BtJd1 oBqOzGN(N&FTicW#w#4G%)S{9pZBuHYLK!R|!xbXHhL`FA0MWHLiU0rr literal 0 HcmV?d00001 diff --git a/irlc/project0/unitgrade_data/BasicClass.pkl b/irlc/project0/unitgrade_data/BasicClass.pkl new file mode 100644 index 0000000000000000000000000000000000000000..110aa845e0142c58c171373055b1d656633a26d1 GIT binary patch literal 446 zcmZo*nYx*g0Ss!VX!LM7B^GBUJLe=87f<QoDo!m4Er4*^ru49sWag$$X`AA1FMk27 zA%n4pvm~{+BtAL6xMWJ(lpfZS%#s|Ck{;2J)Z&uNymSSSltNl*UUErhe%_P}#tgQ$ zDLrh7#l@*bAT701G`tzSS-cs&IlP&?xxJaaIZGjmGFU)1IZc7u1lGrqoL`n&l$Z{( zqIOD;bY@XbvVLlXfq{NnQE6sLd`5n5YI%N9wq8Ny6p*}vf`URyY8u!P8pWwOX*vpE zg_>3hQ@j;>c7fzUSV>7qAt<$^v?x!ZBqJ59Tp=@0p&-9BFQr%^KMgDj)~QgQS(2fU zmzbNXpbi#L*HiE;Q7A1=Ee0zBS)x}^l$o4btWcI%l$n^6lgb6M0)$KQ71C2n!0NzC z^x!g)`K1ae`FZLk3VEriDGDX|3Mu&tsTIko1)yM4$Vkjf$pM9CMru*2o`RB+(v-F- I#l@w10RQKfH~;_u literal 0 HcmV?d00001 diff --git a/irlc/project0/unitgrade_data/ClassUse.pkl b/irlc/project0/unitgrade_data/ClassUse.pkl new file mode 100644 index 0000000000000000000000000000000000000000..25c6e361e111f36205adfa0ef92620470f6a0198 GIT binary patch literal 1380 zcmZo*nHtH;00y;FG<rCka}tY-LyJ?V^l%lYmV_37`BU1a^stm<=B7?*o8oRSumG$) zgRw`jB(=CCzBnVlAig*^v8W`q2&9s=B(o$3q_jsdB(=CCGcR4CBqLP;S(!pwX<l+k zW`5q348{z$wkbVqiN(dKMI}?(rqoW+@Mh>?1*vwN;>`$QIZY{rD9m61xxju6)CFL@ z9Lf1*sYQwDAS-L9^hjqG<s|E;Ru~xQrxlfEmc(b|=cbnD7iH@eRDw+JkycPpP)JEl zQ%KG)F3~7X%}LWy0ISrrQkdec*s}{H55h`HN(w=#C8b4qU=M(lD`e&=6y%rYr4%dV zr-4PmIu*(@OEMJl5_3}()WHJkdJ3K;3Z=!V#b8AsOY{ngGLut_70MEeG82<>Qn^4@ zfN)8^LV9WmSRGi29$Y3ezf>V5KTo|xAulyGMWG~LAthfSwIVsS02Fo#8Hsr*IiTRp zNG(d$Q&3V;0tLS+$V`y;z=p-=r^V+NrKA=?Jql)nJ*pcK&B(w2QVhaMN=k5R!D`}D zGLuUbY!#~26AKD*Qq`>#Om!603sMt{)U6bZbQJXT^lBB#K{kV3o>!Wilv-4*kXV!o z<`<SG=9OfYR4RZCOHI+^f*bFVnO9P5rQnhYP63HUl?uuExdlb38L4^2nfZANIhon1 zR&dn{b_!|vMUV*6frWi$9>iR*BlR*%Qge$nG?BG{13W#o#5upXBp|gY02E~!;F!@= zNX*H}FE3W8%r6CnC@AQ`F`J*JkO;8`*&tBLEy*uQ%u&cJRwypb1x0%`Bn8weXem^K zw8j^t7R7_bYT;U;k)Z;L2vAyvWDpH-Xh4%2IO7z9<H9E5A~Y_r$AgsuC^j<l^FX16 zh!JCGG~}m29A2!Dn3n<$ez0qbA%T>d0(TWS1cEd23yQ52d@_qmK)&(M%gM}3bpvG; zunZ)kAdv*uXr~aAnwtuWVvzAgsi4qER49g|X?Pk_$W1ND$VXUbrx02UN)DODP#I8w zr)3rumnh^WW~VA7D&&A1k({4bl9-tXO39$$1_dd|VIVd*yc7~k6jBqDGa#M>7bHjy z1N$Q*u^5z0auuRMx(#)}dD|#f2jtp3g|tj)uw>??q*lPpF3wHN$w@6PQ7B8yDNR+- x0NDq256G~@JO!{~U06wlNM3ddMUX-P5t`9C`Q@OZ5UeE@l7S&9ptQJD4*+Od#A^Tm literal 0 HcmV?d00001 diff --git a/irlc/project0/unitgrade_data/FruitsOrdered.pkl b/irlc/project0/unitgrade_data/FruitsOrdered.pkl new file mode 100644 index 0000000000000000000000000000000000000000..b55dba6dd8f3b84b5a4bdd0a9f85ba60a0ce7f29 GIT binary patch literal 307 zcmZo*nX19a00y;FG<ta5ib^v}iv5dHQj1bkru1+Xr<Q~kIOil57f)%M(!)}cnVUML zZHl`+*8{Mg48|VelGNgo_%yJ-_<X3wwkbWVC7C5TAjLg=Xp$L>8EkD+de{<+i&KkA zrnF6|ouc8*5IaSqhb^(7ASbnWN)LN}QDR<tYVnj*Z^qau8W{pTY)OfEiFt`rG6Z{A z3sMt{il?NOLJZ1a0XfLO2<jlP*&NCFWvNAp=^*=Sr}Ri?7Ud-Cr&bsk=!4x7pOK%N yTAp8&tyfSvrFKe>LP~0y0$8RP<^>I~SK?DLlS?$M6sC9!^)O6nn^Ig{ss{ibp>cZv literal 0 HcmV?d00001 diff --git a/irlc/project0/unitgrade_data/Inheritance.pkl b/irlc/project0/unitgrade_data/Inheritance.pkl new file mode 100644 index 0000000000000000000000000000000000000000..32072c814e584f70b67d9d0895c4d07be7286c27 GIT binary patch literal 875 zcmZo*nVP`N00y;FG<vu_^D<J4GD{Nkl2fPja22PPgcdmGBo-G>X`9l+Qj(dQI;Cxj zyFK><u#ODI9^sPI;*$7+qRiyf`24i^{Gyc9B9L0vlFX7Ekm4TYkksOm%)E4kl8jUZ zRD}v@rFqFEnfZBBG8i-1+NSidB^DQ_7L`nCn^HSP!<)g~K?H0MgEynQgCT@j3Q?ND z0&+)aFIW&F)WeaSUzS>wm=3bGc1n+QW>HSEerkn*fqq(1X=X`$Mt*K;d45s0UO^?u z{2plq1qFqa)HH?U{NfUg;?$fp9R;vTO)G^d-ikfDK=L50q@<(}lv+|+ln3?%NV!60 zo<c!>X<kaPLVg-p6s%LBJhLQ2AulmERY4srpsuIjS)x!{oLUT41hPaA90<h<Wr;<Z ziAg!BTp%kzxFla8J+%a^4y;5EE)$tws*sYOr(U9vmztWQP?E2ZlCO|jk(^op3O$94 z#JrRoP!MON7NzPbC@Cp{qCgd7CdhkW!{D(4^(Z)|z#i3&h-PG904WAxB_$=ewO}>z zDVfP73bqQ>>WKvfIjQPa3Z^;=>IJEZMe0@xMmh?5dU~}A<sh5EF3&5?O-d~)R!A&L z1@j9_6Z1+kODYw>hNY(HalwuE$jmD#wo-7(1gC+-qDqD2{M>?~)Qr@;;>`R!g`CXn zR4ce@1v`bb{31vM>A=E1GY?`e*pYgfC8@c^8k)#jzyY3~TH>5vToRC46ab1c4RFk8 zDkSFQ<d+vKROXk0LKGDA;F!%%Q%HnZgKQ8e^_Jw9B<3h&7Aq8&=7OTV8j=EP6|@wp XL0aPrQj6ljVzqFskjN-4F4Y47;zJtO literal 0 HcmV?d00001 diff --git a/irlc/project0/unitgrade_data/MeanOfDie.pkl b/irlc/project0/unitgrade_data/MeanOfDie.pkl new file mode 100644 index 0000000000000000000000000000000000000000..27877f6a8e70ffb0d0ad3cac120b703d81d980fd GIT binary patch literal 546 zcmZo*nJUi200y;FG<rCFQxo(2(_AuBr}S_Yr<Q~kIOil57f)%M(!)}cnVUMLZHl`+ z{{gW248|V*lGNgo_}tXQy!f)joKlc<4{J$gNe-AL;hdjaP+F3z08*fkpQcb!p0ALS znVdQ$gE51xZAuSYVsUY5QOT6HDYa8Hycygb_-BH^EN@14uni0h45bjI87v@+gC2v0 zAwoSI$@yieMTzMkyK1NONM{!1B<rVE7#QfM6_sX|#AoE^rk3XyW$P7GPN|*JBaxDt z26hR=sTu|GDVfP7npO%^y!j&p7#SE86ciMcl$5wYw0mY*YMw$O$h9Sz`FV*&m0<U0 zq$;H47v)+hR99Fj6cptrB_?I&WR_IM=cmP2=qTvv>D4MELp@!R0rfaIWEAq#zy??7 zC}irT>M0bL=Ei3#RK#a0XektERK#a$>M4X|q$(7pCg<norsk!jrYMvrRw`r`E0p9b zloqEd<YX3?fDJE7%}C8F&dkqKNX$!7$jdKL$Sch)sMG_S?~$2TVx{1dpP#LeSfT)O zgI;DyYHqQHrb2FNNk)DOSQAJ*sWdYuMK?1K<P?qE%6O3ZFhzQxfSA%YrMS3M4*<CE BxWfPd literal 0 HcmV?d00001 diff --git a/irlc/project0/unitgrade_data/MisterfyQuestion.pkl b/irlc/project0/unitgrade_data/MisterfyQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2359530f1174d72bd344f9add58dd05e577704fb GIT binary patch literal 490 zcmZo*nR=g*0Ss!VX!Hp9W)_#E7Nu1NmZlb$Waj5h>ES9)EeS1f&PgmTp3*j@hovMl zH+4$e6nA@W1+caZ#vb01)Z&u(T&Px%D%O(Bk{pn-9xca|6b1F%B6Wq#JcYEP{Jau{ z{4|Bs#N-Tx%#zexkZ7VpaY<2TUiy>_#tgQ$DLrh7#l@*bB~#j_)K1axW{91l(ZiNo zq>z%IJ_XE3PAr+y!=78DkOOjHsyAcolpe0!B8BwKqQtbc)G3MHOtDi+A%<nJfSlU$ z-2voQh)@qla(-EAQDQpCeYI11q%(_hlJ!$73=H(sib^v};xqDdQ_J&<vh@lor_@gA z5l=}?Q-FC+BQY;CH!-JJ(@J5AH%HH61qB5KB_$;;5bd5>mYS!KsF0Ic4E7{csX|U> zcB%rDV;ilMoLHiyqo7otpOXfnQ*%-aG7|HOm11=iN-{Ew71B!cl0iYQP@Iupnv<eX ulv+|+ln1r}YBt!wXr<gD1*loMMG7$Ea*Gt8CYC70g55TyZAx)*sU8618LG4Z literal 0 HcmV?d00001 diff --git a/irlc/project1/Latex/02465project1_handin.tex b/irlc/project1/Latex/02465project1_handin.tex new file mode 100644 index 0000000..f59e1d2 --- /dev/null +++ b/irlc/project1/Latex/02465project1_handin.tex @@ -0,0 +1,107 @@ +\documentclass[12pt,twoside]{article} +%\usepackage[table]{xcolor} % important to avoid options clash. +%\input{02465shared_preamble} +%\usepackage{cleveref} +\usepackage{url} +\usepackage{graphics} +\usepackage{multicol} +\usepackage{rotate} +\usepackage{rotating} +\usepackage{booktabs} +\usepackage{hyperref} +\usepackage{pifont} +\usepackage{latexsym} +\usepackage[english]{babel} +\usepackage{epstopdf} +\usepackage{etoolbox} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage{multirow,epstopdf} +\usepackage{fancyhdr} +\usepackage{booktabs} +\usepackage{xcolor} +\newcommand\redt[1]{ {\textcolor[rgb]{0.60, 0.00, 0.00}{\textbf{ #1} } } } + + +\newcommand{\m}[1]{\boldsymbol{ #1}} +\newcommand{\yoursolution}{ \redt{(your solution here) } } + + + +\title{ Report 1 hand-in } +\date{ \today } +\author{Alice (\texttt{s000001})\and Bob (\texttt{s000002})\and Clara (\texttt{s000003}) } + +\begin{document} +\maketitle + +\begin{table}[ht!] +\caption{Attribution table. Feel free to add/remove rows and columns} +\begin{tabular}{llll} +\toprule + & Alice & Bob & Clara \\ +\midrule + 1: A basic blaster-business & 0-100\% & 0-100\% & 0-100\% \\ + 2: Warmup & 0-100\% & 0-100\% & 0-100\% \\ + 3: Manually computing $J_{N-1}$ & 0-100\% & 0-100\% & 0-100\% \\ + 4: Compute optimal policy and value function & 0-100\% & 0-100\% & 0-100\% \\ + 5: Kiosk2 & 0-100\% & 0-100\% & 0-100\% \\ + 6: Explaining the policy & 0-100\% & 0-100\% & 0-100\% \\ + 7: Policy explanation continued & 0-100\% & 0-100\% & 0-100\% \\ + 8: Go east & 0-100\% & 0-100\% & 0-100\% \\ + 9: Describe the go-east problem & 0-100\% & 0-100\% & 0-100\% \\ + 10: Predict consequence of actions & 0-100\% & 0-100\% & 0-100\% \\ + 11: Possible future states & 0-100\% & 0-100\% & 0-100\% \\ + 12: Shortest path & 0-100\% & 0-100\% & 0-100\% \\ + 13: Predict consequence of actions with one ghost & 0-100\% & 0-100\% & 0-100\% \\ + 14: Possible future states with one ghost & 0-100\% & 0-100\% & 0-100\% \\ + 15: Optimal one-ghost planning & 0-100\% & 0-100\% & 0-100\% \\ + 16: Predict consequence of actions with several ghosts & 0-100\% & 0-100\% & 0-100\% \\ + 17: Future states & 0-100\% & 0-100\% & 0-100\% \\ + 18: Optimal planning & 0-100\% & 0-100\% & 0-100\% \\ +\bottomrule +\end{tabular} +\end{table} + +%\paragraph{Statement about collaboration:} +%Please edit this section to reflect how you have used external resources. The following statement will in most cases suffice: +%\emph{The code in the irls/project1 directory is entirely} + +%\paragraph{Main report:} +Headings have been inserted in the document for readability. You only have to edit the part which says \yoursolution. + +\section{The kiosk (\texttt{kiosk.py})} +\subsubsection*{{\color{red}Problem 1: A basic blaster-business}} + +\yoursolution +\redt{To get you started: \begin{align} + N & = 14 \\ + \mbox{for $k=0,\dots,N$: }\quad \mathcal{S}_k & = \dots \\ + \mbox{for $k=0,\dots,N-1$: }\quad \mathcal{A}_k(x_k) & = \dots \\ + & \vdots +\end{align} } + +\subsubsection*{{\color{red}Problem 3: Manually computing $J_{N-1}$}} + + \yoursolution + $$ + J_{N-1}(20) = ... + $$ + +\subsubsection*{{\color{red}Problem 6: Explaining the policy}} + + The first policy... this can be explained by noting ... \yoursolution + +\subsubsection*{{\color{red}Problem 7: Policy explanation continued}} + + $$\mu_{N-1}(0) = ...$$ +\yoursolution + +\section{Avoid the droid (\texttt{pacman.py)}} +\subsubsection*{{\color{red}Problem 9: Describe the go-east problem}} + + The environment is an example of a .... \\ + The controller is an example of a ... + \yoursolution + +\end{document} \ No newline at end of file diff --git a/irlc/project1/Latex/figures/kiosk1.pdf b/irlc/project1/Latex/figures/kiosk1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..54c179fa1703c83e77398a3f6382d3e685fc8fd9 GIT binary patch literal 7780 zcmY!laB<T$)HC5yy>R8|4K5P}1BLvgEG`=xE`6WWy!4U`1!D^ZDB#j}%giZBEmF{T z%SkLrbxBRmPf6vnv*Ri*DN0Su<*K-){lqB5fWgU`HP+c#m^D^8x%EkmUhVl9XV&R8 z>m2kLQeUxEbEW2`KsBW1rGP9mMzS=dvLIDKKOiwZl}q0_Kd&S;ucTN3<f<Sp{h-w1 z{L-T2)M5oA1p|d3E`8tBl*~k@{0fC=0|f&GBSSL<BTMsGF8zSSqSU++1yispJ3Ek# zAbSik?1}JC%1TWx;nEK-O)3G~?3Q1Y%cTz@!7ef6(hmr6jnH$;%t`f2%uQ9$(9g)v zP1P?c%}CXE$xklL1vyaPz{teRw4gL8Co@^UI3uwrHAO$aw4|W4L_a$-zc|}auOKB& z6KWL5Z+@k@NvTB&Fw;Hr((+w0lS>rLz%JHzg8RwD%s|gV!Pvx9&ny->06_8MT2bO2 zT#{IlssQ3S8iFZjM+E~eeX!g0;R?9)lM@vTK{2K8XarMch)0>7oxWRsUWtN@je@?L zp@KQcS$1}yfGsIWEy@EKVP~fwP?Vn>oLZs~t)L&^;-;V<l3G!spzoQRn4ancrJbR) zr$Q{3esD%&N@iX<R5vv2K|Fm=Lj?<v9b9&HAZws0&&<G#V3M0NciQQq%MJpr-#?4) zZDC#ea^80%wFgRTd_tzO9zA8Drl^)0(^@}YPPOXhCY6X2s<GL>&cxgeT)pGopUQ~* zeLCVF{)LIYz4~hbhuqT}O>OR$eGVI@B(L5Q^LENtsl{___s)}iec|-fymNILrR%%2 zC5tBfp5`^tbVcOpy@IBdnn@Ol%a3gRbR}?$>m!XI>opTsU8=Uw^|+|qp3%71U8(K9 z^p58EfSAI0Ejk{3$@6%=Oy9M>?baT-Sl(^vTd!Md*a^niANE?C5P$tjQoy>|x)m#R zx_m4b@*mr-oh#bCE^1{|$8Ptn)8l#HZwXQKmWa6hpn*3kt*j}uTd1r5)B3hg`;7Mg zS-0<ybnh?Sn&wY#wHjBwLWKiFBqwvm7A)>*Xg(_P*2iG6HM?==*O@mOqMsT?{Bhk@ zsCI*Q?Tn)luVcmUXecLayd`*^rTw62_r}IxkiY|l2Tz>mxGy`nJm*BB*WHS(r&3Gq z*<E~n^TomEcXGJ>7?0YW6Ex<G^_S+6%)UAK8mEoqP40_--1kWD+J2(4z5L}?Gso%I zr%rYHKkwtTJQFqPUtgkTFDP~>s+wab@uki0(I)ZlyS}(dFQ057zgT`b|FXSHyH8IG znje?lTw)|KN7+-h^Xt4y8GD(Z)ABud-aKD-aoLZgeTBjYXP?+BAscL8vDL)UU#xW2 z3E5uzs*g8|?aQ~CFrK%)<#VLZZ=TKJv)-TASKU5&{9vTMe8%Nh-_{&{-)6Pvj`{Q3 z3(9Z5e&GGJ#Poaa^5^;0>k~8mu0_wk-|8kb{dj55!+nPH<>&F+ugpH{^_O)a%Z&n1 z!GT&-fiftlC;{a-=c3falFa-(7f=?|aIrEnFfukUGB7eUG%zx;&^9nqH!x7w<kAPL z%P&&U@J%c!$jL9s$xKoxGuAWJGt^PYC@Co@w$j(ng-hw>7o~%WilY3K(&SWBT?Hv= z3Q38{*{OLcP!lvknHpM*f^sR$ZBB{Bso)%}@8la8=n|&wlA4tmRvMg`SInjFoRL@r z%Dcr1mf%dM@0ypK56hYQE}3a*sYR)IpmH`^!Ng3zAhjqnKSjaBLcc1tC|^H6FIB&! zJYT`oSU)YZELFkORKGa2EHzKT+*IFN!O*}|KU2Zbz+69D!O+l9KVQMn&{V%T7GBsu ztpd4Q-z~GKxCG=HP?-gCE~Ma7&^0tLGE~qtF*8;$G`BQSFf=kYjs=y<c_l8X#mPmP z1ts}K3WlIUKL{f1n^;nmS)mZEV4!DU04nDV5Uf}(eV;_AJw~RcT>9XG99zJ^YXMOC zX$*5R$YEUi;h8BV8N~{QAj5+|u7`#?sN8~wdS*#+Kx&b5er`d29;gPg099f+`9;A6 ziOH!7(fXcwDXA5yDf%v{WtqvTLGDfpW(pcH#^$Cm#wO+}F-ArPF~&w_&ZaR&X66+N zV7`%|i9vddk)f%JWsH%5kxPt$fnkVdESEl{`VB}d$}I+$q0ad^`9;N`I>k9Zr!+UO zSi#8Dl1o3JC^aQB84_L~XJf6y^*vHE(=$pGjLi+;^}Zprl7$BfxL}6`3bgcwh6~s# zq=vwpx3{dhm<<J34}Sgr&)rP+_CW>dGhMG@7Oeasd))4>n(h7H-}l!`GP50Ra5PK^ z;E@nPFt2Pnm^%O6WC??W0}YJKY&=Me2-6+!E+-423WAh1n>JsZ@mi+VB3}ekl9^2z zEQ@Xt)XpD=5=@?1xuduNDg|=cl}!g<9qvs!ut35<gN>()v3Zn9n{bGGu&{YKW{C?b zqG0*UTfq?2Rt(~Tlstyec44N1A*87XDsw<3bPyM)+yRw`AXZ+gf*~lE264fPGDDD| zL0tO93P#W}1X6+-K{7YEcr$_~e^8mHU<9!isVNE42XmHVaWW{gTN+t%={qMDK=YCT zD2qa5bd8KbEt#Ce^kM~LBS?uwxTwQfOnH_h=42*2=B4MPf(lOG#0qfXq+n=lV#K8% zT#}j_1`-DqVhZ4P9HP+V(vN^U56L$me}jAztzc$gFre7j&_cn)z)-=&%s|1y*h0a~ z*i6CF)Ih=9!a%{u+*HBX(g2K24IuI$^~Pp~3SipU9IPIshY&V4Hdg>)kR32=YHX-r zXaEWT3ljx13o`{XOA7^aa{~o4V<QDqb5jL#5H>YZFtRiSV>44T1yfUV1q(A{1#=S% z1#=5?1v3L<2yJPqU}kKpU}k8jU~X)rU}j;WU}<5gU}gak1JPj5fE;28@eIgQAZ%u6 z4AyIE3bGrd-c-TZ)CeqQW^AHhWNrb*rskGl+S1%a0VHl_2vcLKU}9*fU}|KjU~CBz zGf^<LG*YlIv;fl}wy6=weP-Z500kB(5WtadYz9sM-~cr>QZO~NfCLK2VK59zX<*lw z7#M&mduW;gc?}eN1_qG$09gmamIewS-Qe&=FpLZpAVwG&gKY)7$`BHrpkx4Y88QY% z8Avw>gN-sVH&g(58{~XYIsglTWI-4t2r>nPL424=Aish5AaR%hmS&a;Fbqlvp!mXu z!C`F)N|>N<MPOK(fYIQz0!<U3bb*XP?gI0TjlgLGls-Thlvd0PK=ERr08Rs-bby8} zEsPYv>B10_F3g}bEKR^@P@urm1Snk~VUYcBd1GkWF@~fOP?|NhG>Qe4#GoPp+zbFQ zOwA48VxZy>BnD~*V;d8IjU8B+fSMf8CUnId(_TlR0|qRv-~AqPC_3I*e)*--`~A9} zyB=0HuU~ZILb{l#bMo<Sh3AXJPi*gYZPxUxkXi23USaiZXG~q@R@1WeyY)&|oZ;%W zSANj=oB4vZln%&6P~)NPF>s|ojN6P%EKwZi8|c}^Y{0Yox#%wk#kk3PmOIaMe*XXZ zDZW-q7S8pPCQq9Y!Od^jBClinW1?cQ`CsX}MK^axR!us2^Z$(JO2L6Yf>!7yImLEJ zpI<2W!FFM`P~^tFA1!qj&n(`@F5kL?#dslOa;>M)&K1w5Dhm7Yl*;f$EjhF!JL&MF zsEaneck+I_rKPI1@b;%T-H~YMP<YL>NkV6enVGOr<T>WIyeE0160Wb54(x8yo^p+| zWKr0WRc9V-es-<Q+*$Y2gB7(Oe`SPCPiVd9{WYQ@zSVBV%9&;FCOK6-^tDzxBgeJG z$XZu>YxR*=d5yp9PX~SYd-D4a+4cNq|HRC}5`v)0l$a1SH$n+OW25Z>1_2vP7=_xz z)VQ9dv2kg(#W?I+*}2n6Puzp&$SKCnJPlh^=QMSsH_TAT6*#IO=CW~Sr=*MQ9L9;K zA9yh{sNNPkiN!sjDxDbjSQw+Y$M%e+P=f&n>xFs2f0SEJD19%K>8|)6W^j>BZgtfH zMT_QL2iHDKIJK)p_<iu>tH<UDajvNF@}0JeyXwl8eOLBnJlOsEnfKLB`?Kf8=ko8C zmAs3^X`nU+F-|iwv_N%Rz|LM4L!Q&Itx^#Os@|?l7wh(3_Wz5=&u>Z>#ax55OlMBg z)GwW)8X0`gs%F{|zRI?zc`0V9TCVz&H>iHU!1b}V^O?x^yH}@eb~c%wVOhs*thGv7 z_OiFxtO70JT?_6UHvYw%Tf!XHF1ImS;lh%H>)RBHj`K_K9GofKt;FNy%l3a=QUCn7 zZfU#2ADu-ePU3rJ`ak0Dr()jq!TstJ^YZsSikq{Nk6BP=(yTqou@M{fgak899evLq zh|+D?y*=)q^cLk^JPzMFj}*=d>RY%!yI|>g{io`|H?RZ|sOd#a5TV7MYtL@p0|p!} z)yooC>eRm31x`71Z$GbqYTgd@yS6d1oHI4^j1N1r&EwH&i!E&YGR=TH#yy~K?wiGl zSNFYQ>HWGa=<|F2Df8Z}dDQlrk;zFa4U5x2%|K$DW(poVgO)QDbBxWl1Q-Mum>956 za%*##HnG#GOHtf|;mDb%O`OjfBH0|I7Fn>bQ)}05*5+k+xP^BHrq$qfCoxtV8>1GX zx<TGWM-_N(7jwlfF#f^*#O7tmu8O_?w@sSt>c*Gw#qeocr&mp+!uG}2j%@Ee<IwtW z{pvHV=RIzpu<AHHp?k+9-PURsohODzY>qU&U;R-|?&q2_CpWVn)4y5Hul?;xORD1I zqms80MUN+nK8e^+s<^7UB6!K+l`1zLcmKCLTCB^WTjO@2A^yqy^?eV1P7=%fJ|p+? zx~dI6)~l9mkje2cj#G<|O5bTEcb@&^w{<rJgLX5CwC*%MSNu@pa+uo|u`)A{teBkq zzP}M(7h3aT+`5z}%wMTwvtY@|GiqFq`sc_MX)!0hnzgQ^NIJA|`Mfixv%9w&d#1hK z=dp3-p~_f`&Hs3U)3#QspD$W;WhKY^jp^POE?BOcw|81(M#*g9Jxf~7AM^9~+ZS&9 zTG3LJb7fLg_`yt(nMs_th2nz)gJ)Gq{`>vu-AC)Xe~dcCHN{w>1=bKIRI!;Gpk!xb zW3ym`fDHyrLd%x5aXoXJ1}^&SI;Ngx6+X?l`Haq)Mjd7D3DacsoVk+?a+7kFB%~#= zr9>(iD(o`aafxBZEMaCWt^svHh)E<yXbDs|(6flykz@CH?Jq59%kL*o*KU9E|2oGh zb~fH_hmxpA3wq`&=!EZiI&pQz;rqshP4`*b>$I=uMm%u{QSeL-FkM*ovFeN5jlvn6 zXC`0Uz>~Iy|4)zRofk(R8cL>bzn*$U;7#m$+nJ6h*TfuA6&Clony8%4XFt<OZ%eVQ zxx#a|i0O$F^1`Hyh5AfdJrrA4&0cbj#Zjndom;P2k;w0*`u!zsp}i{%-xTZS#-I1K z$iDC<V$G)~Q{-X`_0+}n*T{VNYQ`)cn7QVYgU5ltdHi3CH%-1@;r;xa*yYF7XHR}Q z6q0as_Vqjmv#XEp@9B8_yJ!9L=Rf~2$0tO0U<pHFn<_?zrYKQr8feMKtjP1`yXZd$ zl^*>H|3w;S|Ls59b1_WrU`*SVDT*^c1x;R|_%ztAYNp<tU3adZ$ufC9ZHsPk!;Wox z^w&;0(3#fJd@ysy4#rtFjLz3Dt_XA%m%DIfX|TqIJ1llx+w=JECU0$=zD@CYr$Um3 zq>kg+m9D~Kx#!iFnC_43mcBRr?cEc>OOH*HXk=pyvyi#|;`)cFw*G1tOGJ&XtTsI@ z!71#jWb?Cc*;V1!Q6`s+gsvPDT$9DT$NH~<9|MDM;c2Fn`Cd~tKRJ@W@ylkm@L&HJ z=evhY!xBD7b0W|&9q_2XXRe_FC^G~pfCl72qlHK#{js2sg0{Di8w-#gXFy_lDrl53 zzcjA|G#urfnNq9}4T^^#WQ|6k-a9OHLv%VPmL%rnr-SAh(o>5u=5LIU?FxVokQSt* zg``G+Cb10kjEs;6TtiYLU|d||w3gZihR|_Z-~1G;L%B#wLW&X#3Q|)P^xYD3ic_Hz zI&P&oIZ26md7#1Ckc`Y?h0J0Fh?{g2!cvQhGxPHljP(pn3{5SK%uJ1Sjr7c5j#bbI zNsUnO0S%)X85kMqr=*tYyQC&%Cgy1>WEUisWE7_+DwILZFw-;EGXW_<9`vm!N=@T3 zP%tv%GJpdGGgDJzQ-w4In3$2VnF3f=ArB^I2I{+_i5VCg8=<Q+FaV9MfD|I>H3top zpo$q98=0f)H8im>#t^eG#ZYI2#XKVmb3=5!#s=mXdQA+CEYa1O7@A;;85@{ls58TK zvxzyTy(X4M7~yAXWQgGwQ)6?C@G~{B#IV=Y(f~u9nSqH3y8FzG%`7m)%*`>yER2xE zN{SLQb5e`AKy!D&nN_Kvw4ooApI@Q?&T&Cp`k?7X1#o5paa<IlZOohu%}vZK3{6ce zEKFT29bF79-JA>@4V?|0Tn$W(-0TzxD~Sb_6vZWpMJ3=gX>Mp>!lkO}>hHz{0Pm>q ASO5S3 literal 0 HcmV?d00001 diff --git a/irlc/project1/Latex/figures/kiosk2.pdf b/irlc/project1/Latex/figures/kiosk2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..07dd964485a357336d64c2393ce3fc97c8af1e14 GIT binary patch literal 8067 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 literal 0 HcmV?d00001 diff --git a/irlc/project1/Latex/figures/your_answer.pdf b/irlc/project1/Latex/figures/your_answer.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d8c092974e20aaaf1165958a53bdce3a2ebdbf8f GIT binary patch literal 6498 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 VQc;we#${$?V9cee>gw;t1pvtyz)}DJ literal 0 HcmV?d00001 diff --git a/irlc/project1/__init__.py b/irlc/project1/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/project1/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/project1/kiosk.py b/irlc/project1/kiosk.py new file mode 100644 index 0000000..70f3371 --- /dev/null +++ b/irlc/project1/kiosk.py @@ -0,0 +1,70 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" +This project resembles the Inventory-control problem discussed in (Her24, Subsection 5.1.2) but with more complicated rules. +If you are stuck, the inventory-control problem will be a good place to start. + +I recommend to use the DP_stochastic function (as we did with the inventory-control example). This means +your main problem is to build appropriate DPModel-classes to represent the different problems. + +References: + [Her24] Tue Herlau. Sequential decision making. (Freely available online), 2024. +""" +from irlc.ex02.dp_model import DPModel +from irlc.ex02.dp import DP_stochastic +import matplotlib.pyplot as plt +from scipy.stats import binom +from irlc import savepdf +import numpy as np + +def plot_policy(pi, title, pdf): + """ Helper function to plot the policy functions pi, as generated by the DP_stochastic function. This function + can be used to visualize which actions are taken in which state (y-axis) at which time step (x-axis). """ + N = len(pi) + W = max(pi[0].keys()) + A = np.zeros((W, N)) + for i in range(W): + for j in range(N): + A[i, j] = pi[j][i] + plt.imshow(A) + plt.title(title) + savepdf(pdf) + plt.show() + +# TODO: 51 lines missing. +raise NotImplementedError("Insert your solution and remove this error.") + +def warmup_states(): + # TODO: 1 lines missing. + raise NotImplementedError("return state set") + +def warmup_actions(): + # TODO: 1 lines missing. + raise NotImplementedError("return action set") + +def solve_kiosk_1(): + # TODO: 1 lines missing. + raise NotImplementedError("Return cost and policy here (same format as DP_stochastic)") + +def solve_kiosk_2(): + # TODO: 1 lines missing. + raise NotImplementedError("Return cost and policy here (same format as DP_stochastic)") + + +def main(): + # Problem 14 + print("Available states S_0:", warmup_states()) + print("Available actions A_0(x_0):", warmup_actions()) + + J, pi = solve_kiosk_1() # Problem 16 + print("Kiosk1: Expected profits: ", -J[0][0], " imperial credits") + plot_policy(pi, "Kiosk1", "Latex/figures/kiosk1") + plt.show() + + J, pi = solve_kiosk_2() # Problem 17 + print("Kiosk 2: Expected profits: ", -J[0][0], " imperial credits") + plot_policy(pi, "Kiosk2", "Latex/figures/kiosk2") + plt.show() + + +if __name__ == "__main__": + main() diff --git a/irlc/project1/pacman.py b/irlc/project1/pacman.py new file mode 100644 index 0000000..6ad08ec --- /dev/null +++ b/irlc/project1/pacman.py @@ -0,0 +1,169 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from collections import defaultdict +from irlc import train +from irlc.ex02.dp_model import DPModel +from irlc.ex02.dp import DP_stochastic +from irlc.ex02.dp_agent import DynamicalProgrammingAgent +from irlc.pacman.pacman_environment import PacmanEnvironment +from irlc.pacman.gamestate import GameState + +east = """ +%%%%%%%% +% P .% +%%%%%%%% """ + +east2 = """ +%%%%%%%% +% P.% +%%%%%%%% """ + +SS2tiny = """ +%%%%%% +%.P % +% GG.% +%%%%%% +""" + +SS0tiny = """ +%%%%%% +%.P % +% .% +%%%%%% +""" + +SS1tiny = """ +%%%%%% +%.P % +% G.% +%%%%%% +""" + +datadiscs = """ +%%%%%%% +% .% +%.P%% % +%. .% +%%%%%%% +""" + +# TODO: 30 lines missing. +raise NotImplementedError("Put your own code here") + +def p_next(x : GameState, u: str): + """ Given the agent is in GameState x and takes action u, the game will transition to a new state xp. + The state xp will be random when there are ghosts. This function should return a dictionary of the form + + {..., xp: p, ...} + + of all possible next states xp and their probability -- you need to compute this probability. + + Hints: + * In the above, xp should be a GameState, and p will be a float. These are generated using the functions in the GameState x. + * Start simple (zero ghosts). Then make it work with one ghosts, and then finally with any number of ghosts. + * Remember the ghosts move at random. I.e. if a ghost has 3 available actions, it will choose one with probability 1/3 + * The slightly tricky part is that when there are multiple ghosts, different actions by the individual ghosts may lead to the same final state + * Check the probabilities sum to 1. This will be your main way of debugging your code and catching issues relating to the previous point. + """ + # TODO: 8 lines missing. + raise NotImplementedError("Return a dictionary {.., xp: p, ..} where xp is a possible next state and p the probability") + return states + + +def go_east(map): + """ Given a map-string map (see examples in the top of this file) that can be solved by only going east, this will return + a list of states Pacman will traverse. The list it returns should therefore be of the form: + + [s0, s1, s2, ..., sn] + + where each sk is a GameState object, the first element s0 is the start-configuration (corresponding to that in the Map), + and the last configuration sn is a won GameState obtained by going east. + + Note this function should work independently of the number of required east-actions. + + Hints: + * Use the GymPacmanEnvironment class. The report description will contain information about how to set it up, as will pacman_demo.py + * Use this environment to get the first GameState, then use the recommended functions to go east + """ + # TODO: 5 lines missing. + raise NotImplementedError("Return the list of states pacman will traverse if he goes east until he wins the map") + return states + +def get_future_states(x, N): + # TODO: 4 lines missing. + raise NotImplementedError("return a list-of-list of future states [S_0,\dots,S_N]. Each S_k is a state space, i.e. a list of GameState objects.") + return state_spaces + +def win_probability(map, N=10): + """ Assuming you get a reward of -1 on wining (and otherwise zero), the win probability is -J_pi(x_0). """ + # TODO: 5 lines missing. + raise NotImplementedError("Return the chance of winning the given map within N steps or less.") + return win_probability + +def shortest_path(map, N=10): + """ If each move has a cost of 1, the shortest path is the path with the lowest cost. + The actions should be the list of actions taken. + The states should be a list of states the agent visit. The first should be the initial state and the last + should be the won state. """ + # TODO: 4 lines missing. + raise NotImplementedError("Return the cost of the shortest path, the list of actions taken, and the list of states.") + return actions, states + + +def no_ghosts(): + # Check the pacman_demo.py file for help on the GameState class and how to get started. + # This function contains examples of calling your functions. However, you should use unitgrade to verify correctness. + + ## Problem 1: Lets try to go East. Run this code to see if the states you return looks sensible. + states = go_east(east) + for s in states: + print(str(s)) + + ## Problem 3: try the p_next function for a few empty environments. Does the result look sensible? + x, _ = PacmanEnvironment(layout_str=east).reset() + action = x.A()[0] + print(f"Transitions when taking action {action} in map: 'east'") + print(x) + print(p_next(x, action)) # use str(state) to get a nicer representation. + + print(f"Transitions when taking action {action} in map: 'east2'") + x, _ = PacmanEnvironment(layout_str=east2).reset() + print(x) + print(p_next(x, action)) + + ## Problem 4 + print(f"Checking states space S_1 for k=1 in SS0tiny:") + x, _ = PacmanEnvironment(layout_str=SS0tiny).reset() + states = get_future_states(x, N=10) + for s in states[1]: # Print all elements in S_1. + print(s) + print("States at time k=10, |S_10| =", len(states[10])) + + ## Problem 6 + N = 20 # Planning horizon + action, states = shortest_path(east, N) + print("east: Optimal action sequence:", action) + + action, states = shortest_path(datadiscs, N) + print("datadiscs: Optimal action sequence:", action) + + action, states = shortest_path(SS0tiny, N) + print("SS0tiny: Optimal action sequence:", action) + + +def one_ghost(): + # Win probability when planning using a single ghost. Notice this tends to increase with planning depth + wp = [] + for n in range(10): + wp.append(win_probability(SS1tiny, N=n)) + print(wp) + print("One ghost:", win_probability(SS1tiny, N=12)) + + +def two_ghosts(): + # Win probability when planning using two ghosts + print("Two ghosts:", win_probability(SS2tiny, N=12)) + +if __name__ == "__main__": + no_ghosts() + one_ghost() + two_ghosts() diff --git a/irlc/project1/pacman_demo1.py b/irlc/project1/pacman_demo1.py new file mode 100644 index 0000000..bf74e07 --- /dev/null +++ b/irlc/project1/pacman_demo1.py @@ -0,0 +1,53 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.pacman.pacman_environment import PacmanEnvironment +from irlc.project1.pacman import east, datadiscs, SS1tiny, SS2tiny +from irlc import interactive, savepdf, Agent, train +import matplotlib +matplotlib.use('qtagg') + +count = """ +%%%% +%P % +%..% +%%%% +""" + + +if __name__ == "__main__": + # Example interaction with an environment: + # Instantiate the map 'east' and get a GameState instance: + env = PacmanEnvironment(layout_str=east, render_mode='human') + x, info = env.reset() # x is a irlc.pacman.gamestate.GameState object. See the online documentation for more examples. + print("Start configuration of board:") + print(x) + env.close() # If you use render_mode = 'human', I recommend you use env.close() at the end of the code to free up graphics resources. + # The GameState object `x` has a handful of useful functions. The important ones are: + # x.A() # Action space + # x.f(action) # State resulting in taking action 'action' in state 'x' + # x.players() # Number of agents on board (at least 1) + # x.player() # Whose turn it is (player = 0 is us) + # x.is_won() # True if we have won + # x.is_lost() # True if we have lost + # You can check if two GameState objects x1 and x2 are the same by simply doing x1 == x2. + # There are other functions in the GameState class, but I advise against using them. + from irlc.pacman.pacman_environment import PacmanEnvironment, datadiscs + env = PacmanEnvironment(layout_str=datadiscs, render_mode='human') + s, _ = env.reset() + + savepdf('pacman_east', env=env) + env.close() + + env = PacmanEnvironment(layout_str=datadiscs, render_mode='human') + env.reset() + savepdf('pacman_datadiscs', env=env) + env.close() + + env = PacmanEnvironment(layout_str=SS1tiny, render_mode='human') + env.reset() + savepdf('pacman_SS1tiny', env=env) + env.close() + + env = PacmanEnvironment(layout_str=SS2tiny, render_mode='human') + env.reset() + savepdf('pacman_SS2tiny', env=env) + env.close() diff --git a/irlc/project1/pacman_demo2.py b/irlc/project1/pacman_demo2.py new file mode 100644 index 0000000..a3bf61d --- /dev/null +++ b/irlc/project1/pacman_demo2.py @@ -0,0 +1,11 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.pacman.pacman_environment import PacmanEnvironment +from irlc.project1.pacman import east, datadiscs, SS1tiny, SS2tiny +from irlc import interactive, savepdf, Agent, train + +if __name__ == "__main__": + env = PacmanEnvironment(layout_str=datadiscs, render_mode='human') + env, agent = interactive(env, Agent(env)) + stats, trajectory = train(env, agent, num_episodes=1) + print("First state was\n", trajectory[0].state[0]) + env.close() diff --git a/irlc/project1/project1_grade.py b/irlc/project1/project1_grade.py new file mode 100644 index 0000000..1321a9d --- /dev/null +++ b/irlc/project1/project1_grade.py @@ -0,0 +1,4 @@ +# irlc/project1/project1_tests.py +''' WARNING: Modifying, decompiling or otherwise tampering with this script, it's data or the resulting .token file will be investigated as a cheating attempt. ''' +import bz2, base64 +exec(bz2.decompress(base64.b64decode('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'))) \ No newline at end of file diff --git a/irlc/project1/project1_tests.py b/irlc/project1/project1_tests.py new file mode 100644 index 0000000..dd84622 --- /dev/null +++ b/irlc/project1/project1_tests.py @@ -0,0 +1,377 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import UTestCase, Report +from irlc.pacman.gamestate import GameState +from irlc.pacman.pacman_environment import PacmanEnvironment +import numpy as np +from unitgrade import hide + +def get_starting_state(name): + s0, _ = PacmanEnvironment(layout_str=get_map(name)).reset() + return s0 + +def get_map(name): + from irlc.project1.pacman import east, east2, SS0tiny, datadiscs, SS1tiny, SS2tiny + names2maps = {'east': east, + 'east2': east2, + 'datadiscs': datadiscs, + 'SS0tiny': SS0tiny, + 'SS1tiny': SS1tiny, + 'SS2tiny': SS2tiny, + } + return names2maps[name] + +class Pacman1(UTestCase): + """ Problem 1: The go_east function """ + + def test_states_length(self): + from irlc.project1.pacman import go_east, east + self.title = "Checking number of states" + self.assertEqualC(len(go_east(east))) + # assert False + + + def test_first_state(self): + from irlc.project1.pacman import go_east, east + self.title = "Checking first state" + self.assertEqualC(str(go_east(east))[0]) # string representation of the first state. + + def test_all_states(self): + self.title = "Checking complete output" + from irlc.project1.pacman import go_east, east + self.assertEqualC(tuple(str(s) for s in go_east(east))) + + +class Pacman3(UTestCase): + """ Problem 3: the p_next function without droids """ + map = 'east' + action = 'East' + + def get_transitions(self): + from irlc.project1.pacman import p_next + + state = get_starting_state(self.map) + state_transitions = p_next(state, self.action) + self.assertIsInstance(state_transitions, dict) + for x in state_transitions: # Test if each new state is actually a GameState. + self.assertIsInstance(x, GameState) + dd = {s: np.round(p, 4) for s, p in state_transitions.items()} + return dd + + def test_dictionary_size(self): + """ Is the number of keys/values in the dictionary correct? """ + # print(self.get_expected_test_value()) + self.assertEqualC(len(self.get_transitions())) + # self.get_expected_value() + + + def test_probabilities(self): + """ Does the probabilities have the right value? """ + self.assertEqualC(set(self.get_transitions().values())) + + def test_states(self): + """ Does the dictionary contains the right states """ + self.assertEqualC(set(self.get_transitions().keys())) + + def test_everything(self): + """ Test both states and probabilities """ + self.assertEqualC(self.get_transitions()) + + +class Pacman4(UTestCase): + """ Problem 4: Compute the state spaces as a list [S_0, ..., S_N] on the map 'east' using N = 7 """ + map = 'east' + N = 7 + + @property + def states(self): + return self.__class__.states_ + + @property + def sizes(self): + return self.__class__.sizes_ + + @classmethod + def setUpClass(cls): + from irlc.project1.pacman import get_future_states + states = get_future_states(get_starting_state(cls.map), cls.N) + assert isinstance(states, list) + for S in states: + assert isinstance(S, list) + for s in S: + assert isinstance(s, GameState) + cls.sizes_ = [len(S) for S in states] + cls.states_ = [set(S) for S in states] + + def test_state_space_size_S0(self): + self.assertEqualC(self.sizes[0]) + + def test_state_space_size_S1(self): + self.assertEqualC(self.sizes[1]) + + def test_state_space_size_all(self): + self.assertEqualC(self.sizes) + + def test_number_of_spaces(self): + """ Check the list of state spaces has the right length. It should be N+1 long (S_0, ..., S_N) """ + self.assertEqualC(len(self.states)) + + def test_state_space_0(self): + """ Check the first element, the state space S0. + + Hints: + * It should be a list containning a single GameState object (the starting state) """ + self.assertEqualC(self.states[0]) + + def test_state_space_1(self): + """ Check the second element, the state space S1. + + Hints: + * It should be a list containing the GameState objects you can go to in one step. + * You should be able to figure out what they are from the description of the game rules. Note pacman will not move if he walks into the walls. """ + self.assertEqualC(self.states[1]) + + def test_state_spaces(self): + """ Test all state spaces S_0, ..., S_N + + Hints: + * If this method breaks, find the first state space which is wrongly computed, and work out which states are missing or should not be there + * I anticipate the won/lost game configurations may become a source of problems. Note you don't have to specify these manually; they should follow by using the s.f(action)-function. """ + + self.assertEqualC(tuple(self.states)) + + +class Pacman6a(UTestCase): + """ Problem 6a: No ghost optimal path (get_shortest_path) in map 'east' using N=20 """ + map = 'east' + N = 20 + + def get_shortest_path(self): + from irlc.project1.pacman import shortest_path + layout = get_map(self.map) + actions, states = shortest_path(layout, self.N) + return actions, states + + def test_sequence_lengths(self): + """ Test the length of the state/action lists. """ + actions, states = self.get_shortest_path() + print("self.map", self.map, 'actions', actions) + self.assertEqualC(len(actions)) + self.assertEqualC(len(states)) + + def test_trajectory(self): + """ Test the state/action trajectory """ + actions, states = self.get_shortest_path() + self.assertTrue(states[-1].is_won()) + + x0 = states[0] + for k, u in enumerate(actions): + x0 = x0.f(u) + self.assertTrue(x0 == states[k + 1]) + self.assertEqualC(states[1]) + # self.assertEqualC(J) + +class Pacman6b(Pacman6a): + """ Problem 6b: No ghost optimal path (get_shortest_path) in map 'SS1tiny' using N=20 """ + map = 'SS0tiny' + +class Pacman6c(Pacman6a): + """ Problem 6b: No ghost optimal path (get_shortest_path) in map 'datadiscs' using N=20 """ + map = 'datadiscs' + +## ONE GHOST +class Pacman7a(Pacman3): + """ Problem 7a: the p_next function with one droid """ + map = 'SS1tiny' + action = 'East' + +class Pacman7b(Pacman3): + """ Problem 7b: the p_next function with one droid """ + map = 'SS1tiny' + action = 'West' + +class Pacman8a(Pacman4): + """ Problem 5: Test the state spaces as a list [S_0, ..., S_N]. on the map 'SS1tiny' using N = 4 """ + map = 'SS1tiny' + N = 4 + +class Pacman8b(Pacman4): + """ Problem 6: Test the state spaces as a list [S_0, ..., S_N]. on the map 'SS1tiny' using N = 6 """ + map = 'SS1tiny' + N = 6 + pass + +class Pacman9(UTestCase): + """ Problem 9: Testing winrate on the map SS1tiny (win_probability) """ + map = 'SS1tiny' + + def _win_rate(self, N): + self.title = f"Testing winrate in {N} steps" + from irlc.project1.pacman import win_probability + p = np.round(win_probability(get_map(self.map), N), 4) + print("win rate in N ", N, "steps was", p) + # print("Testing win rate", self.get_expected_test_value()) + self.assertEqualC(p) + + def test_win_rate_N4(self): + self._win_rate(N=4) + + def test_win_rate_N5(self): + self._win_rate(N=5) + + def test_win_rate_N6(self): + self._win_rate(N=6) + + +# ## TWO GHOSTS +class Pacman10(Pacman3): # p_next for two ghosts + """ Problem 10: Testing the p_next function using SS2tiny """ + map = 'SS2tiny' + N = 4 + +class Pacman11(Pacman4): # State-space lists + """ Problem 11: Test the state spaces as a list [S_0, ..., S_N]. on the map 'SS2tiny' using N = 3 """ + map = 'SS2tiny' + N = 3 + +class Pacman12(Pacman9): # Optimal planning for two ghost-droids. + """ Problem 12: Testing winrate on the map SS2tiny (win_probability) """ + map = 'SS2tiny' + N = 2 + +class Kiosk1(UTestCase): + """ Problem 14: Warmup check of S_0 and A_0(x_0) """ + def test_warmup_states_length(self): + from irlc.project1.kiosk import warmup_states, warmup_actions + n = len(warmup_states()) + self.title = f"Checking length of state space is {n}" + self.assertEqualC(n) + + def test_warmup_actions_length(self): + from irlc.project1.kiosk import warmup_states, warmup_actions + n = len(warmup_actions()) + self.title = f"Checking length of action space is {n}" + self.assertEqualC(n) + + + def test_warmup_states(self): + self.title = "Checking state space" + from irlc.project1.kiosk import warmup_states, warmup_actions + self.assertEqualC(set(warmup_states())) + + def test_warmup_actions(self): + self.title = "Checking action space" + from irlc.project1.kiosk import warmup_states, warmup_actions + self.assertEqualC(set(warmup_actions())) + + +class Kiosk2(UTestCase): + """ Problem 16: solve_kiosk_1 """ + + @classmethod + def setUpClass(cls) -> None: + from irlc.project1.kiosk import solve_kiosk_1 + cls.J, cls.pi = solve_kiosk_1() + + def mk_title(self, k, x): + self.k = k + self.x = x + + if self.k is not None: + if self.k != -1: + sk = f"N-{-self.k - 1}" if self.k < 0 else str(self.k) + else: + sk = "N" + jp = "J_{" + sk + "}" if len(sk) > 1 else "J_"+sk + else: + jp = "J_k" + if self.x is not None: + xp = f"(x={self.x})" + else: + xp = "(x) for all x" + return "Checking cost-to-go " + jp + xp + + def check_J(self, k, x): + J = [{k: v for k, v in J_.items()} for J_ in self.__class__.J] + t = self.mk_title(k, x) + if k is not None and x is not None: + t += f" = {J[k][x]}" + self.title = t + + if k is not None: + J_ = J[k] + if x is not None: + self.assertAlmostEqualC(J_[x], msg=f"Failed test of J[{k}][{x}]", delta=1e-4) + # self.assertL2(J_[x], msg=f"Failed test of J[{k}][{x}]", tol=1e-5) + else: + for state in sorted(J_.keys()): + self.assertAlmostEqualC(J_[state], msg=f"Failed test of J[{k}][{state}]", delta=1e-4) + else: + for k, J_ in enumerate(J): + for state in sorted(J_.keys()): + self.assertAlmostEqualC(J_[state], msg=f"Failed test of J[{k}][{state}]", delta=1e-4) + + def test_case_1(self): + self.check_J(k=-1, x=10) + + def test_case_2(self): + self.check_J(k=-2, x=20) + + def test_case_3(self): + self.check_J(k=-2, x=0) + + def test_case_4(self): + self.check_J(k=0, x=0) + + def test_case_5(self): + self.check_J(k=1, x=4) + + def test_case_6(self): + self.check_J(k=None, x=None) + + +class Kiosk3(Kiosk2): + """ Problem 17: solve_kiosk_2 """ + @classmethod + def setUpClass(cls) -> None: + from irlc.project1.kiosk import solve_kiosk_2 + cls.J, cls.pi = solve_kiosk_2() + + +class Project1(Report): #240 total. + title = "02465 project part 1: Dynamical Programming" + remote_url = "https://02465material.pages.compute.dtu.dk/02465public/_static/evaluation/" + import irlc + pack_imports = [irlc] + abbreviate_questions = True + + pacman_questions = [ + (Pacman1, 10), # east + (Pacman3, 10), # p_next (g=0) + (Pacman4, 10), # future_states (g=0) + (Pacman6a, 4), # shortest_path (g=0) + (Pacman6b, 3), # shortest_path (g=0) + (Pacman6c, 3), # shortest_path (g=0) + (Pacman7a, 5), # p_next (g=1) + (Pacman7b, 5), # p_next (g=1) + (Pacman8a, 5), # future_states (g=1) + (Pacman8b, 5), # future_states (g=1) + (Pacman9, 10), # optimal planning (g=1) + (Pacman10, 10), # p_next (g=2) + (Pacman11, 10), # future_states (g=2) + (Pacman12, 10), # optimal planning (g=2) + ] + + kiosk_questions = [ + (Kiosk1, 10), + (Kiosk2, 25), + (Kiosk3, 25), + ] + + questions = [] + questions += pacman_questions + questions += kiosk_questions + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Project1()) +# 448, 409 # 303 diff --git a/irlc/project1/project1_tests_complete_grade.py b/irlc/project1/project1_tests_complete_grade.py new file mode 100644 index 0000000..aac3b1b --- /dev/null +++ b/irlc/project1/project1_tests_complete_grade.py @@ -0,0 +1,4 @@ +# irlc/project1/project1_tests_complete.py +''' WARNING: Modifying, decompiling or otherwise tampering with this script, it's data or the resulting .token file will be investigated as a cheating attempt. ''' +import bz2, base64 +exec(bz2.decompress(base64.b64decode('QlpoOTFBWSZTWSy+DbgGgRD/gH//xVZ7/////////v////5g/758veo974t9zH1QHfYAFJXMpycIO2KUASKUUFGtUCSSV7aUFOIaKQCEgDzlgG+mQBc+6WbuPjICSKoKNAWxQBR6ADVAaGRJx3QOkL7ddu9m6SPgHAEAEB5k7YD2AAAC8zxAAA41A9aAET75F27OtHA7gAAAPnoAe873QaTYO56640QPWdNRJQ0eAAAR6O+8QTtoS3Pbfd2kuQG7uXdbg0ADVDTV7HwBcQmtjbAiAABXAAAd3QCdtdwu3rnY0PN9h9AUNHR0JKFNPgCgAAAAAAABAHctrZny8AAAR0K1ryG+5x020iprlfK7Vu+uPFTU+saM+t9tJPe3fbaDPY+80S+VtrVhbK30OhoBUPu2u73epJ7U60+Ap7UkgsjJms29rh0DoKV7fd9demiG2m+zR1UXZilALbvDR93zPY7az3L73Xlr19oegHQOgCuvejthvPOiD1Prnt9AfW73u5zw7Du9Cglb4m49voHBw9953APu6+u92OMoC7fEpT0OfTBL6HFk+bMmlXvd03EW99u+8NuPXpoPb2+8fL0A96AaToUTytoNbbu+77Y+9tNtovu27VLpnVhqeXk3vq4+mvXj6e6333m5nXVG5rsq+aZvem+06BQd7zntu88T1gR227H3vdlpmYvPgAG8YPd3dO7nr65rK++9zI7wfXvvtU4j072ZKOuR0iOte+9nPT3nwlNECAEAQCNAJoaBMg1E20phJ5qm9RqNmpMTNJ6jNpTynqCU0BEEJNEaE0aT0BPUamp6n6iPKbyTKNPao9QAeoaAGgaAAlPRJERCNI9JkNE9Jg0mp4po09Q0aGjTQNANAyZNAaAAJPVKSRNGmpk0Taj01TIaPUA00BoNAAAAAA0AAGgiREQBAExCYmEATIyCYEbUmEmxJ4U8TU8k0aZGh6IFRJCaAhJoNRplT2pHo0aRHkxok2o0aekGT1DQB6mgAAB3oh/vPdSKfBARQT/ERQIogAMEUCKKfiFG0EFp+sAgK0iH0RN4iSSwYlQ3TIh/FQGyE3USYkhDZDQyKg/gsGAUoAwUBIoCoQNnyVrP+tC3GSEiv8Miiop9U//T8VJsQTWL1/ytwcFP+khpxnX+Z3K/9u7Nf3PZh/o/8HP+sUjicXbn+hdrOcjBHz/LTVdfckFN9blcUURUllff/JfPdf51Iv3OOutZ1FMd2peECQi0RDtCqH90ZLqbUC8vOc7keHm6iE0Z+7/Noqu9wwuXdG3d0V8YyefTjSoUotYtQ/SJTOQJyvpNl4Rgsu6G6/5TTtPG02n/FL/DJh+Tt/9xXblDvvf+9OtU83viLkbPw29nyhCDuQQPl8pV/Pc/zbECtXq1V+L9TgA21v7La1rstqNFo2Kk2NtoLRW0WjFtfzNrpEbKVE8W81NNtrRbISNf+djJA/0WAjIqSItiGGrSrszmpYhMzDJ9e18UtE+iJguHnwpOdoiCu09t+U5ziJ260c10oqkI0EkiRSSTqleankIIMRf01u00hqEqiaNMzSBix53RbJ9B/5/8dT/HjkqBG2Af7dRLVanx3/wlusWTYOXLm5n0/p+n3Ej5vbQ/b33f7lPJy007zy5+ibVbZAibDrZQpct4T73JSdxZdCIS7C4cenWUrj/p5Z1lklUexDs0Duw5FIQ4hPcQCpq7MjZJLk7ut6gSkP5Ahnb4SiEwyTV1si7hWM1ApD4kc32vlS3jxd/Kl8MGQ4mcN258rd0aIlfCISHeoYnWCGnLV3wnfvB//w0PWWskJ2mzeRnv/auGDC0hn67R25f6cT6/207Zb73OvSllQRamK+TUggSchtzo93n/nddc2tWMg30bd+6W5I/hNgl+FjfLD+2z999eRBj166UnCY8UN835naCvL4eqPt/zdvMRkDe4Qxf6F4muEH5remD88J2QjkmPO43Tv86fPf9fbpjSuTNMRisRTBNcIdN+HT55D50e10e3KCATPjho9r/uEqs7H3uYq/yIDz6CarGQSDKnuE1Rpy7Hpe0cUQgQ4ijxxe/6T+/dbtmAkWLmVgqr+P5I6fLqhPjNkC8OI3rWFxv/WmaINjjpSEDvKJltTJDREEBaUCSZQnF8CL5fV6Ds7OdO8458TrNo8T+/1b/POsMf86mkSarXvVvU8/jDPNIfxYEy0+uu/5qHsi7/L2fdy1Tk0xmmn7SUhzdVsicxHyRh1HmuG6GiSmR9PZK/B6Yu/P/neY40Q+PF4kLko1pOV9oNUclUCurscEzF13hGHV7Q93/e84bmB0GRVr6rEvLOX431aenx3FeCoaiP1aP9RnkXTrR+lPlO88rumW7cUu5j3bY8tDsXDMsQqolG7c/8XQjO7Sl1ETYjheiBS6dMnrvvzicXSnTwu1pz0ra173tc/k5XEfLjulzulJs8uiiu8pu0387Vz5rcSW7lRtcXagr0StG/seG0o/WmFN9C+u73ydE8fRfcK2lXrp5XKV++lSLmf6M4nWdMekE1wEHoJPpoYVkmcvdPTtuRThpynUnZrtpE7tSddlZVL+43ZdtWtUuCMYCGNcHRjlBBsjphKFekXvldEWQtzxMqXVKqSl1P+R4Kth/txs8/P6Zz+a/MiXHHy3E+ra0oTu9yrFPa7rsgvpZNV+BrTNBiq6IlXnEy9McFogUvcKsuYL4Nul8x8SX6fnOnuJBwK9sU6EgRFo3RwxKQHLYdfzzEj3m2eIINkZ5cNHAbHis3rsq+R0nCWA9mZojemDi3SaOLtV2v/T9nBJ+WrG6RKPr0wLYL95QgirRr/1lfS92HBBo5BrzC+7dbNuN6aF1XKBKjPvDg2nalG/9T01GuWDksTIQCMnnM6PHpvSCKnvO0rQlSSC5AgzIhMUSLma4uYvR58onU7LAaZk6u48TQbIamTAdtrW0MArwe6BJs7F5AVbMrTP5nfaHjde412BnIggQhEMZvxb+5zQSOGBPd48b9cT0+BYedhIMP2GlgKqooouJIuTgkqovXUe+dN/ASkw101qth0WZnngUuwHQuL2uzUTVEOkwpGWgxCV5ZCx9d5iCMhmInTF/VL6CoT5SPonmYkjma0Cd8DGKKKWjzRKiGIndDuivT+Xl/B11GacLDnAxBNH7OJe1EzHHhSH0WrDiGMtMoKpgqzuWkOFqOFIdv2UkQ00XAmc9QJyxAHX672lzJ4wvF5j8OH0/o5xJ8cJEcKgiONHFsfU+S2XOFyofQ9FQz6z8nnUMIzjfpgu9elibWmrZMnA9lGpglxyWIMs7QiTqKvHXhy6kdf+TTKaf04enJjfOGfh2GZQQiH9/8XZIUPnMBh+wn58FG2HqmSFgqCu/yCCN9ClGJmhBKXROiQaEC4PVVW/JwhkF9YYj/MOqHxHkNcdBMFTkOQQI7CA33GlHPds7U3TwB3tYASgYHmaM3WdaNH561q5hSx3bzBahdnRmyM90tqTuWTuq0MsIbMRY4F27PFJ9BYaIt3ylJ+PnhftEspSZsbsL3oLYoTmWelPim1J742cnOUHk7NhZhu3nO86HIMj4JiS3kUI5OG73znBXw9uI8cuzZ1QS+4GjuvLVMjeFo2leS278ZH0036ZUperzITWhMYDkLqa2R10ac9U3ZaUcMDTLCiLrO7s95Ig0IelrrmkFeIjTQXriciRYukXUdbZZydGJkh7rjq0OTgolpPofRxmwd57l6F8Taugz6zVkzXk/qfzxUCN9cRIUpFtXbBIkSxiClqBvFB1s8Nz7JQ1brozc6EGQg3Bqdqx42o2WUGuRShhN/jR6Xn5W+7n7OuT0WOcbwlq39lZ4+cGpmD5fKvN85sPjYd1ftrzRRjEdNTlOcE3OZductnTJtlWEFjs1iJHI9l45HgUvnLlTZGL6pomDuLDYlz33ItOuzmpcSvVVfO05ckRlQ7F7N0Gsj8l4mf/fXPZqQNpr2yNeRGAI7uFnfDCNJF+ZLgzBBgssu2qucNCRQRCvn2tP9WX9yghZP7yG9Jn+ceBIliXs3Ak3r46jb6LdumHczUNsGKkGiOqOIg30zuGhHsxoxMvJrpJtoz0R56SE11wgkdR0tkzynpoS3Y5XFriK2CDzmP9SaVMjEWLJmgXcmcSBM2RgzMZRuoilSlxfrrn4Fx1qXezfHCxuMWbIWPu5Rgw5UuCtsnapOlCSPTF21w5WnFPsyBMgmX0EKNmhywPfKPuJahKRKyPJPYvB1jdzZDi7NP1JSb6aZj19982J601e+80t+xENat7/PuOz8FzDvzfeZ40JNb9UGZJfaRtv8IvPSdi7IoGLzKRhZRlKB/lq5FzPrUtGUqI49PHpBqdcupBg1zJY1IJyJe4gg02HHuHrugmxLq9rInG4gF9mRoFUefA6EhT9MxzJ6bHama3vE5F001oQOJCXkUu2sx4ZU1bWuJCWISo+fT0Gr5ml5f5RG/UwIOlHtTcXGpnrlgXCYUFjZyReHSQAhIQWmrR17k8yg6IOdlhSc9WWGxuRMzHCEPKV0mL79cjsYSC2l1bvbg9O/pyrbChAcjjd656nH1ulTiqrf82GJW6oSkqst59UmNKOZb5cfLf2Dms3iHHLqKHf7hPuo/nSrVB3abk3rKE0vUDw5BFah0KCYvjoOfuPet7db1HASjb75TFs7qnzxiukn40liXzJZbkxHdSaaS7HrdsYUlc4nd5BS1NFupNE2PW+R0JGXF1n6oLr9Th6bi2fVrnFy9ksv0zKFttLUyxLr92V95ic5bq+qtBzcU31xxa0uHW8/S2hgfx9d95hiQOGwtZ+niQVrpdu5zNSjYJlu4hlMXn6v8Gn0/jMbKMcJRHb8/1XNbdUNxD6Xj0dwddqI96in+Dn4pN/c5qjFzm8ueb4kioBH3mlIXSPG4IKklRNEEi/G2BhSDa5nY9UMA94dxpbHGl6eUniUlMXr7H4WoYGF33hKsMncSH7nFEBDs47mGIqk9niHTZ/6oiIilLeEQ+V3fqqqb4XO2T1EoPo+3PMNaEYfMy+4tzxA93Cdk+bFxCXscJYCOlBylIHC6/3eiCTb7PUvnI3xKDGDph1n1Iz+P9T64c0JjQtefeeNTZnNjb6NUTxuWKnb76VvActcrTlEIH+r6LXJ3fBvppcK10XJtkw6iv8tuiWbeXOUhzf0flT2tz7QSHoUnf5D39zng3riNgiU0EmwvlSCU/l3Zbb74oceuOJajt73L4PW5Bp8o43Z5dH3x4l5vbgykbnvOm7HhOK23SpzgO9bScEklk0fpuQi8k0wy9qc2MqPFDidmJGhaLlZDy33m26njKnF8fd4c+WV7uV1lhsDmMjE4EbibeCCkaTvLnbw6uAWvX1FX/RhphYLcCMuYi+jUrIvlK7pFVVu26n4dm4vurfUs6Rhw3u4WzzzbJrYmBOyu7J2AY+jw8MTK8Dwpaix2qRH+EmxF2USw7lt+u6KF71N0UTA7CImBCb1DjCKVNFQICmBTJGr3HYWc5pt68VdDsr6DYk8Q58HRvuyA3dXrTdtd3rDd4vtHMzLFczTXQbv0H6oLPvuHdqc1dqcFg+h71E/rWQFuYjZBUYrmXp3CfdB8eMINncXeDrpx7kVH6W/k3OIfnPPgplXH3ckomi6giJMMQ1SdW6lTqFg0xFl4fO0m7Tds9/zmZVJp9r4l09DrTqbQ8IF3jnBCTTUlR+DqaHZAhPKZMCIG01KG4nw0/Pkr7DLxs7tz4dHPHyJMRJ4YwPHFiDoJn26ogTsEtzwT0ckrsbnWcjVXih+V21ZZiJBD0xLUMdsJHSo9qE400a+pD4hdFSf506adRss8HAe9BecnxCGh3E0H39boIkSZGc6WIvYRJEAmBJkhJhx3BAoK123X902bet+UzdFQ3x3uAk/o53n0V9M1rrb+K91/IGIa96kOQoZ8LaC0HPLlKjNxfE0HbTgw97TkXymXBqgujU3mJYIQq3n0XWxbBQQK3OWBoY0thdmN7iC5hEd5k/Ekc+HTdo2SHwM40O3Bxh35m33DXDvHxyx1EP2oB/OltHvOqHkfHla4dAkqA4zlIGxQVjtcdsjO4gJ8VBQkuxG8kNUvK4S3qd2V/GGytakMVLHekmadTOY+djjUfIabYBBJamOxG2DPkTlUmnPDa453FD80gdCzLQJbRs6w1VrZ4WBxKzg6ffhTHZGKWGRk9HfhKWK5FuBs4JJ2c66OiK9FBHun3MZ4+R0dhXs7eiFswdPWKdw6kTfDGzOaaFMmxobjG/GR3bx22rmF5JkY34EtFIkwb0faZ/McK7mWDncYXGDCd95lCTidOh+0m1PiGmWdWyy3U3Pz7uWA/LM9jnyCGuJ37s4w00annfohRv3rVbyHS5LaMCQdMLX0zTL75s0oaOaThRilPf7/XtSdNHZaOSuUMRG6b00phBYgyaWG/Z2epW6GMYO+mUyWegYLsWYjIUkCVwjKt+N6ctXq0y/tV8dhjWXDGHT0MO2s3d+dH+k4GeI5e0PkK7m52nB6skkwVwwsXavWHHvmcJlEbO7GCcw2OTkrXdJBMyoMbkyYb4GFdkuODmHvmTUir8M+jjj4W3dG7GeHLrZ3zGjhFDpiUOb1N2WcqRfrxz3wtsDBMi+blW04FmHUmQM7sy5ZKS51kO6lE6GpTuaA+aj7aaSvXXhJg1QW24dJkySbAHdqILi4QifHlPo0jE2PItkuqGI9CcZj4RHCzsEIN9bPZyhJ+OZJrMeRPIPm9vCwb7A4YcDeGJkC705iWuEW4PzWKaVNLZPWnDBsy0XRIilbS7sK35F5hhI4XFRPVPy0Rs+Fb3ncP6c3xK4jxHFcQONj+JlxZzTe2E/Y1QddGvO277HbqOd4gS7Ck3Jxdmjc8YPyKm4Vm8PIhboTc6KjiG38Oh+voaoPYzvTnnq8d/nknKno6B4RT9eSCX8/hmd7B20O/Sdb1j3TiPk99ezYToFQvInKdhwtR2ObaZDGtl7fOwgw7IuZjxGsJQNAcQZCNWjpqzArG2fJeWXOs7IMPeWm5pspwqj4Upz6PhZttcedUe3DnjVD8TM994qaVNYi3r8ltaIFzR6Y4mZeb43h/J3kiHRXuRIHeuA6QYF8sSRuRcxRibuqlicZH6IKwVc5G+Pk2cRcccNcitOWL4z2kO0s8GNeDxzNL61OfJr4p2EBKvKZlXGuOEu5Nc0ybmxU3qU2vELk5uwe4uKxkIsy3Kg45UW+Q5Yij7PiZJmbO1aIxkcW+zC+D5eZmj4bO0drh2M/lZqmmx28nvhs/QP6XXDsGoaI6dTskb7S4md5Q+mAz7HkgyO2ISXDHHsRdbMyJH51yW8xHDELt8iLglBHB25/BOtXYudV9EnbtR3nDgjEosN308skZdcZLYRojYwlVr8SU31799xKjpUUUdw8tYjBV307TlK5JqfmhsNsJ4T6awTg8TYrgIuIpTob+TF9rYY0ybq3O8tdiRUPCZdpTPHK7O9r+9nGfl7sshhbpG0jOxRNoIzMtw9CRs5WDUum49CAvKOuvYXYBIQhkIqG4k1ZXraQt+OAoKoMmR7x+gvnNiZ8EYHoLiC//XY+RoxajAdv14nXrX+JW6u/gAP+n8zmtvTXn2+qvLTlEUQ38XyPPUcYdsAghRDvrCH6Z+NIH49Sj/xRTpuDaRQNpv+uzyth82znt2dRh3YO2HoN+Yokav3H/mP9MJ3RAqRJCT/S+qcOz5DqHydehuKjg4YvlhIKqqYvj02rlfHqPksHFZljciU/DJmhCQEqIEIiSI45XRzdTJY401o253nwkno9jwb3mq/rU4Hlk+UcYeInzkSjvta8+BR1l9XllKdiOB+kv/2yzxt76Ui1M29H6nxjaPrsZWFPhwls8uKbl5c4zEejRyV743KsDmE/y4XzJ066vc7v81r4kYixv7L36mu7OV12H1YwPKkpk63RG6OUZZ9ld8zPBzdfldlv+OudMueTxLEsXOJUh5qQslpOd8ivyPsBA5703wmPkm9SJwHILzBg0oePjL1nV93eO3daPs7KUfT5N6is81fGmwb+ZQgXT9k/dtf+Pj6PhcX6efHjLdpD7s4UF1NV5r9HZxnla7uv9PXXbes+S6FnYJu+7GM1h4mYhJCzdIcOrxD4fBEMgURE0FQPT1231d69/WdfkUmBEVYlMVmYw6rmjEWyZMf5dMs77EBpDhYDswxkDNkD/L+/MOkw3rsoSwDSdlCOBbMouCqQmX6zh6++BHPQuCAIW7/g4VTHHfQ6PJvfbyhsbn41egmLk9I9SlOp+fGcXfyb+zfxX1PiFk1ln7n7/9kj88jx4Gvlw21bZM7o+2WOJ8nyQriWZRaEEhPoObQVNyRzjSwWaQyoibIjpgJARxrkZ7OAaJv8X1sFP0z7/49BBTLstcwlCTkczjVeJq/wTDVd6hnTySWcZz9HXOdN5MTkw4gr11czreWCcT+j4ldJ20uM/jhAR8eS8xjNe82A7x5+I4ZT+l3zKGnV8y2SSBOzrmwTeoM6n4+ub55qaODHrn8krWX1u7WUhsZnO7bts2cVLznOuanQ9CKxgr0+j4XTP4XLeyrkxFlYRveVs8xGwYlAhOCD+9SGSZC6AeQ59h4/0tQgmOxmP7iqYRfX7fr9X+AJ8U4Fn018dfLjKj1QCsnOxdSANX+vd9H6amDRV47Sbtc/Kbzs+737pJIQkAhK31trfO30fD4Lnx93sJfZNdMRQUzBVVQA53MAeoZ2mfJfHWoX5ezzyvUV735hFoLfus23OVfOK5eKud3XJ3bk7syuJUbcIPVjXIg45h4cFwriOFf68gtLbgyBnO4/JG9xTi6E20lPEjEyGTGAshXz/vHTSQyrnFCadFAWEC4uYDIjCSbFpNUa3R+B2T0Zev8fb3/VOvZToV7s1Kj3iBpoHM8GhiCbund9vwXPMnSkP/mp67jdue/9vmmuF9KlnDxt2xhLI44OCSZEQQcpbXwfY545A4KOYuPq+mMT1M75lKHTnkqpEGn7WkUP6frN0jGddkNuC3epmPseL5eo6gz7XldXqDBP8dZL2nN1Y8XUvH25UM+tZP7+HIl23Dj6TPGO9P91zGKMn4Z1c49oSjlz+ED8vwJJFS4648NTH9IW6f5wKi9KPrhpGGVv3ZiaVj4fyooyD+rlzjlEQubs1yqU45wsJUWH78Pnta2hzwHE3WYxMQUQwhA5v/OeabLTfKz65/Mo2W+5+RNdinrMOD+KpTStBeO9eKLZCQrTx2RvqjniihH4o3bT9z8YD1JZ9uXXSYEIKnUf1CGJKdtoq4IHgb/Y/in0aenWnOzUrakLF7nTkfEsQObUVQcQ7u1S6cZsTaayaao2P54S9Zz+c+JuC0UdBbQOjk6CLOPhJRemgcIBC/vG43TD0zH6k3msihJel+VpTSxahDdVtuQoR8AcusqWRDwpPDO8thefztOhuH3JK1WvGu9xb6oqTuehX61S6ddIgUbOScnAZ6WY4D+02LrYateZku+4TuU7RFtAyBH7PjDL6TZW3A+C7W+AsjaBxMQ1CsTlf3WESJwc9aS9imNqh2cclx6ninz5uR/fUZYncwY8m3NLASKiNx3luLY4Wd/e/sRAtFaB1TfijGTzTjpp9qhqSM4HrL1/7v36aaHu99a1uMGWHpN69aIgfVN6DTnlOYj1WwiSjdiRIknMIoUlFJNMbhIpDKhxlN3+nrGv6/uTfod2TamuKHj07c9FjxRTKTlJBLrIH+lH0aCcpCr6ZQXOi2/wHjHffBVpa80VLJIlp5QiyPVl17ED6LoWSOHs7kM4j0kT8hetXZiL+NZ9FMhNhgQj7iIJMmklrIU54VI8rQW+/5vR/Pahx10kY79qjqRVQrR6Jy0lOJQr4CUqqCU+bxuR1q5PasL57oIXevmyu+iRtY9s/dMlt6X4yloSzkn3x1vmppyXZBIs96oUFMf3r0XYTun9UYO98okmZfkSmkHP68o5LXlvP5qZ+isO+ix3Tikv0NLv5zv7dBwsHn8keeHejnaTSg+op/mrHrhjq2iZUP3OfQm1R0h7/W+nDanU366P2PDpFyHQCQVV0J/0Hg5qtv6SO2OXMvx+UGfsuct7F4LtvnuH9Ho+/QO9iDsy5FuLLwxPA/T6NObbi3cjvlE7iZgVH75Lg/KeBm5LyZX7A+0dfY+0es54tSpHF8OdvsmW5OTlgk1JrGfhOckOksX+pFkXK1HZfc46FzdjHKVe/baRJJZZ5XkhTvfY84NwKhcrUqTUhEz4CZC8vElyS9fz2JAYJTHBwveb/TxnqqVZzN/6pNJKDTRSkcPaQdbyeVuPnbw7q+m58GO0R2l/hDNn2uQdHEpF7tZMRRxr9e+8lwymKClnMlKQqI8r/jBZHan5Pwwe7DH5/GlPG6/Qk2yaovUVH2tWDaRcRspfr9lKEtYobTmpSe7f8e6ZNbgKIdM6LuqrPlR6VEfDGHD2vVI4Wwyw/MNBXKR7hzd+b05h9pzjoqAZcOx+eZKn2OprwlxPPW3frKk1C15+/jjjRSSs81GN1K/bN7XkNO9XXrKg/baBbk3Rdmj/xWz1Lscp6STQ6ZH9i0gV76Sql4vpPH93pieT9q3739OGfdGetIW/lXV3rR/740PC6mMiEsXtCVUkq74y4a2ly7INllrz3Kha5R7u/jb1k6qp9fF7JrpePJ+hhwu+/tgzsvh3h6LLzc9c31EOc++97r4HUPtxXjbh5PYqlX65Yyxo9HeXKGyPhpTS+lUdLOW7L49t7guFIPZjl0kdO27JN61x2jQkkWV+6zct0/olpdScuqdN6Lp7TPCnSuZPRPPDx+7Iik18y+Vi7OXdbhpx9EsNH8ceGB3eMopHOSoZU8vS8pvwar7oe998yms9pNvRdc+6j71LAW0OuOdf3LwU6bLvWinfn7buFKejCy3kzvPTXlQ0s8lvMHuOinepcb9pEh+2/jPsvnLK3y4cKy6Ksr59+6Psl37s53joF9HZBJIruUEk8RA+XuhoXcuSPFS5XxuydhIlJWd0QJ+v3RLN3cuyT4ynvQ9ES76TftiJPsoSF38AWBeqAm8/mr8vZv2eyHS51B8InvnqZl/t1LL8+2K8uTU1LqUq8JzFJvCC+KJ/ZKh5PpFOsv0Sti6aXF/Tac0pQ/0rpqpcJR6ZaxRMyifhpbHwsUMkWRo5KTukCQSr6PKCh93i3PnPtNdYMnb8g/AGVYZiRPmfkSBvw/CtT1F0Pbco7dV3RkJor0+zACbSDIhqRRJkIY9Plnwly+ysTS4khwinWfbt+jD6kBYA7JiP3ZAYiJCdMxg/EYhg7t0SlRM1LfKLb6POT1xUenB6ipMcgWcBZFqOMz41JJJj44cmssBNul2DOrvsj5l59lI07FpOkS+Pu+ySkl/x1uOVuHv+Xl9x3Zc7uijmQX7l3YDfZ/ChK6z3P3Hj5tciyfLG3T5nZuSm9uXD171jjP0K6++DBUq82yTLF4+dN4zpxswTlxuKcyfH08wpbYfjoD7XG4pBTvut+bi6wuvMODj2ls0hW+k13FbjXCOxSua+amd0b86FFKGMlKGWJA2+onvFbwLXeH22OVd6u7nHSZZp063IgwHjOrpiqkx3k77pLwJePGKT8OBaJg47G47fPlmURqjZQJrouPLflUxvfZdbvxvmeNOyDDOk9M74KfcqPqFxwknmt5LXdupHCdUfIjqDy5UedHmpY9OTeyws14h8UkQfI0HNKZUfnnjIl33Bm3WZnTarW+2eN4zKwWbrdAjEnGvs9LDcvzw5XqDzJZUw57NISKkLNYQS3Pj5yCaZDWExSzO2ZbCFROObu20jMzjwy9FDPHAi6j89/DncguMasiWsyCXpdjGF92+xcOsm69M3V1/TY3+JMO5szdY1zce7ebpTMb+nnqq8J8u668y5Z9p+s8EFdcPXGkOb3x7Tdm+kibN2I1KcInpODjz5a97B4W23XLDDIlYtuaRR2uoVh8TioYhA4759787mDPKrT6ZQEcedriYn7yrS59LhzXx3SoYIvRS5wwQ0Ik3bXW4nFqcdvGjYm7dwkdfj87CZAyEH/JzMPpeTFlT7qOJgIf4EKIDl/Bk/DDI9+0fbFmCUhshl0KMYX/zOfKrdU/UkB5dxyZbiR3e+4g7Lt/zlTUCXfaLBZGMDbGvqusH4dbgjEnsSJ2+745XbCujSPSUUiT78XFSRdfOU1cKBD/AT6v8dXsYlPN+MdMNlVaZmBmXRW4tfjF7iyEe33SgoXVjGeWUn+itNZlkJK3hdfwmMm4e3rinjf4NcJvpbMP1cP82Lh2HS4iNJl/Jdr6nO74euKH2h35GyUz81p+fwx9u8cuNRdl7jJlomMcHAuQzPZQhZPCHr1zPwNvEbVSjBo5t9KXUSEx+H5g1OzDMN4jcvaMmJHycHhzkhqDKgNZ/9yOpsi6lIc8JHRRXjxp0kUrh/tnPD39v4s4+6ueeqsmaRqSOVrOKNJzYnuTPNlXXnXGq4Vc/l2dJtad3K3p7fr9E8dp+M6aJ8fqilM8Me7t029V9bsnwLaPToTSQJL6k7CQkkkw0yCxkhcBvVTJhTUnO2igh/q7kzSBTkTk8q2ULyZ+Dz7M2Bw4pGIxMWfr1qMw2KO0zOGyAlQI3Tu5mcEsnDxDJj0xQ5QucTOpAA4novRWjiGiU+H1svZ2CY6R2PcESjfWPfspYInamF/MbwPQBtxodpmBCYb6/pcal4HxeNQFaY81RVBxZvRIcDaG3/Dze/oNd6rH9qQHcL3rzaPScDU4hroMDNGBiBZPPBoOgnWyTuNU2n5oYOWvDym4kIdkXxlupsP10hscMGEPN6CHaWakJsOLDnsM+DzssfDNHYJMhxXBz1/q854xDakIEPdW28PQ63W4d27ojzhq+wereZafopk29DJqXnFhwoqPTKYOkZ6ovMs76SkMh5zqCneNVp2dIEJB67y8PKlBk2rB3k9s6dG2DNgE2oR6TlpIEJg7Ovgr0nCECBsjIvdz02s35NaAwdvAo4SYgVGvO6Nhqxej/E73ZjvShjwHL7BwDflbEaJpouq5VmM9ImkvXbb4zvVGQgTJgV4Oyuq5M8ehExGrk47usXokiEeXLGOCMkLC0wWCYYa1JDe4MMe2+14l1wpWRkd8ZwsihhK/JAkIVSmEjEOXUhrjl0YvkyNDEwMPhvUKOME1N2SXieSOSHLx8caaJK295gwSTTJhcfF8cPr8zp0Kpdle6x0trqulNdz1EZgm+g1OTd7MTOB3ZBcfazHHEMvvO/pvC4QfzzgQFx8W5bskNG6D5yN6r3wN5nwzPtbo0T9mt/DZjHEwCv/EuobwzCgfxh4GmRpsNiDMwACfnfCfwlqIIHiE/b8nqPnZsP7IfX7sftlfmrd/NFIHHhi6m/638WRXksbrPfelSZPnGJQy69eq+/BEgkd7LZISCRT3Coer7fz5kkkkkkkkkkkhIskhv3+e/4P3fG78/wPHPs+fMnOr4/HW5icc17RNdGv0qpkjh+p4H7x95VbHJRuON0cLnFFKJLveSkqYY8MzDIYYTDDKXrkkwhZJKkLColkURT1mAgrULdcINgLBWKhGQBIoNSVEWaskYEsJSSUlSFEqDGJDJCm2YKSbaybTaBkiEVCILBAiiQEipxWgClUiEFIqQRpGlaVCKkFShoTBFQskpFSKkpIqFSGSYGBLBYRkZGIUSwiosiKVJMTEZAsWEwxDIRYtq7UuoUZFISMmM03q67SRhJMk0kxMqQmRopNMkMz1LdjRqJIiIlKlAyzGMyRIqWSyDA66rlkmBHtdxkMEoUqR6lwIyNKZkWlI9VOhGk3SuiphJpGJNgokj2cfnen3vPEQdeFvnkOKWJLl3c58RV2/jqJe08VcadJ6503gUhrwiTsfd94Sjk8Y9PxoeahtRWidGp08yO8bk2iJwlyTXUbiSNc1nTwuogqetReiDbpKE/ja7mqLjvXGXz1tSaUJ1HiuNvvldpZS1GjByL3xRkv11rrffO3rayesOzfLrLtD28J4rUeOdVBEdv4299up1sXSFx1WsvPHEzO+8XHTvho5NgUBp1OceJI51XCVJ3dDuhIdOujK0cZ344kxdTL8Kir7yn77vus8QcclLvx4N0odS/jlafHSSjrY+1GjLxCSzh4y9c7vmvhL3Gdtb1MpqWSkSlJJk22xmlpsRKQtVSRNZrZKbUQhGYWm2y2gNlsqGS1WwaMrS1psW0mSNmrLUCpUNs1tvlq2dQWi8q7tGCRIyhIkQaJQjSj6J2jJJTNiQSJREobKZMzGZZJSaQDMlSCGQho0SDG+F1uWIkTXkuEk1ItHrvxMTJx33rnmjO7w3JwaFAk78VvJ0/iOdcddPR3xdc9nR4jmtXHUHT9da5hznwn8cG+pT987zvvbng7mPF+LjccFcrN+LpyLO1ZxLJ4PFb68eK4Wsdik0XZ4ohOJ35GTcJFsO4ly8ZfO71zXiTmpfXXcz1HXVVF+OO743qN2/Z4XiFvDPCndXT7d/Hi+eV44O/Heb7ONafrvs1uL73XXG4rXPWozfXPG++zxKk44iWhw8diQGuqmh3ScT7l35znt9PwntZfPt50nfXV7tttm19N3eSWS2NJLJYyyW2WSVtsl83PagVcVVBU9qZULwBBMSQFWVzG4IMaMUSYosY3l9Hw7y9JRVFFMyVNuGouW7DTa1OObsZBNkUSSCgqqL5hMU5IKsc3MM4ct0gesttWwXriOLDmzayBo1ERfFRrhtWvZey5eNeOETjhHK4BExTOIpnLMzXA4hXMDUDUqFciYVwrhkcDXNQw1DNSpUImFS1oybbVVdDMKikSJXCsQU1MjldcjGuRKxXUqjdRayYyI6Pq8NcUCIcTFwI5a1jOS327CvMIhOTAkbTFqCrmROnK6rrmeXKWZmuWTPDhEBHtk0jkhiG6GY4iaxW80NQbibIZgbTYdV8an0fTrW9tW4aDEWJkZloiEsRQSJopIgiKJMQRJERSEghCBKUkQaMRpMQmkxtMpNMiMmKMyMWMBqIi0RoAwEGijVJZmowCRCaYmNjGLSWEo0YiCTGCwYiixBBgzNEmKQwYJozRkSsFCVJkoEJlNNiymTQaKoAk2KNigIkpCxjYZiyRimZgptqxk0JJpKIgiJmTJggorFjGDESTZSFFZNEylAQ0mTQYxZKopQooTM2MYyQhRpiEREJZYbGIyYpkUhqTYsYAyESaSgsRjBkmQFGJAksVjKSFEWMJRQaiqr33ixQZIurq7W6o0yUxpjGgi3iYq3DRmEmlnASzGdEnhJSNUxA91UjXDnfDa6cMFXNTKZNx34fii94JtvKbOeF2+uBcJ/DrnYMAN0uRgB8bTU2bNJGpqbTU1ptmzZWrNVZaVNNbMrLU2yySypIWyQIreEIOmZer262c9tvbTzGbBW077SGKJBILUiSIdSBLJHnsiSH+jx583p11ylg26kx6vlfVdeq+m8tb8EyRsESQGBIKUxkIMkzFEltJJSSRJmSUaSkmaMkYIZBk0kTIoDQYghiaQ1JKQiBBkhKMwxiNJAmQkkiCGYiwJiMZhiEhlRo1RoIhNEswyrGIDJEYpKIGWKakI2xRCNBEywZNCUwpANiKEBCjMCkIMkiYFCUkRQtjEJjQZIWCElAwSAIpklAlGSMSDSkJS1gMZmA2TaMMixUlFEUYmQlMkxKjGQ1gpKR5tvm92tyiIbjkXrpoIg7OcxmtVMj0VprhRBQ3qEB6IqohlOOvPdrMg76kwZNDaWWbzBqOp2+/KCC8pGKgwGACO9CJByFChKHbbCR1ISPltr8fURQdbDWIdvXx0ebmMApEAva0oWEgge5gX3+J8tiI5HgjJDMDI8WJNHzfGusTr8+zLMsx3V0FenQbNCvLlOR347JQb0K4SQjNu+og6esnUV46B5DhkcVOQ47y2KaFaHjos0PQ0N9/G90G3OrtESMZvTUCCXeTMwg+ApDtSLId4Hs69q9gU+JwOItLbK25WzELlMJLJkUNddET464QnMbsO+NRElVgbNio8Na30GiggpgA3iLEF6kU6uFtpSyy89tBJHx8aITokj1EsXBEmBSHkhZISd4Zg1001EJdpAErWiSR4IgkHGQI5+OYGiLRv3xJImgoLHFgzoGT1NEkjtSDQUliSPTw0J8KRKkqINlDpQ60gjjYwiTs4nfzNgbBJEOcI4gzbR2QNLgiTvKEb0JYShwbhSBOrJ0helxPQs0JJvuNaaTSLDtbbaqpXAPGyG8kI1DteoY3baJoiSTLoqkBPP4Q5dzwgn+2a9ZQHH0cv3O6OYn4RkQKOQAobFUWQRkZFJACSRJJCEU5dfVRVVjqvmIqEz1kyWSSPCISe3Mk+YfYDPsChoHYKGBQoNIf45a74TU8bGgHNpQ0MPIhVm5nw5XUszAXQraaKJwp65KT0lU9JDOMwHGC5nq91xvzu+tddAwDEC6GHHYAZnF6731rVlMIoYCe+OcGLDOju9+M1ErZTrZCQkhavMuTXiyBmPAPX3HgPv/L0dt0nXwaPDsapjxufD2+yWivu/ZmfKMtdPmhiXua61fRlrpXdcfbbCRIn7P5N/Bma7RZTsAr4h7pQ/YMzd5p2ukngPBzzD77b7sgdnaHwuWtoIm1RRRMslYUZmGBkgqIhqTOfi9OP98knx0gKHUoqHi+0B2xGMXu1zkZUoDMenger1XrDdbeUuCW62e1xRmad231ePH9vWZNdwPgoc7xEkS5Z3tPjrTy6dgC6CBz6M2CuOMrjAih1m/owLx3nDO/kO7Oo1vzaA8d/G90NwJWzlk0UQdFSZ1kTv2fgGE1HK6fxrW8DPEZqghhmGSYADbNhZShctSIrBiixRAQgC8/xdx6HDcHmwR1sgnt7euNpJJHvnTnrz381F2EWCo74A1zSkL0pQV0iLUHAqkRN4JoUqHP4S8znw4ybcFYvQwCbZqqohTtaTZs14ajrqYOQqqog7iJEhMrsV6F5Dvz86/oJLCVfbNn7DyL4SZCUk3ARAmTMgSJMwX3cOpw5QTOS6JKCko51U4Zg6DFOFlV6KXK5WGn2c7yd/StV4jTjLszoGbMMMMxXUe2ZdKg6WDMzegG5dTzDgANH+np7vDcLHXzicy26bwjaf2/ybe2USvPgi2Tmdnl78ykDy0ljXx21zu9BKcYMXe6+QbgZ0AhHh4eg8UzjyJwTICIooeqJaKganZyRH3fkc4PuLfehwBjAsSSTn8TYPuDYiNrdBaEwSTPq41GrCEypllksB+mKZQzMD89mVDsYGER4DmZOlSiZ0F7BuHoNfpDnk3m/4euo69Q6ScnkKHsGwYbBsGgposlNaDB1PA0G5Q3DAMOnAaCh7hoNGg6B2DAbhhgchseQ6hoMDYJhQ2DcjQSmBQwKeA8eu4bnodw6R1HoNw0NB5CnO4YHcKEwOAwOoUHIUOQ4FOQyIaDDQOQp0DYODqGxo6ncOQ6g2BsFDgKdfIaDoRyXA8hxBsHoO4eDgO4YHBDg5DkNw2DYMDDAoPJh2DyGBsDkKKdjA8B1Nw2seA7BgUOQ6FBhT6HAch1DwHkNzoeQpgUdTQaOB2B2BuHsGBoOxFDcOobBgaEwNwwPQOwYGxhyHQOoYG4UGwchgKHIdQ0HUPIfPprqjl41x71333mul29BNd4iMCcw3W0LUK446G+z26B7dHaAidwiRZZYpaKNJiyMLYrImZY1jaNFGxoLGxZMUQlikUkZK2883d55Aio9HLWSskGQHRQ5QSZCIkgiSW2QSZJASRAxJhJkTIiSJKKCxBRjbLUiRDISYhJKLIYkMRSGCQSJDGISIqSCZYKSCSSZESQEWDSSaCopmjYkAkMEQRIjAEoiDKFMRKIwomYCFIQlEQkyZJJktZqWRfhWDUu1YYoRlrnay/GumOGb66z59VHnx3zegY8AxfXPsb2+I8vHE8UzDMDSzDDDMa9HLit9Qd5ncrzfHK85OAaQklgHlF21EyhwGmimb2xTMEAtiEYsksTa5XTB0nCbDeFsLIJsZC8mc5g1mC5gcGTO+mBXOm1cS2GmF+TAwYpmGlILenEediGwRQWJZIiIochSMSFDLB19tokgjmRREIjUsikQqEJF2iTIQpxgia79I3khsDhznhdiOm/OoNVCTaRPG+eI9NnXgntmRDqXaushyGUxgBsAjo6znt568LTEWMYCwI8tzqnczCSJJEZIQKrMDAsiIiW941z1168eufbfrJD2smInZ2CvYNxuMlAlY0UEFIoIKbBRRStVABU5AKChSVzCbvi5+fJEkNvvLfCu6+J2eru9Yn5Nc1+YktSUcpaTiYMMSbksgN3ISgaLKnXr92+Yk445E6DgNg0UGB2FBsG7gtPrnPb7Po22kJ2+gcnhC29Rzj1c/Jj14215538tih3DyGwbh68hsbnAcBgewcB+bm2e1MhZ3CUe4UMDHjiJe0GxG2fsEDBxpJJJxheEltb0uQwA1qWgE2gMEDwOp2+5D9B4PtnV8fy+jOW2vPKz9gbgeXkCjUBQJBWEVUkFQCMUIrZm2raybaUtqpUtk1o50eYeDgM9rGy2XkC7cSZcGFAFICwFUJONY2brpo4NpqcNlLIQiiAkAjm/Cqrx7M4m3t2HdZgsbA02hv+swYZpJ6BjkYJjPqcA6VTf1q13euOOeL8PsOwDYIA4BizR0qSfxnV1Q++Dpa8DDGACYYZmqOcI45ivG5N833yAbBgBmYml0EtIcyRTs8fm421tvru9k5Dfro8U5AE5KyJjW377wAtdd+e/HDatOeeVNeLiFVIxZD+Na7bsZmBimZhmGYvzWuNnHEPo8W+cabrz2HeQ78vz3pgOhcIzxccvnajMOdgCbihzp1iyeA2GELFijrWJ7bc6Scg3BhDrEFiDuNxuhGkibySPBTWoMgjKR2vTt4537cyRx0N7qRNWWpakaqDRFpQ3CwKCgsCklqKyREuQDK7liBJFkkSRSHp6447+19toTgvAzZgw0gwbMJ10vsNFhqszZIZxQacUju74t/OdvXy597I8BdRsCh4DSOL77+HqJQJJvUxXjV+8+8THtu+ffvkbbP3PiLUwp3dHVrxIJu8HvxncmuPHDMzMYyQwN1ykkkx4AhIS8w2iwBUXr6+79/jZb21D2l9hu7QDx8exTA8gNPbEUW/kSTKCwIcx3tpGaqiGRFBltJTFGW1IsCgIL8/Er1Xyzma0whBtSBPlZEQ7Ow7Dadd231PL5/X5467EJCbvzWda85eeOfPi7pjlwY8gxuQ7uLvbt3456Y5aiOSKULEpQKRQoWEUIpQpEydlEQvYjHNuZ3m3sQkkiOApIiJykhMDMDMJnA75cAM1qDurm3jJ3q1+YZJmODgZjz47fAT6CA8gEh143QwMVXleuOYzD1329ezfr3ab99r60cm/YSb2EnuuSCXIYhHI1UkRIskcu3bR69u+/nVucdeXYDjx0cjMa8UWUu9RHZvoMK6sOumHANvPXz657dJyqI8umIiNVVDrszihgUQUKFQ2IsZLUingZJF1kb+PGtiEUSUsSE3KChRQoKFBQtChQpSMDIiKJQqKiMQikFRIyM4RLCULtURGLQ40iDYm0FCod6RHUcAx4699uOM79O++daDeobSWa74AxqiZ0EntBIf7Vf4co0tfsbtKToUpOmWzkyYwupAwYs1GzNQuuxubGrm3K4Q6ooiu6ddddjrtFzGS3MMtyi3LcgDQAMiubSlc24G7cFmgU0ySLkRUoRoy3ISSsmZZuk5JXLhmKV025mkGNCmi6pc2BtyCZRkJG00821tpcoCyNAkyCebpCUS27BF1LmIZE6u3AyMiDEBgdqbkgkx27NMTGZkJKpquWm6EcycriTRk50Z07p0ddLt2XLciRDdJKYa3LSCEkkHAZZSpxBpgE065Eo667KVd3O3SndlzKZjrTcpdRJv2G28l4u7qWZdmEzdXay07Butw2NTa56qtrXwkfVEd+8Xv5+rQajzBTpwB8auB6pvBNkSISHTfr02iI4Cz4QhIsIVCSSKkD6szxzfGjgOmDxO+9OgSZrIHvpSrATBB0xVhFu44Y3LS+5aIRHhSJ9aRBUIUyeNREkmn/ExJGJE+TzmuPHXgk+CBJHQgSRwQJI6KfJAdXyRCQ2kkQLCprEGB1QUyoA7lyNKgCGEymZnBzB9nxDgqI5iyettttttstttPopzznOnTjrm7F043dwmdO3E3dLudXHUG67nddM7tKHdHLicTMd10XbiXSvj3ltLUlsskrIxGKyQWMrbGJCKkXJAYqWNLkapFkW1YWQjbaqSSSFky0hSNuEyjbKtla5WtRkWWSMoowuQa4ySW222222SKDIyIrJCMREWOZAhBJFwOY4hORul0Lnd0Jm7uQTO7g4czp56ptu3mocpBO095vqIJqHeZEDsjaHEIdhFgwjIxSSMZkRZBkjMZJIjrp3duuYuzjkdMnXcSBEZCSCwRYyJCQZDIMyY5CLIMmJIeUaSzLFZWSRktyWI41kYRrkhCOVkmUlQpFhCsCVbbWYxlVEkYVtkkhLKtSSkxfF45066ddnXdc6ZFEJYlcydrumndBdpmcu7N0rgxYRZGBBkxkZFmDgcAww8YCSQ1zwQd5mbSEYFQjEhCO6AochUTPMyloi20GgbgRUTAgjjjYIFgjetIlZ1dpZJvURFNJaj5iBiESiDSeOMjbS7PK/NmaKtgAimeuFQ5kPbrzwaNjnz48SJJEVCEjohBSwiCBwy7A34ccFT68ej0X3B1leieij1nVkbwm5b4h3C+NQHiCGi05BbYEouYp7IahsJtOc6hRpw7BOicYG3NXXdu47UKhxBqp4hwbjXG31vUpud9vXsHtJJgWPLOvX2kznTj7Vikx35T93x9HHW+PWvN93GbYBACYQJSiSR6CxJIUiSJ56kU9bkQdfbkLvHXwkWb9g7BQc0Kwy7vPPfmY8x58A9uDusHl28hQNvgri2O3sAdgAdI7m2HAPHWSHkDuJ8Tru3ZsEsPY79SEu6IOvogSRtG3YZ36c8d9+5Zv3XtsQDCNpjAb8BWzQAXmgKLBUYABFBEii76TEQvhppuvhe2ag8hXeXIkiSIULHiomRJMsDvZ12MCkUkkoekYSRENoiSwe3mQ2lkIjw5bh0iFFtQ3URgWklUIoKkHHTqaLtxvrid+Jwaw56bA1JEqg/0wyDCNUhgUSe1dqR0MbQaWXKJahhTfMUO1bbZtBSyInawAiRxmDvnc93x53z6AKSxmYZHR1pjheaaRqDILwTOwAggwZm24zWHDbLbW7bAGPQtwRRAzy6r7BOqjNdW/PPRXgBtxjHKqYHJRSiREZD6kidJZYUiQKiogqSKBZIWREnaR2dpCEjiIsU0LyosLycMVmQBA2befHfkwBqdVMEQb5fXIR4XKw42a7AK5x5bwhtwB5RyvGiCYBv6dOnTip7GqSNhhmvNGjKcIxRIkOntgZohQW5YXRVUPYMwL3+PndZ8ps+LAI1ydRYIKaojy50oqG807d2/JsOG/TZjICOmc+vPqEPmHSIHcN8Dn289CSbvrkSfAYewUoUOodAz12I7eNwzkbhtIRzCOCI7A9qGBrdgS97gdoO0J55I2MO18TQbB4DpOQskDuHEyQdA7mzrsA2ESAdAFsR0tTcQPx56146YGGnBUmvEOtkTaEPJJMILJERHlIVBJJJPaEKIlD0HLc0R0Nw0Fj1ZEvrr048udZJFPW/GdQ4kjyGB2kk7hhsiKg0eMHt0kw5yNxNg4DpCUNaDAzXr0munD169TjCNhFChOA6hQ39PZrXtv44D0G3oM87G2iTMwN+OwTtrre1Cubc38eCBJHVHLtzzga54DuR5PIoMDQUOA2DYHoNh7BSJoKHkOgaDQdQpgaDDoHOENgpEwKJo5NByHIYBwFBsGg16VOATO3GogH5Xcr/chFQ4qorwNGOweQ/Tt7bB0kk4NiO50vgOAz161Q4IcXiqphA0VERICUgKrvQLD3G3sGg7jRuDsFB8Bsm4cGgopweZsiOngOQbB6279dHwHUw2PYih7jZI6h8nHbaSOvnPVdbbbbxmYmvUHeRE74HoJnHYLdPwuZ3xLedo8sBOsAaZ7ALBhuwBRHbv0kia4DfgPLmIb8pgY74Gxt30RCR5kihDfsHZBSKnmcUR0RRRSx5XrYhrETXbW5UCbr0OdgYG9DRGXyGgHmJOQ6cDZyo3Tfyvh0zz3V1VdNHqmHl2UIvQwEGEDDPdMgQmJ31vmSSSSTHo7VMXN34wwwKUQMkk+MCfAKE87BkE6dEtls0G8ApDoYTr7yWwuQdG/HSxbLZvJwGWRbjMMUxUyc2Le05bCYsbGMRvvXKp5drXr13pbG1c1zRjVFrxVFtblUai3jWuW2NRok1FqvG1y0V41y21zcqjUUVUVJtFUbbRWuXZYjUVSbavHSjVXOGo1SeK3KyW0lyuRFo1i0RsO625orWLJbFa9VNyotRWxqo216Vyi1RgC0RrWItQtSLGHEsKixCUoIKUiNKoAmqggpa4QigiJGILEOhAFEhihVtREU6UEUSIQQCKgcFBUTKqhI3kISKq6hYVEkKiSFZCTGKogoQWQkiUiSJVVVCgokhJ5sSEHmRIE3iwEsKSSLCpJDeohGhIChQCgoairuFVTWIIMiohIKowIgjIoqMIKiMiKgpqtaLY2o21sWjVFbChIqgFKoqVUUWQIRAIhBJZZKKiWSkUUWLFJ3sYbdxa622UtpSKo53ORhFJnLl3bqYyVLm6ZOW6u4Sq5s1bTa5RXa1TTbJAqC0jECICRaiSkWUiUo2RlmSJYihFQsRYc4IySy1ptmttK0xJJbJSZlo1rVKmyKltRURtbPF2rurtSWyUmbc3a2XN2qZaLWtU3NrrbVjdxzprptK0Sru5kZkiou7raABkkJNk3u2tvw7a1rTJokgkogskCShfRIIg5kkkJHSkHsQJI9oe6okhYSUiA+cjaHwsjZtCp3nLUjvBGjba1ktbVg1UW2Sqoxa1tdQWKyWtCBPj3LRBEYphIiTTWNblyKo0kRZd1rlBooMmxRsiXOS7u9rV1dDY0a0bFjSXjW7zV3SyWLRIbQaDUGu1KusovG25pMwzSuXKNY0mZFbypuY2IKNjVEFG3iq8svBk2QAybIRXjnddNcuTKSXd1055XbsplqLTc3CjARqS0UYijbNQxeK5aIKisaNiDRtGxBZkmgsVJtESEaCNk0aKjBoKKNYxkIu7sbGEKNo2gyESYxVBRajY2owTIIxBGu7tN3XZmUttlWRQ0YbSTDIifh/KFsBtFu1qt3yjz7Eb8K5RfQvh3q8nDCRLYQkTFWJMrllIwRxksW5VRHZBFJIkYIoR+O2gTFZJJCdkqKCIKc6hHFgkYuM5N6NN5ytlzml12mvV6sHrqLRhWXqcZIbztp10rBJDm3bsSLblqQVhJUIdbNbzeZpyZLbNGG7a9vL09D1yC1TkJY5NakYa7dakYOwqcQ4c0tZeWovJqR2713e9OtlQ5zq7YLgsYKLJIxk6tsY2Fy22XiSs15u2MdYlkLbS7DdhqFIbTSkNahFLIkdpMWyd05vOETZAx20lllSpKEqM2GuursyXGDF1ta4SW2YhMk2xeiHGsTiWRXsmgot1ChITBsIi2zM6nZK2RlhXFve2yG9s0RZJi4psbajCR5sK5qQSSKK1xbvObIXSanEgjSdVjZ3ZbtlhbKkqa1Y6xNbbui4s13VN1h0dsuZ4DMuZ4LxCYgqKCyitqNylCjTHCKiK4qgIwqjatcA60R1VIIigBSI7+DBWKxCJRSRbJajIkLGJYkqpAVWbarUsbalrVFUWLaXWWyqOZDlEgpCSQshshCR449zWwhEjOfYNgxE289A22hOgUMJ7h7buvcN4Q5EjpOwdYNykUOgMI+x3C7hwHQPG/J8wwN5v3xIHYNhgdzwGXNcEbowPAUKFg4wPJSG4TITxBtgTQYGj83i39w29eYjJEqSWWJZJRZCihZB9VtscsNd3KbdduXXVdbouus7rcIi5VxZOu6HJ2l0TFQHCZDvpUQQS+RPl69vj1khW+QQdR1HxHak3km0SiiWFsq2ZNZS0RqVHy+r6/rnH4nU7uF3iJwiSGDGiYbMpbFub5rVtDIioUUQJJzoKm4RUI0SMzGsqZkiD2ETMw3spoxIxidYGZwyXIYDxOYrmbHz7f9iz535muyS89Tx4SoqHoSYHqJXNB1zFVRGJwpBUqnqSmKuKKNcspppEVzXz58yek+Vit1VVl3bCjYpNxVG8u7xOUaI40VUsuGfV689TeK4PLVruxjRpM3xq0EivNt4SGK5MeAYBTcyzBFxwbduOOOohQnUJ09lJaAYBM6NDNsiDkDAHDQwMwsHXIrH1koYOWYEVEu6uGgIqNNMkALEqwRUbqQYBoCKjNqBdajrXWIguN2m/ldypU8JT6fd8+vh0SS7asu+duZI7ncxIOEURlvuzMl93OFhBBFTFHvx6+tr6MaxvMPI+E8RgCQmeULqbRSL6TIqKe46lF4Py3IuB2BhgJqhYmhpeJMFTNUknIUANsFVMFhg5lJZnUNFREpkhSSYwTwJM3MAm2YqkciuMhCOkg4pVNATKNHOGgaZqjsSOIHALLmFAdQ9fZ5k90+NjrsknM8I+YBGeMMMhB8ge7x4VBXz1LeB5s7K5F1Jp2rt5EiRu0stt4FxYcSXC23Q3mmrVHkbyZNtskIVWpkDDaZUqjIQqRGR4UOFNHBEJ0yIZmBhDzTom7pcjda4bguNrnTynfK/VzVtt90FDqkSROAfabSH1PDW3P233y+uTjr7eSDqFIoUjTPtDXUNdI7Bz09+3qSNyG4YFChmB1wYd2Z8+oYd4IdyKF4qGwCQjVaZgsDQBIwd56vnxRc1U+z77kra3p1zbWdaHjsFB7ZmZ5LnIOyI4MDZId0EoexR01ek0bhoObQ042DjOmdmtaXXZyGg5OQ0UMDAYFKDAYFOvQFKWxoGoTYGgwpBoKDAb9Q3Cg0huUsgb7JjUQpQ0F0SNBTBgdLd4YiRpagCIZJ4g8Plbmd2KABrAEDB4OA1CG7wFbjtCGUNiNrsDIOYIpsCuDc2QmhZ7HsHTYewbEYcx7dg7ag5gF57HYNiFCYXnfJ3DYLtuc8BwPjTupc0NePdqiGdCUh3aGiTNJaXp4IMba7bUrblqXWvjn369Xw2ByFDbA6mgeG4177htCT1JHadiNjKHxr2DAugvJgcd5gjihKRy6HQPe9QzPTzEQXpxrndw6OGc6aA3u52iKjxHbVicfHHf1m2pI8hQpQcxE7BQ4Dt208A2DEL2uA3CeJNjprgNwpDfgOuiexsHSSKRxA2iMxxIaoE4zsOACVJgbb4iNsxrMd41Pbdm7fuzpzQ64J4DYMGYFDDgFDQUFClKbmxoMNBsE2ChuUNztx22DpvXYOPTUbUO4U3OtOdtnLdnXhopCgEAQAcAFsRWVkinxPitpJQh0k64h0oT5mUSTNT7VsZACQHDCARbGDOBYdQsadB7G4bmbbSTLwBulIqxVuYGQSZt5kSdLCESOwFjAmIu+0HSZinXmwBmZm8zwvJ1cVNRXAkkielI8de4UU3jCO5oNBh7Gx1D2Nw2I20YbBgMDgTQdfV4iMpm3N7BWMNg8eOeB4DrxIkjZDehzQoUIbc256bk6xR5hhu5AG0HbGwYZghAGjjji+ekJtv2Dm9KeA4ChsVEM1l6B06wb0O/QiOm27A0G9DqaBeIBMoGgA40xNDO7NuS8NBrt4Iqg5hAkjIiIdXNzntqbamtgpEkTAtDQdJCEjJIjvVpbLYqtmW2SrFqjfOjmrlO6ubia3DmuauFWjajbbGi1GsW0WtG0Woo1UWNsVirRWxpLajaNaKA2NrRto1o1aKLaNtRRVouUbcKrRRqqLaNa3z619lqgTCaq0pIwq1krasFFJMxRBjbWtkBNDFogmTNhVAqxEoboSSR3kizVq5mLavd0J3dCd3ZO7s5zu26MzRGSucIiuchIyYDHN0pKSA3dxpMQUHOTd1umTESJuW6u9/nhPFyhlGTQwXdXMiEXduu67lcucic3TNzc5zM2yFhmwSaGGxju6OcCMmjJFzlpiEWZoxYwUYksSJMLGSik3LcsKGkxkiiSNgEpKNy6BBJiixCbEYmbnNFATMQUmndyoTEZMkUlBGJK7uimFc6TMUdOlGlKNy5IibQKV3dFJEWE0gm7upKXdcTUEJEGTaRmYwZrxcoyJqTBUDJKIiIxgNtRFilEUIQkxshoxKWNUYKJhQbRpkbFYsIUkFqNESWIqNG0RQUaZtFJpmxJoyZmowBaIZQpTMEVIVgxRJZLTKimRgSKYBsUamhoiIjGBklIWtGIpRCE1Jg2iMklRjYjElEhQRJpMkJsUZNkyYIKZBktJRESSQRRshZDMUIRIk1RRSaFMMwzBYSTEbFGyUiGCTRJRRqMRSYAplZTWNd12maYTDBpmINIMTJShSWIse/V77875vTYDRtFRWNIYtJiooNo2KCxbFRFBotijY0kSmCsaNRQUBYo2jGLGMmSxFhKSE2i1EaNaNoKMhk1iMwtFqNkMbaMmxG1GjWMUbFambFFFFRRqxqk2I1RiKSxY0baI0WLJaIogtGKiiITUbRpKjaMRFEWMVGsbYxgkxMsW2SRNBJRWC0WKiDYtdba8rt40RJJtiYmyWiyUGg2i8Y008vJNUQWNkxG0RjadrJto2xotiNgxaefN771a3xjkOQ7kMc/EGB3kT4BzHAPd2gwLoLMjAstnDPaRE2317IZ0DZAuBxtanS7EPNdw5NyMLB1C74FDsdOgdQUB2sScSEJHVA2hI0F6kUJuHQ4gIjwfD04Dq5dkQk7h4O++uvjijptuEtEjpQPjk455DYNwxKFLIR0QdHXZyDzOR2DAoYHgKHgG4dvHhd+l7G4DQF8HQXq2BrPf4mNXlkAKZJBhrAKrE5AETcZYiqqIdsUGtFABUoBJgGwChUPUabjexOHK+ohuw3dZl1ZBVTSKZmGQ/tfmqqZi89/Y32DADT/L5ghmfOxwGm3QehuMJnFqrZZMk8BhUchHsiqdfO84EDZt5bdzu0UN3MVVYhx32dvAMInLZDnv7+dvMN+U57J8qN6AZgZghtUAOHb4eccKx5XUBPd9w2+t23bDPTs5XnPOYzz38GBQMKBN5FFUSDoWG/W9yBeKVxkC1Ec4hEExUwVLCB0SJQRukkkgaILISQiaQhIwiWJEOsd6hKDpPsgCmHh9siyYnx2+5fZ0Gh33MkGLkcjmPWExcE773TFxNyZCY8y5KURRWjfd6HhbFWrRQWJLFtLFYUMmaNMRKTDNMWNaECWElGjINkimQohIkKJqYUhYGMU0EpTTSYGlFNCSZJUll+n+4jWS0zaDGNlNpJNSZjJkSWWWpLIk2NmqZGCjJiMkpQZFFiMKCsGxBKWRIlCYbQNQSUaMEieVastVV5rVrzbbVeW10kyKGZEYSGTIom1NCZDMGIkRopSGCwMaYoUkSzYxITNISSwsSWCIYszebyNBI0RlqUgUmAzaCRFEKREDKiUNjY0kpUgmwZNkYERZaljUVEamxEKZSYwhNoImZoxCWZiIwJIBZTNLx3POTavhtXyvZJbAveQ2JvCzUTxbnyaoL7oUORtoJnv0aklPd01CSPq236hHTcwKKHLJBlt3DdrWgvsQBUwKh0m9pDiKNCCCmBFA3qb88BHMOipIUkjpoiaSRRFggTmSXak7UzbMp0byRCR5dCbbYSTdCHClKiLJUiwskLEWFhYgIxCSSOwkkHaSRUTLsVVBTIIZNBoVIAltCiRgVFklkFhZJIohZVWRtJmtWaSy1VpalkrbVLEpbIFSIqJLCEVLCkgrZaKigHeZKQUBAmFaVUGNLJEEGrECSKqIII469u+tUnfcEQU51L57OMEMCGO09O/kmBoa/pQiZEi7vPnsqLgrnHJrT5S+MQ5ERZMDMJbt8GhNlI8FPaSRJHvRAkjCkgiCmZEIhJbIsnhFZI2qRlkfZmIQkWkISNknW2rVowkSIFBUISPPy/evzv9w7+99nQbeWQzKrFmLyXjNbxFSNRCECRZABICeq4aMB0VQJUYSSSZgvK8kb5V4JnfqL741JLMMMdHxMUtjRMswEd73oA4AF2AcGpzc98LPefC0gKoCADN9dedFBYmGieJbaWkUIiRFsIiJVdpCEjdN3i9xJ6cR5qR1seXOvWwbbXtXgOh7em3LuRnLa6mlh3Jq679fMziQocjUsHjrJdCoKm3QBQUKFQGRZIx4st6N1VVY1Zb6e3J0daht7NnjbeZ47USSSIb2O14CWkZIefAb/oTJNINms79a9XatSkfcDJAulsGnxFezc6A0CuTONJnldYUdlYsa1qqzM3QJNsRge5gmS+fc47debq7dO3cnfj2QhIup3Tw1xx368jO/hyA4a6PETr59XFReMii9WtCEtVUBxYClCCqmESKiqhc6Om8hI2LJE9wsEjiniyQNglClFpHrt20hNnZrQHJQ2K5pGikO6hNrIjahLNTiRBsAICIokCuHIVVUQ2G9XVVfEk5kSyxEkJSFRAPs37R0KUrgJDEMqCCkAzAKVUFI9MaURFIbAS0Pv5/SG3+efxSR0/OX/Tj8N2L/drXpxuR/3f2v+++1cuh3xbif3TwR/bGJjr7UVyS6Jx4b+h99q7Cw/j/LRicaPP2mCaYbi5/mP7fp+U9v4e2dx1np1fQm9dens84uOX67cd2nSW7yET58zrRmoj+WieYm3ex2nPjy91/41O6DBXDu4kPkodz2Skkf4B/iFv4xuqYKMk+Y2ek4Cnix4RPj93ljn/f5Xx2SCdsHWLrBC9FFRkkz+52PH2uY2uykUsOXOWIdB7nHYEgw1nrAiqIr9/2pfYaWwXWAPiBme5ML6tvvsrLPS8Sl7clI+l7sHFyJ5s0EfBGhR/gnrTJClGzl03SEOhM6RfypG9ohxv2md+jA57tp7V+scp0hB+RKre7UHF8X1/Yi2jt9TlLNepNLztzlaa3c4c/QmKU2J1bCP3ScU7QVprxlu+Ltzxrhf89IlN/lKkFYyZZT6eEkvdaMXH6dR/XY/vldfR4zEfJ39OspTL8uDw6qNy3ZNnW80I/a59f3pIQ47O9kc7GCv1iD0NAf0/7ISzMUM/jEz9xCyGLEBczJZH94hAK6YoRcAYKAJFVogoVBSoKYjJW3Kxq3Lmnjq1Ft+ZsbXpAXExEkW4hcRkFG4IVBVslW6eYQAQmGEmA8zDEPb5pEhNrOnZajO17l2hZl0lcMEXzwaQmahlTY8PS13nNYsfQYUybPXCrE66fQ17fz8KtY/nawm4jM2/v2NcipG5ZTHm47o0RH0Wdz+eNRFvqHotyKeWup9k81xDzeo/wL5F8bNX1ojc72ahVLO47rZkOTEj5895anLgl1KiFMN8fZzwuc5eOW6Ezc85vNSaYvXYVRX++Ho4x3PnQw6SKHo7PVvYsJsxqowUgzk2BtGtNqRL01ylvS+/lumCdwg4RdHt9eylonv+7R21j8YajmCVoXHfFEp57vvJXUEs0xlYxPY8mhqOZStMclqO+1xGJLyWg8wwk20OXSwUu9Q00S743ez1B/H393T+jyYCjbqdE/eltECOTaaEYxjRjE91BI9V9PqajMqFCU+a3P+L35f50+H6f2jPnzwsXZGrLkwJDfcWfyCfd/+H2/n/N+1/0f8f6zfv/X409aQ5wOgwEr09dHccEd//Jd7V52SEhNp0tHoRa8G4UUf0f5UB6dn7L2n9M05O134rfMP0O+PnELDYXP6LUfpLZDfmx7K0HHA3Nw0SJP+V/s/UPhsHAecj3O53wGQx+P2feLWHd0CSSXyp4Q+9mFcjwBByYcHAhvuH9O/x9D+S9kxycj8CjcSA9aS5XH+eam3tyvZYh45yZsi4/KrHA4MwFuw4nKdCYUDkqErgQ2WQWrn44bP5dzhkEyJ+l27amMZ1f2PMO1nNzT94QZbeuAPXQ1bQ/6hPsa1ubSagVHR6/Y3oCRJCQwJadmpHsSCA/y9JXh6wSY2XmzYX0SQCEyPAfiIsKWxrALwZuZqdk2H+ZyymNEO/kFuITEhJ5xPZE6OLKO7z/Q/SvL6A5Z1OB/dvPOHMpYYTaSeoK5nY/9/pPmjnYwNqhKRUfpFUVfdfGnqJe9y58M6M1CnRM+u2blzNUnj8FPQGiofAYSEBhFhEIDDGPg7Ht5P4xETNH8ezVmP2eJ3t7TwYnaciR6qfE77fNfd+G6v6q+q+2e/eflAKKMAAhD0BAxBkEfMEo+FRmZIndg3Hrr83j8RNXPLNN8JczlMpK47gd0at/Bw1R/vXdNcGZjcc5rYqvY0b4aFsSy36Po+AcX35wFVSJPQtPVv073tmpzIxCMSdodpsO7GyfUEHWO7+D4Wn5I5BIEbxvBnduoOhxx/lBGbJJC+CgPo4cXN6Cbb4ah65dy5Fze4i4tLaTBrp3L7/1t//G8TMkJNU0C69RtuMJgTD0kOx+8NgJqxh9fHSqo1Lu1nl2ZcDCJjyrS8FwgSfjgFXStBEqc5orTe26cPTG621/fPWv0G00yIYYX2TwP4f1AJi9Ce5siqqrlTsMfAYessteUpnyTwDNYkIvrqlnM9pV7NfcdBhzAHTPudxIKH4xqI34Md37h2cR2smhf0UOFlENt++25Q3yhe/5KY/C2tkELtWlcwV+ziZp/3aloBRrmYwWP6R035bh89bV1OuP7n/hwvt7QpohwYlis3AEwHETI1PvCHzsoovyJ87kJISP7hHujTR7y3Tbs0O2Gf7dTzRX+0fU3zZrlQW8bSkUHYOH/Y78PmfGF3Zkubdyyf9vj79b5/z4ZIXg7u4geYZqyMBBCp++++T+VIJGg7i3aDqQ9484XZKI6/n75i02r3HCPtg/OrZNU/6SHb+jJg70x4fjA2mh17g78zh0me2ueiK1Z++662YZGiHHTrzZP+X4n8IBIZIJAtewt8dN7CEctONt7+C+VbTdxw4vzdQ4epV6F5V6w8xNYYqvZ1InayQOonbG6o7osumMjJKlEYkA7omrZWHQ+W8Rlsf9f9SiqOp/jqcDfmsMxk7ctZ9Pz/rOFaYWQ/Tmj/ObiTszaoZ0kurs6yiPbLwXZg/xn4Qk9wjSURL21vlP/xr30+376XoTXOxsqJmpN/UzfomVl+bCVmfjc9XF+dHuxvS1Uv3Jvlhi+jVKmHy+a6dmVyqq5UvkTJoSVV0X5423uW1414+5umU3Mba+TFoI/W8rTfQ49qUe6/xR1Vn9qOqrAtP/fzmH7X0r1UaX2y9053Dzbv6WhVMUe/6ODGG4WXuT26qZfdrEV6p8vvf+yjzxVk6JL5TlyugjGhu33J9pVSEHpFpJpio4ulAvrWbTz3qipI6e6rqZt1St1xmRmY/CPW03zWwCEkrcbGSRDj28R9EObp6XMPTpqSQL+mZlPqC/8D+2+Id71w+7PC+KKXrU6PVVfZQy9jyUUdsE6Zc3PfvE7aJgpQKg7qWFxCm5C6+L/753We6cs7x5ISFuo9LLBS7/ttvkOGnduXeEdL3viBzrIbt5g1DsTDOjrPoicFkYz539ay+aezQ9BFB9J49OubD+h4js0r1JfD3sXPnk4Md+iZvySev86nZ2bTnqhW8lLOCXUPZuYtzmNfCVU+EE7SM6UyiVx1+iJ2u9e3xtSPT7yE9BNv2E8pqc+O5XFGyCp3DtCEn18pG21O1EhMlfad0y7R/ZYzKvrdQnKUWIOFdvWJrh34gtYhyh66ghpuOfVQ1ZTy77PDpc5GyKLcQ7LOuUn+tJ0Z69W/Y763a9/88Vd8YwnypgsTi1UyS/1WZHVpW9EdalXTWHVKxVQhFt/AvnMFQeIdWW6zqTrKzwlf4e7+adaMgSUHEGvyj0v3+75UU2V4j7IZ0kkp363MFs8bWTVRHrtC7HHxV8uUyc5oh+UvZHKhSJXyCsfTdet+ihVz3QgiPp5SfcdFPubKouJyHTR+MkXFz69hx676L6zplJ92THZ7vBNTH0jIKOIOKfk2VPEw6swVLNHCuZ2Qh9TrUUdfltueWn15ecKcfzwyFfuN8J6Jz3p4xirvLuecOSQ+3TdElHKJ4OTQuDsz7nZxdUrvmz9azbtmpOk3tRFzBPtDXM9xJPTuleWuAiov22Ao6zkzy+mkBHBRD7Py3PKBqLiqucf3mWAvrPiE89z1d6D1bn7WaPgl/HyVxXjNKJ8u3WnO4jZLCYyOpmk6ED74EMakw41Kp1kIq3z9mTdcRHwjCGmlo5JKHHMdIjwd0Ni4/K/2a36UCcPnYcYSRhMlVKSDyKKi9unA7yuPL7QkJEkEJ7F6wcSEhwQkigU7BzY8XIKGF5I8kx53P9KyEUwnEFkknuB6EyGd/HOT/2+iNVO7jd758l81f9a1JOjK+IJI/BYYO1Ec1XxckksHlHmnO+n9kjgsN+kWh23IzQ0JsdXLILvF2mmnTygL0Epu7uaX743FpcXnwoy3xFr6M1dUe6H3Xa/gjixPaME3uWc+kE4X1QPWWkSMU+j2TOjC9y5571JvVN6YJwuo/ydzZFkNUWT4xZJ7r8JHOx7PB2+kwlKIwqmEqJvtjrGEfFU2zp9G1py2TNbxf0c6QFyx5+6C9XvlPGQhNP2udPLfDT6NK8kS+DhHe4SQiF58HJBuiVGQ80Ou+XkdmR0j1eiv5Iv1wHMTMV4xmPDTsx8ETWzxq9EpzlLr4UlSfxftk8f+kdVIlXugssHfrN0votEqTllE+vC6irIYdlf9Pfn4cu5TrZyuz+dSlkUwa02kdZlea5wx6ffKO2HsmqdrlMJRPzx/tzcup7Z19wWmcCRtvjeTCkEKhy3ZSXWcem4uONJlTEVMMK0JzG2PcSainNtmhvXIdSOT5L3T5KE/GrShwy6Ok3Rf2/lkWbJEzKNiC/qxz+HYPwui/Nwu7/DhS6n6+3/tKmNL4e3j33d9OHb22P5p81S7Apjz0rZUXGMHlVZ//v3Ya+GGH450MPRQ2Cqb1Cdt69Xb69iTUJv8XiZ+p/qum6dDWaz1fTm/tN5S5IKcdjvsduIULif4f/X57TEUbSycNcnEJ0kBF32r+jhKQ0n5jiP4J9ncLfubqP2n86/b0vlNq6vHcxIYNz4vUFC8Trp0YSSQOUZ9Nb4Ven6MagHVPmzKDAFw0hSxCItsKCa3erIRuIZgfL9wicoBGdMDsKpv/YQoIhFAuMItSaz8k2flAnBeIn4tlSmxkRyY4zxmiN42N/70/zHKJ/DwBoNDe5X4cNaBeedCnpMWgKZM1jtcQmM2lLUWWFLQfoNRMLsNBrR0oPnNweZiPllQ67xbItXynU+P2Hh/Gnv6jt9rlPPV4muqeBpIyQJIc+dIVBDYFewCfLJFwhIY2INKBUY+IyDkwYByntxDExEq7CQy0DzLjgl7swQfoBVIyNn9p/DptDLA5DL8X5TT5+j7HYq+xGXLkkkIDcIzPG+KikNknzZOwkP05y81Kegf4Ht4Uwx3jTR0a0nPxsbjywv4YmcV9D6or6Cfm7bPaR9PfF4WHBhTTLNB6xe8fKxz5itQTqIekohW4iT3PifHrqt5MyWqsvDt9J1LBbosjDD/J2SY7Tt+rRPg25NdfVtq16pvzvE9FNhMB9GRPNtMWpUJEKeDuSjaGF64oZVcD5t5tU+LDA7APYbu3cHAN242p4yt4PAqU0KslL4Sn5vZ9hunRZI+Xav7V0fQ69DZofuqG6HeSvbi4wX8EUWGgaUZthjQYmFJSoMo2CA2GTd2btyDYLto569yHDe88uurIVkeXm4PnJ2pmpUGk6o/8yBnE2okhnCwnrDEKD9/PHzWWST2TTU+1yZkuRk68Ny9cy6j1hu0Ciknkay0tyJQe0KPexN0CRPBm/+g2J5ER8fnk1jVTAcvS6RyluV6KODiuCjDocBRE/AB90DYej0h06RIibgOwMFurGMUybZqlh8RAatq7eMEIxlYRXzu7AgLGYgoJhsnfBxnEIyTNFECBtOihLgIeuAYb7Z+H+n5bNPqbJbWM+vEgbpCQi58gP1tfmESAMVm2VTU2ypqpqytms1mVtlZTazbSrNrTWVltKyptqalVLNabKypayzWyltNmrSzSiyQlJM0WDSJpFm0GKU2DMpDCQ0k2ixGYlimLLSJBUFJmI1+bSugPqyZ/hLorGWJnNKWqixFYEYRkyNDDMk1IpEspmUymwtJNMk0DMqb2XXt5w4zjXBwnDW3G7cZUMkkiyQKiBZK+otdADCtfN9BSYIhqpBBU2gLFCxQWJYj1bgaDoEyNlAz1XYoERASIAuKV6PkjSqoYBSBFWDBAiAEFgixU/04W2UkM6+v1bA59YdPqxBt2+dup4BHaZXwFCkFCe2jYo82e8iIkc995QDvpNIDUTKggpw2tWqbdTZY9MDfHbFN029FBwVFFMlOkdANtG6IOLPiyR4p1+MmqInysc0dREKt6PWHYpEeEiRIpva4Iyasea1L0qOyEJFJBafKx0LG9UZcZUkhXfI3siSObPUikg4bY4UhI6e2aVLbS1us8TMkjAy5E9q9iAKkXkogTjEFUdILzibKoAAXnyevbtXpXzNbVtrpbFvlAylMAKr6W23jEW17tLWvo+yr7fyd4Q75CaOyCgJIgCvmRglREkGRAaEiXHU+IpTBB1OhdDB8R2U0vn8ayuMnnu4oYNXRd2GMRNxwVAWLIMhIpYk2p++OYuHhkVJrEZlrUPzfRH+S1Ui2EVYlsBki9+J/SxyUSKQgKWbz+bHz/2ugP+SoR8XV2UtHVQtgdz7eont7bQ/Yh73BfvZ6MJ928Bx9+v7L1ifk8N/Dt+Surq7vt7y8lLmq7GNExtlPy7banaijV2dfjvK171PrCRfmfkqQ2iSJFCdB0sKlWrcjbeZdh4t79KvKSX6N7a1Go9yqgpBFKIhJ80qIlIRICpAESKCQiKsgqnhQR96gWIDqPmSRiIniT8jvVpn8TyWUqtrMr4LAauVKma7rjK77/9Pu17t8LFRAcf1zJ/ECFUXCEwz0vySEEEnczFqHy2EaqT7No8kf5VfOOeHS3F4TEwu/kOm/i/lBpBySTozTbDS/k3JhvSBzLWEzpRMbKdCF4FchRi6xQOoUZ/I9fvk62iBs1pSfPTjz+36PjMZJ3wLjsYYNL2tNVdb+QYso4lFM5NQmrF1LPUeCcEiq4Qx1qCf6QCw7EnYSMnvI2kIMe9NQL9D8Od/Ple01q5FjUbb/PbuyZmEbKChxaFTbtV6SiEYpBh4oU1GH1OSU3wzkgKRO0E6cjgghCJqQQ/kIEnm/NdsnogPz5pP64js2eIk3hB4Mjg+MtLYWD4wj0HezaHS6iUG4kB3ekhe0JDMVIwCSA/nN6dGXBPUKTBbRpc4PccRD1rzUxAkAeZVGodCnmOh9siUcFflbUb2SqnHfR8nvu/11Ur5PmdX+G2iAd8ayppGSRiTrIaAknq6/wKP89iBE09iw0e0OgB+4Io9IxSCSIMrL8UTgvQVKSoyPVAdQ1SIc98SQA3Gp8UXkztSKFpESliFxKlBHSOJabgMqv48Pdsh0NVRJGJGJ5IlttVKlBEaGLFScSSPzT+qsQa4T2ffAsotRgpIAQSIpADaeM9f7uOPuz24gdAXBZASSR+5hUbDZsxuZiDSnfQVw6oFRFXSzFT71jWoj9JrR8QypMsi0HVR68k0acwyKMDZg8X58zyLwfHRJvhRFE1Dkqnx9F3qnNhWLKbgiB2IvFYgIInCdNGtSb7Y4bnJqMLE4kjobw0mlEPjVA/TltA7NQvxFu3RTmGqZMGkJABkWFnAX1wkRRkHU4/NBLDTam7fwktHNSxUg56Jr53VblGHEklkrh2xhMFEyOsV6i1Q2VdIakNh61WAfIDsHT7f6/zsWM/abT81T19x3VC2MwaepzT8QReYh+KI4Ie7Eg/YVYHWCZcmA8OPq80jtbvr0nCk1dPubyVl+r9X4ffDNhmB/KKU6ZY5FL8l5Yxv0QxkM2JFNCuWD85y/PCQ5Fn64wI0OP2lloWRG8OEscWWbvbhFUQU2LFIQTls/xNCQmD8RvpIiJPqkEFICgA1BVTVUEgjprQcv5f7uWx7Zofbw/isFEU/7d/WCm0SIio7PmnRymznXFQCzjp16BR1AgCpMSuq52XWmR6NKxCgkRHn14QGpAlkgQsiCWIFQkk7+NHPScVPneueflt4audl/Wvkh6IEkWe0G4Xps6O/R60+CBJF06h4dBISGu0VxYhzThzk6H3/Ixu1N4yEib9kvDvhL9d0wqGw0F6S8V+2rt/YTdyrHqEvzCwP0Qln1D72MwSmiBKChf9bCubz+n+bTeWqV+Au786/eJCQpqvwR+oKDCggoSJ8qZRTvmAwKtfyAThEHBHQRi0mQQBUnrFA9qgnUWfrKHMR+lx/8XmNkpbgsMHX7eAH6hrBZMJJha9rcUKUW+zO8bksyy1fNrb19xvzl+4fNuzNvoH3CGNVgafp67+qfUGi+4ehRPgfYdxrAnESdmxE1sdJ3RQ1Z6CQj8m76TeIu5XxE5FLWCbSsOfl89W+xSKIiVpFrtkWU8Asgf1FBsPZ9nwlB8IMeOPqM/YYW4k0NJiijFlmMZbsXqox9uPl8yoCwyUUyLJkDxW7VQtRUIjPtoDM0g5eVHZHjilGt16PE6EG5BQoUKIolCADhwgyYjpis8s8hcAFQNmwpQVTfpyjZH79ONoddXpECSO/r07cLuQFTOgBdhSiVhpUxAQwCAKkUTU8yMiSK8WSBI87NgHdjxv378RG8jCY5d2SG3YgSRgxQc5PE2IEkaQhIp42OnGeB7PH7a+r7ld92HYYDhtICAKnl+mPnJU8vywu2pAP+9bkecW4yaoXt2rxW8ap+bamFUWdu9tU9NNpZtGMknSxsulsOMqyWwuJ+Enu5cWcrVtMzJqdFqwjx4ggCpy3e711+aAaaKQioApNfzZrMht8PoENeCQPlYR7ymqxA54pIMZEcVEoIXCqt5zAEMQoSqcDBfPZWE3WXsf3BJ03jgVSrZbaRtzHZlZE8ZQ5qfEgC8kVfh3nvTVidJxHbO+EZMp5iBhVQin02HUN0fdEKPs0B+je4O7f1vX8z7z7dzW6naqtoqz41oXWWUslpS0jQwgQVIhgRjdj/VDd9O9R/ziWHHp6fnCdvQaUWinVZr7EKonantfZepHKkg+BS/nhZHNffY5LrmeaCMydYo/jDJ37/vs8CKU7cwjM1FxJMll5cIZIhZH7CCUlydHWawTCnF91aiRNJSw0ugifE/ouGRngZHAn6jVEogOg/klpCKxYmalHb6KMETBoKnlUR/3wMAPYH/6GQ+jB/0+FbhYcyUhyCqo2lruOEQSqaPaGGmgaf4fzzGMMslfnpimZYZZS2IWpBiU61NrKfn9mGWSWCFoFlgHuCUGA94XasWRR1Q6fgYjmkNR+5q3SMBN5o/Mmkpom2nVEpCVCZRiA0RJDZn8w8B7ujoOYSFaTcCwVzCVErtNKd2VxBiuG0K4UIxhec056bM4F2g44nlOZxhBHvlDUvcwhEgRDYRkRuTM5YgJiZthl2FsUolUwCii6piuYOzKFJAjHJmpdfb7jubhTMhdYx6sMxxF7lsXNk6Og4xLjoSBRlCIjNetyIbzXX0kDhK7uyC8POlqT+COX0pEjoUnik2zwlIJh9yOzUiQENKB2Yr3fYuOj/vMJBC/N+Hyf63/BMj8GG/CdKJwgo4TYmh4lMgpKYxNs3u7ffjakTa/zvufySHbrC1K/oDqHz8fzfydPHlOocwPIeddq9tjtI1L7aDoCJZg5nlQr08drUc+VxXlbzAd40pDiVT+euvOgKBLAOU8dRm78XgMASmAA8QMw3XlVQU2Iog6wUFBs0a5NAm7bQJfHXaz1vBzpJOEF9kISPXY52jmSROyCSBRIiKSQRFSIRKWFspEskhJFkBJFRC0gGJQYBu1fopOMnGE47B0gfo7riVYqSIUpMPlThNSBlCOyenzVNKNmv0hYGATB2RydajdKm1jUYYmoyL3eI0m0fbwd3qs+Efm6Lt02QPdLdhBpiGJUun3vqeqBCZkH3hiOH2YqZ7KE4l+ajiHDlkMeC8HtYEbrPGIXEGhcwUMHhsecBRMIvTgx26jzA/G1JCGUasICLcTPnm7uFQmZkSlKsmU0lmhciRJFRlmCw1ZaYg0UwxjXHlYp+i53pksfO8YHfn5godE+bDAf0wzJHuo5Pjc1WMuyk8vHkFBKLzpzuJ3W5ndAkqnvwH6o/ZqU+RDsieJy3R5EOqwhQZR+v3X8FMSWwVwfjEmo3PmfVjy8/R/uNjsfJrq76/dNZceSBOEeJ5TxVPcKph1j8XOuqLoCSJz9AayYoO7pIeH7kZwauOEUQw54A/4M2x0Nl1Igo45JEICGqzHqPxQ9EH0iZPTvanqiVH0KuAr1wN6RLX18FPXqgaH6ym2/+ef83zdo8fp+3T7lbH7hmLS0o0ssNzAafDxs2kDyUUj7SL2zYbR1tMdeTxE+EyD9YrlBd0pSZCAfDt8P3C4Uf6omzKbSkNuAioYQwWu8MG4huNTRNOPdO/9Xr8Z9sxU3H9HNPH/Ks0lbM5/PnBVoYsUw/AkjKah+2SFm6ImCd9kjnRnE+l7H2b7GTfJ0VhT26ZO6zGwdul1l3LmKIRLsYiEcadiFJpyELTsOI5Z9m1xeqWMnwjqOWZopzHP2OuhVVHlE8/e4uuHijNHBskrRyFi48LwQOIMOb+/e+jpIlYWO/VzOOj+yGH4MhHSMFhgOF5i5pg6jTKhYjKQV/qzdmMMx2LYWgwTbrwFQQOW+xBrxAShtFqk6NhJqKcTtaaEN2mZ9uIWIlMdIb+qrNeXrOZppCHsgpNfBUeOrheg9tGtTJO8nxcv7G3FjOmEVAnW9DmLv2I0Vgtp+iQxQpEkkHDun09FUZwYboo76WXnPCTcINprPV8yNLJo737ks1t36+E4Tod0JOA8MuTNpHTt3o3Zo0WbcyTo3vUjINccyBsO6aZE6syWBrnk5wo5TGPA+ZBxLPbcoclnE7kvdnPhnJsqXSzOSuAMJFN+ekzhs5PGwN0V6YO1NdXuCDlpnwUofy11ElucIgydThr1nMlCERMW0dmZS8CO66V8TWjqjgjgTOR7OEWcubKHxq7cfQW8sahNbjiGQ4KesCRXxxi9aIPaOPVcFm1BQUCZo2xtufcvPu8bIt1UePUXc17MHt8KN16W/LsUo0wPyKF5K5biuDeFqEcJ9vbQNsi3EEnU82OJhSmYcQ6IHdqcNE0pqO6OvpRkJ6+uzfFPGw8dS9bzYom40lNjba07UY8Q1AKOEw7Wbggy3WDkhGFSYXZZMQ0O+SXbIHaygsRDniTm31nXW4mm6h0W9JAJMo6fkt5Gvp8FMXcNl0uMq1K/JWt6jKWp1vcEEvBqSuYgk9I8Q7ArBPvl2X8ffjrV8anT4mIAiHNy6dVDpncxPjuk0TKFRSdW651WqN9yjvxUrisicOnvFXT8NvYpoe3bIfUPopCf6VOXxMay91VO5XG7em2rQac4RDDiZP5gaDJUKuJ8TtwewWk+WOQPSUQQtRqCWLT6q9hU3AKS84J16U2zcgS+Z0vGQZ5bXUt6pNh1ShMIVu87x4En/wjLyyb+221AJGefeNqHcdW8Gee58SztMK2DgbJi/FnJAhRUkqXIeJOR5g9eOriNKJ0MW2FMONTNPucnA2gVDYtJ0NKW1K7zwXfezcyQ52cO/DhNPZsDaH0fcT8h2P3reJCQ+yqD7CYJCFtYtyY03VGfuO4kSLhjGBGft/D9G4/mpOvjjynXuFI4kpBhChSRGe30Xv64kjjhx1OZPyGFTgTzQOkkUO5iuv4aUbbEHU9ogQabY3SaYFybWKVtKQXlwwoHMgo46SlUQCIcypFDAUju055zvnq+OntqSSEjiK5yEm1B9iiC0GBUkhbD26SIiR1JEIOog8OOC8N+uiS9/fhJIae6STJJMLIbh20RfZbeZvtKb6q1atyNMQ3ZHXg+3jzh0xNh1CFC7lAhJ4E4mflpdSXTrQomeR82YN9fO8nKrpykbUR8WDnJMzYXxNHxYV3ZzZ69z7m8PKb25uIvpCHgcehx3kc0dQxeP9xBx1pO783BDgiOgkTx0xRxLyJ0fajWnA03A6bGxamgE2+Y00r0K8tHc+88p27d+hpW3rG66mea402lt8TWCbIQrQnrTicn+JteEpXhVm54jiwlHCvLjSXp+NKnf13S1dO45dLbw8cbuJ5fKd1ZcxuNm5B4iJHflPzse6jjNHPOOiPxubhU+W2f7vDd1rZqSrM9W8JqctxvY5wXEMVKq2NbpuR3PidI0mHdNxzHBVpUsY8zom6TzN5gqUirQ7mFfCnVLU7SdY5O0kackmxN02OW0kYbJoaNzNGI1+MycyjTy6po7AyQgUu0IOBCK4IG3eF9qeSnXorjpaPyshdZak1bSolJOlDx4m/9l6XABkflT4w30EfvWJtyOhyE6Rdw8H/yCOh+UzQedD10HidAdQo7B2mteZU/hiGLkUhMS0kUy+a8r3/5N+Bei7O/QjhGBGKF0lRwQUjYXEJAnLgYh5ZMad+BnYShYfkCGhp/R/lfRh+wsnqX1JbkA9kn46HJ+hn1owFFBS+RB3rE1CZ2kkRRz0HCieTaRDzuG2YooiEzm1kqOIh3eibbc1nZgGhnIh6TdhucJQPWG2lqYkeIdg4mkanjK4MAdMLoJjtWxuZhGOZptqbdSd3ikgSzoOyFew3KCnlwF4qWB18RRBON7B4PEeRfGEinS9hQmidm8suO0gn34/jtU8DuOIa6HVQ2oIhp95n826noO85yuXqMD6LLFP7Qg70IbFP6YjIr+V3oHETifh+nHSPpDfE5Tm+CBI8imFEZSEkCAOfUPidZ4mjpqmjqjrCQUZEMdLrQ6za7MUQu5AKbEKp3xoC8FNPs0xFpJa4yxhVkKsssMU41MKs0xjBCoK13gTaer8j9fA2Am6Eh+u0/glSuujaE2sAjt/b7QAWQNozB5syLCN5x5YnxY2JcEc+DPPBUpS/qQMOLh1MZpcz2AmRobHNhvZ9AYPR9T4H309CBJglDD/ENs25bj1KnNmV0/Jx+2z6dbe8cJYh99tIFsgHFdebgGag1hsPUFQa4TF3QXooej2T60c8mzE0+c+imykolhs634+8K9Q2He/MXc5t3Q3hCHZlHMkX1D6MpjrwKU9AlPzeS6mk64RvSkDHXJAb96BjDNtAcGBMsEiK05ePmckLFEsHRyEG3DAR0AHzY/ExwaUgrt2FRyITQdpFcsTev9Fk2HLYJgdSKm+d1NPqKah0NROmyjLRBgmINVYdcE8fr1utF9FkqgJCmSmSMKqlDV2dh0vTxOswlTQ0kasTmj/WQROkkVQ4MK9oZpIH38/HBjssqZdJeS+mtynWpDX3Umiaicy4smCBPosIERyQEc9wYdO3JuYP3Mx1ohpDrCyJnl/u2OLrvpY0cEJpdxOz2mdJJNHRT9Pf+nLUG8SOs3FsjytY8mQ5ku6Dhfmg56QdR+TcpG3jgG2YOzGGDYw0mVLK4eLni80vUyUhnOrIz1sI6Gieyzy9lY57esdG+t+ubN0kyYpnb7YSRYEY7l3mxGyCOLIcV1qZUqrYFYlDPOx/HX25nRPNDoxUiXFpItYWwu4CSKBIYYlWA0sVkiBBP04tHCRRNm6l9fyUbFiaqCadK2LbhoahhD3LIRYRgkkgRUhFQ/HpwaGHIhGUVj4f+lhkPmKY4b40WJUVZ81y2TlZgu1kN9sDCCFkAeZfYKWfGEbQMd+dMne5F/qISMAIrInQLDGYPtr0W/3eLg6SHXBYAdkRQkEYzRMvnLA/F1HhE/iIFEPKP8QQZBxDmW18nb4/Jz4aOkoNIGiP9se1TCeYh9MXV2BxCUdBzH60/H/2/3Voms3r9hveH2Gai4PrWlxhMXFXGLMfPJWMTLGfB+ElirVVD9QKyxw2kyH4yPFK/5tKMgifUe3wjt1v5KPlUEEPoPqArz+Pj3Yr8+P4eMk5jn0ki4jJWMKxWLZVlsZkhJCSe5gVJghEAYYZFdkA+S8d6ar13W1xNMudK2uJtubll0V2xS7tuQpqs1ISEt26647udVXV/yeOUa6mpkiSTIg4UkMrlHCpMTIH3ufZHli0XEYDBcc/S2n7pZ+mMJnwD5/oPXLeuHu74ye1iOthliFuss1bbfbZG1RzQdcALnaRELgisggmYqEIKhyNTYtiAZgLx7cf19NX6tE/hD+T8IH4H8mP3hUrBMFS284MZMuc5MxXP+zHSAqL+BUPQBfesQOBZ/A5ZmZjj/S/sgm+OY54N44xqDnOuM7R1Zh0DFIjrktVbemZ/VeNpERI7yF0jlYHNGBFzuxeAQ88I0znTHHODG2ig0Zjvz5xCEjWDxeOudd99N9EiBtUhIvfXEjI82cT0G+shDNYhYrbMFaxEMm17AJDQWQiUiyQGqiLpq2BlSBgUguZKplDN+5GykbdfOJE589dIdJFBZFQk2653U5QhIzERN6bdTEhpe7VA1EEFKopVsRgggpWIh1gPj/H1ni4o6q9Za0+mfyw9hnlvOIggpHl7AHWKlgqUfU/vpjEPbIhpzS/ADx2KgnbNN4ggpSIlUIIKeVoq8VCWIIKQQGKqokihHr+od3mPA8prr56c4EvxLuzWOeCN6jb5OYVZN6Wsd9eM2PqeIJlFUOndXxEXrdxYQQK7jV6yqlPbvGaqqdJXEPUcKKqLINVkW+OLjFU8PuZ4XGb0ZfGKX2h1EaIfMubq4e6qXt5fKd0KNRKUPwq6TTfTWefPfnwb6WrCXdDx2KPiSYxjFOXdLl3Pv21rK+9tFUUWrEbIJ7B9hLIQhU/XSra9hJEm3kU7IQkbfVwMHSQhDREYD1fHEREe9VVVVVVVVVVVUzMzVVVVMzM1Vc5ziQSptslNV3Zu3UrEkYRhppJkYirBmZBcYqFE1jZCqWW7dF1hLG6W2Num00S2y23bukjJZKXZq7drZSa2zUmWbuhLkSTS6N1gpskkm2bJoy2uVt0YaOkjhJGQkgoLhpIluN2ag0ZFkhYC4usFEiySRkgqyQRjCSMkWLpWzI7LSri2LppLQzDTDBqn3pmhAe0D8Q6Dhy/JHulb1/Fdvv0Z5KTlhgZX41P20Vd1i075EP6P3v2Y1YsXP3fOzpkOOefvmfUlLke1I9k09CR0SNKi6lSOqPCmzbamixTmn69cXTP3TSRpwpBhGO+Ue/aZ3wyukUohcKIMdp09WA6D7fra7/9K5JZbbLFFS3ruzFdmHQiZtnwnMQLGmDEH70MaJpImc3Z0kkJDo/ncPzf4+F+SsX9e9U/f/mzrvy3K5dt8PhOm/5Pda6owNDZYXC4YunDMRWyYsp3TEOt7OknazSNUHcUHZGIz7hB9yA8emkb/0vpi0obgoGRyrBGZgONsmkjfocU0JsRrkwT4rlStXGVHBxUKDtces9TNiH1nMDzWXQuXe+zIGp2O34r2iHR+7P1v5PnI62lbYz1c3xtrAe6yGGmmg1UJlBkllJZatrGSfJYn8CnLmaX5G0NdMNjp7RK2NjGGUlAMhtNJeJdFF4KGhaperTib/KsMfTJFyjoESRIxRYUXOYUQ9V/3bO7BnFbjQH64dnkak96N5zZUpmfGaVWrMtjKcJmWjgqwhQSMIlwcxb9G7Qs6kOl3WkHo4VxbE6Rcp3cKlJWE0Hfd8cKnfgOJJEPHz226AzsJJ6u6rh8RJHtiV2Si6CKRUipBqwnWlCj1GTG05hAgQRkUYQIDikHmks821YHLutuE2S7GofMwZi0oLKr/NqxuKkjKlMIVGmIlBFZEnSFNBVUyRRSB36VLqFPaXNSyyhZGYV59YVeZN4x50a0SNPUQ+Fzyl9YxHlz6qRBo5n3WmIhiHlCQKP5eSfslUlBKp/YRZEbkkyo8R8vUqXytdqLctY2mXLFtdnNy3BqdJMamWjZKqKyc10tUm3N0ip668wlbftAirREQPPw36dHAErnDo/w2sgwhJCKkQj8pqYEyJqMN6/WnQUETnDpIlW7iSaZW6e70TrruUt6zfXtc1ZbIZ0PpPYuXAmzd5V/fOmqDgmhqDvJg9frndYbUnX6fZ8tTDzHRr9WmtjweDIQgySJCEmpEVMySSyWS0m03fi+RmswSILjEaFHnhE9SQf5ooSMxCouaEEsdgRWRCENImg9hp5+b0fTjL9vU26R4H9foicx6VMd8gydjPebmmd/9XRyGP/djImQldVc204PUVgIfIGD+j4eHICoWFsr6hT+iOb5qSCsOr8VfYaVoe+qg5H39pF/2CXg1O0RyH40dkCBJFT8Rj1nf5Y7/RqFXq5zIAVCopTgnmIFnp4c3sSDr3w79510h9R2AdQfnN/wLJPP1/xzh902n6n1fVbsEeT8VdtlZmr+kpSucI5CSd/rbObXgqSSLsud+HnTuUvPGVMpJFWfr1LFS7OPOYxwr2rvT0beoYdBG929Tzzu8HVhJJ48dXiK8noyxX7MzrrgHq63Yo2YQkyMYi5ikHqTj6WJiGYpJJWmN+JmsytDTQvCaE5Kp6QfQA9/SEKChrrA9QuAPD1afzQNB+1fQhveD8MpwDccgfyBqQF4YD8c1FJAf+EVagoHtiFkVUNEIcAiidIHr3QBk/kX+U2hszEkCb6V7/kPQHXoAj/TB5eH2aFAaTD+M+ZNMD9k4RIkPuJ7HOEhn7fCWTqlIdEz73I6wyEIDGBHJnEK/h0IHTtJyVC6ox7bsNTI3e1X6XBx2SjAp9pT1xBkBWk/eo3pD6LJqrS0kftskfhFnFYT3yfUXFSRC90kPdgKJcTWBQDtUlCH4vjH2ntPae1McSAecPPDdxYodRXDaDXbEyQo/gdOeTyvTTxiUfnOlTlETgJUR4QAtUeIfjNeG6vkg/MdXofj8sNsDcuZfw51U+XQqtRIhvEPJvZ8jHWrwlRxRGx92H2ufYt59rDvGPwTodUO4p7V1ZHK1/Mc7eTO38INvsx4cvlKpYKQFBR13pndx1duxAUEDWIZi4TiYCwywSkqtCLVadh39gvcf8Ux2D0ORMk+hY/duWGrHlJTlX3nryqUsUrSwI95ZlSRbOrMkzMgZmP77Ly4jH+sqhMQSBuSihxge9gtEgQeoO1TNIMO1k21zZUshIx8sF5QOiDJqorKahpSJrGmRkgDbY1iSNi2TVptNkUsC2qlq2SRY+xP4ZKPu9P5Ckf6B/8EGhy/EWO0vzpDICV3KD+I4EA4iHfhV4MHzqJQYX/jFQ7okEIQEiRUrSStZjLSo2mWQmzBNBMq/y3w78tfo/q3zyy6aB6FfiIEJS8oFGovADQ/suj0KUvtD6YyB72BItEk5fELr05BzCamCLCAwj+PpnThci8DSKss+ytm23NNdW2cKUwQTV7yoKUmtIboP9+o+qFIeD5H1/Nk7h/XKqgmxu9/EUPMqB85EPnIPVjsaejrew62w2j4gThH5en9t67Hck+y9J2Nmc6M1G08iION/BDIT1n1TdoR20VIrEP0fX5umjxkj+lk/ZKLBV/JmPzA7un6F0n3mTPr899Vvv8y/JOQdJCmdmlIcnMcFzBQ++mepnFrKEM6fDTjm2bGb90xjDpXaZiWbw+ae9JCSZ4LoOFWEU+MgKaF3oHRCRR5MRvJGrBHDZ/gfKKw9/MywttllCfGU03wA6j871L0z/2mv5p2TY7cseQc4m0wOB469YfcesNgjsMjp1UGHD31vOyigIf4qaUxZ5CvozX0t+fC9o/VDU9jkyYv6deZm2xyDB2PQhdzKwFRH88I58Mhr7B2dIuelPHFTykKmbiZXKAiSQaIdplEFEJ+AmFx6Z6TOJtlLZpp3yYEJjkKDsnFmnk2neIG+zHtxwt4nS1Oh6J9F6sEWjXaZ608Sr6MxSngs45Qhx1ydybNXuff6NKEZl7iI9oAiATIfZUHdUNPY5AzNQgbibM6pty7XjFo85J7j+w+4bD608gdC18RZ7oECA8/ZvNIHJD4xIC7BdPyRt478fvf0vyaqSymWUgNLKatAQzc+Zb/H+P6Qn6/H9Vf/KDwpOUm3tmDGpDbHBoYYyFmvM6D0KGr17ke+BJuiSIZMJhTu80v7tYdBs3M+zSBYmIyDBRQYkWflmLKr1Y4ax0VjiYFoznDo0Omrbs3kuYotexXXem8WqNF77utN3eZXh6uTu6ZIlnXaxcLs1indoucV7l0gVE8e/eUs8zXtkU3a9ebC6TqdzO2kSJIPjvqvTETCpiPQA5hDMRSlWyrE4kjczT6f2Q2WV8nlPU6ucdsCoHu9+mgLD/Kv7vZ2731RaIB88qK3D0BLIyHAiehhCg7knZBSEJF6gi1DqXvHocoRkncZLUEQ7z7DHdQFNAUdepv8djBmDcjRxeY4vsH+kkSEJwTDsC+fxnQKNoyLtO1dkmyh1XToKE74nuzTIHQr2MEmvxfpSr4+a5Z7S8eVmZi0a+1xgYmI1VWRT4Yq44gHaypqhgsxiLFdSAQj/mkcDF4m429D+6y7KIdzjyi4GAiAjmSCRQ51gCD2S4QEidzVb1nad5UOuLjRkJrJKXNp2B8lZfVDad72d4ekDP7aCu4yQKxNoW9Q5UTvKA7Pj7vtnTxJOLu2mCFoFSFynEUJCROFTzYC7KxpwUgREgCwFICeRxijmINMHAxMG7W0FtQa1RaQTVXpW9q4Ds4bq8G+shWDzS7Jy/CQr9JyBRJgnFLl8Eybn0zqqMSZHTyQZN5aGcMaeFwwPu48IXHAggtVoTh6gRF75V2/LoZGyHZy4a5KxK3VFzJFuRNngge9+Lxw7ZZu0sNZRrR6c+zz1fUsGe+G/PrmQ/gUHDN663BdNGtUw4gav3iQKm/HPZ6pNLeuGHIbx7RR+tcmJshokA7kYhiwif2GQ4rl9O56EwuIJsofi+o7izyONT20LhIdaeSdkkYQCETv7A55hAk5wKhBLu7ruu3S5ddRDTaS6UUXba5auW0bJltlnJ3JpIFSkigw1eum2zYekpx8WCQ3Aleuzs0mxpmfaWlFkcTaNROrTviZU6z091XKrJYON06rsTtO8unNaOpCD2eGXMIc9DS+HmEOQdGO53+q97MQeIdtTtFPzwTkI8uA6q7thQMhzOksMTDI+o6i3th66o8jQ6YmmPoIeD3UB8YFqgdEuMg+Y6SA9TqEa0VpShF/vighSZ0DJaoWj3GG4msrpOfH4Q4fLOuOnVaWWFyrfuuWr1yMTvmkkOk5IFOA3VXCLqQ2wMQZF5tJ4+ccek6deuv81UVWHF5Qu07OjTjhNSATNYgQ+ajpL1+Lr0+PnkqoKIILn2PIyvTmoOFmXgRFCeQhqYCqP2QNYKhpuUOF0/1NY9BIpqdORNkO3N0k5e8bnXMzn5hCHBm5TMXjkzTYfrOZXiTUoDiluA9no28OFpgKd7m4VNeOXM040uLgGshzNzKaQQTyTopuZHMcsqEMhDBK5RyqVIiioKo4YmdW64ajCRw6ttsyjtPQbg4nRvVrplOuHRvMqXGvB6JATrU6zcC7vNqpdEeDhx53M5zqg4j8eZSk2QSbMqlkwxd2CJVpZ5y7Fuq0lw2YtIpIFkQsihXBsyGCZlSCCNuubuKcGOLlzhQoIikVFJ7WF0337snsJn1g3d7zmOjZ1S8s4wdmysELI5i3w5QllxMMGi9LCoXBpEI4NNQtuQmcUiyHJSYo+Q9rFzlTw7V/bZhbPvradSyd5TGd88Sk92UFTZC4mIISSPGIlQZGES4OsVGyYgKt12FbPgZNUkUMcYA9A7F1AsMEXKzJhbCDYhSUBDPRgsjNxVSBdBcLMZ4nCc/OteaHsNzrFjFkSUqxpvPrlqxixl5YzM4cbNvjiGvnYGSQjJPLJQb6o+TtO7HQ9MRgSKaF++p1bIEmeUTtQaqWGO4AMCPkZG9uihrIBiJRBN0XWNsCiylSzFIOPPKEMt3bptFkVWLKqtomJW2FRpLhibVoZ0BY2LBpvpkxqGFY08m3VLxqZayZIRKNGo2iyY2NNNbZZRavfdteKkmMyT2JiCsCbvTeHsqeoVb5vdZWXxF86ys3itUa2xotkdgm6lbilKRxr6uyp+Sjkf9DcD6tchGbCE90+lk71iqVn7fkd9d1kmTFFFgHRAW+b0QAzQ2nV48vQhkP6GJH00QZ0byRVk62DEkI7oVEIl8Dt60qMD4V8vI9PqwYJZD0wsvkt0SBAU8CJCKKSDCPmlRTyh83do79Qsy/bI5HIWbJJRDAEKhJcqE9lSquJUOXmhS9QPaeJF7xPvpubuL8nkuu2vzrtdirmplbcuDoXoZMNpVZQlWqUQQxJAb+eDMyGjSxKLLFopCKixUVGi0apLRaS1GLMcyWoMkoIMSBCSqWqVItNIUlLVAUcfnNNDSGd7ajguOMY4Liji1RS2WpZG5h27T3+Lgvz+7NNLzI31hg4JrsBkMZCrmO2TIZjymHsFAdPMwhew5YR9cQx6quJVUbIVBH/cR/ycllmNtV8tZjmqiv9cTwKzo4yRuBIEISLcMTCTDS1uUU295DwZd5jZfCecjnN5FomAkWmc0SzJTG1OKFPKBYHJVf4SDFgs+4aDmJDgeQSHNqhmEXyr3z2E9OPiKL+BtLD68X9ExbDbo2WG7pfKBJGB0c1DRMh5mwcomgH5R+2aNqmvffqfc19zttMsFDMnXIlFWFK3kdtSQ+w6yOq8kHzoh3PE4qckOO8Ff3EP3iB5H3NonM6nyIrS+m6rW7Kvs1llCTMplps/k9KRydplOjV0AgZe2FTC5XcAtnY5scJTmQYhPthtcmAE/TFkAT1IYCC2HmpGJblxi8FSy4saoZcSrddXd1utzNpRqU14jb4QX44o57CgSghC6ETSIZHwNbHRQp91aKg6xH1VJ+4Ry6zEUtzrNREuAIXVKYB8OSYQ+yJTtR3QhAV3Ia84dhvouCkIDlOoy/bPR4Ad/MiR2Go7iyzr5AmZBT09AG4g6xYXSZTXGjfcjcjc28aZbkb/dppsqWLNpRb/sVF2ZXLAkTA1wPpcIiOHNgYiCJpZ5Nouandt7Lybz0VD3dctqVetGLT54bzadSRhyxy5ZzudtPtib+4hwpE4PhKhKFMDQNIJ7gj5KmQyAaBFoJouPPxTZCRCRRPMgnyUQe6kQwVIYuSLINjzVIc33e+iQqfv/F80/ywfJDWJ5vojUCNxaZCWtrEYurLS3KPu+kn3vajMMH4xF2iH7ei/PQdbAnmoCsB47oonxMFPjhCItwEyf+tKuIKYEMFetPD6iEWLuF6SrvbTIWWQyiXLax6X3+I25f/r/ATJksk2WM02u31fG0bfpNdWOD8f0xbKlJ3xzJOvZu0g0X9k/SgdiPuk6eX4v6v72i11pG/tjK+JkyYxj737C/7Ji9aKlxGfe0lRVlhX8Dm1MeB8PmtCobie2dQB5uUJD1xMGF+mJIIUWeJ5HWUHdtlKfosUIwMqGbcMwLmGzCZ18iT8RrUWKawhkdhj7/t/b30fnwjjrpCzYQ4R96HgnPuYGR/acuKeysOJCd2Pyq+KcRhzrPKN1tNV9XumJNnc3eEWo8SObJU2aM6uw59Wdau6Sx0Jjol8yOUNpqH9oSn3fgo/PHRZ8FMFQ1DLNszs/mGvd7TOf1dP31osqmz3f1oqP7rTSwccUr3Q9n7Qr78PlIdRsrJ+beV7ZIS89/By+Hzyy1XzrPpqVmrNlsdJEVZBmrqjhw1suHabrrsxdnKFBuQnKHgKdYvgRCPe9Aj5INBg8gWvGCkI9ck2IyG2hylximw1WL8S2iPs+3WG5ommIP1s5uR7zlOEJueQbjVG3Epq3LQizHWINUm0KQZC/1aKsNNNUExgc+07gpZAwEV80yg4EeQ7ND8ISZDq1fw+t6teXvghqiotlK2bNorSm2xrFSNVqQYqWaKyRCQZCESEST36GTiTr3Q6rPSdeJddcP4bLLqEqZYH7PO9nTQLRJ10UWQqydLQRxHZ1uYTZ6OExFzgzh5CabT7vykQ48/Kl6G6bcUX9n/QyvTEyr/6lVFulqnhiSZZO/2vFNSSazHhSty8pKdvE1WCDLTKI8p1skw1UthWJ6J6J6PhHPTru7F7Z2WPIgf8G4gs/5IikaVIdUhtUPKK06XLbMWZmsLLrive0UFQaYBCJFYQeZFitCNPmwrK/tDz9p2vb7VLGwTzA4ibx/hhhAiQsIrAhGiLAjIZQcvv7easVp1/YrWSsrM2MpcibSQ29QxYTaUBCLTBJoGPQMPVMRFyH19OfWBkKiZ+A/7aPpcYnlNRIMGQZCfXD5nxoxNyHX1rKQoIP6wcdrquiQ46f7hULg0+pLeqmTHTOxvJD4MnDZftheCnonkP8cCEgATvXu+BAxMa2u6GY2SjOBISYxEy22If1GQIUYZtuxkGbxcB3np86dFUubnyN182WqKqiP6HV+PvK8MTohjeYduBBFREE+ZhswZmlEGCQtpi4IpjWDkHIO8fSbzgJ2b3zgYcECOGJglxlyYC7Za3daNco2XXZlJaG87eCZUgkrbMxOSanxFDCdeCdGg/q3NU3HMhMzSgZthqZEjAY52UCtRk45Vk8if3lxGc5pVjtEEckzeMVEltCvN4dIgaJBSiGkDMGyzDaRkSWVFUhRTFJJU4VtwkKd2sEWwQcjPLbeGknGkYKHq5tIMPn/F35ziIcQQTx3MTksbSpp/Ar/VKj+dZVjofrg/1lAYKgB24t10c4pKWp9Ep/HhkXsZAYts3EIQF8QyniNOon7BSvmctRPOxJIwB3EIMIlleJISyQB3kohIQ+ROOnR7fQ+SHXi05Q7SSdjKyQVsilYZcmjRBJftG5o5rtipyY6NNTcNkLklIDSgoQojBuIfQevLNokTOBSbjRV3i0aCDBD842x6hedAFy6KJFoYH3HoHsAMj2/Onh14OZB6j1QhCC9HQUmzJ53C8sewWQkTFgXBfZjZMegXACfDuk7Ch88J8dlh7qaH2FPn3V3HBKPn1qHtoaikNZih9M1t16TSzadOhi2drHpue7D6LjUMGm74qsQ5QKHeDRFim6mtIXJiqwUwuYyYuK2wzxhmsMqlNsk8HUw/fMyfC/YuE2zoJv9Zvl7KrAMiQ3BAfRsPTXmMFWF0ccfjgVVBTA3wwyMZ4ptLdd9dMX9UKfNDl5sIedXcRUI1idEA5SMkZKhzh8tzkr3BqtRwgTOhhKa1eILIO++LrInZJP0zN1yZ8IQSqOQIw5b+ZCa/82tjGSLFAicEllszpzftG/nD4Z3h2JvqBPcFB3nxPxhQeoQH5AhiZ6rM6L74X4wT0Dm5h9Gs85CKjZDFRXBHDJiGQVDrJCGzEHUR+/EP65Vv6H+PoOxd0WG5fmihBijIPxqGCkCD5+VAOiBJE5IGUuIgyAEdFWrGD+M2o7QUnNGWRassQ/mKZQ/ZIj/Gw5h9W98Nrzknp8X0XiGJXdwHzKqfwdfvHzHUc52O1+v7JCfyVJ1h9ybK1spKtLRYiNtJa3nnYSZoJ63m8u+y6T0kluXc88K3Zty4s2pXXqqDQhAaoQIqPHKiZDEWMDBF3d1i1Fq5rXbN3XVdtLWybUmkd0W7qdorY1axE7MFkhkplsxYxLCmCymEWqUlT9FSRgqoWWFhqPvP0SUQijIDIobnl8Gn6or0wiQbj6ykuHZMcxx8gv0Ex5yzbMEpDuO61iA0DSIEKHByZuYEhZhTblP2N+kZ9XP8Cb4+dn3tO8D7JtIMhH2HjMnTW0Hz3u1ErsYaCB3HfRXTclCdFoisoL8b/+HnSy8/VkYHqxpp4Hr3XzdFEbJMhHu42HDBW+nE8xA/f5xWlDSJy8L0OiaZMVYRgSD1utFVZ+J4aMxwSJQfM+6fUjjuDoTa3s1D9jXtQuY88YzrbPssBFw7NZZZOhA4mdcH0wWzBlc/5DKZmN0M2S77gUN1o9FWJUX8iUeCcQeO30JSarDQOU4XrqD1w2rNJ0zVwO+zvdymzUR1zcczAoiY+0h5uTWBDlztlIS3CYRBmEhQJ0bdwO0BCG/jlu7khYJm6RsWLhe5o2Q09zB/uPzI7yOiadK1Pxe+XNDw1Sxyya7ppFpqJLdq7qWmbLEh3IZ618g8/mIhtyQ6VvrSUvK+VdU655yJb13B7MiPY1kjpsWdkqB3aEQlCl2yITOjKxotRLjUTbfyr2NOzI5OnNCZIIHMbOtNOiZPI+nYfk54WxIj3OpN7G5TfyFsR9k+GuWTQh652KydKbcMaYl6WD0mhPtqQSXCLuoqzJq4e3zLuMjDKgwgXpH7fnMFu5yYBOunHt1zGP1LP1862uSw71qL1AOdS06l6JJDhcw+QT1N7Nc4BzPAYl8n4d2j3W44aHSPSdRbmneVFmgXeeMpanNKR09MN+ch+PmfmdTWcKezgtFnS0NmEDWxsho7k255PPneVTzcdTRWkkMc35GxjffRrs2uBRgww2Epswvd2FiRcYA4IEW9FtPamzaCKdJuJNJDG5Cu2bLV/wrXfUd37+1mOcYUXZwlGDtN36cHl0KXUKDhFyfX9PemrdnzFw5SgERKKhieJ9/k8tlXhWxJXbhUM5+QiBvxnJs1lCfBgo8QVcmL834Ld83OY9+Oinhg4iJBPA4UtM6uX2lBvnvulGbUCp0naQ+NpHZ0xrIT0Zudarc3bu69TEdo3DlmiFsFUkpsOHMyiNkVEulXeEz5/D++/olXz15nJ1fmIMRxnyJgUj0rWvTarh+lj6Zn5P57O41DgdOE9/UUemXD7o7/sokkUpEhsThqWNhz6xAPZ7SGTczEj4Dhd0cGDnEk5Cl4iSUlHDSkpN46h9WfPw3DcJhcKkJnSQERAVBwQOyTSTAcTuTBUZeQK7WURwhrkzciJIDcscA6WBUblaMGBDIEWgaGg2vyvQUyIdnVRDQ4dW8bcxBcau2QnMaKBPZv0Go7UKA7GJCIK9dDQwPpuiS+y7uNRKhZGqpF/RsEebkMeGLiI5IEUiDiZqTJMxQlIRFjjMmT7ZzdNZmYNJy6WwzKFRv2sd1NwJV4QiiKzaGuy0mSE4/huoOF663pPnePUJ8tyFSTlw+ruQzTlPF42VKboFeqbN3MrlHNzUJ93DmXdpGEyRMOLMNBzUz7t5lFWyZMYsuY7QPOHgfbE56WX3j19koRz4L3RhAQNscpBcA7DB1UhUL5BG266/irhGE7bPPo6zM0urW1hPT9LE4T2or1i85LiUAOXSc6RLZFaLVNLS+79DET522/d67iLn2vt8K9ESCuKuPJ1phOuf6mqa9GumTSdepCE14PQJwisIjEspZpJBOY9htjMWSylNRpJ9sDViYnGQ+paJHiOwIC35b1ZwvyYXiXWG6pm+dARMkqXmOQMyWZD45CRImWHGIH7w5sWN7TBxYG1qQ9cbieeBR7SHidlZpo8YUjrWJcDvjWxKAh6GqJwFJ7Os5IPDBy2iYOdTWuPft29/ttV7bISxikjGwSe8VBtD4bh9Im5uEMRIJBiETMwSSlFCypIVe+GW2Ld0hkmhLKFpYfYX4yXGjASR8wSjS8YHOOdqTBDpmZOZVweurkc0TXMgpoJkxlsCFqiKSIiXCGMjkYDhk4aYxHERuAFQWMal2S7VDCQEMAq7ZhVoqS6mZJUqHCtqke7UDthystxzashJUK40zz084YhJHKHlszs0F9hNQm1j3PUbds21Rl1HGthYXQ0EhuwsCyySVyEz74+TPXM8ePM8EkPBneIQ7wlVVF5MI5ipOiYV4QxxMgEfKq8TZktW7YyqxV8v1vlr1cnwWR0Ok2fy+g3shG+y0Z0Qza97+97s/tDbJ25XzyQd3QZmmbowlQLo7IaJ+OP0Wm1sMSQuzC4wrQGoLk0IdQagckYyMgPmqnGxn6pU9EPIZ7AnMnAGNvR4YyzO4AX5bgX0OifLXNaLPVX2mMZH3XSyH5f3SpSiA0TVt3vH5ve5MmhYiIYiiIdnHUMbTIgITA7IbVdm70aLd14zlM3tR5kvcEEq8U8UfFziQfUfqxvXPXHXA4+0/H6DLZdrIbvqTQT0bT8TT3EsfGnBoNwSvbLLWqD8GATHiSo7GYENRwDsY0vZ7QEvNXTP7CMNEWFME4i6P22OIi0JIIsCJZ+GataqBEfnMM1q4NOEFPpDvwVMHOXJLDiCERH87hRolyjsxcHUsWc2vRGBw6s2LuGJg0PychI2WyMcgvvAg6m7OaY3UkJjSA50r3hS6eZXOtEZbCHZ9iamxl1dkR02BjeMYg1vjgwpt+JwXVMrBzgdmxbOAdjwO4P3kC2PUJnHZkNxTO4QdXI1FR3JfCksmDQK8cnpjcEMJhl21OJZtyHRDd5WUJ+WQ1oaOIhu6LOhKncUMJkQGiCXZNYSmHbp9zAr5coNJo24YSIQnZKnmOYjhUig4YxcUlNCW1oYvh6a7X7ayZIUu9YvHL1pmNMmGQmZmjFIyyHdZJjJ7csrR1bOcb5tyrMslzcTsRUhyymEIXAoeNgXqZhwPEzMJ3M04THchDOKJwoceOVOtmBzEdiRiPlPLmeK6eOsu05nMTg4HSEiZtK0xRrDeet5xVN8E0Un4EPoeVuamqhIT1I6iJiB8eF3L1cUTjbogcoeRFXHV6th0Nhcy0xjjXp0CZmw1GHMDmWURpypW6V0worXORyjD1kI6fum6eMu4d/MPgh2GTm+U5rLnSE5iLEwmBMmxAncTJjZsNaVxgabCswJCMBxBjRQXB7Axsqp5Za2aVhRu8tcud1Cu6WJuOXEyZ6aMZK9kfLTbJlzepjTzld3xLxRHM38rqTfMPqt5WIm455lhMzBjsITM8jBJFdiQwaBS4EcBbUIRWLeQhnExLkAxw1GqlU1KqZDPq5m61CksQlHp3SEbccpVmEEotKRzenunqpmdaVrL126fP6+2nrweCk7HbSdSxLid6asspcHPUnycQRBFxyB09cCUFRFNIlWaMMZGhlhgbChpcljlLRomBpdG6HiGA8/m+c5Vo6ibOoTY2YSKbzkg2iZmQJIDXb/LeNhl6Tu890ig72RIRmyY2ChWYVE5namhyTBSpb3qJFbDuUNEtrX9rfi6+H0dXolti2krSSWNIGR2lljsMmnVoGV3p1vUDh2GptNVQ0HMAgmYZ32PsniUpEZ8xctyEg4NTKNNkQk3ELmDgi64uQaSICtk83dXea7W6cSamNRUEMEpKI4OEhuYmFK5muEkuKuYhaNlBUQiQbG1obUNqbSBqb6wPa8tXaezfbCPjoZvEvooamK1LCmXKkoo4OZRNyGo4J7ZNNkoFuUej06M9DxA4QCQB130sTxNiZjqSn7nLUo1rhZg2BISWkkrdbsKlA4eyFY7GeegSR+d0y6uOXV56xvXpxV8RbC/wYjCxcZmMTmr4/C/gfHr4wbV9iUpkm6sddfpzuzTjJVtURgX4VRAwATDFPCSPcpEcMAhL8iuyRILBwcRY7+3BYzdJ22LbZmo6Te2vt5fD62OHySGEofylkTiyJpak1LEqkRi/jRkNcwJOtVA0ybKNLLKoTCmD99JhM4ncGFQNLQWxRzxyGyNenv6cOQzQvDds7OYVEs79Nl4Ik00Yqkem/Ap8409Bt7E4yzXAfSfH6Q1WDArAPb6oD0kIYo0ya4EjDbW0k8ePsbs+j4/f8m8EUOs7pcOZJQ/tf7l/kGDkYDhJ4PTrI58HFLj6OmbgEmiXCSFAZlhKkTC4ktyWYhXLmBXKQSpRmJZmHiSjiIkMDTlCCDm6IXBN1NwC6Bd03do5GaNEbu6Cet4cRk4NNIJLwMzbTsdhdHb+Xj5KEkijc4EgdKZthBRv7r9hODrHqOL1S4Ge3MPaCGfGSE+0qPq2Mvs/fBu5OLSp9K82RJ9atelr92+Or6evuAH6v47r1Ilonsu33NyFTSjJb8sMzWfkN+tmSbjvpqqQzdSWrbY7qoxiqnzVoekMj+7JkY+c7Qrzhs378TzVxZJiXDT5zio7QglqO+UaD7+HReuM+h+Ujqh9eztWzJSrJaVCDIkiR1g3E+c/UbsdcgxwkrZENADd3lCZYgnMSCLkQsfwh5jrHen2n4ZPrfc/Vn2luJByKpavs0aMI/SfT98u48xicIVB6+TnHnMIK4eAuWuUFUHpybOrlDUxQ5yG0IlSQtzaBUBhCLiMwhBw5lDmYKLl3SnZRXHf3bDYh9J5HAJgIkg0C0+NVZOalIBX1pzU4g+YMC44cCukQ3jFyoDmCkgbQInziaGDYDjcxBXPufaGYdA4Lr3FB3EIq5HprBLD19ooVETTcnWM+74KpSdiwhPCEbXxUHTwgbXpr4oAbYadQRR3CQ3WlGdtNODEMhYtS0tVZZVqHCuUlvZd3cyPbZteu1/9yTWi1nHt2EQ7yL0MbCGRPqhsA2eA4yicwA4ihvZz0DYieMUYEJFh95So9EhRSZEf189xPxtG0Tc7QyJ/Y4nbMVbUlVcYypjMRWZJ8MTyWJ/UphJ0PoMq+yR+mpQfLVj6vRTE90pJB+fSvl91lhuoyQvYSSqKxdff0dKRYQbmOdjO+vdJB9LL/Ul2Fhvg2eKnRY737x9wcxofqIQilm0VfIIIB5XoRxE1v2MAktYDkqyRDwXCwNvf3VN933XZbXKiFH0/YeBnMDquwvSygpuqml3GIR5GOCKv8cJ0YG3AxsK3i9RdB2cTeBkegaoJmRv3Psg1BMhl3HatobIPxBfA6Dw/ZPZR8fUOiAaQ/9yl4j1cduS5y7rd3V52rojY0ZNaxpUr3qy269t1XabaUtsLkGfGc3h3cOj9pBCENohs7R1L/X6LX4vd23NGvQeFH6J9wZH5wOQxD9oQAkQdTyPi3EZJw3AdsZHhpa2H2JwHhVUVVE9NFSRJVthpMplizD7E0TUec+m7Sg6fjH93EouG+dbDiQdh66MhFfPIVQSdKT9P5aPyYDKc+Zl3SBR0XaYtCgpsMGAo6zqTPPxjfs9+YdlhVRbPbq/dNJz16Y0/xLDiU5TI6SaRDE9OH2v4SdXjYuLhaeKj9F+47zufkd28ho7zDH7y1SsKjSUAnnmsDJFHdODOC6hQdjxoTsh/t9FPj/Fyns1zCX/Pm9s01xbiDrLlTpQOKUSL3jyUelcYwskjNkvWlz1mClq42U9BC0b+sRKHYTCDx+UMYBc78TkeIZtjf2+DXEKcJ5LT4FtUzSPT14yhglUV7W9UPbkgSERbBSyS2otGLCMrfhcRNlT50QjJJAJFQkRzEd/A+D7OPxaVZgbE/RpzPp3mZKeq4PJAIdv5bIEAhr4+95DmSI2d2/0Ro4yscR+Aj9hkQwTjtrfXKvT4JuPmHaB/wMqhegnZ64N9AgfVyWKdpEH5GTNKHufQZU9EPBCnvkFwokQX2eJ2HJqTRJglxm5uUJOxDokPW/mvVOjsuTZi4zopkaMGWMyFGNq3EJeAvZWXLmQDiWEnSOA3gRePcDQe6tHIJ7X/d+ijID64pJvPr9RP46LTz09nB5rA7NolWImDAObtOnk7BRwH4HsE2EQes5+rr+iz3YPst98JPAeB8uTE+TwtSEP+sfkun5oXIG6gnwP0hZSLP6U/7hGI5WxHCZrWgkoCBgqj7xH0fA0TDo93/LeRKPgKx/XU7vHBH81TS8xwXs86lr0fvcgP1/+peYFfeYGQtmHcOO8b+Fzsv9HomNCWSXrD6ff/8f/zFBWSZTWQt7ChwAtzTbgH/8EOV/4kAAv/feIGFgfHkvpwAuAHdtsCHdRwAAABHJigFBdAOJB0QAAAAAAAAAAAAAGxgAAAAAAAG0lsG5UAAAMrgAAAAAAAAAAAAAQxYAAAAAAAC7sVGzRIPfSlFVQkKlQooSoEIUgRRjMKSlEiVVKURRVbapRIkpUjO3CEpQgVQpJSUXZhUpUKipO+AAAD3nqRIVVBUUpUVLgADYqpprZM1Bo0sAAB6L3eqpSUqiqpJVSJCKhSklJJWbKhQipRIKJIpBKClQSKlbwAA7pEiWzNa1gqaxJCiqYAAbIDNomWhUpbZ31uqqKlVApKlCFBL53dVCQpSqlkMqpVVCESlFCiqiAiipVVNsApKggVElBA+wahVCVULgHon18AAAAAAAAAUAAABzu1wAAAAAAAC0dzQuAq2d3BcsfWtOr09WXAAAAAAAAAAAAABzYAAAAAAAA2OxuzJLz5UoSqhQiJVVKkFVIrWVSKbj7O8UJJSVIiSqlKo1kVFRElUu74AAAHh5EJtq2KwBazWghBWAAEaVM2qmtEjWWt84KAAHRudFQhRFFJUkIQVCRKinrDDh3QCpFUpIkVIlHbEVSumFXWq+8PfAOgPnygFmK1tqlTQyCVUMAAe7igCqSSfdVRA8b6jAJABlAbAHKy77V3aFKooSSLaqtmrYybW8OgAGdHbKigEhYMNjXOrcLbZ1y7d3HGJWataZXx9UrPeWkpn2p1ylTbBKlIp20BO9jpASFHQPcwHTbBqqK2waAMQF1rtCSCABQpSGkaDQANDTQankyClIgUiaNGgBkGmQw1PEaFKRSn4qADQAAABJ6pSIIEJEmgACYAhgmqSCBMQpTYpg1GCZAZAKiiABKJTSjQAAAAf8m1f9K/5yMUQpChN/yWr/v3eINKQgrapeVtalwYqsGSN1OYIzDEo1WtUwmJEP50TBTRYqI1RNKaAyrbD99VkasssZmYsYyAkQQlMwQW2RjBAJpooAistvNpZGMKtv2VDTnODMyOYqsW9UZomKSXFq3VsMxs0Y20jDViarF02tVQr88s/LPy2gVfs/T+b/H9/5f7bb39v8diiCfyp3lFcVlOmv7Z97/q+v6f24/H+u/5b9rnPFBv+uL0jJq8ctWl70ilt6EJJAXxf+vc1zjWq23F+xXr25zUc3qNQdjVaxbluM2qNuuYvulMW22dY1L3amGmM2rQ3eltM125G+zyuHrmXy96Ua+rPXscve/Ydqbbmu6w7YjtrF5it3rFb5Iiuqavujbe2YaHo5TmtUybvu+dTKfHctXOebs7b3iO7p22aUitY7c0sZL93jdcXx18cs13py2Sc6iHIzeOw82o0y/ZbF5mcOwkkkc3fFIznM7xBGJrvdqzBtr1amI1Xlb9tGsvvV93iNYtPM1pmj5tuk8rLNnE7tdqW1aHkrXLzDGWfku2+RKpW65t69jcSusqsr1AiFdhQlt0k6TIqyKUr0dhmE3L6mWBmZmwR3ZHjOc4yeMm+Ku+W+VrKTmzDSwzIkSE0xINCEZMwwkUwICMgRUzZMaTRqNjEY0mELGCo2jZNJYoCiTSUgaAIMKYjBYsQmJiUGhmyRsbE0hMSklFMaCWLAQChJoyykKpTGxqChhb+eVXq+IEm66Rdl1uuqS3W63U213flbzyYYr586xi1KmMWzEVbjGId3uttMd+d1m7PNOENFMxNN6luWvygkgKWeQBQhAxWzaybYDMpWswVWt19SSQeOun363j1vnOnbfb9GthvRGliAAA3lAkgGUFp1n/AFb0PkKLdigqglav5W/P9V7EUUmSkLJBiSxEkgzMmVBTMyDIZNGzNKTNhKNGGRGwYMTKIqYUajMxECYRoSNMmkTMWLTYmmYplLGTfv5/AkCK3KwxSXQD71T5r5z535rnu+973vUpSlKe973ve973qZMmTJkoZMmTJk8ePHjx48ePHjwCDglf3GN4h+X5fHL42VtrlLcxvO+x7ttUvzxyl6ABvXIBB3joElt5Nsaby22oaoSL1WVC+KYmZUViViJXsoSYohglRrSYJUolJgtKXTV80x7zjBrylOap0TLdtmCSFnzEDXRDCSCn8UNdblJaSurOq1JJef5jFolGZJP2GSX6NBPCUkzSc4TUlm9T9+bbSI4tq1LLRJYo20bUWi2LYqixosmo1EaC20aijYhmQt03vbrbdvJf87cxbFBqormumsVrEVRrz1dvJtkrGuf9C8YsVrGiLGjFb2rblt6/PWt41G1vhzVk/x3x1yjEbYjUYtiwYtQZK18U1c1i1FpNiNfPdsWTQW1vMa+KzrxjWiotbERbb33aK0G2Nk0aiirY1RZIqsYK2mW8ZtepXbXjWMaLRrO6rmixqLG2CPS3NXjpbGxaE1FFqxsavauVFUaKxv7U1qvXxear01Em0VGxsVt8K3NbFrepXNsVpKNkqNiwG123+e7vPTYxaNRWNRVRsWTM1iK2LRaqKii0aKvfdT413qr+27eklisaoqooTb2rmjEajLWm2KLBW/xVy0FjRWgNX27urltCW9q3CwaSLXt0k2NRWNFelvXnbGxqeu1zWDW8yuFGojGNY2jYooxWhV1dNm3prybVytysAaMVHptXLUYjYtvG1cs9da5smgybFpbFsSrIti20YHBPxMP7Rp9jaw2QimFk/l/nmJP6TnHCozT+JZoockslKfohcUYQEs4ZEzQCgoCl8/fsltdjvPvOfvfGp74FQUDALMCcEHeOCkBrvqfmp6TXevnywCMGgFsVdTxpCak5GCfyk1RSb/sQJp0Z8/mU5iGz3i6AJj38SeG/OfXKJHkNbFZ/ruRXKq/0t4xbJRqMWQwWCjUSaTaI1vVbuCgt8STK31r1bW8tXpUWtVYYQRoSgqFJg1sGi2yWNqMRsEWgqCiqiqTEZ/K66Bai2KxFXqtqblt/pXNvKpa5ojf9bbc2owVFGoxoo0WisWojG1FflW5eqpquUWotRaLFo11Wpr5Vt42KN+FuVsbFJqru3VFi3NzWKokxsazIMGxqK3qtWMBaJya6SaVZUt0IfYldTTKStFVioi1ixY0htUbFG2NvluVGxqe7dcosbYsYojaKir5pumiorelXNojbFYoTUWk9rdLYqmVi0W0kW0ajRJW2o1BNkBMT9jKSDFQ+numuW/78O3ji7/X4bfhl5/D61s4wQk7MUu1LekjFJgSkpKCipvZAxNMBK5xEhkmaMJJRKnCiaKQjXxMEk1JUpIYwhglEOdHDKENE54961SOJZIIySyCfc1+70E7iIhSTsldVHe8QLhIJf0wTuk3qST2a4QOEGkwnQpPXnPPv05nKSDM7u3rBIx3iJ9ashbHdOa5sj6yLKO/dzJNIK+to/WO53MCJZBhqyzlMOHU6cIkTpLLCBV06Cx5xmELpG6LWPZEIa6jogEHmTYpRIVCeOs0f1ASYpqLs0a6PIz0ZNVCFRAgXDISiZGdSYJoJ2SkwSklJulJoSQ/6CFJROiYIjS88DUmQWlZHpBBW14BZBWvrAT7r/O731rXDBkLRzaz3azDy/wWlTTVOYilsgBYlBZkzUZOCpCSi+FafkdpYajTF813hAg0Z9UMXaGHGq1ASiK8FD1oW3En35TLMrW1EaXz45s+IPme9NWYU6BxTiDNQHwhOzvm/9zJJJBjZ97sXOQ6ruZ0uijTrt5q1SZhIEaIeOdi4zx9ppea8OcDXNMrT62qX83Ol+C1FDdN3GvQVrvrekBXaXeWY+AsArsJC2wg0JhXNs0tdmZtD8ttpT8grv0xahvxZrer+rq2/H1dbfrEJGSEzBP87mmRqSYGRRQNMlrRNrRgZookUSRJAJDCBGxpYMgaWQkmO7kok0FJo0MmIhKBGKKSjNhIRLJCRiLMSkpRIEFECGmJERIEkYwjQkfPcSlksiVKGgRlkiaYwllDCQyDRf7LqQeu7d10CiMDGmk0KGIibIaCJlCNGUgmGIeLskggwiRZmkSCQmYSJQykwZMxJhEowmvO6zG5XEkqZRkUlQaUYU/S5kJoiZjT06JJUxMxZDEiRopQUoIWEkYGYAxiRZGBsmISaJJLMYgkGGiUAGDE0Sem6JTnEUxpAiGhIMimZpkAyTMUhedumMxsEY0Mra87cgSJCIS0YjApkJoZRIAiGRJg0hEhiXLsiZmTRMAkmgElgxEaTSGPHQkRCIJTQQoI3dda0SzRsGkhokkpNISCcupGIGCmKZIEGEzImKQUSJoUAsRogGSKAkaFnvru/y3l5MsYRqEnvukIoGxiJAiRJmMjIUpoINANrTNoZJBD33ChpLJkMSIypplCLeLokhEEhjEhKQxiaCUIxMxCTJExSSJMQRAYEwRSQomSGhRpZMpCMMMaIP1rvfVvPHfPbzENSCNBMiSGwwh8d0iEkRFkmzRGDRMmLEkykYaJ8ddl46RFKFJQo0mTBoXnXAJtaESiFMFbTAjRiQlJMzMzGmDeddNBJGUEJKSkSMizSoF46wYhlMoIEDN+nBlMmMMSYEwSYTDaU0aSJNEGWAkzed2EJMoJRkGUbOcRpNEMMYgREw1tJGSJkJkJkEUQwkDISJEFJPXXTUiGZFJMiQ5ukKBJEgiNIyzTGaUxMooIgLJv58+bweHclMJgEkgn/Du9uNJkQxTTQpBGaGBmQhoIiyWHLgwyRsJKZMUHd2SRjNEQlJ/u6NNAkGSZiT6/114mk0SkIRCgmaSg1IIBT7dShKIEkhItfDcoTEQMzIMbbQSaTISYGQksQEy5vG8RNAV3cir+N1IkIpCSQQY0JCSWUJRlMW2njmBQ0YRd3TFhmDDIg0xkAjO7sW2iUxDJkZEkr125kEI0IUjCokkmKY2KaI7upIir+6pue3YjDb31wQEHdwT326KCZQEJJROVzRjTCJGEgUYSJILzuEoUxMxMGEhgQmJBsgiM0YCmEMUph3V2kyYTSkwIggSmhhCAMwZigSKDa0Y0KSiFhSki5XRVlSsYjBbbKpbf4/n77u/JI0dG/9/v0AgcvfvjkTaQQfh0IIrmk0rnWt633+epg7OxAl2vptvz5tqlK82d2rsBVl676Q5IIN34qwiGFV3fuBViowPiYlkTgvL+NsM0mQmJGhpFCUpDBimiQhAEGBtf26gCmUsUmMBjl2xGYMajJgSkUYUESQjSREzRmpJEhGDIT/O4jDRSeOSDEyGkiJSJEw2RhJBMyNLGKCW1pJJH1LiZA0MTNIyBIMZYmaE2QWTMZEUxIBBiaK9d0JTZhhCxknLgzJYMQQYpg0koY5zGX+3dGpDE0IlMmJpkYQYkNIkCJSkIxNKE0ihkhRiIkyTRFa09/nzxQIgWIRoMYmGZiaDFCESRogiJoEEPbhimZjIpYNIqEMwDQ7q7FJMCCRkgQkyU0iQkV3cmAUlEiBpswwmUooaUjMAoIRiaRBmMsJJJRosEkCAwIoL0q2u1+7tboxEo8XYDJgpBAUIwMYxmkhenRoynncQmhMmSMMYozGIwzBMhCPO3QkSYQkR/t3CITIRE0Ikl7nEwwTJNFBenETTMyRMSaZkSiYiJQjNRGkMpMIoo+erer8+vP16/vz+vP2/Xr5VMGIgSkhJsaX666IYhaSSkGTKTMpMRjYISIZIwlkkgzSkGQEJmYJJJMjcuZIyIH5cZIQFIjIRJiimijZQwkaEspNAzBJZpljJKkkIgZf7OhP8XWJpmJgpFGxJZJKQyA0pBiZQl/a7+u6SMo0UmM0yNbQKGKYZiIQYRkGiZZRMpo0ShGKQmDRoSTPu7pCmATANMzIGUBFDIJGIlJAkmIBF9LpKJFto2tEMpS0q2xZdvszOp/MxJeZty7riuOMLv5wMfvmpXxkcYX8ZfmUIGABgSYdGAzIPusJJtUR+oh58yzEdUSTrnTOjOCeURNHBMIjCWSRDcn7OScAgw4Jg04JqeBY3FmqAGL1xu9aVCaXtO95U6VLl+V7vkMdvHECSa8MYp6MlATULbe7aOJJ+/czviQiCY9tW2xbVtltlmYxEg00/0uEKb8vf6/l/f4+4eqrqr2QqpBpODXP6FeKDFbuqCe9zMx5l8Cn3gLRscCrd+638UvULBDso5er4KcuZF1kzJoZ7V75XGRobtYrHbb7qatRxcK8vGL6fLWBM4ebMPYy/Ip2vRsCZJAC5kWZYFcozebkvvUorO3yCEJ/L2BMzjuzJhhmWF1d/t9+VZz9eCUmhEeEkpEFHmfdNqyZQ9pvTVNU1RxMhtVG1OKaqa1oJWqZSnihlTBMhgmSZJgCkt3TkmTIZQ807zk8Tek+KbN57pzTmO89EyQyT0n8JlHxPDyJScEpPSaE/mpPibEwTQmxPCcbCZiakpNRMzKbJkmEMETTik7QyTBPSVOSdpgmf2xPjUmqapURSfME8JqTCdkyTJMkNz0mhkmDJOCaEqUlQ7MEwZJuYJknBPxPCep6TZPScJwjJPCbCZJqmSdkqaE8YJ4HhTBMlJgqGxNSbkyTslE0JSckqftuiZJwSpRMGCcJU5StxPk9JgmpNCVKmpNGJglThN5hPCYJyJymhPaTYlJuTomtTUmScE00TJMTZKTYmiH4npNiZTRPDROj4wYJoaEonROSeJqTQTgnJMkwTtOE1Q5TwmybJUwnBMk1JirsTkqb+6kpNUwTKbEwW4xjHpNCck0KmpKTgnZqTUlE0T8TgnJOiek4JwnUKnScpk+J+JyTBOU6mswnCYE8EwTk0PCaE1JTgmAxNCdkwTBNzQS+YTo6TYnJNCbGTB8J6TBNENk1TtOyek1J6lTclE4J6TAlSZJunJOxOCoINAuswhDcwa7vsN3q+L+f7T/ca3Zvi/JYVBe+T6h2G98BW/Y+6oZBCE5HAUCkF+QOe7oRE8T4Q8EpKSyJSVCFaj3KscarVYvW9ayHMguc29N7NMkE5r83q+wMaMmxtNKWtJCEQEjQKSA0ybImGzZMkVtGIpAEQkIxSQYmCKQmRK/4dwxkKYZSiZlIlAc1xGWJNMhEjA0UYIhMxLBQGEsQkoQkoRYkggbIkoowT99zH+3diUZIQSQzKBkBYmBDTIhSkUmSgk1tMZKYZmGmwhIECMlIqbnBChElGEEraSkhCkMQE0xYCSnddGSKTCE5xYCDSSUxPS6TBM0SSaRJkMjMgiYZlKNCMoTM+63V0soRjENDFGaGxBFmSDRCGQGGUJCLJJjEUyREmRIy0jSYFMxsUEkDMxJmIyRZECITQAMBElNDJAJiglIkSNhSgpkQTJGaLKGQzP93KSMJiIwCYhKKNM0ExvXdEYSjTIojLAabMmgYBZAijZpIwxKJFEg2TBBmFEND31yZGxJhlCZQYUlMGKCQSZiRFJYiIkCUSiYhihjASJGUM3i/nz+/N7ARmwsxIQkiNCJiKSUswmRfDhJkyYM2DFChigSWJkIFCkiSvh0kiU0gKRo0GCZzcqLBSXqbsSJAbDx0iZiTGkERKKSGZARIAIMT03WHndhTGEJor893v77eJKSC+HFEoUkZMiFDJiYGaKmTTCYrurjCQBRVZNLuuzBF8N0ikp3cJFM0hChNFCJBkWZSE0pYyQTGJCmbBJTTGEDKmZMppUYDC1rzuyBMKMkgilEIm++4IKKERSYwiSMlLMFFIJKQSQ0o9duLCIxEgKZClIyJIpNlEFLuugyYkkozQxFBRQoSJoJFL+qzpAwLEw99d67qMzJLxcopYMgEgE0YUwRBmMpNMkIYiCMManqt9eefd9d5hIIUmSSkETJRPluZkgtaYEiL57pAshEkC863TIWZMitooIgoQzRMBSZIjGJKbCYiUURu7mRhGXnXZEpJCpCQZJkWEQEjCYSTAYZNKRAwjMiUkaQGPx7PPMKJRJASkpFKMiQWRJgEApYaGZAiSaEjKKSTINiXvtwhgzA3OmiSkhK7ulNB77oQSgsndyQEIaSwXduiZCChKCSSJNmYTMmYhmAGgxRJSSRIAkAxSvHIi+7355IG20GBGGbWiTRFEpSKR7cjJEpgwYJRUaYEkYGEmwMjCxCTIjJlIRjGhM0aU0Roa9roxhBIoiQkgIoUhRRRElDOV0hmYphkYggRmjSgoGZhmTWM9sbDByoSw0PEkurp7AgsfCPoIGQcPu/YPuqM12X1VrjRpmwLRu1i8nHru1841zOt976Ms1Y1FqPGkgFSokAKmC5G6PLQ2S2vZxur31vldUMDCsAg0CBgVgEYJghgl52J3ROKTSIUTdgIbxKEiZIUJSFEolCUJljVWttRO5qTSkNKTGdP2vfmvGbcMBhZ24zs7Y0vW1XpZp4ydcHgYZmYZmaCGMFGSaDJkkkP7dgjCIxlgxlGAhRBkoNJLu6kkktKZCEwQiWQ2QMX+/cEMMVEWQwKSUIyQQxMyStsB43SRMSxKREIiiRjGySiJkw38q17at55r7dDe+4gAYAAf6bqGospAmTTMlJrM0ZGCTGkTMgCzSNGYGAzA0kI0KDCSgSSMUlIYhgwYjGFKMUGZEghGTBkkTJEBhiZhJu66SYShYADKi9tyjP58+bySEiDBAYmUZRQMTGimQkDIzKDCRBIsAMojBZCEyKBjLMyJMAyw0Za+O5iZEoLAp8d2JYYlEpkEaYmMZCRKZljNNGpmQNNJlINJtWCJRMhQXxbugwzZKGkigyZkija0hpTGLMSJomZBTJDZSSZkJCMrxuZ++3IREikpIkYDPa5mUO66pGiihgmYxGZJgwQYQhKKYYGYwwBjMQiTBmSJjRUo/vuPX5+/VtvqtsrKbVexZEFMhAhTMZMCDIqsyfLpEoMAzSKkhIySSIoRmEohsEYSTDMMJCL67XJRDKTAyBmiNBFvVb+vLw9uwREkYgSUxYpGkEzTG9Vu3QKjJJTMGEymTGZAWEtttrq38rK3VZbbzsPpchoYaLJJgQ0po0qZQNgQxN7a6WlNrSWLEySSSlhJKTQwLu5Hy1tcgkPFxGUFmKGSIkRkCSxFIUxkCEQSGI2ZRTQgtSoyJglEyKRCkJQDUfjuGxW4vmdLmLx958vj2vved/QJCEUTCABBGIpMIViqp3plDKc+dkb0nGpM4zlBRM7OnesJoy05aEvnWSQlcFtHixp56ChHYVhdYAWnBeriKD9QBYF2931YVg24CsAYcIvGSlehmsFB12lpYXfV8EY91LNcECAkQUdAISSYSQU6TRP2EZJq7JseVfFct0kAa5W4kgSZgAmFvV56/fdxSXQLyBbPdHE1tsaE8OG50mqaBdPqnhMEyTtOioIbYwj9mZUtttlW1Usosv8xhRVFrmba7ZxnTwBPwE4UqbAP44gT4RSc3GeM1lvulifez8ZzdASTZt8ATMrVpXtLbGoqPW5Ll1BFav4sLC19C1jeig6CWGZmbrRSMo6yyTkmSYJgmxOSk1SoZO0pOBUEOAvArXRlh8NfgoSeH47syLMatOPcntkOxm2lEvQfLgsXsCJBkNi+5StwMBkFwEwK1bAuioF68iHvikjX5BEgugtidIbk9S/WOYm61ZVU5JsmCUmxwTwmxPPxOSUliJtCfEwJwVH1bOyk4qVYL0ECxrmQVLjBoFQVwTgpxY2n3S1NM9zUucPP2DW90YFj2LvzvIL2sKwgyILYCrAoAMb1pwqPej+CHjeMCQgVuhRkDMJmta50xmXnNcZGiKl040ECYFPRhdZJYs63U3LRa1aOWag1ZhrVci39u/nF23VnuusmxMrYuoZyzeBrzvHh/p3FqQvhm1TMHViqifjbFAqTE77ZIFub0Z+v5g5HYacWW/q6MVuB1Qs1SeDMEOuqqO6d59gaTnTqPOtgay6ZO5mpR0WGUN3iu3sG2D7Y928lhJPTmqiLsTMB0VlzNRDuQyeTNUqdvu7anW0GbqVuw8wbvkdV4+xzb0VTokeHhvKXOYe98uzbPwo+Oa2VIHYXvibYd1fweYtFsN2McWSEeHhJmbTpCXg2bI3a3jlB0FSOUjcsiN0lfFaGU2F0sUJxt2gzwtUPAPsc7FznC0QhLq3PdJDeKYxWknu2rzFotwU+y2LR8kzHNoxGElHMWZVaYsDk4quoX2vOW0a5Xe7ajhp2xKKjMwZlkSMFOnV5qx2SKyCRxRbWDlK59qRErsVObrk7nRV6pUlZlUry4lu3J2g7Br3JvVESTEPDwg7rzSreibM4nLMu8RfN2xd2EXyHh4bWqbUuSE9zVO+XHexqY7Crrm3WjOd301GDITHS5Iabh68HHEokmbvpdY+UHd3J9ktrCqD+yjaPvDw1Ck6lffdTiEdDOWvOP2tjw8HtaqXyQvKX1BzCN3VPqJzeN87mbxku91tl3/HJoowO987edd0c5KoKODdzKCCf1uTLSahcWnWnxXPq44spGI5mevDahsKMOK3r3c4W9s1UNsZaSFZ6Ks5ipn4nMNfdmvPvtWS7ZqDw8ML41SoOY7gkYrEFHa4ulxxK3YQcuu2ffL5Tl/mfn03851e2wmeWe/E9hEu6y6LxwXUMGDSs3N0XmPeFE1Cc66Yrs5TH19N9zcpSpHCl7hhmLJV0N28Ap24qFy9zi4Zckrc47mG8/JB3Zr1L838/Py/Z9+CqP4oV+Z+cglxNkmJ7Tms91GaM28e6H2zbs23kcSfjnRR343b52KU4K1KxR7wg30nc67Qso8vdVdlTn9fVyxiteuyI52S5AufyrxYutMN0pyobJ02+p52c5Q3cZ7SqeGhNS7OKfDio73q29rK0cgprMMl1pDtVk2WcxovJSsU+azdcd3N9DfLy07Z2obo2ZGrvonkp2uyeJjZfGjmgs2GJyrakOuVlquNcNrrZFLTMza4Peme61uJ7u8W8ppX2VlLdkTncNtWd5yDNplTnQylQzVWPo6llBJiLadrm281Y/qFlrUoPn9Qdm6PU6tE9PqWQYMHPa7G5205hpA7S2hrtyJmVfJdl694FjLIWlpyCA2bRXdTMWtZeWMMwOO5uXWWGRZl4MXyzZtaOF6G5V5zMYSuZBMqRrEHdVVSUHmVVXHG/IatIpzYEvtXJ9e7Y6LZMw5yF5SO2zfNF8Rr5cwnuLLQ3d2sDnudMrJiMrzMRNWG9TxpVXz7jczOBfWg69SbX2ZSFic1DqNex1q3T3a8eO8003iHJqyhwRyd1LTQJNNY1xqZPbT1J4YbSuwU6UGZm8Fxx/nSZv1Gvz8kP11+ZqOBhLrW+zNuf3/OfXF91fd+zGD+dS2hUXcy08Dt3DzsGU4sOYZ2McejNIkPlStunc06f12DVeTZeR/BsfKzAuvOGJDXWbns+D+fsqDvtX1ur+FyB3ixbY0j5vXY5fKccK260/Z96FVHspByzrFm6w6FmPMmEXF8njicSphjuxNUkOvXWu4kuv1i27PZiazn0uV5cudbBqZyK+XZoWTkctkURc1Ud9alx5PJPl3PqMXl3PhWXsTsm3K0ZfjUgvs4jZjljoTdlHm78yaIku7wORJp5U43MxsGxR1WFNeZ3anXbLlvM2YUzdvJyarearl6qWupxtRX113UwZe0y1NjLu01kt79iZaM+wzRyJBS3DQrIbc1O2CIs/03nnCz4oIPds+6UqKsJQwvBX5bZUa8bqTXvM3zyV1+d1XUUXlVM2YGDaina5nXlTb2a+rNPd2X1FXJvLBaMX+umSKwYhWvHp+1HJ8SJMdd1PG8nahBZ2bcSOUsVwSse8avpzEJ0alWYoREtx3Jt8Me6KxRm4d6F9vmaBre5EdUamK5trF2pt6mVnbHBa6mJks+UuSPknll09EkB2qmLlKmBK4Rtjcpunde8PArCNIRhc5WFWcecIDYmCsrq0Uty3EWTDmuY11CTpVYSqzDY2bu0O44O2u152ZHYKwi70LNCZQlVqYOoWZzjLvxbrpuZjsQYnI0LfO8ushCpduh5era0zSFobYwhA7JN/0u6OIcNjyyaMqbZGfIiCn9vHc2XMogvuRV8aBNRU/JXUEalSZgccl4FJ24MW3ThqsWXkYF8qxXgwPNuGzFRvFpRllOQUtgvBTiLVLcHX5q03zGmnmyhJLx8V128j1W8Mdnocyyf5/zgW8CEJShgYTCSXzP5sNrkaszk57Q5NqF+vETMgpBU7hYkitLNjj9/iNtGSPMMNRnE2UwgdgVwBxKjmWzdt87PaUpNou8FnYfB0MxmykOuac3YgsHh4PalQVdR1bkOmbj4upVydtdByhpPASrlYtzbkd5T5Y2wHd9djGEYqo1R09FPTJhsJVF5sTZXKZiZinpBl6Jc7E9KKsLKftRq06Yu/Ic5R7cztO6xCo92A1fs7gsns525N6m9sW9Xkefqx0s6pKk212mtqlswX1t47dxuVkV3KDd8sU6PZJFuNq6VnJeWrWYFLVROUHUlVLl1bgvRsXNRA50ccJaV7i9LfNeJvdoMGdqMCzMSdbUmK5kFBuy3rkGSxuZqW88wXqVVDgrDPFzpwjlTRBfFjESNeF5arX1Xt5rWSXbzMzqV9G5DLtPcy9RIu1mRHvS20II3t+ce3brZfFg0ZHvbzzXJdnt29vNbVK+mLcdbwR9uUps/qk++1rueWftV/FsccpvQuHh4JGcZf9MbM+T+y7q5FT4H3ZX0S0hajxO3dCHqZTD6g6GFNlU0Db9TU4XoZs1ormhYU4d2PsehOgmx2UPDws4Z2td123nczXcs6C2grewy3g1RsWmuzpTtDmoj2InixRTtUr0xIUZCxKQnXmCa8YgUWQgoiUKdtPE8GZL3u6I4ojQyrtDd7JL0GLpOd0LET6qbHh4atmqFwRRvDNUocQ7RzEjovhI92sxC5zFbtmrQZ5OKdJWu86V2ve7DbDRGHNuhDgzu7hpLNEpvIKsdaJEvnWxzjJxhFc+rMTC7lciSxZtjBg3NViOstVzreGdnQh8Nu+92sdMGBG+El23g5zWY8tN0wi8oyLM3Ghs1xKt5xvqEu+K1PGXOpVSvHne8PA47YRt+mDw8DupwKO+2yHYN3rzobkrIeaVCXtudzeVFCk8iKloLlQeY/y0nZD++539fwxWM+WnVaEyVMHyqzH2ZFFUO1J9XCu375TeSXtKeyzUTWfVUwUKkekNJTnJCRlLqk3U9WBBZYw5M0y3KC56xvJntIuupbj9mOinu52zemTsnJHrV4FuN+21HUuSm9Q6Vrad6sPszYIezLVFi6UFINVNLNx3RBypnYwVKLbeWhfq43rVbZUl028flnp+fY96yvlVs0NGfH4WWlLj4VLGZTf5WTMYe39ezVm29lS38be5lTLBO2SJYPjo+oN2hnuyuRhSalu7RWG2Ik/LuS7MxnL7putCGkWZNvU9dH2HHe9yC2ch4eGTF1ahXFfpDOxv5uWy9Uva75bk8iQXEOT7GeyA52YC2HuzLAsOipUquOOWqa42gbDrlYrcT6kHOayOkdvrzPOeSUGa+nvDw48Q1z3nvbyvL/Ps2Zhb+CR6qZ++NCzLedrMm06l4rUuF7nlbsPIx2WLmVhC0WwcaylC3pdF2DJQlW9OvmulWcK9DNGi3yhnpNvcfLPrqfD47ou2/n9r+Fcd2qxdBfGfrdofCIg9Wl80LN+bbFy1AVBWVlSyLH1QSmIX8hFRusqO4W2ERSwZJRNv3h4GseZs4VnLFrWRSBPZYYge83xN76lyl8PXx87U5crvEUbbk5rxmctjJm1FeM2tRBrcSYmDNRzAKxJa80padqGSpHpW0l+tbt1l7bCK9xXpqKqlz4Ytea8nig3aGZptmdBu3ujduZiOrMkNxop9REvtDdTFkre2VjJ26yGkvEljw8CB7wnMc9o7tFA23z1SU7xVSyOIVKpI7aj3OLvTz1K8b0q5EbQW50W5lLr5bbSw3ctKdIqG6cnOmmY2cGnqL5d++63u9v159FNtdlttaE62ZYuxg6lLqTtw4HXTM28zZbIV1qmdSyrwVMjRGc8qsZzszAdqC+oWcDkbKhe7M7s7DRQR2UhE2DqL9OQwrnmzd3puZt7MB1Haq+zNywp64YzFiQva01MSIsylx222mNDDWU8eixqw5nn17ymrW9LN4Or/L3tQRqXCpH9Z+rOuvq9M3Tw1PtqMq1Br6szNHVmBKtiJj3d5k2CVziqZWBFaS8Ssxb29zVidPbvQ1GrrLfTaUoSXU3HWLNF9NBhrDOIZFXTVKGxmQVjGRTeGyB4MW4a2VEV272bdWqqoJGNxSq4zRnbqyWFgqURL85yxkrpe85BXXBXazpwhHcrEKnN2xFw6NsRSpBT3sqB121hm4W8B4jnyvcNbs3ZZUyzrnQLILmw7vaVxXJjIDKBx9S49iw9tt9svnuHIqj3Vl28dzNDK6o/VE1tbWlQnMQvY6vN1QTTuguuWA5BXc6SmZeyHT2QjD1LSDE7fUF1aOPZYvXrx9vXa01m4NRbazfw6ORBEQt1ipbGiLO3aCWY5E4uHh4ZJf1RvDs29vYHdrshFurfPEG+iWc8uZSBPEY9srIMuaXagYe0xT4iNybHjettZ165L4V0+iwj4b9VFY50mZ33C7uRi/8mjM1ZpWLO9KmMPFsxS3fxRC8GYUgsWH/Xi74fnHzxq81eFNC8Xti16tZSy/Mpt+u+awjzdA8JSTJUiR+dk749Jy4192Q+D+f75hkFvh4eDn6FQd+sQvPryru0kqVdeFowPA92zmzMarlTnanvsTYvMHGXIdvLM4vXVSOclSkRB7b3FtKqCd3D2w1jYL40tku9obqgQtrzYKP8tbj37ty6JUTt3wpPXmoqp81VPHG0OhzZd4MqsbTdytT9YJvtlvK6PNy+aq9RFjJlUDsxhYxQlp1tMu0BSbo5G6mK7xQhXpsraNyZkgxrdG4VeZmHdg8PDGCndJDsyqmhLdBZdtJcYXkdGg7FqyOlBUptlTrrTq0UNrY1s7ZNzOpyjGHMoFUJoRHLQdSYUY/DA+sNOmuvfqXxi9Yv5vikL7o9q8nRpujhdQJ1Wa1l7S1PEdw9KF65SCrCQje4aHcceHLikIPcxgTVGHEopNdUdMpcrydzHYNze3N4jIUcuMKnNqn5lyZsd0sG9X4GoWfiH9pVO+zo/lpZoIPdDT48+0yyKlcczBWbsNKPsq37LQqhNvGm9kaDR2Cs51W4N5R6KLOLCCtpt9C9gQuNvKO5ku919uM3Fssc0qc1dumww3HQk15azKy+u7VpsZHu4ddx5SSyC8qXbQ7tJFh2YayhIILwZSG1ANWKU+BiyyqDyGKSDXUOjktI1a8sQ+p3G2m4JdwUuitNjYiUdqrygX3a8wGxsYWXfyH3DFhX2D5/Q/XYjVXBeVz4Oum6u4RPMxXubomw6WycuScxDfFq77LEMZWvX9tijnI8XFtB+K7468r7BOmiozfR9BXS5gZrWrakhyr71ZL2sWpmtGVyqdLuUWJQ8PCpAekrOXC9Y3J1maWjG2eYxqTq3NcMKl3kGa4OxDBvLTRzQZdK21pmWZai2yLWyJy2F2JMFGNGa8Ulh4h4eG8aq12rJseDRZXWQ6IVlzNqssYLhhgzGHhd0+x9L4rRlXZrIgbzygPSUNxkSsm5JLDQYqFtRh1mzgbg2uPYbKGPWnvdylyoaI2+y4MRhO5HevnWOZKkJVRrbsOS7y8OfXk++PMVWWb2+MDw3c0Ypv2TsfDHND7lK3ezoZzwZ7srfVqOxCVd1lV1yR9s7VzgocHw8PDFOznMrHDioLIluZXdim0reNCFS7PdR3NOixtbxBfP2MSo4IMVsPsHJPqEpwWVRpLNSkqvc9RWujIszemy3OPZ2ysfA+7HU3cVLLzMcBOAkvKyF0hPWIeV0qhhysmUiin8tonc2FoNOy65csouL7lbRH3xlJHV0R4d1izvXl9XdOyVbZ3hvSULGOufcngu2LymM2FTLZo1udrdYemmgndlHr1jmRuZu87avJmzpWYrgLsHLlzOy6lvLlhGOYFztkeHhyqZbw2lojQe9o2+s0dYJPPS6n6yVCO4jJvG28Rf0zU9t3pZeWTRGGlZ6YnS8+Nzz12G3Qk0RSVEb2ruVWIht82XRF8pl13Ea4X3crhei/xI4Mrsr4m9vsQstWxDSmZvfeGoHGTFYMve9JvVqSV1SIXT+L0T9bgrt2zgsraNnSJBsK1IWmG6y9Yg2bdoF9fB9XdW7msd+9Dc6fcPqu82M/Hjs3e7NuoN3bU68e2nrGM0UnV7lM8tuR6kMhLJF8bfaepTa2ArsGayuqzSJOwNvguzp0BGkFU0EdOK9eWmU5A+qzJLU3MqSjNNddChXI7Xd+1oJHwphL5Pb6ciWGGnLFWLh6KXVjNLuI7cmKaW6qpK2z+HRfd2Xa58SWIIoJse3UxbM3cy28/NFzi7iqZZ3CWXeX1MXyMnG8xjLE4ZsejLV5jFEGpTtEbFiQxArS1L6skNqG8sdQ4UdOuGNdc7L65qIZR3udF7e2senXq6CnXCuDzSpThaen77tqdNvfsFfd82wbrHmCfblH4l5dB4VC8dvd51up7pub7dF42zbp4tx0clfjndY94DiB1KOLY6rpHtP16p9jJvb89SF1BkpmyV1K57w8Jl3iHbc11SfRRTmd6BVA2jjF6487sy9wdmSoeV0R1jC1seac72Or5brGvn6LOPPq2IKzu0NkrQSTWTE89HhPFjLfb1XKHVOnRyzxjQZ7Q+26eM9dVdndsQPJvDOmgw889yzWtojpO9xaM0KnFkzBrvMUm7GktGdqlaX4pi5LXu7XuOXBm8CjNsVLQZtDe10wmD2pB492uLJ0qwtM3HeU+M2y50PF49qXA9qPlC+yCmNo9zGjldFVy5Ytq96PgtVs5LsdIqmod1lzE0xyj3Uhdtmo/Gx4eDV7JOSuFuhZsqGyNFBdU1Yk84eHhbxYY7vuRpzEsD7fzq+YVWH0+S769YIz57QhVBc/s+E+wL5FJESq+nzHCUytrfCxNaoU9v63vP93/Fgebbg8B/NIDwkrurtQdNYfmYYGCvw1f6MMtfk5fgHve9B/MHnfH8/vyI0sifdoPkiE1XFstSRQUETSlJEyaZKUEoRCESAZAmGaCZFMECCbBTMAxiEiUYgDMAwSkiWMSgSfjq5DBNEw00BImaUlINDMY2MQFiQ0YgzMUU0jKv1WdPxW7imgk/tdTYzRM7tyGRUlJkYRQZFrTMihJsZEzNCImYMlhCRliAExhMQEJEEMyQRCOXMihgwZJMNCQE2tMJGYSiImkCZIqWJkRRQhSZlRMeq3XX6rOmBmDGpmWVEmKExERKf45EoBRJUgQAAyRiJAQySM1IkmZMyFKbuuZBhBhQGhMUGFKkMsNk0BRiMQyzRAiCGGRJCyMxgEmBhpBTEMyYSEC4fJflPg80sw1ay1Jmv7NVeSOMnD/EZva3GY9dOkGEdWVDkgNbu0ZZEl3dJZNSkmXuODS28M3KxlKt2rQ1Qg+1q1t1ESYjjKeuy/NDdF4rFa/w1i7tgZMW6lUl9hhqut8s1bs686vW3jGDNvNOBYw9W5uEMRCU8q2rFDw8LqOLdp0VDgimWMadTdRy9VRGleSOtOYHLqZb15e5TyMuYdFmYM2SyctCre3ohy3SHh4bVSaQrBlaTGxKV1Mj2z3CDYKtJK3ylvZDf8NVNzTev7LiZbdwE1ewpCZFis2d3YXKEnmQKM8qRR0mTLmFY6dFZV0URNzFTvTrBxymdpa0MNxjW4cxzCle3eKbsIrU4qat2ZiGUPsWyFDJTTIYeFsu3IkVUK6iqrwHv0fAe4ge9o3F29Ap8Irjjjz7Vgra8YELpM+RRJAKFIOnqQWx7LLVrMuyS1SoXj4y0Vd0/eA8iEWBlc9nnC2qxrJloV2pF6pr3Fty9l7lp4mLtrRtQ5L3TmDW5TZJBBqqo4lupqgiZeuCqKmMw1Vj0pUcBGGH3tDsHZBBfUGcCD23XcOFXAsqrBC15bcZlFpnzWZmSpsyBxXtsokakKd5scFLRoO3yjniitsGjrUq5b185YvIZclVdEEPKO0z6SUHUFkO7YsEasd5jgqm2lgpkweHhiIlES7xRwOlTRS3fzeagyyc5VWR4ZHWYzS6Ojo2ro49UGymkttuWtWGHICNGqq2gsCVObAynp+jZQ3K5prRQkNqtmF2MuJVDF2LQhSgrYg61wsukkJKrXpd4buBC1kTulaORaqLFpFGRV4AAonQS3FpsNi9qYdIIwY9oEaQC5FdjMp+RGkFynrxujaoH0UEVY3YGkBM66pTVEEnarIw0zZWqnGxT01RlloAexOFU6tvaFWJfgFQwv1qC5ekBmtavb1liN+m6Lx0FJTs0GvA5TRCh1ZL9byko7onPQW3ro3q2s3RV1hGx6S6h9YqSJbeR3lyWJRMVXmYnFUpSWL2ApmYno0jBdHMd4yFpcMOSCIZKGmVdmvGylsLsSkCt0SqBkqQa26wiZq16ReqnFuJGHN3JlmY8EDsF6m7t3HKN1m0YiQauohTpQ4s8aibWHK2SEG8uqRirCoIlWUwmrYjeFrTa28CC3R4eCeityHJWOXso1tDA5cSDDtXVR087dqGxuncBLoxQQRinMrFOpDZeB5UAZ1LDBubSpu8vCXVsbJpYoOqXqQcimrXjlFsHUKjem5RVOS0etZj4NVHkklXoq6KeMqgsJaJuHHwx0STQeTdYWww3hpRnXQpUHhsEU5RUqqNiY/f3+xCQAT4+I8QT4kDFGGyaEhQoZkiEbFDMwSZNITEEzZhIySGjIIijKMUikjGJLMooBUURQSTRCKBmUjMgJSKERkZMhJRAbWv2rsJgmzMxgZfP+eeQRSBM2FMEIFJMDCRJmCYJmNJZA0BAgQGNlIxEzMiUMCbMYpRBgWMoqYJNIiyBIhIkkRACLJZMWUiJAYIlIpTZIhCCwJiYjMQbMB1ZxqflSnCWYrUdfflUlLr9IKRZMYTZ2+e5na5BlxrTcNrQU1BdxJ7UHh4G7HZ25YN1U3cqxqc3pa5vR3JW6GEMydnSUZKdG2d1E4CSTa/f6lEnfubf4qGn8q7s1DMheZn2NgN1E8Qel3WXd5tBiEv819A4VXrvSqB1pKdThJh6bdW71+x13XjghyxNjDwI8ZFlzqxNrAcLmQVTvITQkvMfth6aL7sOA2tDrTA6cs7d480yY9usaWbR4hY5xXtITN3K1oPRLMdI3nQFQot5oe3beGp0dWMPiCCSQCGyllApIxCIkIkSfEAk+M7fwhmX2tnEOoRhX2m7yMWZp20JuHQzstPzXMMgQECu+wXe/R0CC/u5YlMu1fZMvTTS0Mkyup0S7yUCxGQzdvR4eFLLyNrLMDoaqGMGxuvHL3p996t6AMpCRgZkRNAobt2b7BJ2onEVBNuYKas77CSDCEdXTDGai15SiC8JZJRWcNYNuygvNbd/P18/f19by++76fHnAlJCRiTYMAiBD6vjt5JI9Xh7+/L4vpe03mR6hVTrK7hm9XFzLDQYrT2YNERKVEQHaGunjdTdqgcZehSRCrgzB2TKd1UqlZNVM9hhSCrewuKTEi7IwM80Z1PSxhE6w082zuo6MphTdllsONF1tMnIFCubjJpA3SDIw9u12ZUxund0Kw5ucITuVWaMT3SeoNFkKUjtioW0rTgUZ9LvpmA9N1i1iGcUb13o3Lzqt1LgaNqqLVxdLkTYwXL7dzMzXleuh2sVG4EapGkFEFx2QPlss5uV6ggcvwJACaRiiTFQZH113ny+nvz5nXk7S+NWo7knbXacAyAtl4QI3TZV46E+76Tx36tSHveD8ffDn9hwusvBr6nXu9lU+0XX5EMlGsIQJHzQLpmvtlt30vGGWGmEhRLnrG7ReXlS0wQCQSSCfEA+JBIPiASfH1B0aa1krGNwRYFWk1TqhXjGKFEhEkflPk+rlAfRY2rJEdcFA6E53QHvDAdIWWnn6YYJdfuqBBBIJBJSGUyDDSUkQIsfp2KIBpIEWGkxkiJEJMMZkgBJsEEUFLENfruiQslEBJDKUhXjkixZYhIyEgKImMJmkEUjIGiWUwgYhMpGGSUTRKGMwmJkwTZZMQkQcukAEJN45CZoGRIiGGgMlCkBGIySMgSSjCKRoJrMpqsWSBJGxIZCRTGpkzDKMFMxZSEmSESQghkQEjRkwhJpCACGJolkRoyYUkoTIoYJDGBGzGCNMNRSJG8dmRJQJIIyGUklqyyyrVqqUtWXTfb99114x9zjOdML9+vj6+J758Ph835SQgAjEWSMaMpmLJJCCR+u3BlIphmKEyMSQC1LVtq2223OhP0ccd69da/2z3XD3lsmRtkzKBvtPtXr0i7tqOdpL2sPR3itR7u9pqNJvdgoybNShptUaqUG1f132ZydBNN9rPVig7Sd3Q9GEVf9z6sBIy5jSjp24bnZhl+l/VdHW0nqrEnMyTcLVh/OrnDMwzMmjw8MBTaYqkC1hubJlwEhy4MJ5I9Z2PNFHKg2gtmr3LNbFo9izNocY6BZh4A3TzGbcWlLe6U87sGrfdzrKV4gxy6+znRGHaSL54ptkitgxhY5rXvDwalu5iikU5vIKvq8geQvSXoq6YdzdG7kIS3HjKunuY8meKObitWbbt1HDg8PBSgq6e0x45t4z1et7mdgbF1lacEd5uXZCObwcltVZuVTRBeSUMzS42TUGHq5sWWZde7tidE4tvu3Fpu9onjJknHet8950jXK330dzr5ga8U+LeVUWiE4JQ2InM9nskCw4ZMqr1LNsGaUd+uSYSGdkl0NuiwXeWTTfHulCYL5Dic8sy5W7qzddnnQqew2S5vOM5e1lvlhN3XNpOOkLWLDV6nd067nwOK41Y1v4ufR657bpnqs5gUPfb21u1CLJjmjN0PhFmS3j6x3PZlvNeyIXaYmnbQnHt3s1bVbyRFxYpi5hkjsqRVm3FbZWrsj4Y9QimWRBY8PBestCtBDlMFDNbmV2aIyxpdULD24DMpDOKHh4JY3qyPFsHh4Zto8Iu3JFvsd63MeCjbgdWIhqiu9ptZ20qutm7eiCCBSgcwJ63NIpIXbBGS9mumEKKeUE/tfDR1PKvlJFctRqj9Z+u/uw71LRu3Gr6oGwK3c2Ej7vq1FbnQP3w++rjWYU9Jk6JZy7Mx1LZ6ncXXvaFoc2oQhClrm3UXU82vZiuL3a5YhFylV29KveRiMa3ozKw2Y3QUqVdVjBfU8PbN4Tb48+Ita9sWuSM0Uny4M6S1VSt6MHM5Sgtq2JJYyrLvxynyRD9WqzHK9zCMVV6GMZVpCiLNe+kvYV9np8RmIT68khKP2bOhQOJVeRjRFY7JVg1Hz7hsNPpp15CXphFKXVTmu2tNx9fMYcuLO7rv1rtPJ8C2hCmejlOchuDnrh7Ie94eFBs70rp5y2tKBy9bpmlY8PDcN8YXVIx1WGbdW+WUaeiZdnzF02Ji3Rqg44fSy+TquvWZmPqiXbmqsSA11j2ZenqPGZfCA4cbvYuTnDaM0dTF3GpTYLnVrJF5ofSAkXuCu6nV1aiswMMu2kHmI8pcvcGXdR3uEwGXgcuWQ1e1ZeCVHcyZglMoukLDLHFi8tiwqlVXV7ictbbu7eUjnYI5fYGQ4694eEIglNnlzhcm3alNohooT4rFuJyqTeVXwvDdYR2HJvy4ak6Wl19iq7f2r66k+EGufZt4U1S3mPDwq8RVYOZqGXUuHtbrBrKjXDGHdlDXdZ3CCTRsqIS7mKbuOMb9Pvn9r1BtfdQKjVwu+v1gu1vdxvO+bHWEKzmGkpj7nOxNM7nDDDBYMyXlkfuxhi+d6h30t/Fm1mP6yXncY9mHasN1b66PYNXnQ/jvvqc34HbnWqpqnJasT7dFZKYL4iSamDOhFddaF3XSwaT0116A1TtnIlS2pWYJLLenjiLfPeIXYDHVKrBoM0kW9dXIo1IE6QtuGG/LpZ0Gy37Mozpq/TmB/PUjPtHVPsOXjU0S87rzTeK6sXBRgyXeSNZSaXPclEZVJpJA0qx1M2rDdabGiCYz63h03j0Vvd7w8HMBNxs47snG9YophWdDyoKbQ5PV1aW9rJQ67u1DWzm1JDVdLGItTN6qw3b5HOybBgk00ykCTbNDXeOhizMKeYhCjFOE14Kl7rzWSU6N0bl83dynPqHXDJxqbkrtvMqeuBQfCXeLc3s5iiY3ydHldDKXP0OCBby4E7CHTzLfRCUDRwrx67oy08QqbNh0w7RBiFVElpsUiW0Ucpkb1A77L0XouuMrU9Mc1veqC+CcxVlZmbGsrM3jHI0OplcrTyQRnl1OQ+VR7rxHIGPlnZed2DAfZLP0+oTKHC83p3NPD1U9mBGtmOnjEFvqWDLDb9feJzKgoHsuuQiV8/7qVqX3w7h22wmbMjOZcJqT7NztQbys/wz7klhd0lH9oRSXL9XtQzcNH8vt+pzB2bM63mbHtZS7qq8my8pjOHOHpbuj1JvZbF3SLHh4dnZbyjePI3jFUhNU9ZkQfYM7UQzcy3otgwKYNV923lhlZqLOMUEqi1VzpXBm8XvZu7lv96PsRT4RagPpPgbAjm5YyVbUwV86uTDEkc0EOOKsGbdHqudCxF5sc7wbBrxDVm1Zs3NoCTxfb4Zke5kLo6N3zgzKUvcFnJh3PSFIX7DXGSiGs1eVHa1ycl/b+wn8fn8/1XP2se1rfveSDteaedUhou191acNM24V3IkBtAgFiut28a1D+515kgpG7D6gjXe6rdmcvT7CaMtPEHULpFVMuutfdIrkhLafdbYt6LLaGPTHMEpG2HwnKUd7UzB3Uc3EVCLzOGEUI3Xa6fSPZXBx7S7KraRbst8bxF2UqxHayu7K3LwToKAb6xUkF4aqVVyRbgj0Mt1rvBrO3RiyZejCczevhmcXQtNQ6ug0twWnZx3bt8YpTqhNOS+HGlVisrFqwGca5mnvW4N7dhkpkLzu8nbambWa8eS5dRtYiVbzt7aYnTobEfCqtkMx5eZhq9mt6qq3byEVb69zc/m38kZbp/GsHZ459nxEMCwWTmNBWoowZaUcZ9xFwhmMndRzBWS5VmUcrKvkMxmhu73TcUvbwmGYOEBHh4c1lm0RmGOx0zmttiBS7rSLxOrltliVhrYjnRaOnW+zTVd2kbgzlmXUJDyR63I3m4bczVQ8PCMN+I1zZDZu0C1Y16+zizxnG68PAZwU7pcbZ3jbzQx4eDmg4uKlGTNUvdgjDX2vVPvuN19kguE2ZQqbyOZYX2ag+i2/se9HgWck8kxDrGRyr4Jb0Eok5dXuRZ0SZyF6Y7OKjoZ0Ur3WdFdFtnXTYNXhOqrJItd8V9DxbHdDSIocXeLOf3X16GOL2Sqlg2VmKDaLzenvDwarE+lp7U5VZ7tE6Dmd1sVWCg1dQ8rdmSuK3as9C3mRjtqV0qusSQvyvI5qoN33bVRHaoOLzDmMPJbqk8KT1hBJOkIMV5GcFqcqMKaBsIpagUSXpqpq6TJHaM3DmtVAb3Mq8x7E+izq24bKMVM6OITNOcekfvDw62LoTC4tlZmtneFOJcL4YNO67wYzYblglBI3gvKJa2jokIN4bTB8sC1Q+hBg7aukzuA7LrmTp5tZ3WELQeSA71R3gNNZGdEDHLR4eG7etTO61xHNbNresvqat23bL1pVn0F3K7WKcJrfvqyxfxx/OdCdxQbdVCqVUnxqQgyfLZpqatr4pixxI4J4msymY+rXgchJtCauMybSqgUnwRu9ktU1u1oePqgopeyuVxILNaQJaWUNg1joMXK4K3d3Bi4tino8PDdqpMadLKdnqqCW1VGmkRc5XKLV5zLindIsIx1Tj5g7eI+xoO6PbAU4c0Q1ZmZbxO63Bmy68haytMg3jka3fNsiiq8UnhXY64OrOLUGbfN3cXJt3Ursx5WS+cvA6nYZzdsts+zMlsHA+mYtjWZ1phIWZnXTuW2TQKjw07IvdG524Cg450yb0Eq8zehw3u8ejXLcyT0ErBOsQXUzE0oPDwx1UzescCPDw43UNzbS3BKhDjJvIxXRA3ENV7DEtztJ9e9BkyjMs1pcmHEnCx2Se11SpQrm9LPe2mxWPIFlOKwyj7rEJqtqMeHhqoHEG0LdHLmxatE0I9aT3GOyIrDYJTiuoHebssctruW46nRSsMFN3grnzsLq0coJigq7t1MvRPdtW5uGsqb3TMSWPBBUm3SzKkjmXd1lHKU4qtrWuagS1SToh/A/f9foT8vK/X6f35VOL9Z6QU8ijdVIMtA7mS9h7OvlNg3Xg408p0d3kO6ZsfJ6Xt10tkaVR/ebUAhGHtWSs7GnVx23hg+N7c0duic5uULmVvYUsy9Mo43MkoBFG7BzkHltOY6LliPGLfZuULwPHDnqt0MoIRuXM3Zgo3owrGfeHhha3DHqqApKEMnWq01IuJjLtuWLD2Nbuvu9ryxQlDJ1qyFZslcxWQUbNWnrKmXZ5SdBlOxg3Eg3lE05uZE4RZxLngpDTLI0c/XTl8x3cjzejtQh60tw1SnVg7iCXlodOLJKtzt1lbDqa8uCrelFElLQXOVW+k3pOHbXE7w7HNtwbmnc6d2vBfbqO1SDGyzBuesNARainRQkgzVcYrVo0VsfYmreUtnLn2VmPrB609vXbVC4ipIXQXXursO7r00YMyXlA2UrSXEOmpkYrA32Tbmbx/vFbhPQdxyZWYRKxFW0PDwdqnOZVo6WbPrTYMjs6CvyLYqQX52Bxg8wer13T1zR2tj66stNzN+j0P7eqd1W9YquvMa3cqS1F1UarahvI5u+oGdrYPBbKfP0l8cph3qVu994eDcoXJeLFHMuyDedSax9s2+eHbLrWLte3t68u9OUNe5re1rkoTbG9lRxy1J81C+Sedyj++NHr0Vz68pMjMhk6sVBt428685PNWGigRmYcNh52VHmmtrd3dzTE0MobLDKC6IpbWK+1zN1Jt1TVFjYMH2Zkx2en3LMlY9LdZMNa3K0Ebj2ZebeC9IvN9cvRceD5ayjeTomFWi0DFV5HzFtTZ2Vj0G3xeXN4zEejudwuy+nJ1mzWqx9t8bmZN0uoLymOUyesN5S6h3BWUsivKmk5Tn6f8pLx4fz/GTGsVmNRyZK7tFGHysfUP937kPyuRi1aiwZaUiwGxiImaMiRiiwzKKREkrNGZGl89zTA0KCSijGqzMmISEyTUn+LpKRSUxkRIJgoNkNSJEyCDDIEIgiJCYFMaaDDGihqTRGTNIT6rLa6In6+rvGGJlDMYmGQmkJBkkxUSRklI0KSjJLAyEj33SSgSlKMKJlCwpLRDJkQ0kAkzYJiJEmNTJiwyDEIJopRiZJpmjMxmJERKamlCwQmAZlEyIMYwTxPv4aoH37z+HywWl+V74E47lk4zUYrpu3GsQv93tmyMYZeyFhbtCVjzHaW6FpYRaKc3FVcOTRvbum+5lOxIZ1qtgTquzNN4LoKnl+3BSLm9ezb6BrFYdQvH7OmnYi6UFA1kS1EKiF2Y/FTcrYedHVGgIIH0TeG9zbx5V1xXbkE2vPrlPFj0dMblYKuWKxQHaZzK7ap3w4dJSjVMyYrOTZpV0seLWR4eFZIkMFmU83jtBRnSgrJp2+IkByFM7pmh3iRi7RF1dtDlFokkzK3ou0GN5aojlmG7IIq8bVqpcxv2ZZrKJsUud7xYnWXFmzA500PYmKvVFv9W39g2181QUnzwVEUD9lPNr4LRtYOzaMyLozZa5915ZXPlN2n1dfPa4b0dQ7zObUiyoq6lZs4q0V5vE1Nrb3kN5SWVbnc8fBceyrVp9MOb3DrZJJJmVBpFDMGZkMwRiQCRSNThxYcuxxw8oK1qtwZTNzMeEHxIRs1aVCFsMnxNG2E5nUMlsiragtDi3S2ljegp1qW634aRjThb0ENYncclbS493LYKqxxmYNWzll5rZol6+q89e/Xed58+e/eSBFCZUxQp6XTYqqjvUaQl7b3Q3HoRJJprSBQLR5AUD4kE+JPmMg17zpp2KTGbKb9VvXj9ZBIuqmPs94eGY6rde1bjzwP6KBB8GKSSI2UTYSUCR97+kEAfA+xW8YZWN/k/FFTNG7xVlMs22fw5Uy3TkMwfjfSzfarvCPDwuDLOdtDuvTCi5U8jKPHDnRsLRzXctwigduNXsvJtwoNRuvZeiMaIuDFms2rR26lMK+ET7G6O3HWmrNMVAu1x1MqJ3Vt5Wcl0wY+rA1pVoKZWBM1ukrNqrYyEVkDo0DJpGNp9bIl22R3QUqwtnKFet0axBluKhvU800cNmqGpU9kt8w6wb2tNTdWjaJMKrvnC4736S2klYbpBU97T8aFCTO3bc+qXSWbtfPCIfrRr7G2M9urPn18+/r0+/n18VETBIFGEkASSQfEHwIJGNkEWV2anu08nStWPtvCL55yUPgQ92CQhkleJxafeoAjFgtahrshaHWcpYvEHrOlnxBJJXKryYdNjRxcVyyTpY1XZitMEEkgggkAkggggnw8QQCQSSQ1pTp68ccZeUK8SvlRyZlEn2HWi8KDPKpuUPithx2xsrTKDi6hMobICFfqq7sMyGyq4S468SmDwHjsIUPrRtxnTG5V1KG4k3vCtudnLx5vqGuI8+zCna3LG6NUre2tl5vDdwGOvHh+qguxz1VZvdLnXGW82jMatM+t5Ax8lYuY9lkPt2q07uWS6DO7hFIFuK9SnJ93RWyd0y33MRKbR05MLo7uHe49WVSdAHItayPSZdtVEmzbSmZnS6I8PDU4wVq3Dtdq3T0d97LUrNzUJHSaeNrqth0nusFpJHHjuRdmB7naF+KMfaQjvxCLHwxlKUp1MZjwbvw3qM63TCXVnYnj7XV5kvel7eukadMt1rOlB09FbJWYU9zQdtNdKpBZ1CiqbamytQzCsVTEemR5eDAq4uZlvlVp6RZYSlYQfGlgpTBHS2sd+dHmxeOSDSVJTCS7kXjTSYda8MkcqW2I4RsVzGLl0OIGeCQTTKZJKM0ZH47lEkJJkzTRGSBEEJIDMCJoaS5yiUsIYzQxTRL+S6ppmIhk0qMppSkYpGYNQGGEQAolLNhhsowyQSiaEEwhkPdbumMBZsmQI/11z863S1dxpRKCMYhlFGAjZSKSUtI0QQoMkwoCIiSGREkQJsxlDSQ0ygCSJJiiyjEmkXW7mjQU2AkbFKQMjHw5p5TdiMBBTRSYQpAYb+dckZjISM82r99eED3h97fyDw8Pyo3+9/a1a6x2dthQae2rchphEsu1RzWgglhrrCfsCxPIbidUSupSXkyVhD6tlNAjC7LrcUOZeI3Ikkgiq9M3LIde7ZMzahM6UiZUq1NWrKfuxN9rtrJVSa6699zVQN9b7FnVmTM6Ybi3WsYfN5PfydD6bhsVtVPvh+sH16M+48EC+Vv7iqEqU6sT57B9a1zNWWj85F9lyA7mRDLe1JgkTF0Fjzus7fay9NHsV5Pru91hHBDWr6sqHKqN4smYpSnhHVNqvjlOoWqz6+vQ3NiFAh1aSY2q/C4CfFEMFhmQYJAxIEKYkZiIzT7+fL49r8fjx+Pny78S9o027FsdjtvrPFzsoYBXPYrIJBBJVqj4kFnlNUGvsO1vJ5e+VXFrm4uqhVpu2DNoUAZdseHhL6qyWxB17BFcLSI56q6DE+0EVkVafE+BJJ/CiQT4g+BJ8SCSACASSKJ1u4c2c4ZhYwJQZF9zwTRh8r67YNbmkDSLSxoNoY6FNUMdzM1wInQWEqVuUGCRr3blm9jZBGd8efPv19evh5GKSRSZDSShAzCYYkhvz6+PPQIj775+5zHD7ZzBtde1qkx0SM1nOTFZnagsd520TW5Qe63cPrOdjzb18ha00OGSRYQySXOe6LlHAl0nBUKRdPpSsPZkC26VS5obehiNS5tvN6OtvKoNB9dqt2s66pQ4wXedCMUoQyTTKLh6UKIwlT2vXhdyeYV9vdehg9CZoy+Hh4ZjlmTsRfbe2d5RJ9Exw3jtZzSiL1E4UDM43NiUWurjyB4uSGVVPdFy4G9usBeK0psOeOW46yhlkdpLp6qWKYdsSIBlxQnCcqY4qs2Ntv21DsuaCSSSSSQQfA+JJJBBBBBO1024u3Ttvpt2E4lU0jO0adq7mQVYMWtl2QiTGsJ7BeXDiDTDj21IKnuW0IrnWLEUvuF2NB89wVQ0MeHhKiqnZkrRqN7VlR2uYqjMebojoT5+/b49sYTICDMMDMID4rsRF1nCkntHaYOPS5ZZANvKRGR62fZ4kHSNx0PDws91aOGeeYdgUaWHqFRSFzm4lHdQtQD37dEGf4/7Y8AMA97UAmBJPul/na/s81r3fegGvnde08Q0TduMzZbvrr0ZZZ05KrYCwm9MMo369e+u/iwLMawgIqxTHOk2btLoQiJyXRBRl2lbd/C08YNPRTEOXMdrN0eHgr/jFszc6Y7aG2XWmnhtizcFUsyEzE31VI+hYrDgV1ceyoGderM7CtlVbcOi8bDYxijL3FDFlMH2Mdox9tOkFhW7KYLxQYZYqtzSnsvRdZxjwZqwmzZ7k4rbuLd11REYhU0vrXkk5UW9Osl32zVS9QYgsRq+t8gJyQpd17smIR0eYo3xFbi5um+uFyDuO0plDgtXMaM3e2Cs7L3LyDXaQuBKV1mi3jvlzBxnZKOSku2EsGu66cnDlw0aLGZYqtCDBTuMcYXvEcc3o+6cYqHh4LKfSAyaKQO+IHmod5yELpkuC1pvyB4FcbXBGW3HuXurarH0mGR5w7qfVfI9mjexqBlrcvWu4VRG6+FjCdMLyNqOUd0gu+uuFjembHFY8PCzmXWyHQj2V19s1tTsVntey9FOOcqMsWCJSZFxdeGmEsF8Vs1YdM6TO7inWVadhUTdsVvKYYu3Kj2Tb6VO2gmO4dcuZiV8BLNXsx7RaWK82xtFOPzB6xzhV7t3xu9jK5SnkN3lHd589LTZ3L3WqJ4wqzl0wjJrzWwkc5yXtc82mqrLsVkiqdOmbYqJ9ZMwJSklILtYCx4eFYMo9dntStog97w8GKx0psJI3mDMmoXz7TTSwWzuTcvtb3UFnEIQCOh2Xmms49aEk7Hfa8MnbQy3aeayLRML7JzdSS09lDNqsyjruwptBB5jM0zxHXUqxgno6edJVs7jmHt3tNs3eDcLfumHs6Lx08socUUI84DScW2RmTYiVxUl0kMQNjH1mVdzsunnXXTZSHh4cvBa4pZSmdjwYcpC7GyqOW/GDXSjxtZmZka5psLOQevT2xwd2makOEq1VYJsVXyPVlt5iZrQeqsznRbdElUGGpzpJmhhyLShukeHgbDIhoneLkAyrMMeevqVbj2GM9Y5HmsTNZjFuOG7j9VYChaEqZkmVemxmr0WZFwxZg4EmxWTGjBvbOy2Abyry7mPOWISSqmIXRWMtXt9nEOJTRYxmG68Wr3APWjWJYG8Crm7ul2Rw6k062zuMHrbdc/3NmJtbtK6sqxu5iP1fbMPo6Wq0O0bRP8PXnYVdd8pPjsIW0SY2/pdZlY2u0VL07vYcp1fDry9HgE7hcohu7D2zmrrvmjNmyzkrTLm4t3BfWra5boVOcz2+11DXvusULtBE98FXYmLfyGQL4x9jQ21FxVh5aZlKcKwwXTPjUEzdzTpq0LzhvvDwJydRN9JXGTOFq044WOu9uKjbJbuFSngN3vpgEsRmrxA8ZlyWxyc0mXyl7VAx83bR5DTtrErkqCVfquygXevHZHYJimupZrY2ZsLlSUQlDo2htkR7ZVSCPHkT+enerh3CpXYby/tMmN1RvUH9mPKVmanhrO6S+dZ7s0rlYrbshjtKHac26cOZgjc04N3jMrRi9iFLSgRbkdzEY5T2GRCbQdNMUeuu6qNI73S4D2SblrT044c7WhvNrRfDw94IALA1JRKJRKJQN6jIkPTBgsgn8wTZztpj9sgIbwSSkI0xnG8tBcim2aIpDbq8ViTbvF8WlqyWYcZExhJUnpVUtdQq2b5DZUa5aulCCrTF883Rul02c2IUUn19uZozyaCNEU6WOmgqLewnKt7gcNWXaHVcdVuFTAhqroNetdhe4C1tC+eUsfP908Ng5tERp1dJ/QJJdBGDhbHZHFK1GjmUFhrGfqpE4XXDgrGk6LG+nEvak6Vr7G8nV12+NGjmYzTk5zSjUWuisr1B1qJ0OEw11WYCJ2drqMAjOoVmWIIdEkqojJ2DLfmaMUdqdnnJID29rlriNxXB21mPLqYzc1O+QqylbgV1eZMdimc0YOiap0xW5QWCqkSzIuqOaEytO1SdSrRMcymduEnxL1K4nT6MwnbvTCHdxUuM1SkGhVGTKOS2Tgqh23b5TaJByHRwT7uTdSYoVWGG5tXg2z0dUYw70QncpoXIcc7dUCuR1eVdpdPY8OsUOmNO4hceuYDfci+NuX2XUbvHtMwWiydouLKVs5fevepxmqgOBrCZdOUa0ZeOXWLGEjMds1G2vdJm5nXs6rrjz0mlgeNFFnKmydUnIo9XL59yRVzKzl8VW3lx7PpLvG42bhvavQSelwdtuoqVRdgiuY6zpQajIGyPIpaWnddqlMEeZuFKmCnb0Grjq325dRaWBsmJUqq6yjCI3j6M7SrDA9E1JP2mjUrPbnZUOMutFYDhzMVSZMlZMBlJqz1OLftwaLwPPjfcb25LLNfXTvaw5m73dUeTOeUHI7uZVR52WCR3bR3F2KLnOadGlRMGorSs93Dw8M2duXy6tbPHMw5tkaNeZiDgi4tulVKUhGpapbRObqq60jNfTppuueio2063REuG1FIYpTnumGqHWDW3w2LS1DMUpM15tyk8Itilx5kq0vfO+fNczVr1O0+aqZGnbV7TEar6xEWrTu/jQrswfyhldtdLd1VdTzg2T02Mimy3jbxEUbIXC1znQhPNm2Lw53lUQq2EM5diGtX2aba5BiMc6/x8c02R0h+YYrf7X4DpYtoSui49lE84/zkxt/GxyXdnib18rp5yWUrJtLuE4wYjdazs4vBybcwzBiW1lg5pFvrst559reiArL3LuRRLCL5yMynnZd5pooUt2bL29tjuzMxrC5MgOF4KpRrNXOgcp+g3dXXpGndxu9gNMxkS9MCG6uzSandSl73IabC65O0EKKHGV3DXDtPo9lajOebZdl05s3eaN4Y0em9MtiSstVczAiUTvXqScCS1aTsHVsPSXu80zlxtHrvjQusvSTM1G4s6g7Szmu1t7JZxbiN46vZdr0jgo1fNCOC8zptqF5W2U+Wli+rSNxVE6RfYZvPlOGhXubsBt1HpC3eHbQXasrOvuObx6becyisTmrrDmq1Hm7lYkNmVerczUEHNpk5mZLvIJAksuxlLgdgN5EZNQzujV8VU65oWu2YttEpOE6GjTfS6NyYXEvKrHSPZULimuZgDGrBs4hCvsdc+ZIqaQSbRPYsQRhEr19oyCQupr/r8vfs2u0U/E9GDmP4pqxjF9zKmt9TKzOjm60Rtbj63Y8PC3dk0DFdbmZ0JRi7MMOkVNZrBbF3xzXZi7kd2cC+Kd80s61prWr2nzZrcrtW7BIw8WYMIrK9trcqG6QgUyDFzHh4TIZbv2Qjw8OnZ/PTAL02Pjpiv9MUGfsLdCh+dT6wTarGetxD4YxKbQymH3ZUug+WKteKdevzTPtdI2r2e8PCHEajNsHtHc+eN9LDvVd1ZTJNWTW82KOat28WK3nbky2jmynBz2cOzrDWkPku1CF4X2V16OStHehubZdCWipHK5XM5l7Sc4VTYrupjcOaDl7dWgnzZdQXV5NYg6b13Ku3WKNNdgg8PCtZBtm0Vs2S4zoKIToybmut3SMEuWGaI3kITznM7i8PeB3mbyVUOHzm4aOXlMGms2c+0Mi6bBTWLab7nPpBX270b7Oa+dblwBVM1WDJS18b3avCc043hHKhmF0H328euaS6pjGhQgjvsy+3N26s22/i7FnA7uXWJdfGGpXSYFujGkYo5luhWZV5uM0XtrJxG7C4N4ZHqVbk1Awi56+gredaNtsqlmaNkGC9NI7WSQ2nXEa9prqk1b2sfN577Qe+BfVLuKsIifCslRIWy/kDaeB7jyzuKy4gbTr2ceM6Ze5fe1K9a6CWuPsnWJYldjSzRtbM0+Z7CZZmZw4Sz2Xv02t4OBvn8KSnNEWtYwv4Yqcm0Ntocx1zKupo5NzOYhLkOERWkgzbM1Z1M9xysyNBAtoJHC4sXvDwuiGsGeyhlzha10OFurTkEDTSM5y90Ww4eMpGj7M52RcFw3DmDssZJ2XjNvqzbFAy7E3lBIoz/n+f5+cEhL+/X5YKofkkCsV+fqsY34qcJuQzpVmh2WFky9OIjul2y3A9GBGDcN52FXY3fUWtVbbRtTdQST3t6U8clURNuS9NaCx4eDDD1BuZVeQLWYJUMS5rkelVnSlsvma0vUNzSFJMTwLe4J0N3lRo3eVGakyWrrrZguDewZtnBoLsmlkHc0ocHIKSNurl2KwvbpGnjxjnuDuXWcQ5TO7RxlDXmWdZbCdUuIWtDULyBfuVEn9bJi94eGxfGqjoTPoxhRju70zfoxYyX2KxtcI8lM0tT2dhrLi7D2hZtqHFzePME7Lcds93ZOWnqEsR3KQZi2vavq7FN+2jTNTfjXXg+msWvtb41Uez6nKyXs7otvr6trrZL3tEUerePZQjMx1pyOumXKq0m9YyVAdTYjMUzL8pOqnu860gqvdofu3BHQ2xb2IEuIm+MF31COQ244MzB915lrQ6b4X1n6kjNirdYZ2rW+z6FqHoFnKKu1nQSzMuoxPZHLupnEZclxhDIw0natwV1TMBJmXvaDeot90yqW2tp468zAszdrS7qt2XZbO3hscDk6QxXruS7BgzXbdujU04wq4UumDcuS3vHdvZc1bZkNUsBb2bUGdbnVuC7bLzj2WHN61lQuuQrSoZtnx7nOut0KTMDvHe6wrfdzIvUTp3p1MOpgq3uJcUi+dY64qm7FZL4afZblXGDrTN8uvsu66RiLX3TBQ4qydt9UYT2Crw5mY5WJuhVzo8dIsZw107dXt1xkh3phZzo6tLLWFZh9XOAg4SDB9OYkq9hD7PZYgcYjdiFZ99l9h7HKQvEsF4KyLZyvMESVXRHXHJH6jyyhuypjt1KarDL3MEyhV2k3jVMxNzFIu+InxuyK7tgk7TPrz1XmHdRC9OorVcicVRm/zQBYAB/oD+kSRsefrF1T9ZCTdaw80q172CcUx30RTPPmhBSove35x7aeLFT9+LRT/kI/kt/zeM+KKwqRMzpWXhLVWq/WOaM8PeB0+8PCVzoXLzlzx5u7Yo3jhNO+vd4ybNWdBdanmaqPGKW6Ya457bd9t0yV2hwHczJRGbYe6u0PIs3SZ2uA9wV6zabJxO3nDht+rrthibx3MxdG7yQvJ0NDLmX15nb4rkdWss3WMeHhS3uK6Xi6lQuTI9R6xei6IkiDwhE0daCezGuN9Euyueve3tXSs6hjDBQu/S+O7v8/z9VnIPzqRqz8/yZn4pmUkMKd6V0iTDJ5S+N6egRGYXwYN47eKzr6k67jL0LOi3e28V6zSMy6J2M9Zge6oSQaNGpImY9qNN9Yp9nKsJ0nlpo1j1VHz7KermqyKlxq6ijpylla4hwiYSFPL7tZ3pwxSyqxRVnRTs3Bzdas2nTOaF1tITixzXMvMVZXKme2mSNtx2bEssEyq6oe5uoyu15rKHX3qJAPdgSx1WURl68vSr7lI6Te4wXpeLtF3i4eHgrE7MT0o7tC3onE4tM6+VEs70eslEt821UrcnIWUEopebe5TDaGMbuZOlM9NpTE5E8ea4wlj5CWFGLHWdiXzv5Qj7rdX81f0qO6fFxQyaXW1jwipdNy6NZUNU9GGlqSXx2IjqoumGuF9znuWLsL16H0SFwbJCD9K3ur3NSfDfhuLBtA1oq9ZyfXx3tM2tVurNozJGcnF7fRVNuwwi6Zxo2eLuujNjRodKbiLgo5u51ysdndF4RHqy5vGYTFLzr6qGuHkeoVSdp9tMibdU5RvHK471mp9dW8+OGNFfcvmMkyy+0beStU3Ow7zK2hFtnkINuM1oy2zjKdDNqhhA5Sxm3BQGGbjPZhYmF7BpmKvKk8muuIOEPHmrLDNhJ32wH2i7oJRQmx4eFy8CCOvbCWqkeoKK3k7ZM2fdPT6ZvCCYKmOfFpi9SR1jMcO19uRHRpVylW6LOau4kPFAW0JndD244KnQalsPNzbA3CSabts3NRi3cZReb1VCqIod6ltYcK7oSr3FNyy6fs0WYq+6TbE++jtA2/ksI+soSJ3LZ4rn2YOOW63LCePL7azt2pTeVnnnbPOce1guceRjWHW2xZSpXG7BSc08ehVKGsd4DMwEu3rl2wW53LLYRNUEaG5gqTdnOJZvM1uUK3Figo5asZmOKHBixF1XOm93RZPoRypN9BxVac3luFQROmQtTnTKllQPLaD34/DTUFKvN7fqr499p+CaMe2+xm+j1YOBGBuDFe5VK77E+02L4NuiM7dFx7pGYNmcUZWGmxRhuzG7xPMqVw05BOGjr543RFZadM6TL64LvsTfXJ0usbzacxZeVQL3JZEkyU35OPZu5RO5lf5lyVh2bJr+eCjmV9ahyiTkuShU5W8dsLCRl7unS8B3OBkWm/S65um1lq5ppeJ9/SXq3RoZMRiCIZECkD6oX9mn4Ohghcv9MOrYsdXOeKsWaMEP4cjN0C/sc7aYvYeV184E6GfGfQY5267llRCnGpnKYY+emyTVblVWFHSJljphLy2eu5qDtzUWlInSx104y95K+6h6o+5a4TgqlNVOZs7MdmwyZd5aT00mLr7dhedQfznBQZLbu8+sXftpncCJ+yZduDpmmbfJA1t6HsPKDL2X5LmcKQ7WSgcuBo4eaQkR51eqN13ZBnaybdQTCELptOzVWjyoB98/s6uvjU0Zj+99JJzXLzlKQ91Bjw8OJz3L1bC5HKlG7dHR2Tp3WoqyVt3TKdZHXIdnS26XpMe1RrNmFNbhGM485vLxKpeWGSF2cO2acnXb25MrncjUvu11fuzjcJIJCM6sqiNphVQqttnMOQIu6bzcrmnSDjyDrBrQxFafEoR6nSUb3unezr6gltxWQKGR+0uEoBxDH1DQ4+b4WZks3WHSPDw3j1FVzBL1c6ukjd5m2J4jcgstDN7Zi+36DtXbjxnL37j9X29NwLVfSt0V3TZnrdTZT3Tzt5lvr1xM24KNRyPD5c8usVREUJjdt5vcsr3KHZsEBlnXLIqPMqOqku61LYI3V1rJMraMw1jmFzZ1rBMY7jBBDNnDCKptHO6THdRgY5bfNzJlrKQldbN7vbmnMIXDFWH7cmr4EjeTtCCUd+oO9qKxLD+24hlyF5VlKKRGHFlQUGaKiaB3XmWKpHqzScuOrnLIiCzTGV7WDyjePCHuk7vZnBkIaTiMPFjq68OcGdOUcdazvtixVRyDszrnFQTZ3mQeSsSY7sqIm9qPTnNdLru3pBywlHLmzRjhmjOierO4jMlkwUoNmQkvaOu4RerxS0Yil3tS+XwWoU1938aGiPtK7zvT4lubmIeJYtNHqztZrtSb2tsa1tPf77lwMc516thrjVBMkLQKghHb5zyaRb9AjSu+8uXkahzbw7M7Pp38xvnDzVZwl1bo7MSbz2Ii1MCnUR207QbZmTMYfd+NE7Y22NRwJtVrdvTjvPa+26oywwgRWmBbBMid5Fp91TCrV1S7by7lK4tPeVijlvc40lPPEuGuZe2fdiLcay2zLUQVYSltdW3pmaHSKVvfV5xh8Rt3p3CsM3GeBJGEkQ9zi84YJX3a4S3GLjFZvtJJAeriSA2wCEXebkzMxxsXiwszWmgdgpezurioqsFJ30xJMyNyLUseblGGBBR6d0CCpRuGOPCB7uN18Z3zsyTN+ScElUEKoFSoVCoUlSTRhDCKBUSUnMnP1el4rF4IZ+/XrYu9zfv2PcATzTIQ8eFc1XFvVVPdx62y/atNNHPXzsJzUp04tkpbatlKRmINL++uSRSCopGJDM0wf6cU1JQMDJJgiIihkzKMY0iKZikpMEed1LCTRMzSM0SUSRmIpMRkmJIQCJJKMkyUGhDNrRpCyYGRlNCYkHVtanPr4qvLyCKYQWFSlMaFIsQYGIeuukIiBMxExEpJBEkKRLIkUwbCSRiMmGgWcuwkkkMNNIpEKYDIbbRDIqRRkike3IZrxXEKBmTKISTFEaQSDEZAkYzQyKQhGgL1WbWuDM0jDGkZIohBMZSHrtcCM0TFME2LAiRAUxU0taDCCIYxGyG1pKaAiIkogaDCEoRQESYokpZM0ZMUiJQnLpAIZpEkiSkhoCRoYERZNJIxEUokopRYRKREESJCxIyGMJZyuqEBMskiQSBIRo2MGkoIQAkhigkCZAAmhDTJ+O7Gle3XOEikJAgYhRmBiQSZBIFJEogmEoYYYICRKCmRSNCBEsgxUUBhNHOyQz123SA0kiJQSMgZYzNrSDBGDRhJZpRhMspKawEKGPO5REzKbWipkRtaMNgREBRGGSlJmJAgiMpIyzZDAiQxAgYxgEgZSRLKffXX5vv+vPWDJfDtMYN3dCTMQmTJQiYzTFkRpIMgQki+euiQYMhvO4SGRDNCkS20xEJGgjEzzuxSFKaIZpCZQkTITMUBmEimYyFpZRjMW53jsUiMlCiSUTCaQVIgMpNIsIgUjMZSI2IRCRQTUQEQIwozRkk0oEaZSkRDDEUpkmIFGUhSgyUwjE0YIKYjSkCVBLGgGRohZkTKICJZBiREgittlqlKt1J/Of3Fn9bTVh3nhZXskk13QJphi2IZpEUwwDEMMYX5dMxiaJIwiRRLbTNKRRp/rt2yIxQlrQNKMkIQiYJSREQRkWUmRJDMjTQikmMAEpobMYTCbCCkMspslExEMxhkiyCDzt2JhZfztd77mJppGUpCCEMRBMyypTElEAQyTF666JgzRkifu1puJgSi3/HtyZExkxiGiM8c0skohLKIp3dBLeu4xUmZJIikZmUiNrSWM1AYJMICYoBJCMkACiZjJhGZmYBiRNBYpCmWUBZIzIlgaBtaMmGPF1GSGBopEhQaSkCMYpsbu5JBDUwmTMQYTNDMlL39d4p79+bwJJ53MaMQGllI0jUYyIkSGIyaECIURpFIjMRhN/n8+/PTP63n+V16vdfx+kmfzs1f53VKCP5X38oQisurZ0hB/OvjnddtnXuc572m6kjHGQh3dIewMyAAUQRAYV7wu+IvjA7YVmIu+Kmsqr6w6tqdWGKkb11UTfdt3ppo0zEd1ArkWsAKFIJCBuNcT5Ng+CLAtF/PfbbVppp31r3bOYht8cFq2v7cWqWrLJshGiLAEmQIolJimhKKUgjQhFAEyGZMk0M/zuEmRBoS0ZMmlJEjzromIEmJAyQEAQaRghNLNNIhQBBAjGhGST3W64pIQlEsAGBpkh87y1XVltavNdopJEIUSI990mg1MUESZHvuQxUUZjRiTm3SmAxDSZLRolhpA0sRMxCZSpDRmNBzVbsKUc5oU+lyiSAhhoTAppBITSGMhAvXcaA0pmKUweuulFSbFAv23RgaBsZIJHruRXruil553ndyUoRGCwmREYyXi5KiUSEkRTEpNLSRBSly6JgyEUNMuckwGEaRHjllGgYslDNEaJIGRIIMNMiDMYZJCNIySRCgEz4rdXx+vXiZg2gkMZjMxGKRBBsEhkJSSJZKKZkgTSWYKSYbEpGIkpZjMIaGQR7ckwiwSYohExAjTYyibnMpowYTREkhSpZEiZEkkgMIzZEke63888k8reK8rLWpWVqeAjLGJQUURmSMGPToIkgkZgaTGjGFIknz10kRCkoyMwI0iJmGTTESkyiSCRoZCJmQ9Zcmos0VtKmEghtkwYoDJM3VXckiMSIhGTCkyAlrZGZjKyCSJW+95q2/lmtLd39fVvdyviNMzRERNKYZQkyQBGEiNKGQimYNBEJliSIgUiApolNEDIyU2b57olEZaTNCCRIiEREECJpkoRDKjKApqMANJgXNcJGpMJZpQCoSjNDEpESnrt+b/LXpV9aqmKHEA5SpJUskQolSpSBgTCSYEmBMCZCxX7i27W58z958797hOAE3JCIWjCNiFJSVESUlKTnV0kkkam1l5wNyRDOImjG7nbtto09/ch+48faa2EOCUKJTO3jeVx441rmk4pvoqeEcI7qK/jX/jlsVJYAoRJGwZP/HksTIyIkMso0ZhE0N9YBpIaVakWzWGKsiy1VFlMzSmgoGZLKiW2hLBa25ZSSEQEZGBhpQQSlGgwJ3Xc6CjB3cmutUy13ltqtakIp/CHhDvsmvP72v8fsk2/CfgDiBUu4KusSb+zgAWHQucs7tS78z+gQbpzX61rd49rW72he73170gs5zmee3ve9797hzlud5305fuOW3ju221e6t7V9Nzfe9r7fjto73va+vOH7012O7i2um/X7duW7Pb+5yr05POc76M8NZrunO+btt8NvzVe+4Y5y/Oe9HM15uO99iOc1yOV77c75znO+jmd7fvfY1rm557W6Zz7fY3n2udz7Gu9z6+vc97G+etrXb4r72aHdUmSkX84kCEC4c9mnLci1u9v2x+43M6dyEkZJ0mGiz6ASlEkkjVNyg125aSWASSDaMdq/uMhmZgtlpz+/Y9ic0nWvOgl3Y/Zy6XyKpZcpRGSMoAYvPz9/eWr5+eheNTa7piI6Xm+9oxMwIS0gQmSBMs6BS8wI4JgtLDRaG2b3vE1cSALt00wMrLzUsT2gVeECrhAq9OlIb/PYiDSIgsI5ctiTVYhtPPvv9/VVfOqva/X9+XYcHSdMcIHD7peeLudbvLnSvLzx3nbl111w8u7zuolIby7+viq30ttL3e/NrbV8625vja75N3diu3Ya4onZdoLL3sEGnE67juuuRGMYYxhcMSrMN9pAw1jPWkhwsjdRIAE8ulaMkUQACm3CZDgABjDkyDgqUJgtfxLeHroe2h2+D4+O1z0dTJRR839c39vjfzFttvH8zm3u63lIEr2+X6632+37f09vp9K/j9vw5w5rePTx/T+n7e3y7z9vz+v7+Oftv458D7H05zbx8T5eL+nw/bb+m/T01+X6fDft+x+32Ob7fb5fx/Hj199+308flDn7X8etE/h8PfJcaH6WpMo4eOF/wvw8Wf2Y9t+3yD9ufI/j7f0/T+Nb5fx8v3537e38fl9ZPbbres4tze7rfYVZPca2Tu93a93q8XN8e35fh+ge3Ln8f08fb8t+/134HPwPw9sML++FyEkk6QysSMP4cOnT5n9mz+jhh/l/B9P4/p8v24H5enw/bfhufz3313fx7fp6fT+n2/p9vb0+n5fL6fh+Qfl+36bfoYft81qPPxBSHR1gajcWLk7fV6sGou92ZutxttRvy4AAH/l/n58N+X5+e+X93cAAzMzMzMzM1sgIvdKzZKrTfNLXvYX1mzsxUem1c7OF9cU47ZlAt1VToAWdhOemphg+9i+rNE6fvDmsvte5erZe7dFpHhel0mdnBndXZjNLRcaIdC4hBdkJwFznmnr9vi4xTB5t5yKfXtOiUkknEJxuHLgni+oReaRhX3m7Zuh0kIwCGBMArEpMUkh2SoFSpEpLJBUyFW9kp0ySb+aVz3e99qh7wgXTDzTxi6Yu3jjztOlEr131454o6SUTnXOkTRD1iQmn2iaS1VttlFMkUiiRowy0EYjMTIxhIS/vuxiUppIigyIEGAkmJIIERSKRSkgOcmJMIRGjCUMaQTSYRTDMslzkDINhJQmkDMAkTGZMhiTDBsEMjQIiECFDIzItaFEaRIaaBIGBMk0w7uRkmGLnEQkTIhIndXJkhFkptaN/wcDSFMjMzEYKUwkpJEhiEwspMTEzAYYZZjNCwFCyjCbJSSSTRmQoyTJmhpjGBTJhZmnp1JmYoJBRoja00gIFMhRFESSCjEL125MkhIIkCEgttGFIlBIAoRjGgyiU0zQwAMZlIkpM0jLElEmLAjTFkyJC1pkNrQAqKRY0aSUDJJLGQIk01qGISIFBETKS1pCRJGEBlE0kTKQiCUg7uIMhkEjJBlIRoUKTQYGEJIiiKaBUJBsASgn07E0zZiSbFmyMikEBAGGb32uGSRbBSLTSRk2JIl8dbkf8erqCkUlMfHc9t1rQBkZkhiJgSTBkMwaUzJLMAUyMJsKCwj07DFJYyYsZRIwbJKETGECIZEZpKTCMxMU0QSQwwYxIUND05QppkpJIiZGTGIhYvh8+V2ULBmaFhmRSCkjCGTRYmto/dauumaBMpqTSRntcYSkIxkJJKQSkgwZMEzMBiaIpa00AiSQSBiMZkssi7uzTShJb5a883SSZgQSZSkza0kDUZIMbu5jCUlO7g0osz+u3CDJESSgTJhgmUhIgASKISSJEokklmJiSmYpCmRMjAxEgpMUQUZjRJNmI0FCUEpNkB+O6FJEgoICNRS9r28yOdEiSESLuuzSSAUiJlCQMVtBn0/DzEGTISUz9yuZPbpGhXdwZFBjEREmFJgGkhmESRJqZKLEUUgmwCUUYaSUTJpQgxQAIPhcqQmMIf1W/1VbrxiESCUJhJIhGZIk0yNikljAglmIQxm99yJgkUjDJiIEufn9Pw894E01CBSgYgJQCAMY0fXdlJSKIpmRETW1y4pgpNrTDDuuCREQLEsxENMhEkZQFDBTDSkKFREmQSyMYQUyllmBjSCGiCkiShEkkIoICEoCTHx3QPrtyiWtIbCZEeldBiSJDISMKMkGmlEI0hDFL03TztxoQjZEILIkYQkRmTWKQyTEmEqUKaUwYzeOSMzBkNtoA1NJELApNJDnNGxMomYYXnc0iEmTDZ6CxyM4lVJK/o6W7xYTCYSSIcSSSGH+/vn7PO57nPe894fKEkkBVVevTVqmba5z5MZa76nYTze7y99d+puBYSSWQ2b8/z59ajbefNyFKRMGMRSCMiBo0iJMhIMpDJQQH9uoQ0KSTRKQgATJX+dXTGwiaWRkyc4kgwURkjMSSEiIRBGMTMTASKMIEDGhS2hSYyBQyjNMYyIISJMabNL+qrqt2kYtaQNmCSK2lAEUFDEhC87djCj/lcjMBYSIiQBQAAYNgaBsyTMTE2EhLMoJZEwTKYRjAle12AE95rpFKGGMUhUNCMhRDMosIG87sKeW2206kxALJl1q1ta6svOvCEUSJGkWITMZBEZDSpQSYxohRmDKO7cxDA2IEwGkEkzUMyMoCARCKRGYCJpok0GNCEgxiUyDZSEJQiYAWNFIkZQigJkBS8rdVq5VX+Xcg2SZlmExjYYmUmGZhkMaKCYjTJYgTLKMmTK2kISEDEmZGVMJ8dckyIpFBEpEvfbkvHRYkpEoy0Zert0kyYpiEoqEj04SFjJDRFkSNKECbu5EzBp/K67RpCElHxW+/h6vS+e9XnRjBICECQLWlKYEJIMl892UmJL/l6vPOwCRkiIUGmCZDKQTa0y0oxQSUEaDJNDEmYzAKYmYJiYxMSUZTCjIZJMliZgowwkymYmViZlEUhTRJlIGFISSF86y1X48v88rW7MEvbdk0QIpTCClCJmogsm5cQZRkIlGLKTOXRhpmCCMJRJSSgxCU0ZpQJEMxKL464MTJEZpGmgJjKzDIQIs0EJMwKiCbGLJMoyiRiSTGYJQkyt9p6rvwwCbf1nr85i3zudfz9/PMsCSSQzAIA6nvsI8VZUi2SLUqpViUpGhMBKikPYpMEKnWJIMESkRi/vPcmqLJvzkmSkoFJ/SWmqnXBqmKq9ZTVHGNQsy85AcFDAnBR2hTnOWEkXS6yVWIBYqZgQfBhCMPWrp9Ex3VnpSs/FkFHzFxdRYTcLWckGLVeN/MM/kII4cTtUMobeK6vUoxTWP23GvExOe6/E0hoZstklq0qrYW2KNJQYxgwvld7+vP1fHv35+/SwozEZmu+z6dVEkkhmw6OzmvcNyb0tnmbd11uIlmbx7GmSwwzDNx01K6ECjFWkx6mFpl9rz5HXPXWMU7vqDESSR1JP1ttiRVkApFklkpEWrU5nH4BNZZZUWq0hNb1Xz5849mthJJIp0svIKTecZ7mV1RoXqOUEx4lkzQ6NWVFReEbFpgUFaGO2xM6pUpvC5NSVMDQ0n5xPcbaOWZ9dQkj49Klls3xd9ftCRDGnL1Ee5E5fvNt1O2ZfcHHpigruLnBCRed2pWN2F0Qf4W/pYszVchsJppTQqlRUPDwPDEyY6znfbKpne2qbqVdjHOJR3NxrIghZez3Urct1mY72Huvgk8KUejHhTLSaQlPxFrW5HozdsK+67rno2hr4c47JVXNyqcYy8YO45o09miVWIGLHUN25kqhs0w8Zkx0KZRuurtw45a4vXV528128teZqWTqyxpEOrmKq+QLD27YeTkrmyk7CMzOJvCKzc1+vNxlGuIiQyZabWK6oVmcdjtqStW5QIvHrhYPKy4e4aTi3YsoYEdIIIupx5OZBp2CUtx6baV7MOdTvdSnXwi2X7qa2aToUuMPnXRY2lyYIayrFZn+bgxJaV1r7qYx/YqUyPL3XJQpOqJYy3v2ERl928LrZoldzvpOKJp10YQO204eypBdUMOU5gyy4LuVFVNRtJqaS5mKLkapTLnaq0U05pzt2amNENudVnlkZWDdzLh1rCS8t260PsFXeknairezb3c2+OzHpvHpMHZGzYuSVglMvtqyDelZx4E5yOiQFk9sjGugcblR9WrcxmKmEKdZL56Wt3FbVh3NyXS14r3uP1p/Y+kzsXCg3dz7cp1bmVI7BZNTATT5SuWBjMzLdwV3tth9t4tDyMNWbpBbILjvW5joW9Jd73WGesbVmuJrFVEW9cotq20xZLsYxpIqSgd+waHkRLxnvpnwVn4Z25go3eLs4bNdTpm5yEbOYwuuW+wtXNmW9ddoOSw8pJHblRMBI6sqYa2U465V9XD7plH29x0G01chr5x+wS5KahiqOy7JorM2UHtXQrbDRbSrVxnMLKGEnkGaMxZKcWPdG3r0ZkaYd20aQjkq9CTvsHGjL1XSnaL2cTUeMYwuQpNiFp3czgdWJZlMO1cWHcDT0aJnHTsz7u3ELEYz4cE8DG7pyBhfRsgy5t5TFb9dXNWvdQa75YqHh4aDtA2goopcSs7VFhTcWQa07WZ0e2/SGXWs66lRmbHlS9CYNFZjl6y9xTBWdxbMOLsvIwaD5k3261Ak7e5d9VW3YnWju112asiB7TwuO2LQUY1BTt3LjXE9esK+65DrOLcuI+7BuHdd0+WsxyiuTm1mdkmXt1se9GsUryBtCk8SYOvG5zybU45MdHdK0rSehnWGVUFhVZF71zpQOKRWkcki72qjXZl4zm5R0Y6t4yF2SXoKBHUuDI+qX1xi6dgZK+0yAfZk9cG5rEEiuMZfzHbt1Sm37w8HkvUynWLXLynWd0L2JsrQhUKlLsjO3nmS2D2VK2xk5U3Jo085u6eboUyygucgL4uTcto415sak85ALurOF853UuxuLIiVGHU3d5Cr7DyKbrKFU0RUNPJUZOVoJNgjIIzWESgV07Rcvk5bXdsewHNFVN7b2NqhYesXQnc6nR5t4m891Mqq9jQg7QtIRm5YqzMoHPESDXWkzIMWK18f6/mfn0/Nj++/Dl1Hn6yshs5ljXkmSlM6uG3VmXYNY+4c1iyaYK8pkIrRtUlcQaclUnpzJ27V42e6kTtrnxQ5NbjrThi3FOZJZoXohvRtxXsHUq850ySgVQvL5sLqeutk4i7znc27l5LMeaQ4+Oc13R5uiLc1irDaa2lu5e6OFDrG7okjyqdzic50Wbmp6mtWeJy2jXbMRmmlQnQaOF1ajuWq5LL55Ocb59MvrGXVwnspZhHOZk7bdQUwW9NbsTXbsS7O26W847d4uOuZz53qC4J1Ws1mWt0SsgCdED3vfgHsA9Uz6trY/vsxqvjkg/SRP3C/b8P9X5+an2habuS1sdWfz50849fVIlei60nTASQnjSrJjOa2+21NvhBSvMy+zNSQ1ZsW/h2pjxkYzcsONowHstfZSy8F7VPbr7UO1x3zRamHKuChXQcy0aI4aZj7E9o7fSQvV6wnaB4GtOL2mtrCsgPJhkwCGGDxCHvUcERP28VUvaBeUpOmfbdh83+Z99z4SsoUe+n17Vu8cYmU1IsHdgMarbgrZNWyupVQ5bJ3YGn5tDKoztFPMl8IKCCcGa7el71bfaqSdU1l05CbqahHasHUSc6xsfHRCB6/4z5j5XWP72nsXzdGhvUlpzGh3RprN17qV9BLd3r0HHWMQdtaqKBV4aaadVIgmE6Wp3sfLZY6t5OrnDWqpcjh2NEYxVJarT9xu8KbbIsbjKvhf+L226sojPowujnV9BMZ7dr9ZkzV3RgkyusZMd0e2TXmP52S4gd1lUDt4s+7r+7oOUo1fzS5EJmzaEoy24TRRQWKXu5Tp6MRx3rH26n2tnLV7oePBuUurcUyC5FHtOXN1s3cW1hDXS3CIKh1wXl6aOzMa3MRwrJU65FQ3PVB4eEt0PCMMNi8XrWDGBp2iwg4L5dVW1kF+BSDE/uqR2Tom6dEyVJknZPSSU4g0J8lSJ0QpP80JsmRFRSdE4E3QyHCY47ToTJqSkp8ThOlMi6TIlhWSW8rpTmnmmwLQI0Ctul+TfxqHOO5qKxeK1Ys0We416uWLsS2ZpQiQElIySCnaS05y2IhpnNM2phrLjQKmbZerF558qfdcbnTxUL4xg9VJdMO4iv46bxHh4GUp8/P625hVJdcXwM9MV7m93OSiH1ZNfOrI4js2ZqHQ2Txw4poo3t10BaLvMyVac6y6McQI7A32ikyQNyrZWiyps4S+ErNmXdcmXFxVQjDA6GF7pVi+eOKxtiQ5oUCje6NtLDu8sdLJWDw8NWGllR2aZR65KCiWmaYl2DrTjua+CPPBSrnix5AdFWOyXgmVt5m3edsfDsDoakslTl2bxfTSRt6jbd7e4/Q2Mbus5OXxha67cViPXaT3OPN5noEmsndS6d1RiqJ7JiUJHCULyjJxUycbwyVtYgJWXgd4qLPteEmZmHac3Hoi2IwHNHJDJYpU+QrUtuwoDMXCDdBByb0Zl9U6Zu48N+sXev/N0Ue2uzXXub99BSVQK9p52pa9sSmnT5XjgvXSKO68UFwvtD13ul7Op3g1zZgGvYqHGG951gvsynBkt0T6Tr6o1NyrGKmwU70RzTL24lkwaeP47+0/bkfwQ6kNTx5dX9NOu3kNQbUsbrd7Uy5VRoQNirVdjJNhrN3RQzq0QGsY4YDtth6CN3gXKwURrVXnrycmFeTGpMl7Bat3sp1ph9su7LDBW9XbYSLV8Rw3O81M0SskqQphZ2N8L4a83pk2y7DBBbvQmNOCsO9AT1zJKDSHPNHQXeUcO1AeVOJZJL3FUeuMYc15IZaxp9dMY2ik4tIdNLKMZ4uroSZjEtomPGayzIDBeYs3sWeNy1h0ZutDHdRJ3w3dYsVPPQY6ImFa6t9bO5nDM2U1La5HkdxngVe1rbGaKok9BdzXY3AqbqMbTss2XEbOy5eMZgKI4zu79fcNmtivl8pPq/DeYvRH80TiLlte/C7+qBG4e2aO7cVT2ycRhUru2O08oWcQuRU3LXbmxUauabna9gF5Me6cfZenBGW96SZNu1NiLmVkl1x9drbq0cmWjxx5AzDOK7eAfW2WrK3KeUm0TVwlcOOZOzK3MCwSHDV0jdEYVN3Ie09JxmW3MmA0sy+SeTdWus7bdS6v1xjw8MKxYt0O4mjqKOawxihqmzjV6s02G1Qbg6bKE53iyffT5y328qk+iEbFdGduIFyQCiqN8p0PFnuBlGZgx81fXdu3khDzdXLhzaW6hfXZR9hqsWvuNzX6MWMiQMpFx2K6ZQp/bmE9lWxv2Bznvx3TuXz100dTdnMz5r6aHM+VFi74izkm/EVmjit2DN6KKN8uLq+oM7SOU6huEOuKYzFtztgRXHEehW0O0biwHoaY1tx1NFDPYXOmqqWNqDw8DlShHYJD9oW3OPxHxgJRDb4HUeG5we/XYsHaBvG6SfzthXhG5EJt+z5Z8b92A4OzGqnwaRqOnhzNJ5fZWJBfaQ6EZXLocoH7fLoyL1Xm7KzDFlXlI9kyTMdN9vbuJzpJzUzOG3li5D2khirfPrnKBN8ZziHjbSO1pGeNONu5NjrNZcaV3VKszcdHPXr3ZmBqq0MTCo5Czl44zD+7EpHv0vl93bdhzD9fZNzWbFjg1NFbzGvX0cOkWNk0T8A972YQThYzHX1Qtt29cHVlR5m03j3BBS9m6LN1mQH4u9T9cQceCd0w6u7bLFR7tyY3OY2F1xKn4vt3n99uQZL9nyy6NZPfN9xcwTZY0qcpJ8q26XH77RZzvaVmSQkdauzHixNv7PrupW/XmnSjH6EHIQV0yNGqSubj6aUw8Lpytljtd9Eq5QsTpci++ErsOCqfzbVfDt+zdpBu3pNSVznTTnMx6nkidXz7bs30xqQzd9u72ZpGmuLS2ZauyKl9OUYRhhsUW+lFqxrjkEu2uO5c55VQNlp0FnPbcmTd0vE1m1O1UDm5hnJyDCOXOoLYs5dGaMw90u+mGrby6a9bge7kulc6aJukapmvK1WdZ7M3tUvRzV0jqoMxOjQdJ485zcokYw82oOw6ev7O4yhtD6auQgt80MI+hGLcTVjBNM5rOo4kCKJ7dDLK6Kq3HM04xeoatrLGVyQeCZAPeAfOq7a3mVRUtyDZU3rEEOFYhgoweHhWnds4NtNcXQS92yC43VKIHrukrUkcJi5N3Z2V228QdJiO1Nxi+Iy9s1jyOGQJ1wLk1+wZ3WpUa3KFNqPCJks7JXLDql1Yl9vEbZRy02aFR3G9octQ267Hg973veH8AD0dzG4dfCvpB8DexB7dcVmmuMjUnXWchxZnBVK6Hdqs2oWF2nsx7Fzcy+LFbBwYtIVThcWMlE8MwtHzN5LVjVuz1Wllw7KWFLFp59hzu0s7hwjg6O8SOmw3TNXh58G+N4qFV24lkc3Y+jopv26p+VlnLgX9lFJLehiltqnNMpvuOKrjj53MIm94sSUyNME6nDEtatL7cgWrV1j6FLXvdmCYZRhKSEygkZTNMgSAzEwmTSGQGJCiJj/XdKhJUQkkjFDI/ndSMMRIJJNRQxMMMhhKQv9O0o0oCiKMSYJohKJmZZhQySaRiiTFGEpBB4ul8/r6+/7+N8QZmUmGgjMEShEyCGSMlIkyYkTSJNKZEyZmIUpiZFDMkZm+10+u3EJoJpJW0EoJKEEQzImMhYF47DJREwkyRDBEQJSzZM0NhMUzMJIJkjGSJiRZ7/1r9V6vQJMkoDEhTCiWLCRITJiIZFIEBGmANCYSJPfcyNNRBNikZRKQJmUMJk0MIZIaYSRkv13EU00mQmxFBgEzSMiEiiJpkxJEJijCELJkACCfEkEE2PADv6E/pXVXX9XIR0bn7EjP9nKXBdZyxi15JBm7HVHay5BRO0d896d/RU+qluaZ8gcsrorxfHSDKbrKZMT6uLdrKwK9wKI5m6t2XvXbjec+linlfxo4VXbeG53aZtyHN2UfI7kWgRXDrkxmDast0nQVHZJXpzqzvVvfc8+mYhuIGzig6R9boSxXTARK4apuYUxdpu12LF0nJ3Mu9e8bE+2cPsyRdZq9dND7t4/dufOA8mRUkzvt5zA1vdV0mmdWTtvdzaZ3eWKReRDOQaKT85IuOPZfVCNF7hp1SZJqrLE6wzyKs6UawNrKEqOFoZqxSQPorrBQYPi6aUcPXTxmn8YCQfvlrazPhQYx4Psop/dnSG3lZ2rBWbXSGXwu4DSONzHMtzVeHNByuRfW0bNYeeK/PBNGlWXLu59a+Sw3q3b+mHMm7Rxz7ITwJSSMIgEooSY2Fj4EkkgkEgEkjq7dB2a7bv3JaNPGVMpY24KVq+eVMKdVglJ5Fet4EUNq0KVY/O4w0pKZPg8DCUq5Nwwby3bQuh1Ruqpc9m5lZwdamGCATkoCj+0iNd8z+O+C9XfH118e+oGFIpFiEEEkkeIJBBIPiCPqQWtNzdDNVhdZadZrczCCD8kSCSb1tXtC6WkCC203TcZXZwhV+2EWUEUFtHpX5MDxr4bV4fQjKQRaUCGAwIHx8SQfEEkkJI+JJBPo6QohTuzcmt3QwfOMQ93msosTJeCFC923Ou1Kk1FCU0dzHMtWuzNbNanDUVO8fWWWSEbPTMl9Gs7slvbw6wSL2A2XVlBw0eSOHKgwUe7K3X2bREIzrvc1rEWFcbnqBqneF1Dar+Ip96DaR+A4rM5QOvvYq2C3tUHhixbQO1u44iGoHc5u+5zt1LFpOXxMzh3Q7KctC+6twPbsupkzMrGRUqhPwzdxU26KFzrszQctYXzUo/VYwZweb5dtCxmx3J1U6mW90MqJXDmK75jg3VYCS0y8xZHdOr7bnkSASSQSSCQCCDhEbDMmGnx7vXq9/N58rz6+e9enr0EMzaLd8525jIuHHua9Pj4gcVVZTqvdzuG0lGsi8RwS7Ko3Urtp2YjGk45VKLNvrzEggm0HeU69jVhh42uygRWnL+Pfr6+PPPn31567kKSFSgJhInwIJPgRx24rNsFw1MM49a8U8dHm2qZBJIa/wH4irtv3h4aSGEyCCD9v0oX4gm/ojWusR6d5ut9hVRCENW7MHh4KIs85NJ9YeAq9pXvYTJJiYtJu2w1xNylUy9IW7TG5HfCZmrFuIRFdgCmJ48qWeCxoLZIGbymd6sReVTUBXXdZ059+LM3Mrlc5wZX31VvPnlZK7cfOt487mmm2OMxdM3WMq5JpqjnQikcq+3YdRKF9yu5t6aektsUtuzxJsS7bnIrTj9DnYGKyn5xvCqJgmbuXUEvRc7lWHYKuwVHHgJ1bKFRXpKyiFd8xhqNjHqiY0wX1LdXJ5RSMldysHTzRqTRjePMza3Uyel7mlULs4LTTu8ZOKTC6NzbTeqkjkc6wyzvRquXFsasrO01cFObYvLvhIX6utvpzdYzghueXbu1OSFWbo6U8qJ7qq9woPCc7iS9uW1FGCwbGcaJzUaUQeytRl3WDZcaQ3TDTypvdzxEqaZdHXtB7BWVFcaDFWg0p7xIBBBJIPgJpJpEppkkSySIiATGUUMMRbaaZAZkBkamWATIn7XUZNbQGGKUjZsGJBmSjJFCwJTEpkfl2ARMpoZNDCYSlFMKFGUIxNiZCZfn/O8v9f7P369aSRJISzIhAhCJJkiYYmKEoSTBo02tPnukkUQzGERGpMyQyYlojEzEKMIUhZRmKDCZKkYCkChMMZTCAICoqYQwIQiSMykZRpSQzGEYwu7dEKQLM+b9/nv57/Xry+OvP2pFMZbn8Z9sLlQKud26SNhHkqcmWJ2mPJTXTDUfZ1tmXc3cdHgbFXN3KyeIJ46cOI3e7l1jtuLD2OaMs4Oa7lT4uULEzNVMo3sMqHlrZ6kQk9QZywvbHoedKMK3KS3IFnPZW5d92TspbaA/Q8fD1Hbv4E18xIhxqyFXeWCpfzblZz60NEmOrKZag3gJW8OxMILg+UXqpkIYJ1XM7ljEzOks9ldxVzMtdu7LvzugczIjbHDErekfknfL7mrGGhLcOtC/t+wYqOCWWK7JId+6y3Sebiz77deKfCKi6I2v5VTfs9fV79989fWaBDEJAEMiQwyZSGUSZ+Pfx8+r09/L69Y36Xyvu5qVjQ9hBKwqs1sNkdHIFASARgWk7n5QXdmcDLa3kKcxVoigN/cK20SRYI3F0CAQW7ryUsZgaWnaLq8SwO1mNHDVQ8d0vH72AgEE+8QCfEEgEkkkgnxJeFGlk66j2JRKBHDm0vNr2kQW2CfUiSRTCPRsnxHFZMDaddZGy5IMfa1E0rzG/I1RQWSrWxgjOL8xMSMAGgkJKMhBIIB9Nx+oHxBPRM52Php7Lp7N2ycm4mHsrCNKsGMGXo7d1zHruVWKPtVkFjUsBwXrGMxIh697MpmsYeGoSsqrgTNAgnd24ZiM4wnjbF73jPW+PteI5golnxNuHsvKElNhkMYOsIsh5aXY+DGovYos0bNtZtWGNZVmxz9zyU6r2Yryqx0LcMhNbNF3JYrsW4Y9vK7UYjuDGx+D6Vaudb2H7FG/ld5sdVGbKvJJvXe2KjYRjBO7JZdn+ckuGIL6qe2vZV3cx9m7po6bVyS5AdufNua3MWwxlzsqsl2O9+s+r7vfepLvFrXzeyYTJBB8SD4EkEAvFjmvCMZDEQ2PO3dEM61QpvLWDtpAvTQZJpXbMCDDOULzXBARtrX1CsRmerUUmhni12uFzOOOeJnWvcCrhXLov0Wc1cZihY+wqXYPXQQm/OfH19+vu+qUpmRJSMSQhde5rizqYWbCd5evm+u9fqB8SE3yXEWRYJlPmlJQ0JmmO3NiHbmggEbitgVdcYrjU1Sm5Kem5OCfuGxJsTeDUn+xKTQlJ1RNsEi1bKtllyoRmSUKTa0ZWSTDMhAhSYkwS1ojCKYjQkxFJRn7XEjMhIhpMpkppIRiTMxJppjESkT+73Vf1OJSVQskpyJgMkyGCTBlb38ZJkBDL+241JolGIVKSIJmMITQaRAQUKQSxlJJEGF5V3A+VuoiTSIyChYkmwjKBRShCYX13UhQxGYKMBExQza0STQxRgoaFIkzDE0QoTCyKgmSSYSFMIhFCZMhokwoTMIYYxihkiIRZmGSRmkwzPwvfvr0JGCiAwxJE0IIxJMRQNMyKDIaBCSMoyJkI0khSbRMUJJhhDGKEmAREZGQvH8Xn14vz5fsRqv4bsa6vLNP+HDoEIPj4nxBII/S4UgJTEJMBGIgmkQYCKGykTEQk50oNMQhmIR+p+PH+2/rPH838tuWxD43J2lQySojJNiUABAeIZHfr6q/I8/gu4pjN4p9tVTc/hejGMsaRSbw1OW6JUqqRnsGa949dzBR1OgVeXkm3Ls53q54+jVWOmno1xZd1HXUwne06O9MpDtDfZsNJ2pmclJpHXTlVmjM6qLZEPP1Q5ro3hyoEQekrxi1FHxSRu75Lcm7DILvckPTHcG8VtnLdN3Tfdm0N1LUHtTrdC5bpZjOpJ29MDisGgzWXP4MZSD2nak+PfMYTX1UMIYVpWVZRqqZrakkoiMhOpaTkpwOrG0YcoqVVyqKZwuKxouemkyqO70tcxO5iSx0eZyDrNhwvRpdyUssOzWIEApzaDveIjo44ypMrBmA4lj3dqysQ8PBLVZuGqVq8yrD0jGPDwm8XuTjldzeYUEnWYjSNRSLLFg9g6uua9jZrYKmoQdpI7AczZm6LHQunLtKumCCkyNEvcoE6FwyCsKS3J1RwM0zF999rNVPs08pn3XtpszaqhpLzrdrZzkmc45KC081VocKlG9RE2q8txQui44tHDnMuzHvajCXSqslh7nA8m6GrxtIFsEoWJx3tG4yTh6cs7cWawRSaxNnXrlFHqZJDOv+s4WInksWLPz5quDqicGUG7blZPr/N+tD7XtnPsuqrvufjj83mtt13dE+cqCqzsqmWTri4WxnaavjuxOpTuBaXjDXys4NwOBDkF0yvoNX3NRJiiXFK7t29Wq85KDl01pakKvsVbiRo7UsGPtwLI47Ku1GDJkPbZ3eramrFk4azdvHCilMw3R8bx3C1kvAopkKwXqoazZyalSW0Ns6PDwdzNbGXh9iV4ELvaak16O7KnJLhBN26QfsdThM7chmjBuXiz4/T5PN341IcBTsuBDLccqnZydS9qbqkdxbSGkNDa+M1o7Omc7CbOp+Kudqu67Bp43U+65D3wfwtmlXK/klE9SBQlRq2mIrSssNsbC3eVoNbWFwY3Fry2sdfPTIrIh7FqkJ3OXdqjymXH3rZt0W3ixiCpYlGqYV6bLkk1IvMco4Cmao6RjtOFbqcHIxz7dztbzPu3WGdPmcv5QXtWhJzY282ERB4zgPEUQQLjrux8yu++3U+GvHDR41f2O1ojpYKu4qCL3PjpsOZuSPaZ6Lnddze8bGXlIZjV13Nl7OMG1mCrGwbWcSs3VnooNidDMd1iVRTKSMcykT27Wm8V+PHZ5vZEtfYr6SsmrZZqc75vtnm8OfYoNc36+vkjibBp3KmX9bjeg3XKmNa6ixKLoSi7yZqMzQl2WKuXIKlaFEL15SwEai4clYUDueW4ll7eG3yWLRjFdfTb7EWwiOPG8hRFCnyUBJlVUEy0RUwWc42R2XmBCELejudac3tq6kZ4L6nB98XDp158Wcho5sW6fizDrCmN5zcXqwwZdDUZ17w0Ik50MuntLMEtPnQeTBo430GAuzuMWrZbh/sTv96/wIIW8z6zxv8NBXcQ78rmueTb/anhUlTkZHSqbJBAzjurs40ftp2vtvJr1qsTvmLwwlhrHRcwpJhKKftD53tuhTyiTe0LZscZoLSq6uUa2OleiZNwP7W+sVGKvtExVk1GCSX1mxltK9pQuWo0QiP6A89jP1zaZKXwz69OTGvpnCcds6K58mO7EZm2mJzd8KuF2dhi2Sd2ndx3gRaqy6TlPdStbpW1nG3VCn+T6pl60Y+LdgsX9r0nLmHRmmZoPTRRMC9mvXfzqyyKosxffAi0dnbyTVjcirt3aRsImzvHnobDWdmK1CWyq1KPqGnZDLy72tFddt4lHbbd0IhScqnCJ1jJWLGDBg71wHJ25uVGX225rCPqyGYrS7ZFmq1JKHctV9WOhm5jq/JVCOg7Ja43tbSDUbzqcEnufUqRbMXqw4iJ0XbNd3wpljj158awU2Yx9j2R/WbubMrAt+qo9jlvNoUDVNwZbq+j1iuZy62ipuZ07MB5Mdes9HQ4bydpStw1VHyElZ0Mb8QeddLHNZYnZyWrFmMXlkc+Lda8S2xo3WNX7/sAe38/Sn5+jt/X+nRJ82/xBZ+kdpiMDHm8os463k0ObryTMq5tbS12GMOdq2gW+ndmQ9lldmQX1M7SgYQyLZQ0blY3ofZYbJrJXKhzT3GirA9mruDcCSikb6qPbVDH1QmlgYtiXvd4iktbwKQWRHwVDIQKrNrVIkPT5psDx1AJUElmX9v5b2XUY22TwrOUGTK51RV3+j3U2I2sxBsRMoy0b2H4/O5Dfa6JF7WdN4bY7jmvDYrJJtBKj5sIKg7SrdusVnZRoHzwvBAkM2rcLUxvEdLuVbex3xdrp1H62fo7rnROtA0tMD0tgfMMWxOMTLtWb17ICyCYFYFsE3GbIKAF0QWwCo0Ur9tzOM9+d77pPCk1Hej2tVq1meND1ic1hzTj4wXPMZnqEkkBk9Mwop63n13ePBe+59fl6WToBwXgS0CoJJxDJKkmiHZNBPxOyaojJKTcm5Mk1TdNUN3pMRGpNiaEykjJKkmqicGTYlQ0JT00JqnJKmoTUm6fapoJyUnRKmSWTvf7E/Z76ir/l2ZrvA/TTl5mOKiKI/nXHSudpwYdOhVXX/B76L50XjLPFfH4sFY/qwIRMVcO+bEkpsO3vK5u2aJrAtNK9ygskJQ2pjhpVpyqxtOsrYXQxBrbxDEdd+OZnGxLmwR5cTlmP0jqoK4XQwVuDw8DLLvULezf7m99mGDTdamVTUz7DWKU1WX9TWqB4ulDaFR2h4eCammZafKieSNWT2MXLFuW3DLjhudBpyGVl0aRHSo2XdjO5XFl2UOb3NPFZh4B/RWNWbPrc5S06+vLlPSqvKqVgypfwBxlJ6Y5Itc5OjabmG+e2h4eDmPFe4Sg+oY8qpUSa7FJ3GDtzFseGBU1TPZZrperq7U9ojM2B9ekbUvnmnMw92Xq6HBXcHOi29E7tyWz/LrPufcXU+qZ3vDw16PsOZpD65KODem006Q5E4qNTc/Tn0UGtI8+roTmrHv3VSlS8URnO0XWBXEt47natLN8tdKZUvDnISbHJzui1xSRajG8sWihoYsZd6YIlkQvSpgNvHZsyom3HyWdu3EshnRde6VyGid0zZi9tLXe1I9N6sxp4zojMNZQ4Zo2LuiozHmVjRDztuyJqQtUe3E6unkPJhKVS8WURyEvNbUWUOZrTLGLDV/YFig6iRb+lKoxsdxUhKNK6OHt1/LKT3idW4OHEY3aFNhJ+2+Y7jI8OaM+2Z1e74N/M/Kr+8Jp3JNVhobmPbUWNH5aUhVLXr0zTDufUz9kq8OiZuZDCL3dpP64/iO5Njjpqi203rxoxiK3Y8PBt0WXLmEddOttjKVQrNIRhBGOgwyyWT3TWp2hw7ZIwl6zebkN7usr3YGuqlLvlS0UkcyxMYXtdjppeyDW1Tb283INlzOQW5lsQ7p7QTYWs28joWDLGSDcl6jcWPWqbgoptjGr17uC3U09A8KzxvBJWCg1KgnWaFrBdQb0jp+MfXmak9Q6jG8LPTQuoSnFL2xBDy6uPFcjlbMmWxZ3r5l5tAjU5uBZkcqnVZsUfy7NpKWQ8cLE4k1mXC4RVOKUKsku5KgbpOQxHn69+WillDZPSrhaK0FapmUFNxyc+y9krh2u7ZG7x6V5b1dUDfVNQN7BgI0dNqrwRVMCbiwdpG1eY2o4rBG5U5m3turR7b3uTeLfWrLOrBhEviMw5iGLMkbGvsHZHLKzeeHQe3ufXnd1STc7Rm6NRvGcg0dYjCRec+jrevVxeO8gaqC+r0rITmVjuYkiahrjOk6nmo9tYTe8cc2F6kKYt2a3VGjqW9rtX3DnzQ51yIwkbT3W0s3ZeUEjW3O8w1eyOqTyjmzGTdRjpHubxOjcydJiPhRoFKPspNO6OE4NXF5UlLdaxWnULzCy6qW2PDwqpbjxlm1kqVJRl31Rr2YgaRdg70V2NoF5skuX2ZWex5+fwAAv6bS/wYP+bB1ACMC6vz9QtvWPe7iIpak0igVKHWNv+WXAhOKaOWiMTTp2SkqVYGGXbvo81jlzqu92Yw5mCsvThkVa9I7JYrMxnjhgT2sqysjynKmxyObmbWCUjDstOMbq3ddV3D3wHvnOS11lMbxDUN1IRzdPGqrCl9Ih/QHv9QHvx8dQ8PDt/HU+WfM4sl1JauOvPQjj9k3dek4CawbRpaKrZgYza/Jmrj2p252ZhoK6R13mYtjs72LOuTPXQfRbjq7G0TOa4l9st4+3LKeOQNR1eUTtXKvaxOV+UE32vfnfqzFaDzn9kUPJ2+rcA8UqaF120uJJb9tu8zt3rxi/qdvzK4iCggTiollct0IOCyu1TGcpgm0/sDx3kJSMCVJiufY61bdGqPuCGtGdYfHRcIg128TKFDcpsQlA9My9lWWtG4qZFKtfWQrprZDvRLZRBvBJSdh4Sm5sTswTvrfq9+Z84xjW50wJfodmSj9Oyo8loGxw2bkcrMbqVYvck+zS+501Q+p6omX9eV0X3CwnVZ1ayLZ0bm5pWjjMSS7sHO2d3B1aRwoZ6dDdVn6d7Of1fIkdzxLX9KWEr3aXuqSTY+xEUeFYGV2TureXHak2bwiYs91ewS3oQsjIKmkPEEGzdiDYzNnPzI1cx1atlonOepJjsh3iHmDNSGB4PDwtQNS3IonCVdGSKDM5BEalLbWrDesLKM1N1HBIddaZS5LM4XHUh26EWXnGVjr/QCxE0xWIMXfO63i1q2rGoJzMUU5u/vfNpJWQh7gvjv1RUfz8n5JHajstunsMmsK3P1s9l8YOGA3D0x8q1TH53WQr9/ZUBubAYi7+pufGtOKHE8Zs34paCNWM3NnlQqUElGZJI1g+UA9p4jfXsyKtUxl1M6Aod2a51VMuqKJTosslFRbHbzjok002Jrb77QFu4UHSm1OZqvum1PqmSblJ0SiYTnYngbDcmCZJSf52jrw2E/wOxNkKlnZOycJ6SyDUnSYEYuEOCaoOiYJySp/pDAm2tTJmn7b9Y2ua3xgtnF1041lQzjIKMzEsVYo1G4yjT3pMM00dapfmct7P19+vzVbaLzVZhIYqCaVMsGWGkkhkomDIRkSgxKRmaJIChUf8O6GNmEhAWTMIlEMlCRkZEd3INKA0BSaFjEmkFAQyRIskkyQhExBgxg0RskhSPKyt2WW95p5pgZO1NUyjIspqnHBEYkjEgakJNGJJRClGYmMMYUCDNEwEgkZJRNiMjKRmZRjRQCWZ89dlIzGWgRJJKUKFEkwUyRGJCiJRAJLSESEBRREgQR+AJE/D036x+8SYN/uhFRsn9XjnOXHp0iNKC0s3SJgd1BtjPznwa3dvK524TeuS2yncdR8lecLw7kBstOltbeylzoWz41M9q/isD5KbvPrG5vzx7e9l7r7f7OSEkR/J/KrYffLdFI06r9zh+KfaAj9L7ni+yaIuO7ZNwhRr1UCNP4ehWQVjEGLU2/qpMVQaIyItxzQRZGD43h5UaWHRh08Oya6gsHAlIJHTqiLyY1IrODDXHkajrCN6p2emRFyMGFQodcnnoOlUMe1GUUqwqCOpAQnroitORepBmbhzFWZOUsBPM6ufChOOkTIrnkLQ3QxusQvts0aYvBnNN92B3O7sjeFQSzlZTu6O3ewTZ21l72jC03nK5u1OmR87WbeWIXeY7BLgyjqq4xjoUnuUi1NhooUFzz49+Z8/Pq9Xl8CjGATEmmCV+nMJEQxl9fZ8fb383ee/Pf332/EsiXaSuzol65h6urm9HEEkk1vefmVVVLmQBYjieLoiLkvj6fkFYs+3HJRCfxZPzo0lryY0agPwuptR+zQpkTbudNHH2nv0+rkRMMJpkwxoiAQQQSQQeB7FHjplPqmQk7YObVq8FduAJalpl6/JkLMdH1EnNfGJ8cFla1rcGbAKEQwjdUnqKFv2xgAeok+IPhRFMSjJDEmKEQEEnxJJu+C3s26E1YJ9aM6OZPr+duw8HyqGqti5yylmY7t4K3sD08u+LDJI6blCzHx+pDw8NhFStp1SRC+GbF2Kai3cf3J5XK3ofVUcvMt4Gp9MpUzqdE6t+lvLR2WAS8WcTXTshwRjnLNiUzto+o20MooJrHTGXxfdBhqnOmhHOGge8NVnrgzXsemzrxyN12tvJmYbTPXoas5MxP25b2ZuOhEYy+w6xCjNdskJprI8sci32nOVUZJqk55u1JWixsz67++Q+yh9vVPiqrsYLo7sKIjXcrrtrIdRIEINIEN+m6RqAZTMvvr13w/M4n8+iX530fVPqF2OLf1Bk1KBGEFmiTYlOehGKxQuIMeW0j99evfVtOOQvbDPiC5Gnt5Qs2dQR8kNNna0Xx1ZBLXJuQiLrWahbzyXLaXVtPuwk+IIIJ8QQfEEgnx8T4HwPiT7xEC08KWZbTyKSNJwIIEkHFNjQNir1rcfoR4+Fmubl9K3qY4vHeeiavavlsKA3XrWyoTUY8PCgXW40+Z5BhAvOwhF8PDwmN/b8bXW39Wti6UgHvDZk5/HMRWd22ZQYtk0LTrFrjLHVlMhY7ta4cyiby2OKktnkypWcZ8/uyBdtbWWco5Tshu0L5xsJINxmNp2hMDFfZKGgo2rurGU2dy9naC/UZGw2nfDTlUb6roiZx0Petw3l1UKYdde2HIqYWTLaiHCjK2MmBHJGbunDfnpDCFdWbUzippWUtoFMOt7KphzWhbHH3ScrwO9Zqsk83lnBASNzDXauqC3uZzu4WJfHKnmYVxvFDI9arw10+Gjpmm71l+yuiUHZ1bBeUFmc65a6aT7Y5qNLcj2tzKZ+26IXT32LnMnAhVqolqTG4fozBZCunc5UR2Vu0dLYm547ebV8O0YLRO0ed0eTLIpvBlw0aTxJv0EOIPj39+V70IthRICZTEYiEwSMKYAhSZKIyQoJJEgiNBUwggSMMjBESKKbIAolBgNRMwzEskI2JSxImUgKTUpmEJkkJJJQm/K58y4hKQUIk/vunu23bhgxlEZGmQ0ImWrFEY0mkaIUyz26RikgEUChIEgIGIFkMiSmYmkVCUpmYQa2k0ojETJomEGbDAmZppERkmJX6XStpEMopslEwzMmTNIJ04AkjF9S+tRqsV3iazRq3rMCZjwXgoKLKiyXuqliFk2IZlkTSplswV6eXnhSYFaRqxY5Sqjt6DE0SZVb5Ldo0bs6INTDuiajK11H51bb3Yotlp5dumDL2XuXsVEDxBZzb3dzQV5TE1MgOSlrw2reHDVjQmN0KYbyinHbs3GtiMkPyxxQN2wlQ58XnTNmjMSe5gpCIanRDuydjypgZVW8YlUhWFDW7x5kt6HaBV7NWSVbZyu7enDhnh7zNVT7pFWHSSDp12Hl+QuZmX6/B6mR7G3VArUgXFBVRsndgG3KGFlQGqLwShtqG48wNkXhGObBLyhYctNXl6LGwD3hbG6vTQpZIju5OIZhDJvd0QcrWZBdL0RORsPa2BjczGiJTWeUqhtVl44cOIHwHvf6z4D4+8B8fAP4dM0k9DSxgIbrLumfqXsMYpPsGqYpN3ciN7jygyJW1BFtT1zHt2bzMVhPC2HT10pBV029vKv0DW7Ics4nAzLUXshxbcteo2G1rx6ndoFZm1bsurzNovdGsqqcyrLNTW3gyaaE2IlERh1plNyM2bhOZlobmq0m9OHMmM754pbGtC7c1RqqVTDuZAcwairvJcEuh4eFMh2GcwptHJA9pJbJBCMLLtLRAlHiyBXeeHvDI8OxTLLrSqpYtFj3vPMou5rTtGZdXkoBwpxIWWV3SEGe1hezGqa64Q9mYsJs0KZe1zssbLsP1C0iONpystvCaFltE1rNPSgAPCZFgkTxZLoxUt1OI7VWhmIVPegwJ6cvJ7RAhVIqg8cq9WFYi6sPQPRmXujJFtae/fzgTUlQylSak4JgP8JRNhfjOb3/U3W2vvuc77wgATrUcrT0TDbUapMRM51619J4kKTcwmEfexENfUSSClZHaoKmvXkVEMJPNTVRJIoAn9nKL71xjgDr7JJuJUOyUE59J0TonAUaQdPdZcRTMJBrvn4IthIJrjF438LKqkPqSc2JGP50ZQqWJKFSlTipp+12nfnf87n5DXw7gkKSUh2JURjjJMEyRKJgEoTeZ2nmdJ1u2ucz7582e29NPilmrytbbi9qX9resatvPvYrq0716fNjUcrOZ4zdrvXbvzfORFm53uiJ7OozmL+2+/XfvfUjtd0fb6tagTuZzTm89tq04MYtjG55Mdl7d5fu9X7SvK19Ed3PaYj1fczr3s+vZ66zCpx17mfR31e1tTFOZwZzverXqyzcfblrW1Wm9Z3nXO49n3ZG91981T3b+3qluZpTXXt3G337i7575BYq17hv7VuWvw23ktGqMm0aKpLREYLG2jRtf6auFsQlFtRi1EWxsVGos7mKtLVsho1d37DEiYbgJghJdqqpztAWZZ7zuAsyzL3vFVPgEtlssfyATc/u8gJ51IBygW1AWIFW8KlzgWWIq0ik3VSX7cJLvT0oK6WQmYUpmlQyK0xRl701JyLrIDDWMWNIuXNSy7rqbSmlTbWaS5dNBIUUgS7uEJO7XHd0xdzuGQNco2NFt1pVcNurJra0GwbYoxVY3d1tSzbWnOUzRptCCjctdtmucxucuRcprWwJd1wE5xIBEMu7g7rju1WZy+4CyAsgLuISdECr0gVfb5gL5b6+uWz55bOHhTbfnNaq6qJmIxsgQElaDGDfpunOS7uY0ZIiMWUNEDJTJYIoubkUm5cogIO7lPa8eKigyEUJsEoJ3d3dRtNLlzHOYjc5gxmNXk/MtV/xatX1/vQQwMhJv4uskxgzRS5nbsQyhpKZNEGTu3XTcmZYzJEMRJoQozGSnd3Xc7ukOXcuiCYoYsD/ah4W2JIg8B5COgYmIILL+4JE7SIRmAT/bUjRCCP1RX+7ba6a1Tes1FJKSmUarYrDpMkpgmxMEP6NSYJuSkyTO+CdEzsSTwkmxyThEZSk2JTENhMEpKnicxOiWbicIf4nCG6VP9E3JqITeTknOSf4TYlTQ3JU/cjkKSkqFI3JqmqaE+kmDBDxNER8TtNiaE3MBNSYJg1xm68R5r3n9sDyElKiSyoyqZViKyFmQZWBYkypbW+a22xmd07LuO5duUd12iCXOhXca6lc66cdK7I6U6LspXcudZrrJ0dODI67uLnTrkhSI3Z103JErnMR3d1yLrru43ckdcubrubOZdzu66/n7/Hq222vxeWr9amtoQGQg2pqltoIIRNqgMxmTMykyTNKkxZNKTFMQaUDK6JmQNXRBG3TjDKNV/o7/2u8O7sf3tUwsYh3/oujkspmFXdEstLJfGT2dWUOcccJcO34XO8O8ubs99dEvTeZq8vXetttholxRS2P7Hd3f+72D5nJBbUDwNXGInF0rQmXICy1m2q1plrNoC+Gmbamb7wFsd99Yz8ICytYzLMVfqrK97auunvxtmZmZmaP6/w+L77IVToyyX9kiJB4gPNMIea3okQr/aEJX9u9LY2jXG8/uMSmuEUiUL8Ei0kkkkn7zB8EEAyEmj4FgzEM5T95+O7u7u7u/aVCzOzu4zs6DSEvAFFpDpu84223mAV/XNkfteRFlCz5FunQPMfWx/Mu8a28xusTH9tVqWdIdaaAZv6fYfbdl5SVk5el3yzL7pz8yRzXOdr8eNmVP9MZzJjWRiTFX/UdXMmbrZjFwVnn2PJT4CYFMLwpSfNhfz3gXwEySKWALBuwSzqxtxp3x36mlltt4umoSkpKhUm2deomvBN/E9JhBQmCYJSUmxpknJLB5Nk3Jxkck1kTckmpQlJSVoSk7Jok3JOSck9Y1zjAbvata4n5bplrU+XGtJBWkVGBT0BcCUmApO323f28fCZg4JgmRNifikkwT0lJ1zhME2Q43IZJkmhDTO/V3epz18c1VivPS3KVZreaBym2rI1Xbv0752TxDcm56G8pNEwCiYIDpJOAMJxMEAtsjhZszHiGGnkuTtP3cNoonQnXcRKIUmSYEpMpJ6TQKJiJkhMjjCGZINSXREZJUpNSbMENSc5nnv5i/Y+/cYDWK5fXM1eNVtTnMP23gXQTAJwTAAwmE/aQvmHmfibEk2MiaRIbUmgWGSYE0EwJ7EcJZEapSSieppkQ+J02EpNiZJudk2k0JoTcSkR2e00TVEaBKQ9Q8FQVU4reJilvcHMODMO7Xak73n3otB7V+zgx7pxPFwyAoBMC7N5BOCkFcEwKZbGiYJhO+DwmglSn43wmUpwfidkpMjPrAamhMIGEpKFBZFALwgKL2n9CBAu1Are1jfcNHD1ayUZ6N6z+64Vv0172dPZstkroFsQGQTApMtBHBKTYnG8efeR7sYEpMpzOA1+TAlEUmwlJUk33JsJ0gpNkezdJNyQ8E2TYmwlJ42KAFARMWVwFl4jFa91bj641n5BzHEkgXzAXqmKfWKKvljHFW9NqZK6E5DQMmCYJSfwSmhMkqGJlMmqamSspwL8sFH54qtq4Umo2JpRNCf4mJEykDaiS2d4FtTCqtslTMIveRrFS3yRFqBaWyGLCbcbkyRDglkOMc5cJ5pxPE2r6m/WnKFxqh32JOCqArCyCeEy0H2Pv9+HiiVDSUAt7cPIH1CNSUPSapgRUPE0Q0JhOEqZQ0JiI3IjKFRkymVtTKS4bZXhAq3p0plMm+2g+sktEi1H6kkdUWon/FSGLEq3yHmVkRtkV06zPn1vLjElx+r7v3DpCBH9jY+xrGT2qXmjoQkhOJgQMC5TcmE4JSYJglJgT+kqZJ0TE7LP6TZNgwJqTQmhKmU0JlMknPn+9498IbJ4SpoWHJOEjCCNU80yHFMFNpYpeZ2mTfp+HPnjs67Uye1qGqbCK6TKbU37Y1OkpNDYmUwTBNyZgaEskSdE1PxIhoUnWp5qQekyRieUTQkJIR4F0BYAE9ntOd6x3Xec96B0YQpBzuu/xRNddCq2QKsqqt7I79TFyp7nWKWtFjvfVnjX5fd3txra3TFW7aIeMyJGME4pNOdOMk1iBNf1tS1ZxjFmKtFzdN3dXK4520muWKNaMaMWuHIuXIuYtY2Oc2uFsajU7tO6ijXMRtzW5pIjVzfe/za0lRkjQrCsir6ZFWpzQF9NrVlmCEJKZQEaTKaDCSdx2d1zEmIOlcRCkJDFjYi7u3NySJKJu7XMV3bqWJSYijRRQpWxtFtoqimW0bVJWQtBBBJioyRqYFjJERMKyWNSbFIFkjTaTREqTGwBixmYqYYZgwCLINRpMkWSFNFRmKBSCRSaIMJPj5+vrW9k1JWoqybGotkrRSaDaMUUmkrRWQDRVGpMbGk0ao0rVK9NiNKlpaTUm5NME0J3pPbtf+GMHl+Cck/pOiekqckTKNRPRKTkkcGBSCcuzMg8rtf61P6saCl42IDMb9P6vHjH2mvRIh4R/lCH+VBbCYsRbEeE/gT+En+NBA+4/negjqki2IPOcIIzYiO7EhzTSxJE7EvEyVp6698903Qu2IXG8PVNihlwXgVxF+0yC3FNggkAFM07mt7az/N/fv7+4JqAmDqgLIhklJ0ShP0TfaRCeVEh1l99+83fvCdpSUm375mvv1bSgQKtUJhTYWWN261hYNDAxSVKQ17wIZlJwlJJr1r3p16z1j79jD8q1r2o746x2uNoUgts5VgXBggFwQOI0Y5qO2zYXr6A92wJLYCY70vOLL1O9x0uzl+TejsUdQqgKwIMg4uAsgpBOJgnJKHwnG+6U7ME+6mtt014ZwL4wJWpi2b7EAZ2xq/b4VhAN8OtV0BtCd7gjfK5xLUo9lEZ57FHwFgVxV5LTywjT8j5Tzz2JaSo+qWdkMzMDMzLruzJgWeWmOaKBuJK+xy5xbGTgkIHZmGMWd91o1DLFXrkx6my3PUl6682svFa1t6gLYUY5mRsrKSQCBShJJAMkhxP4UnXjzEYvx5o5SOXw1NO8BnWa7o0y8amZlnxUpjuXuje9FHFxkkdTQwnAZmZM7CnI18RDVh+MUaks7bUd89cdee/t8OkIb13dXzGbPrHRJIeCgxPvMPiaxC6yJMURMrJJr9w09Mmb/AawJM2ysQCTGWxzfz4x6cMzz8h56xUvZ9hEfNcbFZkAn4xR/ihmNpAhAJ3NDI61xNtwT0s/HMvxqSTR2uCgGBMhCLW1upym4V6Ynz0ywizJol4FaHFQWpHuKyJCJvokts2XXvOhaTp+y2udbINUMJfeJK8fHOyofeax9a1VNsiX54dMosyZlVV+WSRrKLMUm+DWRtil796QLt71VXOQnbIV1yic9NVVyxG+CXODMnz82k3wKb4LayFrCW+FV8Yq2yJcZSQzCSdkkq4PjHhEue+mNM+4kLQFWs8scw4MViEd7/M7v+/mu61vnvSKo2mIbrOlxPlOYgq2s3GPc93rTzWtQyjYJJI5BpjHnjw4vXNq8POTkaYk5tRHhmfcXEA3d7UQoF3f6+Z+yzp1vxhIkOk8kkYgf2oki0RmLMl94FWsUq+8rWUPOAvGcqKspcZZiKvQyVrEbUYVzgtU8VhFxsKuMhVximsoMArPb2nxM/tfsfffvfv3vXEIBAwMkgEK4VVNUyidUr2Er0vnMqszaOU0UosmotG2vi+2oiYzSQkWaExAKZraq1J/zIg/5ykyBiEGUGZLbN4gmMyY0JYwauqkZUVUlotkJnNrSNYlKT2N6YLK3uPVxXNqaLU0yZapgzp9wJwTAI+AfkY4Z+sse2z2GKWDAKwKfWwMUAQhs0G7ZwSTBJ+ZVT/pFM1qAnASQfqtTTde4kiHcMv07bhUExu6jiEkkBMQXK+FRJFq48OdtENL0bFY7NGMBvGmy5HjfdVU+KJxO3XXwLwOvbUykxYmkNJE0lWRRQWyIJZxkjdsyKQAYKqHUjkKKYzq247Y6tPA0WrcqqZ795rzvbi2+PT3Re7BmGFYIqiQb5JJJH0RB3AJ+nSCJvSEjHVX3nWlqykWJREqWakqrUrRNtlptWjViKwkksotkEpUS21GNQE3YIvKQAL1UMOkgBYj1O+itzyM6zuokAKrIEArddAgE1l2kITwuzhlA1XN+azGZATzDe7XT3OZkBKUkkg+x3hsgVateNkUmji86cM3RSZx0JAhUCjgoZCSSAqdzR35XJdvvf6vub2vF3uur8CF9tPdvdvLdr0W8t3JkmMJb/wshoVEpLH86Jg9p/mnfP775t1sqHnXbPrdAq1iBVldszNIFXHHGduO0zflAq137Uh+3Kqr4ypLhAqymtIFX1zpAq/nR0AAm6vtqhDM2Qaqb3852szQ4wM1k47MjjuF9kv4cmGwmwzpbHrhQty4Mcc7Dw2ctLZfGaSTto58rOF3q43KbrdUUsqbo/PWtae8MQCfuEJp+0gE26+00gEqaTEAmJPLGmljCYaQCVYBOcQxAJXeMJYBLYBKWAT9jTRzLMwmZ2HYGlpmXtrPL8KDxWtMrwiMtztdM5OqVsDsjTbz5y0Wham2u63L4wye85xq07/baaekk9R5UMIRuSiOOaTWT7ZhmbwPhucx1oiqpqgjoL1AcMiYJDbAoizmnFe+/HqiX45J+GAeGUawkZknbnSkt8VL49aSL6xJXTJxZBzQhxZzj+51qRI2qI5+wCO8lLfKumPWIVvYpdMD88d/rUquKga2Ik1qTpymCa2QNbALQBvzCEZYRk+YPjwVblCl7s37r1pUYSBqgSSTICf3+c86f5EP5vJHwdpQxh4plLJi1lqYu9YywWUwSksKlRUsGtgjOmIh3uSIdb96d6z/DfNuYkTruQEwSESgIDI81Si97VWmnon0M1FazNE6EYEBNPRrlN93ru++96e9RgEIQC3R4BQAMkizA5DiQQ9W2Vk535958Yzts5vOpP+AjZ5aZSgp6MAMDCAYTJCrrFtvyY5m0K1n0uv1T2zjGnY5G/3/iGkGKyQczQbHyLuRU2Ls05dv8R+7lZvG0JJkgQ5LevzMYModYurixFjGmbddk2plpF7kYxylIyYRy7Bt3VvcgdWVjUubrtdtTmLdLlzO5WcL5sHjcLeGQmSqspUG8zYrl1ujS7vGzDtc5cyhevcOhR2E3ipFUAdi6mQQm85Ut3ng7tq73TOWO9oU+hkZrNx5QiLkapZbFKPVcogYFcFu8qqeK1JSEw9jwbgZeCmd3MFafTaqvLEMDDvDjDto0jL2wrQRgRmxyJRV1lwtGWGu5NC9GZqVpsF9rDZpkp8wtur5+TT7ijdKsyqMgAFyHr9y49ojPp7ua6q4GbQAg/jJS+soq7PqafXTQrjFR6MVVcU9x9kxCBSDbfLbViH+1SBwqSZWQjcnGWV/v7GYkN7JLUSb07gLJG2bZWsNgxVig601ZTzIeWKMhJJSCw7gus1dTH39u3PvNfPfJBJJLLBKXX4+7vT3iJdfjVK2phBr1okviVWU75nxqnW4+NknPxoRUYBAV1NLuIB/VAVZQgSRdpxlNNQpSz2tqmK89qDfZ1X0pAhAKtc03arU6vU2CXw1vt8roZhMsKV9Yoq0zMRIyYQkFUWwrpjFOGPNz5XF3t5d1MJAMhBbdqPYtWce2jgAAt8rVrhw0bw3zf3liW4VOf3dtpYpZe5I0fM2k446ztnjnGiem/OVttttttXKcVXltOrDj7g3xnrPd9S7v39vv+ftfz+CAgIn1+Pfd3d3TjjuzOalebPs3br2SABbxXtu8EYt3dO8IWwRARJBHv8z937+vf758f173xFq1i1CpZprZmtDNNqvcUBnQljaBha4+oFZrdrJarDcdhk2hIAWOYjOHfOJxC0hCf/X9/8f4b/0/vxb7/V76/VAq+3zrWszVVUzTMaQAIZnYEbQIFVxfx4/HweKBj86+3iKXxHFbf5ETrvT/WMa6bE8IYjR/veDWg/3sIZNa93GOadVI1rZJHuNP5pGdqb2zRPIXu/eJ0yQMjTIu7hLUbAkgOgqkoSiZqI9xoE/Y8r9LPMepAneme+uSINDG/sZk2gEuKjklN9+srLPE0lEjFmNMYugQCdD5zCyzsDMqsnehg7xMdc4J9jEBN71mEE2yzVv3UgghJeh7ez2++b37nfdOdV9OpsUu1crHcT7KdkB3GUUtn/XNliaAKA+QgAE4gAXZ1LmlY08zUBe/nrraZl846ee21bZ2wgTvOH81xH05wkkkdJybUzUWOtbq7Qta+Qr6BWi4SEgoQhxAwpYBdpk2+t75f5rXe+76+UJJIDPWEkkiCwK2hQIMZmMnDVZRurrzC8NgYxR1rWHmaslWk53RAJBLFcehIQKjRDhuuYDTJLvLQDbdK+4hb2nB2RsYpTUSruJ2OctD6YjUoLsfWTq61x6jjzTPpxbLauWnmmW1G1m0ka4jF5L1e+MCZpzXlylzwxJm5sgjthgsIrCS3p++ebujFX9V6X53dHoDnGHY3ZHdaRJC8HdU/fd6zziYsrrjExS3k4zgh2WtOeYF5hr4jKJZJzl/6R8bLANZmcNNthIQO7iZlWzoQAX8/jLpXZfM5GfpATD+WGdqXXGVlifsTP5hpH8wDdnCG+b9CKu9WFLObuQjcOQ1WO+cqJJJjgOB6Ac/+r5/Z/l/n/7b9c8caHdhoTRCeHdmVZhaE/ncSSAf6+x/sohjOEEM1EiH+rICa5wjgBKkCZsSQ1GcSHP8wdZwclk/tfzbENLOK1Bjf5zXHrx1DEsaj+BBVi8OF/6OabzVarJIE/aYaV0J7nJmrXmmDFdVov6+2LXI0TGJL7hJrlglaFOZHGEma6xSbbVdd+evS+1553Pr+fXn25ehAa8UXo5TDqjMw7F+OpZKMMJIEDj66Pn3d779z95599+yc7zOZ97JDgCgqSRZEiBkAJi5gTV5bF3zSfYYrexR1W0gQ4OLwMJ2ca9HM3cNMTv0M0+cqwYYswG2JlxV6/GGayZpmiBSMJDEaQkkgHL3aWdpZ5Gtbvb4v3eu+77ywCGXajkjIBxxzAMLmTULPKQXBjIxeqEkkBp6zAm51nOMoj0DMNgFSAOsWPOHHcPKyejShIEJgxfewlhu6KEFWNxMEAxVklduJi13tTat3mDnjG1GbvnXNtrNmlb/ph7X4nvkjPcUn1htFkOrb9e9mGnPbI/a4szWcZsyu+NdtTvlbQpXGANLVnTDIJBLP8Hj6iAPiCSB/JFq2N5AO0i0J7+11pa7tV3WK2rNXiMS28YMUbaYN89xIROGhp9ic39frzwYXOEtbVzXVZrOdsy3N2JfJ3+yjFb9sPuhgxXUpz3tyHOipSR2O0qhJJAQcYbfdBPWLsjmm2AbZ6uNx71m1bbZbX5GaP337WbV9EkKR554zM5wkjKyJE/X9zwNKK7BlgvjFzuuG78Nb6d752973vHvePe8e90d/e97x73j3vHvdOzEe9073p3vTu+nOUmY7z3e9O96b7w52taUnvu8Oc4a1w3vl7WrWnPc9zJzWjm9nb2tWve+7jmeaNc2b1nF72tznu+94znxrRnF72tX1vX9j2dmtENnF7Wtvfue7j3teV53qMTSnq79fi8HbPv1613TaRRs07ABy4oxD5QShOymmnjrFme8QiWSZAwoYFKa+nSnlHgQX03CZlJOwmEYJglJKSpUKSUlIV+nU0GbInvGONWHfzXJOrvAVQYBOms8b8G9ovUhtG2OX3UrIwENxkISTROXxb1Js7M7Z5VmyXiIw1+dtil791ho2++Y7ffN6773qUQkkgIj0sFDMXMeDmPVMy++75uEqEISSQFISjKMLwLnr+5iEqgHR9zlBw2wE73SSSDnMSFpHlFNgxVlIJi/KY5XG/Z73nvb6tJJCYSSSKewwZrFRAJu8l6xWgvJpCwheYNT7jVoAt9qhJJAcHaKM+zmtYAVEgfObtfrdgCq332+Pd7475nXqgVb0Tt60kq4Gt3bzwzwR4R2dgrXyXY7nQE6eNpi/cd2MwGN941q75S1OPdCSSAdrej+s6ta+YxSh2yEkkAyRl+a57GbV+JbAqqsyuzNScZnMaq15HlAAKpkRneMgUvzD/M35svDdobbRlG6PsKS+QJa7TTt76itAP6u4UuhU3k0NPG3nc5+3a99wuKqpLN35GKU3VE8zPUCBo5mnpV+6/Lt3cU3XadzcdcvLa5q3v93u9JV68XGT6vsYMV37hOyeE7y2pupxS/zDivK26930PvdszjbDeprVKfVmnnkFRAhwBSCg5pzLDgxl3IekFqxy1VbJc0+QpJ0JrBQFDl6uDMYBe3NyhcEx4YoHM5kylQSbbBBA+4HNIck5FJKbE5qvoM6ctjh7VC4xa3fR2t78plt7DnZ3HY2x1r0rGM13nvec9728pSm3qdBtsmuL2hSJ8eVuHRc33d0YruEIVgGBBhwXttBxjAJjjea4AlcFPEIQRyQU75X16V732t+97344KqeEDpO/u2ii+Mkj1nFPXhNmc0SDbACYD3eaBWmokM/jFBV1sz2Onmtw4L1aqivyXfYJNjSbPs1vVkAAq8Z+/c9aTjPn427xxGqCwghYkkipFBipGUZgsKqYgVY6sJ0kM8zqkWsgvJxmYbGW9HIjG6tcWB7Gu3K57hJHKWzm85p6MVmzl2ddZ98eGZ3h2zQWqxxhkbwUIMTd66EYPT4u9Ya0y7epfW7bdREVEIS7DNOcd09lQ5W/d75XV30FxMGvCvmM99DAZ9kSSX0/yn/P+7r6F1HWbwzuzMO7iqrjBhbirLgzIjOcJE1/2/qIk/v97VEnioV9/j+vvcX1eoCCofc/t81bu8jatGpcsvSMWec2vrvxj/Wlx5DvndNIkqFSCgkwJhCEV1D1VJe23KoEid5qSwKXCd+aGvaOtiGCUlq18+w63x1jp/rF/cyk7veWrFYVUMzMCZZz617CBqN6uKVv7W+d772lpD+BIXEyEIChSrZrmmDtQnFic79trdEC6U870imY1aapP3lECAWkDImJlCTF+5TERNqRHaUh15cIjklAayOlOHEki7AT683z7Hsdz7nfecSAF4QKus9ZOu0BdIC99rNuurx598TEHmvSaKRG1EPs0mCa8Pbp7WNWPXAFqLO2/cBYGq9g2qmZ9U/23H+cy3y+G215tQ1iia23i8mXLwkYhCg+drtpgZB3Hnp22f3+ds95uFEfDz5+Wfni+Pg94PwrvaW+Ac+Y0GmGYzveuvZAzszxtj7qzzYr/notHotXuPdnRfK38eiC0fIoqlhQ1ptmUi/MHHr8h8t1vk6T0pmzL368+O3xVR+df8/u2BL1XazHrUzGtaOh3d7fd6sCQg+Am88VGfHq1u8VvTydUdPi/v2mpWsXV8TOWDVX+lxantM4Gvvk0cEkVzoU2TbFnrO0P3AnJ5cSAFdR+pe7Mziw6wAt75E09mE9t5eAJz14TMSCaLP5h2izjcxIq0IhaFnPalebuaO5MYrtmKnOqbDUaaHR8UxTN753znPevfom49wvuvkAArw8NXJfDFOq3tIrWnceFkEkk7IQBgGSBdsm9S2OecWxHQWKuCS7InBKggv7PZEEAUQkFUKrdesc72uOexzWtc971riECFcFBMQjikkZCpIjXHnLrwxNCD6iZqQMksIXXBPmhNEiht7q0lA8pMWSJUikRzYeVM99wAV6eqJJLtKECSrq4QJlt1pepeoXO4rDYtzT4o4bi7IABYpeYpyNBhFd5JoboWZt42qMqh7phmZmleelRmIzWKZsgAF5ks4fwMi7YajIywo67aN4JxGYQACiXxF23xD5rf2IEgyyQkIY48MEWx7PV3nXRRmbb34ajDG22EwyqyAAV+KOtFIB2K1tq1XaSzUmIFQxusoABVtlqT16WYLiSSi/OawgJv1nOK65Zz5r00n1tbYjEXi4qy5uLAmMmMbzuiAJ153kzVVWLhVsz5CNo9stkWxMA2G8SSEVBIQUl4nz9tRtIABPaCwzEbZpz9+7464xcAkY4y/CRP0C2BbItSzMYsyLt+v+v63bbh+n6f/fp2r/P+Hj/rpx8fuunWv++l/jH/H3+n4P+GzpEnsGKf6fkVzz/HPz/BlU+fxVvI2D8mKf/i7kinChIKQOItgA='))) \ No newline at end of file diff --git a/irlc/project1/unitgrade_data/Kiosk1.pkl b/irlc/project1/unitgrade_data/Kiosk1.pkl new file mode 100644 index 0000000000000000000000000000000000000000..9b5467cdfccda39aa44e3d37c721875ed038a5ee GIT binary patch literal 1975 zcmZo*nYxCZ0Ss!VX!NjoXXY1Y8&2urDo!m4EpX0BEH0kXHl>H9Br`X4O4}57drk$g z;ta+f$&%FKlKAq(qTJGg_~MeplGNh(oYcJZk_?azw#4G%)S{9pZBuHecr$p57H2SK zu(eI;VJ*ol$pIPFqvD*Anw*`Pm#zTOrI4Sd05(RUxF9h(RUxxj!N_n5L|X<6$Zp>t zsNG<bIFj?rQi~GPL59^%=@H8;%1PEQD9X=DO)fFi&jxu!ub^@Y$Xg02sc8xYIr$~= z1^GFd$(0%fnK}w!hv+C2q@-zDP4V{Xd7z-6prE9rq~MX7Q;=GukXD+PT#}ier%;j) z)~isGk*WaE50@)e0GX6ntdO3Xms*rqlA5BBR0&q-5)fZplAoNBSX`2s3|FtG5R#Eu z4CiuztV~YKQ%FixC@oG+0a;a+SzMZ!lUbFjP@a*QoS~2ic0{p4Vo|C>Nn&<to<e3G zR0<MW8kM?<6`94F3W+69aZqF_6qlqHC}>nb<n%xu14WA{C?rtgOheO3VTyNP55ttU zDW%03j6G7w@d~va5wRH@&=?f}#i(rClnkD>DLtxK;u4}25t)W&pvVO207s^Y1S~Q^ zLP8)@DUCy|5gvyb(rr_E#E@bb5(UMOC=LNhgJW0-IflWB2$acTG21^y!<)gI(VNMe z*_*|i)tk+m-J8Rk)0@ki+ndLm*PG9q-&??2&|An`*jr=*C>0n%Q-KIP6@U$eL_H|d zK?=Z;Zaf1P=^&xeNT))^g~zHea;!pQeoEUE5~39xnQqX?6op47#4JQ?f>eNG)2s&; Rn;@al*rZZy63oJ-dH^wBv&#Sg literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Kiosk2.pkl b/irlc/project1/unitgrade_data/Kiosk2.pkl new file mode 100644 index 0000000000000000000000000000000000000000..066206a99d6cfaa3faf6427d526b8d872f6f8b4c GIT binary patch literal 11083 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 literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Kiosk3.pkl b/irlc/project1/unitgrade_data/Kiosk3.pkl new file mode 100644 index 0000000000000000000000000000000000000000..066206a99d6cfaa3faf6427d526b8d872f6f8b4c GIT binary patch literal 11083 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 literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman1.pkl b/irlc/project1/unitgrade_data/Pacman1.pkl new file mode 100644 index 0000000000000000000000000000000000000000..f37fc807282017b9e603748155519d4e98aec43b GIT binary patch literal 1605 zcmZo*nQFzx00y;FG<w(r5|eWi^9-l-a22PPgcdmGBo-G>X`9l+Qj(dQI;CxjyS>^3 zu<8uP9-)%d;*$8{lEjkK;`p4@y!4U`kW#k9;^Nezk|}LdYNvQJc(WE~FlMl|P3d7R z$t=kMnb9NZoRONGotc-ekXM?Ulv<>apQZpYW(q`Y1`Eihf`<(ts~|!>9Lf1*sYQwD zAQNh*^oVB`<s|DD6y;~7CYKoM7l7TZS5P?x<PGJtqWoNi<oukR)Z~)P{Jdg?%-n+f zq7sFa)U?FXoRXBx<dP}gJ`wVa3=FA>#U%>13Q9^!3S6pCz@@4XprD|jrwSJV%PT7u zbAgl_LDa(~xl|Pt6chr`lye0K8<k|{RiY^7Qq>DkP*CMkRd9EQtLIWuQsN2@Ho&7A z$uUsXhWJ#YnVphYl9-ZNoLr3J7LY5TzSIj)RRy_956Xvx1IQ*&jP`)M2f|tkp~a~R zB^jv-?v=Taq~e-amRXdamz$bbqL2(qEqV$e8L0|IsnGB)PA<wU0L6hqd1g+ILUMjy zNn&Q6LS|lCeo<~BSRyegzqCXlBfngsBwwL8wL~GaM4_}mM<KBoq6ZSU@hPdf`Jf2) zuI<qWIR+GH?v6oDj_$5p1n4PkQ%Z|77<&Z3DK;&$2$pWAv`xw2fF#r&#^@=aq$=As zC4;AJN{<LUk%HAj5-2Erf)s$$XTk<h@?^+h%m4`qfsDbIEPIASFcyP?ksln4i8(pY z%#Rd`8a*nIw4(}2T{bAmNtG)&Ilm~?O2L3@N)JpGNST5SQu0=XE7LVZSEpcuoF`$% z=^A0EQ?P+&E+q4exu*1}!7PSkS_K<K9*3D{YGB4Sr39Q9^r4AC0-hL>^K%PwQcF@5 d@=Hq!N=rZq0;C9>Ad-&35(G$Sq$G$^Jpf0<-FN^1 literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman10.pkl b/irlc/project1/unitgrade_data/Pacman10.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2d64b4d89e99ddca0c6962c11fd8ba8aa491825a GIT binary patch literal 32230 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 F0{|m-^SuB7 literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman11.pkl b/irlc/project1/unitgrade_data/Pacman11.pkl new file mode 100644 index 0000000000000000000000000000000000000000..78b2e18bbd93181f3b8ce15001c4913c34de1d6d GIT binary patch literal 486956 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 UY@3q7(l*82URMF!6)n{R07Rf0>;M1& literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman12.pkl b/irlc/project1/unitgrade_data/Pacman12.pkl new file mode 100644 index 0000000000000000000000000000000000000000..5a930f541bb5dcc56c4ffc4cd181f270c7f6cd6d GIT binary patch literal 11970 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 QAPlM;(AJls)X=4R0KgZ*ApigX literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman3.pkl b/irlc/project1/unitgrade_data/Pacman3.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2d64b4d89e99ddca0c6962c11fd8ba8aa491825a GIT binary patch literal 32230 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 F0{|m-^SuB7 literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman4.pkl b/irlc/project1/unitgrade_data/Pacman4.pkl new file mode 100644 index 0000000000000000000000000000000000000000..78b2e18bbd93181f3b8ce15001c4913c34de1d6d GIT binary patch literal 486956 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 UY@3q7(l*82URMF!6)n{R07Rf0>;M1& literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman6a.pkl b/irlc/project1/unitgrade_data/Pacman6a.pkl new file mode 100644 index 0000000000000000000000000000000000000000..3e711ce40b06ce356765ef1172d9f9524d665ea8 GIT binary patch literal 15361 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 literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman6b.pkl b/irlc/project1/unitgrade_data/Pacman6b.pkl new file mode 100644 index 0000000000000000000000000000000000000000..3e711ce40b06ce356765ef1172d9f9524d665ea8 GIT binary patch literal 15361 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 literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman6c.pkl b/irlc/project1/unitgrade_data/Pacman6c.pkl new file mode 100644 index 0000000000000000000000000000000000000000..3e711ce40b06ce356765ef1172d9f9524d665ea8 GIT binary patch literal 15361 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 literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman7a.pkl b/irlc/project1/unitgrade_data/Pacman7a.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2d64b4d89e99ddca0c6962c11fd8ba8aa491825a GIT binary patch literal 32230 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 F0{|m-^SuB7 literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman7b.pkl b/irlc/project1/unitgrade_data/Pacman7b.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2d64b4d89e99ddca0c6962c11fd8ba8aa491825a GIT binary patch literal 32230 zcmZo*nR>gH0Ss!VX!NiLBqrx3<{3}v;VMoo2`zBWNh~g&(l(`sr6e;qbxPY5cYBTn zVAUCnJt8Hk#U=46naL%Y`FV*&mGQ-yRUkDztR<NxIbfE#XR$&_Myf(yX>L+#kwSi& zLUw9pv3^-%PHAefLS`OV5@CWua(+=!YI2GFlnllUwzerfY>CCisYNAI+NRV_@n-O5 zEQW|@uz*|=-2`<BSSd$xepzZ!Vmip)+9^HanMFCt`UOS#S*gh-hWZ6yf9VxePN|*J zqnwhOrce-{ms(MxQK4X^;GUS98eEcClB%OnYNb$IQlx36FvUA9f|Z4VK|w)5K}ktT z!9BAq72@2)^whi(g-o#X;W`y66cY1N6iO1aQ;QW6!6Bkhssr|3dSY&>LV0FRjzURM zVqS43D6|wx@)Z&l@>0tcib3`&R21lOfouxNNQH|)^dzM!6eZ@R<mW1sXFwcKl&X+e zl&X-PkzZU=tfvr?ky)&eR+<N~vp6HaG$%!&D7B=tC{H0#0V!<r)4<M2%P-310$WzC zr>Cc*P*Gr|P@torr>9p75zbFjNX*GmD9A4^&P>WlRR9GO#8Jfx6$KD)W~62oDHIgt zCnY9j=46&sD(LDeROXi|<fW#jfc%!6pIcB`lB!SwavYL6J%|+^nRz9}R$xbfe66M6 z2@Tq${IXP#lN6x-NJ>>mM2;R%7#F|;CQ%_RCqJ<S6b7lq&`?RuOD#$)Nlj5GEzZnK zhxiy8IN%rqrADM!g9JOo5y2&iMI{QwnYjfysR|lZsYUtFK-L7?kf)HFn4PMSS)x#$ zUzDv-o>`Kike>&O2pw3!<SC?O<|XFjR6<lF=2ar4erTj2`8+5!Hx-;WKn{aQE9B;v zr79$rKqFpH!Ba0)Pa!i+Araypg^a{v1!IN8vc$}sL{JPt(p#|(*lnPMmYk8FUz`ed z9oU&jF`!_mZ;WI;IKky)re~DoR4SAdWhQ4=DinZ%Arq8w6HCxjU2bVkNhT<KAWqd$ zNXbk~ODzKB2&gL*k}AQWo|%`DS(cennwSG|b+JNjVx>Y(Y9cs+fP7mF${66lf+Q~_ zXE|r2CTD|<K{!1#wOFCJG#8Y-3_%f+Sqx7ImHDMb3b~1yc?#u;m7r24B{iuuJsp$) zz*5QiDXHN2Nlq+D&HxE#78ip`prX{A#1as{Bp+&9YFTD}X|X~<er8??BylJyDNSjc zQe2$D*dqik@lc#JrEN+EN86Mh9hdx6P>`h}WebptGZM={*&tP+2o%T);F1qqyh*i9 z$>4#MYyDF+dPMU|a|<f<lJkpF^}vCgSX7i)Ii-iKI5{yVv1rQVDLt%UB~yA>Q%Wie zQb8h2nHEzzJKCoNP0{dX?qRf<;^*h*_5c6>|6szKp=3&uGY2EMlw@F-(l#Y%$^=je z3bGnpg2u>!<uVvEKte(w*NhgNqXj28Lu91FYn9Q06I8{G7M!4TL0-Yh4K6srZ5>c^ z5?o^H!b?n~MoMyiUP)qR9;76N6q!(68H^cLXhkNdiKho`*@0SFV3kvPIN|mCl*v;x z8>fI8wk#=$C5cmdB#^a0bjFvKWabo4>EVUzaseqt=uFGcPnnY8(Zk|il$nAsk=NPP z$0s;Gz%?k|(=TL-w_Fcvd1gvU#uRUk9=42BP-#EKn>oWhc8W&q6phZ#&Qv0)4!FwH z(xe`a<ivvF(wx-dDX~*}xWR2ta8nh;&+zEsas;(T!6FE!u@-|`G9WkeI_Kx5Wu})F zC4yR=2o=l)`NdPbnY<a>ru1;8WP;k<nfZBBdRT%>@(ZSvCiU<pqiD>?fP`a4wl_0K zQ$}tNi)&(W2}mhNW-+AKFr}l1yEr+qC^aP{GdHzpiZ??KcV20(b7E0ZWoBMFj2{GU zo2I6K_*^MPiRJOB6(vQ9poTd|N@`9?Vthp<sIkw`Hl?^UDY1twC$TcWv}8(;5OU<f z1lfEbvatBd2=?a42=Qj_VJ%P0$tj+a;SY6rkhdI64i+gL9UY)Z>F6Yy>gY&KEltYs z#b+wHQJoPNJEeyY9K!+mkZuAfk~<*L)HWrthcmA<*B#vK2ZtRb2traTN~Xk4(dgk& zg@P$P9I6Td3JMB(svsszG_{AbB)=pv#|@O8y%|fBdf4Jq6H8L_ro>L^OzdGT2DLq= zfLjhdT=Ae(?+TXngYq0xQc_c<`1SC{Lz5&-nmZosXy5!YNTjmH=j0csPU-Ani7(I0 zo6-qN75PP}&KZe$>8TJ4N|Son;|p>UE5XU6Gzr`+0cCG+vn0wF)+_-DjW$b0`*WlH zxzYX{4f=EZ;ATl`S!z*b38-5L>&z*Iq!yPbB;}W6KzgRd;Lamzzb}I^V;7=5QadHX z1zOR#XLvzbG^-{u5@M%hBtvaUL#mv?HF`#FMqX)BMm~}_w9?KfE=|fP>BuPcX2>Y> zX2>Y_X2__hosv<NQ4OkUGioyGp@u?h(Tpa1HQnH=KQm^<PC-<d8S}guGUgLiH)bpW z)rc8OK~-VKa&RS>vBEE7rC-J>zl_!13>j-WGuC!ytOLuGCS|PmW++X{P|46j>tBP0 z3Bc(BT#?1>fmLLnq%vBOjaFo%71?M-M(v8MhXd08GEbb6!PGVdGC9Jb04{p6xEL82 zK=UKuE;rfJF$iOzLzdpm#RxHQS(mUG&BD>*ZnU@?E$&8(J8Bnqka7n!VL|%53qmin z9P6K=k)e{I-ouoJG?S8{jcpz!Gyg;D$&jn|(0LSuQQ+b)accvp{6mP27Js9~-)QkS zTKv(b_yY}$f{H&9Cs8296G$^s`A2x*f-NJ&n*}y%-U%PzhR;;MW-K6d2Yjxh6FgcT z7dr(sV4;Cy!~)c0#WrFA5yv}Xfz?FVSO?k|h`R#^sDNf*aCd;v3~f^~a(h_)@{39` zrhvvpI&qAPq@s+AK*9ojTm&Kto$Tp=4~)QO7I4rYb=c+;P)s8$yl2Hu(EtsEFttr- zo6-rHv}v1?nlaCt5i%me2ALL^(!-{z7oeb^3SuZIxPzt)U{a|WOT3v%lR$$a8l9b~ z8Oy!6|NZ}uJS@VPv8DquEW-2e|9|+f2+;{D%ZZTzG>(FqLb7~8{g(W!01$<9#0nAr zSz#cBNJC!mSa!Gn0EusKbhCt~f@iHVO7O&XRvgH%rCGHg3Ue@s5jGeE9s`1m1Pu-^ z3qX8|;$_H~A60!j0owNil_TKBPihQO;|C-<+V~l5{ERk!MjJo0Y5af&(?N|NVy0;z zEgp~#Xp5(IiUtu=HI&!D39(ZKWs4^(22$tZs{oOvfgk}f+S~!n0^w-xsAQ=zGB7xE zpbQWYpT@FwKq3T7Bj_-w0g|6}3`7yr2s#5&h|&lmuSIYfWX{s8Paul8_RnAr14yHY z0i{)x)dvZ5e7PWtO2JSHZ7zWdA#igk@d?;Th@xq<xis2b8f`9(HkYW~T!POGCLzxZ zCO}Fb4JNA048o0pwy!`lgK#lOai<RH9l}LNi@VX{ZnU@?E$*mY++~4F7&2!D;d-Iv z7<gt7Tg!ezF~S~j`IZulRK9_1A1&WT%eT?;ZM1x&P5A~IUk8nTkvjDUF5p0#kqS7X zr!C;Sm>^Sp@F_r~sXoy5CaO&RF?xfi{@`77T<et)vp-l?I%CZKku?%BIuHh$_w(jN zoAiUMg(hqID~1Wzj9)saKa!u71)_)<>?!~$L>cS?_iGr)80aYn8MQQP8i-mxRD6qV zI-8im-7M043v2FxN)B*yCv^i-a|a|k+T0m!?u<5fMw>gdY3_hV%|Xo_q9*&mZ5)se zXd8#3$v(8U4Xn*Gh}$^iRtclc9O9Zel+JQpz}fh@4QhJiXWau)#58`MfE1!Me#mOy zX1xZPvowo~nSmjLh?dV_4gj)Sf7A$rQs|%%sO$l^k`e=uT1g<$(N@xED`~WqG}=m{ zb}I=s$7g7OG{+|jDGak5K;=3c^oTO@cmKhSfi|nWIg1fSgNwW3_h1_lqNBy#XmK}M z+>I7@)GqEIB@Aem4b&+l?bJntUT8UnJjeIw<<w0)g?r%J`@m%$$R2R{Rx%&FYXo7! zX!$l;zKxb|qvacI$~VxkI;eajb&d~QXn`~%6>wzF@eR)HeK?LdLTv9t-tUEf^Al+k zh~Ne;8M8}6eQ*sN;Aoo&nec2PbjP!a5H!pNK0*n3LXnB0{d6VFxF!_qL7kuctR@ge z%$QmSNFmCY8Z64ebw2|Gc*iKgDK<o^%9@B_B6*{9GeG7n&Dsf~FxTS`+VF$rMABB? z;|)J@N4T?4gAjcqD-)#~S*e{0v+jZ78t3i=ykRu_(^%GV@<V6Dq@Zr{!)P=G!4Fr& zQij871z7P0+E@->tb}i)HEJ0II;Vf|R)bj-B%cwJ#V9DG>6eHmK*wr9-2(7fMw0{h zY&ghR21s;tEMs&mV{|NIbS#55V;P{yZ_ro<Q44s$0~jD3&;bmJ7Vr$Q0Ss7`KxS`~ zm_^X!*36@07>I+Az+)Ihb|7KvWl$y;NH`jxoCVk5MiUDILq>j9D~KXyaHAWfFh8pg zL=n@ioB~paG8jT$r(ib7oTXWNKooI97sDycU|E{vuENj{Hbikm+0bkjW=bTt6w5*l z)uEb)e}nSUXdY(3eUkyw@EEk*qae&i^RPxnHhc&d&LC>k11Ta#voZK4vW&DWXp(eh zWnjR43?bf-8?jX}1z|SO*|-!s3<K)ifQMm9Rzg+?!@E4A!!V=6Fr&jTqr))N9)>B^ F0{|m-^SuB7 literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman8a.pkl b/irlc/project1/unitgrade_data/Pacman8a.pkl new file mode 100644 index 0000000000000000000000000000000000000000..78b2e18bbd93181f3b8ce15001c4913c34de1d6d GIT binary patch literal 486956 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 UY@3q7(l*82URMF!6)n{R07Rf0>;M1& literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman8b.pkl b/irlc/project1/unitgrade_data/Pacman8b.pkl new file mode 100644 index 0000000000000000000000000000000000000000..78b2e18bbd93181f3b8ce15001c4913c34de1d6d GIT binary patch literal 486956 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 UY@3q7(l*82URMF!6)n{R07Rf0>;M1& literal 0 HcmV?d00001 diff --git a/irlc/project1/unitgrade_data/Pacman9.pkl b/irlc/project1/unitgrade_data/Pacman9.pkl new file mode 100644 index 0000000000000000000000000000000000000000..5a930f541bb5dcc56c4ffc4cd181f270c7f6cd6d GIT binary patch literal 11970 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 QAPlM;(AJls)X=4R0KgZ*ApigX literal 0 HcmV?d00001 diff --git a/irlc/project2/Latex/02465project2_handin.tex b/irlc/project2/Latex/02465project2_handin.tex new file mode 100644 index 0000000..045ca4d --- /dev/null +++ b/irlc/project2/Latex/02465project2_handin.tex @@ -0,0 +1,146 @@ +\documentclass[12pt,twoside]{article} +%\usepackage[table]{xcolor} % important to avoid options clash. +%\input{02465shared_preamble} +%\usepackage{cleveref} +\usepackage{url} +\usepackage{graphics} +\usepackage{multicol} +\usepackage{rotate} +\usepackage{rotating} +\usepackage{booktabs} +\usepackage{hyperref} +\usepackage{pifont} +\usepackage{latexsym} +\usepackage[english]{babel} +\usepackage{epstopdf} +\usepackage{etoolbox} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage{multirow,epstopdf} +\usepackage{fancyhdr} +\usepackage{booktabs} +\usepackage{xcolor} +\newcommand\redt[1]{ {\textcolor[rgb]{0.60, 0.00, 0.00}{\textbf{ #1} } } } + + +\newcommand{\m}[1]{\boldsymbol{ #1}} +\newcommand{\yoursolution}{ \redt{(your solution here) } } + + + +\title{ Report 2 hand-in } +\date{ \today } +\author{Alice (\texttt{s000001})\and Bob (\texttt{s000002})\and Clara (\texttt{s000003}) } + +\begin{document} +\maketitle + +\begin{table}[ht!] +\caption{Attribution table. Feel free to add/remove rows and columns} +\begin{tabular}{llll} +\toprule + & Alice & Bob & Clara \\ +\midrule + 1: Formulate Yodas pendulum as a linear problem & 0-100\% & 0-100\% & 0-100\% \\ + 2: State at a later time & 0-100\% & 0-100\% & 0-100\% \\ + 3: State at a later time II & 0-100\% & 0-100\% & 0-100\% \\ + 4: Eigenvalues and powers & 0-100\% & 0-100\% & 0-100\% \\ + 5: Analytical expression of Eigenvalues using Euler discretization & 0-100\% & 0-100\% & 0-100\% \\ + 6: Bound using Euler discretization & 0-100\% & 0-100\% & 0-100\% \\ + 7: Matrix norm of Exponential discretization (harder) & 0-100\% & 0-100\% & 0-100\% \\ + 8: Stability & 0-100\% & 0-100\% & 0-100\% \\ + 9: Discretization & 0-100\% & 0-100\% & 0-100\% \\ + 10: Linearization & 0-100\% & 0-100\% & 0-100\% \\ + 11: Unitgrade self-check & 0-100\% & 0-100\% & 0-100\% \\ + 12: Optimal planning & 0-100\% & 0-100\% & 0-100\% \\ + 13: Control using simple linearization & 0-100\% & 0-100\% & 0-100\% \\ + 14: MPC & 0-100\% & 0-100\% & 0-100\% \\ +\bottomrule +\end{tabular} +\end{table} + +%\paragraph{Statement about collaboration:} +%Please edit this section to reflect how you have used external resources. The following statement will in most cases suffice: +%\emph{The code in the irls/project1 directory is entirely} + +%\paragraph{Main report:} +Headings have been inserted in the document for readability. You only have to edit the part which says \yoursolution. + +\section{Master Yodas pendulum (\texttt{yoda.py})}\label{yoda1} +\subsubsection*{{\color{red}Problem 1: Formulate Yodas pendulum as a linear problem}} + + \begin{align} + A & = \begin{bmatrix} \cdots \end{bmatrix} \\ + B & = \begin{bmatrix} \cdots \end{bmatrix} + \end{align} + \yoursolution + +\subsubsection*{{\color{red}Problem 2: State at a later time}} + + To solve the first part, we can write $\m x_N = \begin{bmatrix} \cdots \end{bmatrix}$ + + As for the second part we get: +\begin{align} +\tilde A_0 & = \begin{bmatrix} \cdots \end{bmatrix}, \quad A_0 = \begin{bmatrix} \cdots \end{bmatrix} +\end{align} + \yoursolution +\subsubsection*{{\color{red}Problem 4: Eigenvalues and powers}} + +Assume $\lambda_1, \lambda_2$ are the eigenvalues ... then the Eigenvalues of $M$ is ... similarly for $\tilde M$ ... +\yoursolution + +\subsubsection*{{\color{red}Problem 5: Analytical expression of Eigenvalues using Euler discretization}} + +... we get a characteristic polynomial of ... and therefore it follows from Mat1 that the two Eigenvalues are ... +\yoursolution + +\subsubsection*{{\color{red}Problem 6: Bound using Euler discretization}} + + Using Euler discretization we get the upper bound: + $$ +\| \m x_N \| \leq \cdots +$$ +\yoursolution + +\subsubsection*{{\color{red}Problem 7: Matrix norm of Exponential discretization (harder)}} + +Using exponential discretization we get an upper bound of: + $$ + \| \m x_N \| \leq \cdots + $$ + \yoursolution + +\section{R2D2 and control (\texttt{r2d2.py})} +\subsubsection*{{\color{red}Problem 9: Discretization}} + + $$ + \m x_{k+1} = \m f_k(\m x_k, \m u_k) = \begin{bmatrix} \cdots \\ \cdots \\ \cdots \end{bmatrix}$$ + +\subsubsection*{{\color{red}Problem 10: Linearization}} + +$$ + \m x_{k+1} \approx \begin{bmatrix} \cdots \\ \cdots \\ \cdots \end{bmatrix} \m x_k + + \begin{bmatrix} \cdots \\ \cdots \\ \cdots \end{bmatrix} \m u_k + + \begin{bmatrix} \vdots \end{bmatrix} +$$ + +\subsubsection*{{\color{red}Problem 12: Optimal planning}} + + \begin{center}\includegraphics[width=.5\linewidth]{figures/your_answer}~ + \includegraphics[width=.5\linewidth]{figures/your_answer} \end{center} + +\subsubsection*{{\color{red}Problem 13: Control using simple linearization}} + + % Just generate the figures using the script and change the path below. + \begin{center}\includegraphics[width=.5\linewidth]{figures/your_answer}~ + \includegraphics[width=.5\linewidth]{figures/your_answer} \end{center} +Intuitively, the second case fails because... \yoursolution + +\subsubsection*{{\color{red}Problem 14: MPC}} + + \begin{center}\includegraphics[width=.6\linewidth]{figures/your_answer}%~ + % \includegraphics[width=.5\linewidth]{figures/your_answer} + \end{center} + Iterative linearization solves the problem because... \yoursolution + +\end{document} \ No newline at end of file diff --git a/irlc/project2/Latex/figures/your_answer.pdf b/irlc/project2/Latex/figures/your_answer.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d8c092974e20aaaf1165958a53bdce3a2ebdbf8f GIT binary patch literal 6498 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 VQc;we#${$?V9cee>gw;t1pvtyz)}DJ literal 0 HcmV?d00001 diff --git a/irlc/project2/__init__.py b/irlc/project2/__init__.py new file mode 100644 index 0000000..8794db4 --- /dev/null +++ b/irlc/project2/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This file is required for the test system but should otherwise be empty.""" diff --git a/irlc/project2/project2_grade.py b/irlc/project2/project2_grade.py new file mode 100644 index 0000000..4dfffbd --- /dev/null +++ b/irlc/project2/project2_grade.py @@ -0,0 +1,4 @@ +# irlc/project2/project2_tests.py +''' WARNING: Modifying, decompiling or otherwise tampering with this script, it's data or the resulting .token file will be investigated as a cheating attempt. ''' +import bz2, base64 +exec(bz2.decompress(base64.b64decode('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'))) \ No newline at end of file diff --git a/irlc/project2/project2_tests.py b/irlc/project2/project2_tests.py new file mode 100644 index 0000000..8b43727 --- /dev/null +++ b/irlc/project2/project2_tests.py @@ -0,0 +1,184 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import UTestCase, Report +import irlc +import numpy as np + +class YodaProblem1(UTestCase): + """ Test the get_A_B() function (Section 1, Problem 1) """ + def test_A_B(self): + from irlc.project2.yoda import get_A_B + for g in [9.82, 5.1]: + for L in [0.2, 0.5, 1.1]: + A,B = get_A_B(g,L) + # To get the expected output of a test (in the cases where it is not specified manually), + # simply use the line self.get_expected_test_value() *right before* running the test-function itself. + # print("The expected value is", self.get_expected_test_value()) + # If the code does not work, you need to upgrade unitgrade to the most recent version: + # pip install unitgrade --upgrade --no-cache + print(A) + self.assertLinf(A) + print(B) + self.assertLinf(B) + +class YodaProblem2(UTestCase): + r""" Yodas pendulum: Problem 2 """ + def test_A0(self): + from irlc.project2.yoda import A_ei, A_euler + for g in [9.2, 10]: + for L in [0.2, 0.4]: + for Delta in [0.1, 0.2]: + self.assertLinf(A_euler(g, L, Delta)) # Test Euler discretization + self.assertLinf(A_ei(g, L, Delta)) # Test exponential discretization + + +class YodaProblem3(UTestCase): + r""" Yodas pendulum: Problem 3 """ + def test_M(self): + from irlc.project2.yoda import M_ei, M_euler + for g in [9.2, 10]: + for L in [0.2, 0.4]: + for Delta in [0.1, 0.2]: + for N in [3, 5]: + self.assertLinf(M_ei(g, L, Delta, N)) # Test Euler discretization + self.assertLinf(M_euler(g, L, Delta, N)) # Test exponential discretization + + +class YodaProblem6(UTestCase): + r""" Yodas pendulum: Bound using Euler discretization Problem 6 """ + def test_xN_euler_bound(self): + from irlc.project2.yoda import xN_bound_euler + for g in [9.2, 10]: + for L in [0.2, 0.4]: + for Delta in [0.1, 0.2]: + for N in [3, 5]: + self.assertLinf(xN_bound_euler(g, L, Delta, N)) + +class YodaProblem7(UTestCase): + r"""Yodas pendulum: Bound using exponential discretization Problem 7 """ + def test_xN_euler_bound(self): + from irlc.project2.yoda import xN_bound_ei + for g in [9.2, 10]: + for L in [0.2, 0.4]: + for Delta in [0.1, 0.2]: + for N in [3, 5]: + self.assertLinf(xN_bound_ei(g, L, Delta, N)) + + +class R2D2Problem15(UTestCase): + r"""R2D2: Tests the linearization and discretization code in Problem 9 and Problem 10""" + def test_f_euler_zeros(self): + # Test in a simple case: + x = np.zeros((3,)) + u = np.asarray([1,0]) + from irlc.project2.r2d2 import f_euler + self.assertLinf(f_euler(x, u, Delta=0.05)) + self.assertLinf(f_euler(x, u, Delta=0.1)) + + def test_f_euler(self): + np.random.seed(42) + for _ in range(4): + x = np.random.randn(3) + u = np.random.randn(2) + from irlc.project2.r2d2 import f_euler + self.assertLinf(f_euler(x, u, Delta=0.05)) + self.assertLinf(f_euler(x, u, Delta=0.1)) + + def checklin(self, x_bar, u_bar): + from irlc.project2.r2d2 import linearize + A, B, d = linearize(x_bar, u_bar, Delta=0.05) + self.assertLinf(A) + self.assertLinf(B) + self.assertLinf(d) + + def test_linearization1(self): + x_bar = np.asarray([0, 0, 0]) + u_bar = np.asarray([1, 0]) + self.checklin(x_bar, u_bar) + + def test_linearization2(self): + x_bar = np.asarray([0, 0, 0.24]) + u_bar = np.asarray([1, 0]) + self.checklin(x_bar, u_bar) + + def test_linearization3(self): + np.random.seed(42) + for _ in range(10): + x_bar = np.random.randn(3) + u_bar = np.asarray([1, 0]) + self.checklin(x_bar, u_bar) + +class R2D2Direct(UTestCase): + r"""Problem 12: R2D2 and direct methods """ + def chk_direct(self, x_target): + from irlc.project2.r2d2 import drive_to_direct + states = drive_to_direct(x_target=x_target, plot=False) + self.assertIsInstance(states, np.ndarray) # Test states are an ndarray + self.assertEqualC(states.shape) # Test states have the right shape + self.assertL2(states, tol=0.03) + + def test_direct_1(self): + x_target = (2, 0, 0) + self.chk_direct(x_target) + + def test_direct_2(self): + x_target = (2, 2, np.pi / 2) + self.chk_direct(x_target) + + +class R2D2Linearization(UTestCase): + """Problem 13: R2D2 and simple linearization.""" + def chk_linearization(self, x_target): + from irlc.project2.r2d2 import drive_to_linearization + states = drive_to_linearization(x_target=x_target, plot=False) + self.assertIsInstance(states, np.ndarray) # Test states are an ndarray + self.assertEqualC(states.shape) # Test states have the right shape + self.assertL2(states, tol=0.03) + + def test_linearization_1(self): + x_target = (2, 0, 0) + self.chk_linearization(x_target) + + def test_linearization_2(self): + x_target = (2, 2, np.pi / 2) + self.chk_linearization(x_target) + +class R2D2_MPC(UTestCase): + r"""Problem 14: R2D2 and MPC.""" + def chk_mpc(self, x_target): + from irlc.project2.r2d2 import drive_to_mpc + states = drive_to_mpc(x_target=x_target, plot=False) + self.assertIsInstance(states, np.ndarray) # Test states are an ndarray + self.assertEqualC(states.shape) # Test states have the right shape + self.assertL2(states, tol=0.03) + + def test_mpc_1(self): + self.chk_mpc(x_target=(2,0,0) ) + + def test_mpc_2(self): + self.chk_mpc(x_target=(2, 2, np.pi / 2)) + +class Project2(Report): + title = "Project part 2: Control" + pack_imports = [irlc] + + yoda = [ + (YodaProblem1, 10), + (YodaProblem2, 10), + (YodaProblem3, 10), + (YodaProblem6, 8), + (YodaProblem7, 2) + ] + r2d2 = [ + (R2D2Problem15, 10), + (R2D2Direct, 10), + (R2D2Linearization, 10), + (R2D2_MPC, 10), + ] + + questions = [] + questions += yoda + questions += r2d2 + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Project2() ) diff --git a/irlc/project2/project2_tests_complete_grade.py b/irlc/project2/project2_tests_complete_grade.py new file mode 100644 index 0000000..70f9d0b --- /dev/null +++ b/irlc/project2/project2_tests_complete_grade.py @@ -0,0 +1,4 @@ +# irlc/project2/project2_tests_complete.py +''' WARNING: Modifying, decompiling or otherwise tampering with this script, it's data or the resulting .token file will be investigated as a cheating attempt. ''' +import bz2, base64 +exec(bz2.decompress(base64.b64decode('QlpoOTFBWSZTWSZO0gACUb//gH/+xXd7/////////v////5iGjx6J9vgezovY54jqaYA1pq2yxsFFCgaVoAUAioC2aUu7gA4Q1p9GigA4eu4ab6ctD5c+UllD7tlSVtklBVC9gA0cWzAAERrEsTQfTUSVfe89QntrbwUKAApnu8dGeKB0oFhVcDYMAABTgAAAAAAAAAAAAAF6CwAAAAAAAD3l3h66ABPADQAABIAACgCJG4AAAAAAAAAAAAAHndHAaAAAAAABnvYGRXT0OEBFQbb4AAAAAAABQAAAAj7AAAAAAAANAAAAAnPcAAAAAAAAAAAABzvgAAA94AAAAAAA+4AAwAoUkAUZWAAABGAAAAAAAAAAAAB8gAAAAAAAAAAAAE4AAdwADQ0bYAaKAAEAAHYA3YDIABTc+uAAAAAAAAPdgAAAA5AAAAAAAAUAAAAHrQAAAAaAACQAAAAN0AUDtgAAAAHjarAAAAAAAAAAAAAA3QdwCgAAAAD6AUxuaHbHPdwFAEjwAAAAAAAAAAAAALoYAAAAAADoBsBrDdjkUEQPgAAAAAAAKAAKAA7gFzgAAAAAAAKAAAADdzwAAAO8AAyNskAKNUAAMAAIAKFFAChTzBQAA6Pbl4AAAAAAAHQAAASDsgGAAAAAAABocgFsAAcAd33wHkB74ABoUoAVpoAAbAAH3AAAAHmAfYzYAwUQIiQAlQIkJoMn0DooHcWFCgkOyymKKBQAUKTA33sPeRtsADtgAKXCbrO6d8AI8daVAAHu20GN96zvfYOAAAA72NXNXTJcAKAApfd12lsKQAK05KNGXDQ+jQAOo+zoNz5GgAenbNHpaaAAAUAPr7nuB8QyBiAO9tACiAG7eFDw5FPoGge2ZBRfRiDt8Qqi7NL6ZaGegikegZbYHDW9uHvUFrlwBA6Vc63DBsFBT4QHgegSUr07B3NsC9b0rQFB6Bzk2YO20Ho2ZSnoe+TPpkNZNPkkaV0PrAvS0GPQFO923PEAcFsae120E21QplTnY6G1qG3TqdAYgetzPfTOjQ3ruqdizBkYtKXKTO+22zuwfa3vXnGJ9hYY9Ads2zu7h17CnR97DPbyV2+nyvczOYD7ddtts9tyB0cgGmq9Z7HrJdqeQlAgASECAmgJpoAgAptT1TehMTDSnlPU9NT0yJ6MUbUPUwanhApSIgpQaNAMhp6QMAhoAyDQGg0GgDIDQ0CUxEJBEEE9ExNNGgCanqbCo3qnpih6nqeTUGjamh6jR5TQMgASeqUkCEZEiFHkm1GmepNqeUaGEGg0AyDGpoDTIDTIAyCJEhABAE00AmIGgmjJoZEZGim9U9TNpDQaNR6j0htTTygKiSAgSEUbSNT0E9KZpGmjIxADQAGgA0GgAAB/ctr/Hf5na2v8G1P8HX+IjFEKQoTf4fX/P1rz0g0pCH+51bVOrgxVYMkUYIzDEopRtAICEVGigJFwCh9EAVs+vrVrerbySYNNjICRBCUzBBtb/cboxggE00UaAlVXmtX1bV1ebddwXQiWIF4G7UZAuoSYpMKP2QAXJTLWEyzSf8c1AQKsaTXQxByjX1RebvJJN5i2Wt7pJtTKgsShBZtFtK/b/F33f/frbxhGP27iEX+Lv+N/ng7aBFppa/85KFQkf+rZxlNf3Nmf+/nRz+x6Nn+z/Bn+oVjExeWf7F5W++5sQuv/aFpK16IYkX3lRUkJCEkOOL2/4Trzn+tWL5mNeOb8TKPOlbiBIRpEjqLI/ejdtXpQXq7336scd6yRVN/zf3cMzz1KF3bR020Z8U3ff2Mq1FaNLa5H4RapkEzPlOjW5sXn6ZXw/+8TrPHMrP57/99IN6Mn/J6dvSUO7+H/5Ky9K02u7/OiISGjfDuZAzbSyJKW0mttlprbU2m1S0atspairFtFmlkCwEJ+PxKv8Nz+7tIgQbRJ5VI+f+lwAWtf+VatXZrUaLRsbJY22C1GrRaMba/1drpEbKVE8W81NNW22K1a8/sRkB/foEZaUiRakROuOckx0ai4qMrl4Vuk4yuMMgnV6+qxxNWl2V1nss4Tda/qX77f3eu7U3UGm0H8q81PIQQYi/8S3aaQ1CVRNGmZpAxY87otk+9/w/3L/9/1fd7V51cP82xV2vY/P/0fqhRUuxVVPK+lR5KSUZKKCjoMtFeMWCXZiIZhfssO6r0VGGnuIseXvm+VWY9kdVBuhDSGNeWVpFpW6ajbcp7lqaYXY/jBFOvv3IgpKvXaOvZqeVBWPwT8b9nV65zkv8KJxMSMRWEpge9OYKCERUkeU2JRd69wb/kbPmUqqiskkT4Ge3/gvphBe7o3t06H/11/8eR/jl7+8LZj198/1rMUrOOyqf/z9XP+taunKIZDvNO39sdlU/6SQI/jqd4/10z8b0Yx7e25SdUPmon5/3sDlPP9H239H+dPqIbwfcQTYeeeY5bbPq1eiz8tymEOuJ9ms7yvL9Vv1+7eJ5RIFMLggGSooynp+lxsyalX+7DukJK17/i1bPpJNGk+ujdNnvLH1dpDR3hgN+fuI4vvrLY31QuBCiFHW9+WNvzG9aiEk1ywkVVVp2U59f2qtfi1QJBpaN61hf7W4T/QkbKhcmTsrO8ZWTVHEJ8ZWn0+c7+zHidW7qO7Jv83+Pr7t2f93SU5Ousn11l81theUhfihGcPrz6PlzPivX/++zq4zG/HsHcY++aZJSFP2KX9hpL0yM6wP+v3Ra7Twze7/yueuZqZ8oeBfNX6nKL1c6U81oh4727whCohe/7H9lotvLBtKQtihNilsUSW/y7FPJZmxT+TjfsN6LSpNu8/1yuh87emu/cnbzGt2z3wSOLJSH66b+b0HzbU7TX1mHjCjCx6+u2t3xx5PaJT+NpenJ0pZi1W+bFMDZ8u8elohN69Vencn2kh/168esR9TW6dfBC+PWadtMkxcKRV/L4M51NvfPE/KZenj8YZSWer2FryjU59LLF/E6D2Rv1beVJTz7OSXyFD6iG5wxSFRi7K0/hZSflz0lQlXs5FejFOyky/bPvykioNhwdDlmUxlx+lPW8Ot1U7Px1JxC9rmGzrZmWYvF/wcM1Q/u7rfxvIzwqU7esbmklV1Zmqs3p97Mvs5edVSjdzc9KGVojz+d4NcTonCMx7SaY6wnvdXvy+M+Qy+/I+n3lYPqIdJq8Hl6kAo9ny/lom4TNM2jLzpZGdxyw+QwiFNwFzIK1b2sRLI3xkO8A6AdkRHfdkC82CeNaWeUyukSeNHba/6zCE1U8/+F9GlQgQJQhMSIyl1rT4tTUAq0LJAPy9/4oKYQLkhUUVUhN8qvQ57L0gQkj2G44DiG2kMGKmoUkKkXEZFkzNbrz0Ktl5Gl5QOUHOc56LBKyTD9kVkKqZkcHQgvA44ooroXb7K/vZW0Uuta9Dx1/GRnEKxM/YoRgkkkhISEqSR0mCS22e5fIPtevf7hKwrrF7F7Ro4iNLBO2BlF7tXd3ks1GVUFsg6SNcEJGCyk3ermhugEcgyiJcT9F8i4T2k8mM4odkHAQ8YlRC4nXDoivH82/8/OplRtfLgvViw4wMQjf49RqM2KdXfndcpzSiCcOW+zSIaNUarGHNMNR1/l1ZKxHQIZ6gmcIB8Oqnxl93X5tD/ms37W6MUVWoxdYCT3qXmh7NSEpNqEycqlHoThGrX58ZCxTpAn07JGEnUiCw0yRaHIYaEHKTDRBh5Toy7YnKBl/4JEKkfdQ6Yh7TTClPy/DYVrMHUdvL+WldkwoN+vThYoR7sEjvn7pECkha/9QcfykX1RCZsclHuUgOECrNZr40wQpBjB/xh8yH2HZXD4CoNnyDIQR85A8WNTY/Rxkn3kq0oAKriA0HdE90tTR/5aUoxidT5eML0FtzRNG+8dpysumZaTNYdNilTyLd95VW4LjilfnEQ3n92L9njUQiZti7TF7TJOt4ONDqN2ZR48yAsey3HRdzM3WlTKQvc6LNOxRGC6ati5Hfs27MiYzkIaziPYpMydwo/UWI6+OIP1T771Od1uaFSrqhgYdfY5VT24kpdKfVWH8YOaxNS1WZka5AOcHadbWSAp5CnOCtDjlCsMi1my9Z1DKYMq1bHqjsScdHPm1S5N7A7vq3gved1rA38Dmi7z1P4Pq2IzsJCkNejOkiCLvOQdhWPabOnp7odKWZT1GMCh0Gz3rfxWaYw5vJ3pQzNv00amD/tr/BixwgYrTJCSr7qa86lYhz3++W54pYPEw1KfVeSJmRlSfnKTinoW/Bim7aTstHUK+/p39D8LjFPkTvKPSfZTLdd2SJgzC57kevr51YYbCl6W8MdzBGVouZVlHqo/Jp71/Bjs5/2r9Rr/z5rpJuJvnx9elVVUbAKefijNjD8gzsjwiA5heBvKIZ6vBx9+390subPjKfUdP2lWSG42L0lv4dXETtNe3iQe9CZ2whQc2p7KfYKHee7COp+GZoSLkl9oTs++KfPkCpawoQe4ZV7KjRLnCO+dWK2H01BZ68in646ZOm83E3MbPLRRIEXeblTffexRilSkjHXXPmWPahb8Oz0OxhEyLj8fR7oMUKhvnh1szWi0fXNarUZnGK/ZSBUgu3wIp0VGJgd6SPoQkhVgVZj7I0LszRNRMdhdC5c9Loh7fZLFCXU+mxcp/WoyUnZv0dz3np8ct2PPEyEoxkdf4B+dvi9j6Hsvs8ww0ib0bL5G/Xxh7I3KFXlB49Pl6OcPXPqOXSyKuKDkoI/Acc30MNYbsxCDssrLPkrpg91Kug3XBlFUWPWHxB2SzJJE0v5xmHtJRau7AvzJ27/HcuydTwNLG/X6jptG7GPm7+O5gc+E2rPuWOjfWsFhUFcqdmINqqqAKKooTVJVM+CMQoZHMWJhJWPs1jsd1JGxgdRkizoW60e9BVCfL7t92Gn8vb0pXExw9Dzt9sujz+1lWfmtF8fnxkpagRC0RfB+2EOTY14jz+Xj3jHSszDOsUf8ZH7tP7NbrdN1jMe7iq3kHGQmdKCuQ875DH0PErWZbVe4QpZvHaUxWYX9D5X2s3nSMl5Efgh4xHyik1D4VviHqwrM1iktr4l3Ukho9hqh/Oh/zTshyvrRevwczvfg192C0/glmF9fxjX9EiZXnK4K2/pzWpftHlT81JjHcn4pmj+lT+lNFjuf1fRrHbA4wdC8l9/gcpu3bzg6MphUXt5GpCt5f3C0le1Wb0+r91kpygcHbOBlUJr9aj9SeTcY90FvqYrIouKWpOMTvA8nBT7CqwE/xmx9VwcqQtFR3IMatkkx3qjIfc6INYPeddZzO6tEM8Qshfv9m86zMGLfyBbrbYkP5mKQI6Y2d/AtmJtqvP+WSSZv7rXjnplrrbru5GMYLi71xlqA0z7ic8ElI8KxaPuVFSX2oL7CPl0M1qDDnX49fVZlfC3svKDu8OZcygy09lIp960syG+1qziRe0xK4Kyiso0fD8ea6AZ56XMuRA/8X8XOk2+9fq10LnU6VfoSDK8v/zNlIRLUnFEt9Fq3Tkw4LBn5yVS0u/ce53XyHhQfGFGf93wv371eZ5e2OFZsn2sXcUY3+5/Kus+jd3+Zc7p4RYOzXPl2z4k9K9on6OGvj2ltG/puopghJB9/GLGps8zzPdofhV7LVSPFzt3lb5yp5tn83y9fTiqXxjsDGYMnkP3JJ8lQbccLMny9zAlLL+4o38+uYqFfIfXqKXmk6QXiLNNfZKHuX4Xp/L3L3naZRlUx5eGYK73pPglcmCVVt8JVEA9ds6EQu2dYSRodZYj/IXoRrRhdDZqvxawwXxZesMGKhFXZCPK6EjlMm8rYBntM98OVazwNVHdEPC/VYRlVB7tMTJLKeFU7zyB297e6fft88d/qbs/qaKHNnOuGxfZQovepDJ8/VbViq0GqT/iecBJprUhkMkdthfvQfF1shw8zWtjXdj1Ytq0PqNQmqfVcdSFLWFHhBB0oSkegTDOBf0fL9SQnuOumv+kyUVU9y5LR3PWfqfB2dQX4jHkoqpJYWbeTWIdIEJ2qVAiFcrFK7X5rsT5jLyl4zZ2wXv5EFFFLBcO93NCsgYS1SMGCF85w5tbCu1g8rcrLQpAO1MlpmeutSPSo1qEn3LLoncM+Bln++mqvk6NHqdg+LA1vuegSo2JUJJf3ut0ESJMjOdLEXtL0vAiEjISJRVMCWaac/kteidG3cYMU9WnVYQWpPzj0iVL1bUu6/kFFEnasBgJCNivBdjH1ecTRPJsnBk54Qa6SgvEiwdKFn6O5kqDqLS5+m1cphXHFr6Rg4ZnUxbYn3jlkFH1SkeRAx3ymlLEIdyl6jJcvQ1yJtZ0m7M/lSYyu7e9QG+ydeNc9lGg/L0rYZQVVmDCMTcTKhR/ewyaN2HCXmrkyF96nggShcpiPCytrzZNUpJ0JlD4qqokqG5DaqedBsiSTAOQvRnsP1hG0SihJWPs72PWxM/hgGUXZVxV7P2ZcdLWu8VBhVqwMreMT7aTKrjRpps3lEZX0PI7XBVVkYzkyPLokD+Fa0P7689DRsn3Y7JcoMsUV/AyyJNnVkY66J6TMzwZvmD4+Qyd6bC5CKZvgjkEIHkp+83+R5c91Luz6Dv0dyveebSYmmfdRcR6ihUepHHJaLr9F3UYL5HXhV7hBapHoXwssVo6v6WQU+uRJbvc2xwGxYUSLtVlT2u3ZAsVWPCJpEPb7etpJqp8/J8i6UJPdj16679qs6LPHaCKwgx86OPrYXX3rgUwLCgq1FMe6s+dd8s5FqEjF29xmceMuytMv5vH6jwZwVR8i582PceGmVuUK8absNaR4kTU6ZkLqyHnMSwOYPhHaJQLnxW27p6yPGJX+Pqq6Et2meuSR5tM7a3E3t1333de202xhsyo0ePUakqYYDVLOrfDr0sqpneWZyJ/BHD8827c5F193lCB0oV7eXn7TJklRVSahYsKIfj5Op4OI2q27F0W1hVT2CYe6Tst+QQgtmx2YmQ3nshKofQloPz/f5VDxUGDHkeAyaRfirGSthSvk3quVqpKnFtp6z8qpsq9ngenxxKsaKjtoUfynP1S/PN8Mn65fzz1Q6/2tr6xh/bi8dhOphexPU0x3GS73tRQVcBJUskFBrQNYzBsUWlBUrQk9XS1+yja80k50U1Vjksr6zqYWMmQZ1JZ4MPKWKAySGa6ss+UacmFPDTx0lCoZgvQTMdDDSngZ1V2G61S9nyaCGzyTV2+3rQhQRwu5R1KzUykqUCVEseF4i4rTQ5Q7wkTiSUkwSl2ksU8u8yyVvSDtZjVJDWiIzmiyIWJUV1m8vlJJuwot5HEPI0XPD9w/r+BA7KU96LBvfcaQdztfgs9yOqrVGNrZwyeRmmaY8jv+tNNKp5X5kpP1y2ZdKj7whzwyA/octT0qLbzRXn+gcIp5yN0zTOI+pUskiTHYoeFiSXFF9GO+GsWKPoUqi918UHHKixAxMUke/yKQUpY0s1Hoil5tZKE7nnyIkd7GlNLdkKXHhFTZFD7Rtri9nQHR2uy2sQJ8C5I+BM/U4a9zQobPe7qqm859ylq7NEH8q+S+8p40asDDeTJ6firL0yF2W31Qye9T4nl5KZJ47/o9NKa92YXsKcVOxmKJfMl6+PixFmVZq82YPq6dyfiXwPSJf+7JftaXUvbqTHzOxToUsPOfsePRDGFfSe5PWhnmB6B85Fua+SOTD0m4gvVYNSJoWFOGODPoU2xlzsWkw0xwuTZfb3FsBAooiilA8EJSLryBe+cCuGkU/YN6i/kczI90PQcCtf3aHwOKcc0DyfTuO/v0/Gau+q8Va/P+ajlq9Onb4evTs49l3nA9kPx+c+jmUJTuCy5d0+oIffPqSP1aFEI69RFdR+Wjw3kPk0479XQYdmDrh4m3KAkav4j+r/VJ2VUhCfG3/XN0MzUdJnpZXTLmm20XTf0Xln36XAn2/Hq88fb9p97zphzdS2oWe6qcBRVABUCEBkExyujm6GEKvW3fg/Gkvp+xw+N4tfzrIO/D8T5Y5M91lz6a1ufoJsuv2/XqJVH8H8xf/hG81/Kc3rPafX/O2X7P++pqosvLyjs0eap6fX6vsU+zjEXbNlo4xiX9fleRKfu6azM36a3eDIub++7e4677i1sfXlxonEiVLO/d/R9b99PEjeGO99W14/T1uevXTPGSpZhVm7SWBdLyUrwU/afwAoUe+Px5Fb4+uFB2BsNqHHI8/nx7Dvro8Sny1+TyZZN3+0nGlq++g7+hMcX1/sl+Hlf+j5/T89i/Ps8vKNt377dXLT6X7I9vKWYr77fTfOy68l9CjIEmbrD6W/yNCiqoumSGHyuR9/ehBTCCEIsElVdu9yd1evZquP57WQyiqkzGHa5Uaslf6+Ms87MCIwjFbG3EFOOqEqP+X/O6MRRebIDjAseyA1EAo6glQkkMdQPeg7+1g1HzwMXXP+NOI844jpiuUvT0y9MzrxWn48OvhynwraGqapv9nd/TZ+bI8nScvL08+TzjVQ7S6jDo6KLjC3UEoDEMf3DLgJIum1WKEYk7GVEqtrjZDGFWXVL63Gyv735Ra/xs/j/o7AgSKluRVQ4C6iqsUSWItL/S6LSV6ZWlg248Tz8+szSmOkILQJLWQrLYxspCLR+zjiselCVHP+1jBC3wmhNO1urYK8z75hVn7d5Vmn05G22D2ZlsRe2J2v+NdTqkBJN1/sJllP8cjKYVUy/PG3G1FRJDqquoRYNgklFAk2fjpMHv/SfN4GJUomNTdRR9Se0PGiJgg/6FZSVIX3APQUfQef+hzLMikyj+BVMIvp9nyen9X+1H0Tees+FZ18mMlHpgFZHKxdCANX+nb8331MGYrw1k2aZfJfe/r/z/7PsCQBCVv4a19m+/19Ln49/YS/qm6YiiwBtvb47VPfrfEHovVniBfDKXYYJA0nvkhIJJInxsBpz7CuXirnd1yd25O7MriVG3Cr7ueNymbXyo14ya8f8fdSWXdoyBllsPqjewpxdCa6SneRiZBkYwFkK+b9o55yGSuWKEz5UBYQLi5QGNZCxtJqjW6Py7J6MvX+Pt8ewTMQNC7MrWzsQKxV0oenepRDTabft/418vDNaj/2w73Slyvb/Nlloqdovarmjq5caY51c1zclJ5eeeL6v7ftryJsZ+H3zkeCsyoSq4NJDQLn8LGkH7+zuxpp62Suoaby7nzzXd3PWG/odrxrqGxPeo8TOYJ5dufRrJT38m7/h2ZLddRj4qc23jyPSmr9uu+r29ISnZsXT6Eki7b68VlH8A00/lcOQ+ZCTPWWDEvop+/+IuqKskY+3qZIsfqCU/v1L/VL+z/R/7V/zrn9qHQd3cO8sj5NBNCBwiFSmBR09B7YaPVkbNXrU6NPq/qLzyK/G9nY+GWqtcDW289MNISFpzRFsyxeROYx8YtRI+xr0BpQTPlScsqgKSisf3RRCCTJZSU3HGcT/SCZD+z759i7UZbscLwuFgNC+I9GT4zQgZ0pmB2jbrLa/UhC+K+xldq4G8ZVfK+vznoWcmpIyE0cZTBkHJl/SCROtQYQEdcuhyqPsVemamCSbotNFdXuuBgj3AzWby6RHFZ3pu66/4qvD0aRrK4Vv8pv970JdmmU/gWdpU27iv6MQxJwmh3OfmOitL8Sxoj5WFZifyFK7DQKft8Oi+hYlZgOy6W1wmPZAxFSsFoTM/r0EsTBns4l7TKOlg6YyGGlF5N6qN/ph7FGYwh9Sd0jAqlBTufAr5pnFaoISuev0f9/NZmaR08JZ7dtZ5nGcb93x21TDHoNU9aGLuq+093x8zBHlNdePBLLTO00auasUX6JoTqZNRFmMIsUn2zRJ+vzVPuZkVKxK8hmu0EMDev7WP16FYk6z+kPZO6eSL8zPleZVIruRKEVVISMKI0T10az2EHw1gt2w97ZKYj7xM+kX2Lquvj1ZY1XXREftJC6R6PpB8Ddc00vgNtwn7/y/V/j1M8usQa79qDLBRXWr/rlH2xJ4dbuERRXIl6s/hT3UYl2o6/zWcdfmv5at/BB2qffL80iO32t5xHCNwreH93bFiZfzws4+y0aFg/xr6+u+dZ/jndvtfyZ9zTVUsP+4WiqHZNpX6mj1XvXX0ibNtcJ2k7/tR+vOK/GgWWg0fP4RLeHahq6qkKHsSb1WY0qoam8Qrt8GPyVOynq7XXnr2l5Hjm29mdlUsoygKoUWzq3858WOL0y+PIqpj7JTcb7F9l9ay2N8vl/Hr3IOeuu5Xsi+/J7z+f5c9k7lfco7RUguTG90L4bzlc0xz/JP5K7xJfUXgs12vUWjOzhEdlW16MkdtoSrVr038+ZaaXov0oqv4Vm6/vGGUX2Ykoa3Lfz8u/0Odcx5ZbL+R9cjzBfWuZwtWKvlSYwMSgwYW1+j337lmqZx/2XUKrnEhQ+UpHYY9bEZp3+qvx99MWbCHsKepf4Oib82HPNiC7JVUHmwl+va541AsydWNLECzU+V/xcqp+lW+LeWGtjMRPI2Vd2TMFx8rH9f2TmRh55lJYhrMib/H2eQuybMylvNaS7Sm7UFMKQZWUkzJCVsrGflFASVQa0wy793bK+RVjRkEhsk4fSv0aHltd9yX21BzO/v/F+++0XDqov8/9X+Lm0duOkXW112vtWovZU9V+7jf1V32LZ1LgNCop/rXji3bkUVfg3JZ/z/N5ab3r48N88b+D76m6+PSnTNSbf8X4fK08wOq5arrRlVaeH15dVj0+D9l11jUK61woq6q0TikpR5SHi6u6jUm6u8LRT6Q1hRjx77dFruMvhtdL8ryWZNVn++MxibTZo6dMH3cny86Kd6sV87v+67BJT7cZ+EHlTCp9i/t4+iFUotnT8v9H8l/3+x+G1WOrSxHwVl+z2lBaXun0S7LKhDX+r+PI9JL3X9tS94+NfPnp9ccW/ex8PnDyf0j0oZp9PsaJN5JRuzthu8ifJdQndS1m8pt4WMC93ZfPdJr3u06dL9F2ssU/C3ic/3n15tRvG/4WsfIv6UO12hbGmqeyyssed+8fRZD/DHpL4U+maT5f9vrN/es/TMvn5P/DH1eW5XGUF+HxchVKeSuQrO7ja/F0dfmvsp9Fj2u/fToSLtcbRBP5/pl+jbOvKfi896HpF/TrH9E5cu0Oqi94l8tEQvfBTjdDsq3u52eLZ5EQ3wrCL9tkJejESiUMr05ECwnxcu81b7omd1l2h50x96/XWdFWHZs0f6R6SWfeb/VHHmqIry+PK6+NSZtSqnTEQzSBIGNPN5LMz7PK9PX3nLlq30/lBzpdkDBl1n8pgH835dWh4l0PVco6tF2RkJmrzv0RUNZEkQ0IJIwgHn9HDqx1/RpeUnWYKC8+7Lyc/t2oaKnugU/tyBgUgVlEL+QgyB7dnlE1RJ1/Y9e82lb34U+93exawZBMNo3jffRaSo/F2+OuLsKvbjvPOQuQKSFSbPmvHdevf8/HMO+uX68NzW3+zl79D4dfzD/We+Hz/D1fkIOz6w69nR3Fnj9f+Vno0zrSvQer2uuGqV9mK/qVE9lhqe3b8fkuMS+i2vdzCzo0kyqLln9yp++U/KqBKPKxP8CX4egSp0N+/YNQ7EuxP7bV+7yZcWuY8MNWOkgX3dj99Tq9vesWhYPl41kks+RDouhxPFBWuLX6itv3/ZU9KeFt8WGVUXasrL3Ucwz7oyoUWEPkSvaF+ZH1+bzl+fyKvIGGQ7nw/P6bJqddmcVLPY+vxqhm7dl91XPnHuctqct505P86zap4dWhe5G+upv4lRTyMp6pLUjjFH5cZDqQ8rlwdJleQ1FgdzzJhic9zb15mCPlYNp1I3PtRK/dLN0EWoVPWzqZJP12aS0LQ2LsS6c5BMlDsdkciSi0rQchMb9YCSoqISojJsph1vNHGO/viDZt/l8gwh9KG9ZHuvt5eftVQqaoikdpDkfW2HX7d1LDKwT9dnb6j1wH1Jg5Y1lhr9HIkav6/Z8lp2l5/K1zXlv4fnX57939Z9FDHif4+Xb8PNqB6syHjwOiWU7ni7y3Jz193tv6IH1131ZcY0RUr0kE2S0yjtk9FdB1Bhm38W91kDeqJL36HB/q9a2JCt7iiQnr77DHX2d4mYUupOzBhRHUw+OnLWZXqz6+fpzdx0dHVg7/l+YIwGED/nRwD4VhLKn5KN5gIf8CFMBmT+1k/badutPiiwkHeTuMnbs/no+n5dT5JfkyA9PidrOkwZaFHffP6DzHIDHyrWFCqmHE7HPutUPaoYODDrT9OKcFs+n+hNYI8sROD/6XiJLYVxRvzitxv1dNUyTXw3p1LG9FzRZ6WK3w92FyKfh+aHJlqPmWtQ37aSSZSY6qs2dfH9Nzd6j087Y51jVfJWtc/E/tj+WjcdDS7SdKl+ac19mNTw0ryGsozZEpCo2JVbH56N2+AxY6F91wrjE3baA1wCtUuE31cK07+B9pz4+OL2t9r8JF7yLD67r6qwn6QiYxQSD913JiB0Hl38g6yHVPcMU7YOBmAdK/2Q8h0Q1553R58d8vTs7M+/Bks3b5xTbT+fypeL3xEiIkpSB7r9dLyKqxYVpwU5MlOXK3rK6yxUwqUoqkVp3ej5++L6VsUyjxv8zy+7G/hy+nTLTZW48vCs+ZlJGSeyUkhJJIpkWajdBe8r9evNCxWz9elCP9fzqqsFlmW73xMmOvxdeKthhiQ00JopJ/44ohOi2kK4VWFtgiIBqWblVWCI3hxlOlpNIMgSsg51QAZQ2SZlyyMwQs6ul0NAS+Y6nrCJRtrHv2UjBA60wv7DaB5QNeMzfFCEQT3erIEl2NRd1cJVQ5KRKQXmWqQGSwW/8fb38jTaAEfzpAdgvavFo8TcaG8NMxgZUYGIFkGBxJ0Mk6zNNR90MG/Tb5JsJCId8pzND8KNHDBhDt8pDpLNCE1G5hw1GXc8LLHth0CTAb10P9fgd0Q0SECHsrS8PF23WrpOEMnnqMNPwpk38GTMvLFhs402OcZ5ou8s/oZGQ8zg/gfYyek6nHeWlWn7vLyft44Su3dfW8Q3CCZoZtcTdpIEJkdvPyqcjXCBA1RkXr+bPWzbkaUBg69xRukxAqNfKPiOgEBVFRO3+w9ktHsgwh9QxioeYapgPKSo9tFXNSnHleck9uvR6OjPbNGECMQmQZwwefvL2kOzEn+PueykKOp9PXL+amlFxURBKRMT8Qvj4WrYVfPc6QaPk+3XRMxF9KCqKLQniDIenuHSx6eyF4RThkwQnuwiAxpaF5CvC/BBJCm/f74nNCVr7TBgi2U0Eo5zI69znmEIEwQ5ETOSGolkOXRWhDeHkTP6Tkna+KmZ1mm8Nh+VTy0G/5T5evgD+F5g4SfyS6aIDJaQesCdS8UCc+85/JMlCX6Ot+XZDOTAU/2FpngNhMP3B8zJvsJhFB/O98/AsBQPJPx9/oND+yZA/j6/z/sx/RJhdc0Jye39A+iZ/UKlOLRUXFC85gUB1QcQdFNx9uYgq7oEiIKyAxkE/KbwzIWfokCSSSSaSv5i69peSuvK8kAQaFQiHs+6sX03+H33fPn1qfkOZzhM63uq+C0S9873SHetWG2Qy27QMToyRWnFNIJM/Yn0arZWq8WUueOtcecXl4496dpl7zmckuydWE3h3mwyItstOCdiurcnKbAJOrm3dzck8lfEqqnNW/WenzrX06enr1hIlkgvSm50sQVDIRK+FAVlFYc4qqMg88VmPxb5MXOOxGlnuWmrzK045ibACJySlmW0pkSzkqIjQmizs3JznvbiLBjWObjOpVi+InfVp/7p8spORTrHUUdcRvOJk91thZKzNkAjx+ZwG/49BqSIJPIorMIwV4UE9NMlVNKmmisQYVH4KwqaCBgijRBCwivHQrfx2ccbOjO1AeWwy1zsXmIghJyNxjcsXxgdQRE1UGTyYpvSyRIbvhs5rvR7pafKn2o6sR2gWB1p68uxSkIoIPQYREbRj/LaCoooKIEc1VERnPI46DQ8yinMQYjYrtxryLOOwxNfE5v3++8YYffFVdMac+B7pQ+W1alKiSxRbRtRaLYtiqLGiyajURoLbRqKNiGZC3034+favdet7y/1W5i2KDVRXNdNYrWIqipNsm0a9/V3+0vTFitY0RY0YJvSTKjut6NWFpJbCVf79zfGWjEbYjUYtiwYtQZNbGsWotJsRr37tiyaC2t/Gs1zFaKi1sRFtvXdorQbY2TRqKKtjVFqq0JbLbSRZU1zjrb3tfb165RxYhjRaNYqNFjUWNsEfS3LSWxXu3LQmootWNjV9lcqKo0Vjf0lKstbmok2io2NitvZW5rYtsbYrSUbJUbFgNr29/b9vWvs92xi0aisaiqjYsmZrEVsWjaqKii0aKvjup7a77ddt4ksVjVFVFD7u29lc0YjUZa02xRYKxUWgsaK0Bq+zu6uW0Jb91fz7/XlXsLBpItfDpJsaisaK+FubGxqedrmsGt9/q2vq8r0KNRGMaxtGxRLZaRbpMFQ+aXPXr8byeLHKyGU3KwBoxUfZtXLUYjYtvFq5YtGyaDJsWxo0wikiSSJ0x16lBLrGL0nLlU0MqzsSUTlKhByrjLNbmogYNGhOmDsiHPUaZGh3PaFQVDXEu7reDSMHkriatUexNFESMvKkavFbXLVttebOHjwv3PUu6+GhALWIcQwoGqZKwgjqiJ2VBN3fdJ5/tEqCoKCTedymGzilQ8AKiJ0U1MrIvMWVCDUkJXLY6agLRgszCBPgwJcRQCkXzAR0kh3HHbpzdSA7GDsMENV8OVCmhExFDPM43RbP5J0HDG6FSFZES676h04K02LCgECgmD7uu8dUh0EAc7azckKKD8JUc7NIO/GAug732sgNdoc6VMAJpFtY5hZguLy7W0JjFgD66MTvnrz73ngVJLye6jyz575c2w4Pjoean1T3U4QpO/mzfeIdQ+qtI/r7kVyqv61vGLZKNRiyGCwUaiS/P7dvJtEa3va7goLfxJN5Zq/TrKvSosSsMITZJYgrH2zHVg3W1VS2ajEbBFoKgoqoqkxG/S6Bvem25bFYirrWm5q6kpv5V428rXpt/N5a9NEb/bbbm1GCoo1GNFGi0Vi1EY2or5va6t4u1TVcotRai0WLRrtrW9+p+f2/X4/jn0auexErlAXdFkCR6INQFkWQIRKu7dUWLc3NY2+Wrkl+9tObGsyDBsai2e9rFq9/NvBHooamAQ5kBxbyNAvBnkLIkgAya+zci1ixY0htUbFG2Nvs3Kj8/F73r1sanW45RY1vLLljFEbRUVeVt5UqlS1Lp+92vSore6rm0RtisUJqLSeLdLYqmW9qy3Kuly2ki2jUaJJ13K3WsO8ggbUtrLVytVyORgiXedIkiLVUeEoiPy7YgacZHWz5pJtU8NmG/3eediHSKWRUVUkKcb422COqd2PlkLZJJ1v022QOUiikqpRLHeJGe+XnPfDOHBSlkRZOWevGAa3Vv40riIBosANhSPAYi2GlPO1IO+vpoTzWKqpUsiSTgipIlGsoWw1aSWopYqasWZRF20nAsEVzfUSOKQ9qOVHbm9d+ekcFUvyBwAcRE5BeckRC13VwAyXYxPc31S9DRjVbG54KlZypVVGpxi7C05snlpVL5fRqzU1Zr0LSGOXca8gBEtJpuqGUxKmZj4lzMx6Rq9eVbOowUbjtXktzzi9tQWc2I8sW5ZdU1glLc50w2rVEE0YLKqigq0yqIJGdPoruYWplESepSrvatoJlZvZsSqVR6Sz9nyU+CdKIL/mangYDx9SUhfoqmSVGReQRCzPadcHmFEKORvOZYwsn2n5X95s2Vy4YY/1mGytP3mNmxTdXJ0bE7KdFGGjCYWzcwYctK0bGNm6VNmitUuMfvXRsp5O2yfhu/J0xwxitzGmmjScU7PD+BTeNpZWlYbvM5eU0qYlNhywUwMSIKIo4pGNEWx6va3RMkbMgqCioooiZBQBgUQvKC3SyagYbdWa7kNl7vXqRzOEmVpOr5u1LyfLTa174rJMIV2wtrVvatnfNzRPN1g8Sq+zqs1tAXHelmi8syM1jS35q8FDWaEsRq7RV4GtFORHMVN3mjcxjGpzGy27ZdUzVJu5RY3BctNaFGpKmNPw2Lzk0KrmSZ5TU121HiyyLk85xyuoxmF3uksxpqbll8VUrTBawLq72L4L3dpSlPRXFyj5pMa1ZHIas0uW4sjMRacqRUvm8s7xvnGvYZsa5LE3jZFOXN8JHL7wUa+13EbcnmMbL5MSnyMvtLtZNIiIJonTkTrnTZlNiuuU4u3vXOlklC9mGk8UvKU1tpW3ajDs1CqtIriRUFbbmeXsZpxsPVxt2xgkLYNYnyct2lMgrnFLynzZJ0rM2yY2SHzTBa8q65LNCpfK5k2MaJGTGJxY1+f5H2DX/7/2Udl/Yj/L3E/Xf7PzfoUrT6+Gj+GM83+2P0Jes/ruCpufap/LJxyPx/vPymViESbNx3dvcIIfJfT6xGsHt8pS+Xx+cH0It9n09yYRLrm9bfYMXPo7/YL1yFOYpxhnwVw/MdZCJdwXM7FrN/oIkuelG7LXpN3vHx3zBcbtjs/eZnLY3Qti7oiIJRr0e05UVqlELyd9SJz5SZZ1zSb27LGKkpPaLYy6zZaVU7r2RU8DoqfYp2rxSbLE0yS/T1t9qbfW+/c+qz5TGNudfSJOTp2UbTdavpbBoFQCI6o2eicrYOolP9JzOlECYocYBlCgHE2XeuZjip+f30/j9fb71+vPn7fPr67EJGSEzBP47mmRqSYGRRQNMlrRNrRgZookUSRJAJDCBGxpYMgaWQkmO7kok0FJo0MmIhKBGKKSjfjdtxIRLJCRiLMSkpRIEFECGmJERIEkYwjQu9/tfXtez8evbevRKWSyJUoaBGWSJpjCWUMJDINF/nLqQfPdu66BRGBjTSaF6lxiImyGgiZQjRlIJhiHpdkkEGESLM0iQSEzCRKGUmDJmJMIlGE167rMblcSVKmUZUUlQaUYWft9very9MhNETMae7oklTEzFkMSJGilBSghYSRgZgDGJFkYGyYhJol5XXSzGIJBholABgxNEnu3RKc58/v5eKY0gRDQkGRTM0yAZJmKQvft0xmNgjGhlbXt25AkTX67kXfF54loxGBTITQyiQBEMiTBpCJDEvS7ImZk0TAJJoBJYMRGk0hj2dCREIglNBCgjd11rRLNGwaSGiSSk0hIJy6kYgYKYpkgQYTMiYpBRImhQCxGiAZIoCRoWJ+P5/e+/n6ve95ljCNQk+e6QigbGIkCJEmYyMhSmgg0A2tM2hkkEPnuFDSWTIYkRlTTKEW8XRJCIJDGJCUhjE0EoRiZiEmSJikkSYgiAwJgikhRMkNCjSyZSEYYY0QR9vrq8xDUgjQTIkhsMIe3dIhJERZJs0Rg0TJixJMpGGie3XZeOkRShSUKNJkwaF51wCbWhEohTBW0wI0Yl+3clJMzMzGmDeuumgkjKCElJSJGRZpUC9OsGIZTKCBAr8Lt7fj9fj17BlMmMMSYEwSYTDaU0aSJNEGWAkzfHdhCTKCUZBlGznEaTRDDGIERMNbSRkiZCZCZBFEMJAyEiRBST566akQzIpJkSHN0hQJIkERpGWaYzSmJlFBEBZN+11x7X7fjz0lMJgEkgn9nd8ONJkQxTTQpBGUMDMhDQRFksOXBhkjYSUyYoO7skjGaIhKT+x0aaBIMkzEnxX9Pr69Xsmk0SkIRCgmaSg1IIBT7OpQlECSQkWvluUJiIGZkGNtoJNJ+l1+fz3kmBkJLEBMvZvdvETQFd3I2lIkIpCSQQY0JCSWUJRlMW2nOYFDRhF3dMWGYMMiDTGQ/b588Iz13YttEpiGTIyJJXt25kEI0IUjCokkmKY2KaI7upIir322t+e3j5diMNvfrggIO7gnv26KCZQEJJROVzRjTCJGEgUYSJILzuEoUxMxMGEhgQmJJZBEZowFMIYpTDurtJkwmlJgRBAlNDCEAZgzFAkUG1oxoUlELClJFyuhMsu7TAqqqKKGMdohceJ6ouYWffVdSQeFuhbhissMKvDkdRCQJe67u0tubd0iJEgmwQhxU0RD61lbLPpkwalV4rX/2MXjOnaC0F/K5FFOnKCAEFcy6vKVemuo8NvputDUREQRhBBGjF1gSzKzeZ7GLxLOeSwHQCgKEddu1Jxem+u3Z/sMcfYmKbNJMxSYGFCkxACnM73Ylm+Zi9T1l7igDQy6edCTSmMTubkagjqRuc3REc9Q368ssK8+vnxvedG5LLQkIVISQqSEJoaRQlKQwYpokIQBBgbX9TqAKZSxSYwGOXbEZgxqMmBKRRhQRJCNJETNGakk+OuhGDIT+vuIw0UnpyQYmQ0kRKRImGyMJIJmRpYxQS2tJfx10j9+/HlxMgaGJmkZAkGMsTNCbILJmMiKYkAgxNFe/dCU2YYQsZJy4MyWDEEGKYNJKGOcxl/b7o17K6GJoRKZMTTIwgxIaRIESlIRiaUJpFDJCjERJkmiLV+O+fmr14oEQLEI0GMTDMxNBihCJI0QRE0CCHw4YpmYyKWDSKhDMA0O6uxSTAgkZIEJMlNIkJFd3JgF5WXSiRA02YYTKUUNKRmAUEIxNIgzGWEkko0VBMEBgRQXptr8ea74/Hv5r1GIlHuuwGTBSCAoRgYxjNJC+HRoynncQmhMmSMN67sUZjEYZgmQhHrt0JEmEJEf2+4RCZCImhEkiEwwTJNFBeOImmZkiYk0zIqUTERKEZqI0hlJhFFH2bd/P6+Pt69lTBiIEpISbGl9ddEMQtJJSDJlJmUmIxsEJEMkYSySQZpSDICEzMEkkmRuXMkZED5cZIQFIjIRJiimijZQwkaEspNAzBJZpljJKkkIgZLEJ93fv11iaZiYKRRsSWSSkMgNKQYmUJT790kZRopMZpka2gUMUwzEQgwjINEyyiZTRolCMUhMGjQkmfXz73r1IUwCYBpmZAygIoZBIxEpIEkxAIvldJRIttG1ohpSiISRIzYU1x4aYXBjDIsg8cHO6EcJnz6/tcfnyPy/Pnddkk813UD4VPqk+WQbPmSG6ydKJJt07289eOYi/O/Lf1wSflFBeWqxQcBelpREUy40Cb+jFioBjblA9eqoSGVEHizQc1awo84evF5xZqFYqpBm5Mu5qFpra3JSsQIhxzLnN43kqpwb8vfu/BbKGG7C3oyyl2jhtLz1gk3aXTrmmqN2kM0hFJ5dpVy9GFQVUWNVtJuqPYW18aHSJ5h1qyaXc+043l8ixacLt4w+LyvQ48KFKoSFVVQVVFVhkzGIQaaf1rhDXn2e366LFhZbrLpeie91quYV9TnZtTeWX5Geh/u7/ezfP81fxMTjjTDPQfKa7kYSd5CoYJSwJDCJx2b/X2z39ZwdqSWXop6XjzGxCTnaD0KJSdD1xVbe15V3jVfbMtl5RLeqcxvK6lwehKe6tsxeGSGFtkdnvHM/WcOdVsEPOGvbkkREE1JdRfqlqG6RNR+uRXHWInO62kWm+KlIlidJ11tiVM1FnTkrrIW/DeTLX5Vs4BR62lleNW0tNPmZDqbpptaaHJ5jO+MbtKWyzytvRXWDdrKVaJruVJD8JFiCai6oaFxBScZTb450YaMdDHSxV+RrrNpym+eUJ1o3OjrZvP3F51ltzBjC0npp4kbrvdn6nqtaLWVZTsW3qMa6vs6311y2orXKyxZa3Ctb/K7SancWmpFUzXs7zwiDtuyuTtui8n2oVrgbbVy+IrKLdNK6VjGKS088ra+7YK956LXvOxMzLlt7cs3JFLytyWbYtdjg5WRwnhda1MfMpaU9D3H4jKb7oIInv/+Pw+dvJWp3/M/y5H9ps8tZ6xxlDt8cffXu2fCH7wy3nphs5UVzqvo7jKz545dWMHcnCBT5u3q47HtxnVp8A6h2xMvT2gPKcfORt/Ftq/s/j/cz7v5TdiqopjCsOGv5c3eM2kN1RP3KPpUVQlR/CqGEGGMUrDDFfvqIYpKVClVSVBJKo0mK/c8K0bKKVKSlfUrStKKKJRUiqKopFUpYmxTClKKoqxUpSpSyp5TBvPseHlucyOEcqqh24c7z+Oe9+HKqqUqlilLIJ7UQkqjdRHpU2VIj7rIDPWHlKHKkyyc2TCqvazdYCJ9WgzSViZ0dxLGiCii4EuOHEJkgsEx8eXkbGnc04bK+OK2PEVZy9OE8JUpTZXg5emmRFKUHZylYGK249bH2Km0YxkY6OU8vuuzp9OHtu4eGN3CHl6fTpo4OimCdlhopyfDl6Ph9Mae1KcHZ2Y02bGxRy8uXl4dtMHbSaR9PKepNJyeJ8PBubMNjpXlPMlkcGpHDc+Pp5G5zIw8etjlN7JiNnTQ4PQw0cMLPZo8jc3Po0bG5ymfHBudMOnLSZBp25423mjc5NtS/TDo8jYnrtodJVh5NysYMxdJjNnibNm7GJgqmOuOtm5wOSlKUquW0fTpo04aI68w2Ts2buzQ3bt1HL0zI03axKVNjT2cNpvXLdh9NjhNG6tm704PSq5nTY8uHzJ3PDTSbtMU9Hhw5ZMPKnWzwbunHBibjk2dOG6tnDh6K4NGGGxTlqMm6nBjRw6cKxp2+jk67dvBnTtXCnaorHLtsr0buzqeXTkxy3bOzY3NFcvDR6YbNicqnubHqTDU0ibpyV2bO/T23Yr2x4cy2+Tbd6U2nth5mCCokVDIMGAUEmUKCOFyhIcgg5cigZKmTZYgmYFJhg4IiZLBcSZIcNEFSmNhjY3PD04dOnLk+s5V2TbOzT4+jWyu3yYnB8U6cO3vZ6Lh6TDdk3OXRsVjT4emzkrZO1Ppz2eHxVeDRyZK6eTwejE8OVNNMY8nDhyw0nBs+homHbHJox7dMYx9Gzdudk3O1Z7+j2cnDpT0rhy3NMbHlpt0NJ4Tl2w5OTDk9mHgm5js4fTk4PMpvN3004KaYOXSfE03eSm6vDJWH1PM2PhtMLKWmJjE0dmOGxo03ezf6O5OQ0fDHQ4ejwND37dKl6Op7cuG6VXoryrSlVKpsUmGMT2V0Y08MY04dp6VOU9q5aPDp0nJ6bpsqqbnNY084dnRhhh7ySbjYquSvo8zo0psjDDGkaSmMbtj0sxoUphu3Y2bNT6YeHDT6mzdXSsPejToqu/BWn0eHl2xw3abvD49uW6p6VwU+nTcpo9GHc8HpWjgbsbFTFNOGnRumPTftyjTZmxTyqwUE5IkTBjRIGKBBBgUc4QMSJEwubTabirPLTHJ9HLg9N3g0+FOXTw0p6TZ6Pjy7Oj02Uw6NN3Zwedml7YVuYVynKcKw8Nmzw6NlaO3CVulKLOzhobKo8mMVpWHjyqYnU03aO3B4MaemnxuYeJjd5O3l5N3LTGJqcNFbNk9Hg5Nm26bscGMaco3PbhN2RNj6NT401MN27GzUycGJh8Kr2po7bp2aTTlGNOWxzo2NmOXDZNPjHRW6uRjgndRlzwsIJut+IaNxY1yVNkuLxRVKKJUtn/UVM8oWWyrW5nRnWoruOlpiXS5pQfEiW5NrSqt2tPeJqGMaKRzTSnrksnC9E0LSJPqTo/OIIJPfiuk0OWT6YqlVJk8mGKQpUmFRMkpo76+fXPURJsbx5SJssIhVERbXLjjNqyjjvdjKE6UmYJSoWFEzxMOXwWK1SEVEkpOtypAMSuOxSXMeCk9X/ZdLBdEsnAgQgOMFerRroiU7goXEhSqog6GXHfrz569Smoibr2b5zNMs5JIyJIwiyKNKWtJCEQEjQKSA0ybImGzZMkVtGIpAEQkIxSQYmCKQmRK/wdwxkKYZSiZlIlAc1xGWJNMhEjA0UYIhMxLBQGEsQkoQkoRYkggbIkoowZ7fx54x/X3YlGSEEkMygZAWJgQ0yIUpFJkoJNbTGSmGZhpsISBAjJSKm5wQoRJRhBK2kpIQpDEBNMWAkp3XRkikwhOcWAg0klMT2XSYJmiSTSJMhkZkETDMpRoRlCZP17/xdbWv29re0soRj2XIaGKM0NiCLMkGiEMgMMoSEWSTGIpkiJMiRlpGkwKZjYoJIGZiTMT77fbyvJFkQIhNAAwESU0MkAmKCU/backSNhvl1BTIgmSM0WUMhmfLlJGExEYBMQn7NyjTMExvt3RGEo0yKIywGmzJoGAWQIo2aSMMSiRRINkwQZhRDQ+/XJkbEmGUJlBhSUwYoJBJmJEUliIiQJRKJiGKGMBIkZX7dzN6X69dvQCM2FmJCEkRoRMRSSlmEyL2cJMmTBmwYoUMUBLEyGFCkiSvZ0kiU0gKRo0GCZzcqLBSX7t2JEgNh46RMxJjSCIlFJDMgIkAEGJ6brDzuwpjCE0Uf8i/Hv5vSSkgvdxRKFJGTIhQyYmBmipk0wmK7q4wkAUVWTS7rswRe7dIpKd3CRTNIQoTRQiQZFmUhNKW+3dkgmMSFM2CSmmMIGVMyZTSowGFrXruyBMKMkgilEIm/H5+PPQgooRFJjCJIyUswYpBJSCSGlHx24sIjESApkKUjIkik2UQUu66DJiSSjNDEUFFChImgkUyQMCxMPfrvO6jMyS8XKKWDIBIBNGFMEQZjKTTJCGIgjDGpovTsJBCkySUgiZKJ6bmZILWmBIi9d0gWQiSBedbpkLMmRW0UEQUIZomApMkRjElNhMRKKI3dzIwn57deuuyJSSFSEgyTIsIgJGEwkmAwyaUiBhGZEpI0gMGFEokgJSUilGRILIkwCAUsNDMgRJNCRlFJJkGxL124QwZgbnTRJSQld3Smg87oQSgsndyQEIaSwXduiZCChKCSSJNmYTMmYhmAGgxRJSSRIAkAxSvHIiSSNtoMCMM2tEmiKJSkUjxyMkSmDBBKKjTAkjAwk2BkYWISZEZMpCMY0JmjSmiNDXi6MUIJFESEkBFCkKKKIkoZyukMzFMMjEECM0aUFEIv2d9/1+r8v2/j+PXensXBaURfsAzRr3a36og6r3JsT9qbTabfiP0QmzyJ5q5Z1GTCYrvuzFLeJa57npaR0IAZqvIUQAac/ImZA5cx1WusmF4m1qbbx1Xz4bMwNYxYKMBSoqHDeZbusK5b+WrGsqT6tKIMSrq1GZotMFfav3Kbo8F7GJapIHv2IsojLuuOrYzhdqau+AmBjPNTkTZaRw1spFb6HoslS665jecOX5WqhbGBRVVRVVRVVRVXGCjJNBkySSH9TsEYRGMsGMowEKIMlBpJd3UkklpTIQmCESyGyBi/w9wQwxURZDP47iklCMkEMTMmB6bpIme911iUiIRFEjGNklEUYRkpEoIIwFiAb6Tn1GvneNCSOruIAGAAH9puoaiykCZNMyUmszRkYJMaRMyALNI0ZgYDMDSQjQoMJKBJIxSUhiGDBiMYUoxQZkSCEZMGSRMkQGGJmEm7rpJhKFgAMqNFGft73X163SQkQYIDEyjKKBiY0UyEgZGZQYSIJFgBlEYLIQmRQMZZmRJgGWGjLXv3MTIlBYFPfuxLDEolMgjTExjISJTMsZpo1MyBppMpBpNqwRKJkN9nC+/n8fb29oMM2ShpIoMmY2iKNrSGlMYsxImiZkFMkNlJJmQkIyvduYxCIkUlJEjAZ8LmZQ7rqkaKe3VxgmYxGZJgwQYQhKKYYGYwwBjMQiTBmfqfGvLkxoqULpx/Mv49b1ZtKpKmlSpTaeCyIKZCBCmYyYEGRVZk+HSJQYBmkVJCRkkkRQjMJRDYIwkmGYYSEXz2uSiGUmBkDNEaCLIeOwREk9Vu3IElMWKRpBZmmN1a7dAqMklMwYTKZMZkBYXVt0tZVNqTVv6TbrxgsiGhhoskmBDSmjSplA2BDE3prpaU2tJYsTJJJKWEkpNDAu7kezW1yCQ8XEZQWYp/PdkiJEZASxFIUxkCEQSGI2ZRTQgtSoyJglEyKRCkJQDUe0uT6/pCHYlEySqoSQ7aNs4UBURAmqIBucdpVJkrU7WvcKIiIqIApfk3sKIgWfpwQvaV4DmmbMkDwilLJHWudbFkoTUjKrPb6l2ZsdVrZvc3gievAhdVQwQV6IEE7nIRMqJYKMHDhYgleU0SpUaFGM0HCShheSeZCITEBQW6ikyMPtSZU5vhSqSCgorKFc6EnIaDEqJrIaLVUh5X4gjXvKbczQsYDBvdLY489cnWbW0povXEtlPUeOBIHotoArg0OKIHRwoJ0OYvsmTCYSn0onFfBcKF1mRCAARUOgRQ08s3DhgeRCFlSUyYTUnBptsqkFqx3TE3YMOz2MNEzIyR5h0nDY2N+O2NlbEhxTBNHGyY0pqqAmhRJxFcG7zvS2aLspmjQpanClpm13zm5Urng+7XJFyxoGEKkBQGGCwoOFC4b5mY5IuOaRDQGBxLjknDg307noezljlXtyfDydvjZXoYCYKFhxJGTeEuVKAFBGxYtrATDIyWDdKvX57Vbe/5+ffT8/nxKAyEswBUXszCgKKAql8Z5suxjeCQxNBeYsS3Wx0XkLXwdSeYefK5yU3pJmX6lg5nvM9fw/Cf2f9wJgeJaSGr5y2TV6vl+b5z0BV7DyvrenxJvJ25AHYSf3giko9uhhiXv+Po4FrfCqvT35D4aL1fG5YixaUls9S2sJT4UJM9N1OAccppZqU3UuIiXw1nm+8glhNBgcnCJSkjeTm6YpTlNYW651CxqchNbejyaLaJ3u/OVozVU1q8bYwqSN4LzgRxGJQek2dTJNOTzPqcDR4Suk5adHio5Thu3e25jl7dHpPCTynw4Njlu8TopieHLTuVsnlsY7GmyuGzwqvKfSnabnl7HTSYmR5PD4VyV9HtPBcUxr6cv0aBgOBDYyaYBhIUyFAJhmVDS9PjqoUCSDBcLhcNkgYNBNyUD6tLOKXerVutTPBZFltjdzE7Wboipi1sGSWDmMTziNxR2pj8QMiEalsBg2aBlkSmIgzQw9eSMlKikBExge2xxH4nRBAdE8jryr0h573iKaga49WNKTv+Rhu1cHAgWykJAxBImGgQHoDhkKEMEsi1HBiAcHNEB1Xe9TRw6dtFNlk6Nmynbyxs9t09npjg6csaYY7Y+mw72qMVN5UiekwkdIpor5Ytnh5leVmorjq+9fPnXrScdBF7EZE1UkJMERTIODUGJSA1YOFSbDnCe5Hl7VMyU34PLy+ivBWxsYHNa0QCZAnzcnzyhpCBR6E7S1N76Mq99bzNylDE6TGaVLsWxtdyxuzOYrPDc3fNbzYrxS8rgtKacnfdJOpMrZXCEMIiYCagwBZEFa/MrflDQKhutbmZXFyjPd4LLFt4V96qbapok+gcwLdayuuX1Xc9avehjwjf1n9SIe4qIggPlPmnV83z4x8hWx89Z+Zy+VPuDRF7uueF9vWHI8nN1d5Y0o/RjDoUxxmFsv6N2Ghib6UUPiiDCpP4Zrcy6vf4WkxRZCzh1pNpxWtd2WLkdntt5W0oVtJC9V5oL9OyYf+E6takK4ZsjNjpikJ+NMQFXeJ123dhbm9UP1/QHKliKUsufPqge4I2LLamDMFHY26luXn2CJSurmej2hFluE7malThYZQ3eK7ewbQPtt7tZdBJPTmqEVQvMB0PLrNREuqNV5Qtpy53drrriENunu0egN3yOq8nZK29DcZI8PDeVXXQTe+XZtH4Q+Oa2Vdh0F74mmHUr4ZlaKYboZKWVRHh4VWZrjQq8G1tVJa3jjEYTRxo3VkVI0r4rRCpAuqwxXG5aENF7bm8ulcLRCFW7le6qo3irIHpJ7tdZi0U7EfZTFI+SZt3sNo2SUcxZkmm1glVxT5i+2Zy1l8rvdtVKLlwUyqhrBmURdsFOOVmrHRImWLt2rWzByuc+1Iin2Jyt2VXdGVeqnVPMbV5dJbt1XaDtjXuXvS0STaHh4WO6s1hOpovbwdlG6rEZ0lwXdhGch4eGvVWurqqJ7onL5cd7IqyWE+utt6M6XfVqNDKJqNckNN0evBxxKklDd9VvJyod3cp2VcWFMT7GbR94eGoNR0/vucpCoxnLZnH7ZB4eE16mvkhWRfQO8I3dV/QnN41zq83jd1W623WlIo0HWedO9qoc1KWIcG7mQIJ9Tu8tKKjKWnYpxXTnxxY0aRzM9eG1RsKoJSubN3OFzbLdG4MtJB56k86B1nylYX92bM++1ZV3C6Hh4YZxbTErJdCqgeIKpa4xrjiVywhKt9tffL5Vy/yM/Pq386O9v/g+BAoOH5b79J9ZF1UyoXjsVLNjBxWbm6KzHvwZLonOtwPs5Vk6+rfdJTVOqlFL3DDWLLlQbtYBHTtQVdbnF2bq7ubnHcw1n6ux3Zr1L9b+fn5Xs+/BIfxWV+Z+cglxNEm09jvYe5mtGbeTdE7a27NyZUrvBuvHZSqX43c50Ir4KlcxW94WN9d9znaFkPL3Sdkvn9fPlkD2bLIqV2VdUF0+T8YLemjbVcmNqurb5zOzpTG7kPaU5hYrUuzipw4qpe89vXj0cgq2GjVW9Ilp5W1ZWYkZlNWHOizdlS7rfUb5eWnbOujfgzZqorvqUy46XZfibbL4w5oLNBi+U2XZ13MpTjOGvrhDWmszXwm9We61uKbu8ZMcSvseNbtUpXcNtWd6VQzXCq6MY0xmp5OqOrKCUFLXLXSSZqyfMWYtSofT5iWbZ5uUiev6LLGDBz2djd9sd4Ygdi2DXTu1DTvkuy9m8DBlkLTFKoUDZtFdzhpbFl5Yw1glS63LeWIRZq8GL5Zta9HC9ElO86GoErrKFY6qLEJbbdUxMxt3UqTyGrSHK2gl9q5Tr3bHUtqsw5yF40duGuaL4jXy5hPcWUhu7swO/c4ysvEbnmbRMoN6njSk+fcavM4F9SDnom19mRCxXRUdRfsj1bp7tmTJeaXJiHKKyhwRy9faYCTGsa4y8v2x6k8NmkqoFOKxmZvBccn51Vm/Mv8/Ko/W/zNRwQJda32ZtuX42f3v9eim+OHYRNBveWvZ9bwsoFrt2q48mtaFhooRcuj0sGnKWHMNdkHHqhaJE5NXI5dadP89g1XlbV5U+Eg+VmguvOGJDY83PZ8J9PY6Hfavrjv4XVCXixbY0j6TZY5fKuOFbb0/Z96inU2mhKs7BZt4dCzJmVhF0vlMlKUk4GO7E1Eh1a5rq0l1eoU3R7MTWc+urnly5zbGpnLVcuzQsvkcpkQir1Q76ldW8vyT5dz6G15dz4TK206Jp3NGV4y7FdnEbeO6HWTVFHm68yYRd1VYHdpNPJfG6zJAbDOqwq2Zndqj7aurmZtYVDdzK5RPeifLza2OuNqlfW+5wGr1wxVtQy7UWVc37FDEa+w1o5EgpbhYeUblapcBFLP8O9M4WfFBCbtn3U0yrCVGjMD/LkKtrxqXeveZrnlzq86k6FF5JebeBg0qVdsrOvHW3e3tc9453ZfMq6reWC0aX+g4SHgxB7Mmn7Ucr4kVWR9zmSZXahQs7W1aRyLFVi5j3jK6+YsnRqUzFZFpbjq72uGPdExWzVnesvt8zAZvciOltXiq9pYu1NvUys7bdil0YvLo+V1d2+SeUXHou7B2S8XK5eBKrI2huRuOp7w8CsI0hGy75UFM487IDYvBMnTRFuU7RZNnNd410F31yYSpmGht7uwdxwds7XnZluwVhF3oWaFChTeqA7/RjDf1XDM8ZH9XZmSxQxSqiFz6XlvKITXbomXq16a0haJIMIQO1VbVI2hoypdks06yyM5EUHO3jubdXkIL7kVXGAmWo/JVLFtXLvMEqVV4FVduDFtuUW8WXlQC+TxXgwTNujZpM3i0o1ZUqg1tC8DlIxNbg6/RWpOg0uZtMVVXk4rruZU1XMNS+hrzWtaKq+LXZnr2tOtuy5mxJa0Z3xZWIvqRiKSK3Z3iKkszAFY7wzs2K3V95zidmnN75bcavZ4N2gStZw2Q1awKKBgKJLajgcBS6Yqp6Keq558X65mXuccNtHclm9xYmzrNcW+c0xYPDwey5YlS3Kd2dN7j4uXKu+2dY5WYngJVXMW5tXbrI+WSQCXfXYyBGk2Wzp6lXqysNhJ0vSCtp8qzFDSr1UMvRV12KaUVYWOe1F2o4LvyHSme3M7TuwUVU3aBd+zuCyvZ0uVW85NsXNXkennkaznVOq212l62trBfU3jp1bdzLVVcDdcsV9b27u1uNqoqOXeWrWYFVp0pTEdU3V1buUL0bS6KkDnVKlExK9xeq50Xib3WIDXajQWZiWj1ROr0e13m4IG6Ldu7GXQG5mpbzzBWpSWcEw34u+vhbuXosVxYxEjXheUpr6VtZrWXV3MzM5q+qSqNXam5l6iRdrMpHvVciFC29rzt7VObdcWDDdve3nmu7qj27W1mtqKuvFuObwR9uRXt/2iffa13PKP2qvi2OOOTQuHh4JGuNWgGMV8p13buqTmg+3H1paQtR4naqCz0ZTD6BwYU2VGgafo1fCtDNGaJzQoK+Hdj7HoTgTY7IPDwo4b7Wu6qbzuZncs6xTQVPbN08Gq2xai7Opy0OipHsRPGBlS01emkgzVGCmhXXmCtmQUFSyiCiKYcuKYpgzKve7rRxWjBkqkN3su60G113zqChafSNjw8NW3qsuxatvDeq4OIdI5iR0Vwu3uzMQq+Ym7RlIM8navrua6zrna97sNMNEYc22KODO7uGkwslSZQdjrRIq+j2pXGq40Q+nPMUC7ldUksWbYwYNz+eeC6e0p853wz7Osh8Nqu92sdeDAjXC7qm8HO9hqZakcCMxmqWZuRDa2Uk96VJzFXfFanjLvopFWPO94eBx0wjT9eDw8Dup2FUvtsiWDd7M6jdU8o9EmKvbld0mOlRSeWirpBcoHmP8pJ0Q/vudfV8MVDPlp1WgR+r26vR+J2an2ZSpOjzqvx8H2/nyreSXtKm1ZdKLPm6wMOqmkRJV0qqJGNc6rdT1YEFlDDl5puncC56xvJntIqdFuP2ZGVN3O2t6srsrkj1q8C3JPbaqOrqnJqHU9kUvVh9mbQo9mWmYLaoNCJ1phunUIOTOsGmW271CvTjWtTaKu6jbx+WerrebRXJ3CxgzjwsxKrqcHVjMcnzysyCbf17WrNubTq58bm5jrLBO2SKsHx0fMSWhnux8jRSiq5dorDcFJTy7kuzMZyu691oWYizd7Wp64fYcdb3ILb5Dw8MvF01CcURe23zdUy8V1k3luX5Egu0OT7Geywc7MBbD3bygKDhVy5OOO6Ti42gbEfKw9xTmhK6LKjR2+vM9K8krGa+v3h4ceIa57z3t5VlffZt5hb+CR6Rn74wUbp52s3exy6xUrqy9zyp0HlsdlCryYQtFMHGsist6XC6Bu4LlPTr5rqdnCvUa0aLnKjXqrb3Jyz63Xw+O6LuT5/a/hOO7JioTTV2xopEHJhfNCjXm3BdWqBVB48dWRY50KcFGchSZt46l0W2ERFgy7hNP3h4GY8zb4TOWLWstXYSz3EMLZvTd+iEq2bNJ7VcrfgJI6YuTwS1l5LViMz2qssQUlTXSvIbWogvcSgrBmo5gDxJbM0padlm7l29K2JfrW6cytphFe4r16ipF04YtmbMrxQktDM03DXUN290bt1mI6sy7NW0U+hF12huXiy5vbcxk7UyzEvEmDw8CB7wroPvq6HuZQOSfTlVOXibWVKQdNpHbVTc+MvT01K8k0q6pG0FudS3Mi6uW00sNVdJX12oN05fONM22cGnoZy7+O65u9v159SrbXZckWhR7WWLsYOaq3VduHBH1Zm3mbVwhW9VZzWO8DrKiIzpjeQ52ZgOuhfMWcEqpCqM3azuzsLKCO3ELTYOov18hhXPNvd3r3M2tvAdR2SuzNygr9Vm2bWJCtmmXiRFG4uO020xogixzJosasOZ6de8q1bJphvBz/te9qCLq6Kqp9Z+edb+fqzdPDVO11CrVDZzzM0c8wJPaRNTd3oTYJXSk6x4EVpMxKja3t7mqF9ft3rMtqplPr2K4Lupe45izRXXoNmYb4hkSo1FZoZliYxlq94bdCYMW4Xv6uWivu77et2m3QqoNxU38a0Z26sqwsDpkVfpXLISuq96VQfXQfbDpwhHcmIS+oekTFrh1tsWrl2I97JYc7ZhvcMmA8R05XuF7tbtWVWWdldQWULraO72lcVygygaYOTmuPYsPbcnbV9Nw5SdPdWVTx1eaGV0t+lprZs0qycxCttys3VQrTugx8sByg+6NKsy9qjp7KIw81pBtOvefT+S/q4fH7aFc9eP7eqlpmbg1FtrN/Z0ciCLQpzFFttEUdqkEsx3adrh4eGVV/OpMO1t7e0Jdrsoi47nTEJOpLOmXWNAniMm2VlDLrTLVCCa4HOIqSq2pkmyRZ17Kq+D6vqWEfDfmysldVZnfcLu6fb/eUSblW8Sqx3J586xDP1J/Q/fMfx4cB/UDojk0mL3VEC4r7xVUrLF2y1KtbKz1urpEir1palZquc6UVbzjEjT2lHea3trj53CAji7F2LT6VNFTWw70mJLEpqVIXItkkNikaUlKkUpVkmqjFEYFkChQs1xW6pz28d1YDN3gUo5673aQQgyUPDwlfoOhn5iF5/F47u0kmn1YWjYeB7tHNvManKO+1PfYmxWYON1dnayjfF65Lt3yUV2iD21uLYpAnVWe2zMbBfGLbuq2DdVhCmvNgo/1a3Hv3blQlWnTrhE9eaipfzUjx22h1nNuqwZJgkUl09U9YJvtq5j6pm5fRO9RFjKxsHayBZAxVqPXDLQDUjOVI6xXeKiFemytZuqzKoZFujcKvMzDu0PDwyAqW0h2Y3WhLdBhlxJcaMyoyxLFqyOphNVtlX1TTq0QbNtrb7bvczo7hth3kBUF6ERy0HUmEh3jQzqDTjXVuRcbXqFc3xSF91TXeV1RSM4Y6CjebFl61qmI7h64K13EFMJCNbhg7jjw5Vq7IPcxgTUNnErV3rkOm4uVZfcx2Dc3tzeIyyjlXAnK1uehlVm1Lawbz+EVGH4ifaU5fZ1v5aWYEHuhp8efaboiXOOZgmbtmK32SnlISC9rGm9u2g0dsTOcm4N5W9ELOLCCtjb6y9sIVbbyHcy6rdfbjNWtuhzSjvV26aDDduC715SzJldVUqTYy3u4dl1MaSyheOruId2kixLNF4xVCheDGhroDVipzgaWWUxMo0qqhsdHRyWkatmWKPnLqSKShV3Qa6lakG0iUdbvGDO7ZYyxtQLL+I+4WrK++H0+o/XYqJ3QvH04R9W6u4UpmYr3N0VtHTITl1VdBRvjFd9lijUK2bPtsM5yPGUtYniu+OzJ9gvr0S2a631iddXgZmtU1d2cld6Zda8WqF6MfJ11XdMwUx4eDqgeqnnLhewbl9RvS0bbZ5jGrvpua7NlXVZYzXY7EMG8tLOaDVtXItNZZq1S2yLW1SlXAuxKAo1Ea2YqqxMQ8PDeLdrtWVtTBosrrIjIVmVmt5YwXRo0MyCYZbnZOq+K3Hdl5SBvPKgeqmNyEU8rcqqsRCB0W1bDmbfA1Y2cew0UMetPe7ldXLMI2uy6GI0TuVL2dHkrKdUSnUW3YlVd5eHPryvvj0DeWb2+NCYbutGKt+yuycMlaJ3K5u9nWb54M92TgOsi+R7UNlVLkyru3232rnYg4Ph4eGK+zneTHZxQLLS3MndivYrmRCiquz3M7mnRY17xBnT2QU6lChiuCdg5KcxTlCymWlmpVTfumorYzVLM3r26d8eztuY+B92OXu4osrMx2CcBJePKMaFesUeVtOjRx5WNFFT5aydzaMQilmPlyxmUvuVxEffGmkdXUjw7rFnevK6d19lymzvDeu4KGOc+5PBVMVkYzbKvKZhm52tzD16YE6oo9WscyNzN3nTV5WbXU8xXQMsHLq6zst1cz+MvEbq9C+lwjw8PlLynhpLRbQe/aNrqMOsEnnpcu6dEbpF3mmm8RfXmp7TrSy8omEYYqPXicXnxq/PXQbcF3otXctF1tOrkxENzpDGRfKst9xGyjO7ldGaL/Ejgx9j+J3P6t++N4GZ4k/odve9P5CTNPNE/YejFXVLs1BeU7Lj+L0X+twTt2jgorYaOkXY2ytSFJhuZWsWNvapAvq4Pp3TdzWO/ehu+v7h9KrNqH48drd7s23Q3dtV15NtTYMhZSjvccPLbqpqQyiYSL43O081WvaBXYM2Fc7LRJ2hJOC7JsBGEFPkEdOK9mWoVKoTnZqqtVuY6pmtL62GHyOvu/a0Ej4RhL5Pa6+RLDDTuhKFWetXUoZpdWjtVWKtMjbqntn8Oi+7su104kwUKVCtqbcvFt5u5lN5+aKvi6tS8o7hLLrK6MVyN3xrMYygf3nw3sfDKVbjEIMuOkR1rEhiBWmKr+eVRtUbyxzHBnTso1F112X11qIZR3ucL2tpY9OvV1iOcJweaVcdlp6fz7tl9e1v2Cfd82wamPMF/bkPxLyoHhVmZLm70e6pum6326LySG45i3IzlP9Su6h7wHEDordrbcnXb2P1ar+xk1teepCpQynDde8EnzUr3h4Vl3iHbdbG1OpUq6HeoJ0JEcgvZUzuzL3B2ZTo8rZHWMMW1M053sjvluwbOnqWcenPaQVndY2qegkl5WKZ6phPGDLnbzumOddXVKs8aiEPaH21HjPVHtWy9oWHl7wzr0Gzzz3LNa2EdVd7jEa0JyllZg2XmKq3aiS0Z2qnpnimKu6Xu7XuO6sZvAo3tCXSDNIb2uMJg9qQePdnFk6VQWm9x1kfG9ou+s8Xj2XVh7LfKy+yxGNh7mNHKoVOXLFsreqcFquHKux1UnWod1mViig5VN1IXchlvxoeHg1W3d8lVluCjRVmiNEC6XqxKZw8PC5iw1LvuRcrEsE7fzn9AnYnV8l317ARn01iimF0+z4V9gXyKSIpv6voOFxlbN8KF61BHtfU95/0H38sA54J0VESLsBUUTt0k5ZpTLDw7VXTrNZjittYlpZrOTZnazEMSjR2IlVgkKIUAUYuyAlzzhjeYetY68fHETZQ+vrz0kQmdcXXFuEkUFBE0pSRMmmSlBKEQhEgGQJhmgmRTBAgmwUzAM7tyEiUYgDMAwSkiWMKBJ3s8rxDBNEw00BImaUlINDMY2MQFiQ0YgzMUU0jKvfzvJ2vd8d69FNBJ+l1NjNEzu3I2fMuipKTIwsUGRa0zIoSbGRMzQiJmDJYQkZYgBMYTEBCRBDMkEQjxcyKGDBgkw0JATa0wkZhKIiaQJkipYmRFFCFJmVEx5XdfN+/l5gZgxqZllRJihMRE0/hyJQCiSyBAADJGIkBDJIzUiSZkzIUpu65kGEGFAaE337qDClSGWGyaAr57sRiGWaIEQQwyJIWRmMkkkGBCSSPE5mMCiDzMYrlnwKxlthM7hqS/6lu8qpUJw/uob17kNTY40IEdWOjlUC93Wasiqu7aWVqVVWXuShpkmGtx5Ck92Uhqsg+1qltQ2TaOMp66L80N0VioPZ/BeLu2hCaW6k6q+w0W+ucs1btdec/U3jGDNrNOBYw9W5uEMWhceSmqEHh4VLdrdjhVnBavKGNOXuo5WqWjFWXbmnMEq3WXNmXuOZUMrDos1gzaqyctBq5t6LN3Gh4eGt1WkKwaek1IKat1lTbPcKG0HaSVzlVzao2ypl4bydl0oZJdAmVtlIXlrFRo7u2Xd35EBmvKJazl5V4VjjhWSoURe5ijrTrBx3Gdi1oYbqDZKOZKwpXt3irdoh6pScVyzWIYx2LaooZTihEEwyGXKpIp0VzKb8B79nwHuIHvaNxdvUFXwpXUqVM+1YHr8aCFtQ+RRJAKDQjmpBbU2rMVrMuyTE0xWPjdIqqj94DyIRYGTnt+dltTGsvKQfakZqrZuLbq9q9y1MUF3Fo10cq905g1u42SQQZJDiW6moETda7EhV4zZkseppnARho+9olg7VChfMQ4EJtx9w4SrCySgQteU3bNwtM+azMy5e3lh2q2oUSNSDl5tSg1o0Hb5VK8UVtgs7FTurmzpVi8o1dU3bIImM64fVVMR0LIl3BYI1ZLzJQbkiWBwmh4eGIimRV3iqUI04ill5qguib1N5Uw1UeZC1tRnRrtnJqobTiS25KtasNHKBGjU3rCwJR3thlPT1tlDcnNNaILs0pt4XQyrSdGl2LQg1Qe0hHsowxpIVTezTLw3dBCllp1FSOWtULFJFEXc8AA0ToJbtaaDYrZeHSCMGPYCNIBd2qoZkfkRpBdx68bhpQH1qxamN0BpATOuRXqtBKWnlQRQ2VqcqQOaWzVmIAexSinHTewShdeAUGF+pWKutIDM1qtrWWLb9e6KxwK7jowNeByNEKzqy69TyJW6hOeoXJsZvVrzdDt4RtTSY6PrDqqS28qVlXdC4TalZmJ2pcV3QrbBTN4no0jBUOY6xkLS7NnLsWhlwablUZ40UtsuhbQK3RTYNU6obJHhFZq2aRep0dxIw3uZeUbx4LDoF6m6p1buGpmw2iQZUtBxqib8VFkWHHtVRN5baNJ4VQpJ44FFcFSYYtNrbwILdHh4KaHuUcp5KvaZesYJV0kIJatuo5nbro2N07gJjNKxYtiO8mK+iGzArywGdSw2NzYo3WVhMdwbVaYGI2vNCVSrVsyUzIDqDqTTVwqO7pHqWY+DUt5d3crRKhTxlQLCWias4+GOEkwPL3WFtmzWGK2dcEUEw6ES8ieSRaM3Z6LwYkAlSpFISpISWKMNk0JChQzJEI2KGZgkyaQmIJmzCRkkNGQRFGUYpFJGMS/XW7KKAVFEUEk0QigZlIzICUihEZGTISUQG1r9ldhME2ZmMDL8rv4u3KQJmwpghApJgYSJMwTBMxpLIGgIECAxb5nUjETMyJQwJsxilEGBYyipgk0iLIEiEiSREAIslkxZSIkBgiUilNkiEILAmJiMxBb3dAjjv4Z+fuXHZLNqlbm/uRK6n8IK7WXjCbO303M7ZVDLqLTdG1oKioXdJTXQ8PA3Y7O3LBtut3HY1St6rXSaO5K4xhENV2dVM1TjNw7qJwEkm1/P8UyTv3ST8TGn8dVRlm8svMz7GwFJbWIPS6mVVZsDFkv82dQlFP13pTB2JKucok0erbdy9nsj7qx2LOUL22HgR43ayr6Ym1gOF3liR1lEsVV5k9tHq0X3YcBtaI9NCOVZ27yZpu8e1MaWbDxCx3xXtITNVc1oPRdG3EazrBVlFvND2qbwy+tytOnxBBJICbKWUCkjEIiQiIJPiASfHO78IZyvubOIfQWwq7TVZbFG9O0he4dDO3SfmuYZAsECd9gqt+twEGfdyxKsu1fZWXpcS0Qk0+cZMvKYMFQhmqejw8IsrLbWUbDg1QYwaG68d1v17/XeregDKQkYGZETRIY3bs32Cq7UTiKoVt1gcVnfYSQaIR1dWGoXS2Y1SC8KskorOGwG5ZQXot9/f4+fj6+fneX13fL384EpISMSbBgEQIfN79vJJHq8Pb68ve01sbzLeoSX1FdwzenF3lBoMTT2YNFolKEWDsGuPG5e7IDjL0K7tCVYzB2Xjlt02rJbrPYaKQT3sMpVWJGWRgh6I30eljCL6g082juo6MjCvdui2HbRc1wnKCorpKhLQNtCEYe3X2Y6yRy7YeHNzhRO43mjFN0nmIjCFTR2w6MiVqUFUPqu+rMB6t2C1iGcUb2Xo3LzncdXQiNpsxXS6rqlIMF1fbuZmbMfrY7YHUlBFtFoKkFx2qE5bVnNx+YQOX4E0E0jFEmKgyPnrvPh8vZ5XXldpnF2ql1Vdr7TgGUDIZhAqRyFXkYr7vqrx356kPe8J4++HT7Dhjy8GznH7vY3O0W/ykMpl4QgSPogY4X9tXJfVeWRQjg2WlNVhzlqbzd6xwQJCSQlSBUkJCpAkqVQuKW+Wk92c2Y9jnEo42H41AwyQiSPxzlOfKgfUskVkio+HolmuplhVGxcQ945vzCCSQhCQkJJSGUyDDSUkQIsfd2KIBpIEWGkxkiJEJMMZkgBJsEEUFLENffuiQslEBJDKUhXjkixZYhIyEgKImMJmkEUjIGiWUwgYhMpGG9+6UTRKGMwmJkwTZZMQkQeLpABCTenITNAkSIhhoDJhSAjEZJGQJJRhFI0E1mU1WNenSBJGxIZCRTGpkzDKMFMxZSEmSESQghkQEjRkx8X154SaQgAhiaJZEaMmFJKEyKGCQxgRsxgjTDUUiRvd2ZElAkgjIZSTEzMiJKUTPX8fP7efb5u/b47zz11fj17/f3ntz3e75+b7JIQARiLJGNGUzFkkhBI+/bgykUwzFCZGJIAWIIA+v4+b525V9vx2+6vj2+f3r6/ZsR7VRpdxNXwEsZnt9b7V7Va9ijpnp6uaeo6xd0xRJU1Xdcs1isnPXLvGbzvNLSM2GJeGjPT116Tzx56kxrk8cy3vY8bmtD43u9Cs1u2Ibvb1KzG1DJcDar6q7M5OBNN9sPPFQ7Sd3RNGEO/6188BIy6yJVHLlG67MN166+lQ62k9UxJ3mXe4WqD+cq+GZhrMrR4eGAqRQNoGLDdbVZdAkSroYTyR6jtvNEOSxsC29XuWa2KR7FmbBxtwGGjwBtzMhuUtKW91OZ3YNW+7o8avEGOXV2c4Rh2JF88V7RIm2MYWO9a94eDV06vFau1fN5YldPIHkK0l6JUYdXujdyiEtyZCrc3MmVnijm4rVm5LjqUcHh4K4FOv2m3jvaxnp6nuZ2BsVMmnBbrNyqIRzeDu6alGrkaILy7gzNLtsmxh7OkFmGrfu7aUZOLb7txabvWTxqsquO9c6b0aL5XO+qXXX0A2Yq+MmN0tFE4Lg20Tmez2XYWHDd5JWpZtA3pR36ru8JEO1VWxtswGXlkuTj3UxWC+Q4nPLMunu6s3ZZ6MOvYbJlb0qHL15c5YTdvpEnbiFLFhlanVRzufA4qtqhrfxd/W9de23Dzs5gVHvt7XuuiLJqVozdE4UsyrePqHc9vKebt2hImK07SF8e3ezVsm8kRdLFWLoISOx1SebdK5CtXZU4ZNQpVlkULHh4L1mIPQRKcBQzZKx9mioYNMbFibdA1jQzih4eCWSasqYtoeHhm2jwtduXa32OtbvHghp2HKFoarVVsbWdrTt7W7eihQoKmDmBTZK0hpC7hGVe3rjCEKeQJ/a+Gjo8lcru1V0rah+o/Vf3Yd5rRu3UV86EgD3c2iR93z1FbnUJ74ffTjMwp6Td9aWcuzMcumejq11b2haJWuiEKKWytt0uczX7MV0vdsqxRF007uaVe8jSNRb1Q08N1JAqdO28gM5zD23vC9rjz4ilr2hS5I3oifLgzpLUlzetg5nK4Fspi7uhkouvHI+SIfpqo27funqbfqNQY7SDIsv31Ve0V9nq+IzEK+vKqiUfs2uooHEneVBopWOynYLqdO4bZj69OvLJemyP8Ip5dTPmvummrf1cxhyrWd3XfrXaeU4GRCioeqU5XIbg6bKPZR73h4QNneudfndNaUDla3GYqHh4bhrjRjaNRvDW27nLGXNFZdn0FuQVi3RqoccProvk5OrWbzH0tLtzVMSA1zHt5WnoeN5XCwcON1trk74bDejoxVW1cbBlc9hIvNE6qBIvcD7nHbtUrNCCGXEhMxHlV1e4Mu3UvcJoGrwSrqyIr12Zgp1LrKzBThRjQsQwcYLy4LCdNvn7icpbTqljRzrGu67AyHbnvDwsixcbPLnZd3tUrjaIaKF/hWLcTuRN5J8Kw1MI7DladGJNrDH1p3c75fW6r4UNlfZt4VE1vQeHg7xFPB0Lo1bq6PbI8GwqouGQS7KGy3ncKFVo2nSFXdYq3clQb9X30+2ahIvuYKqK6Mvr9YMtb3cbzvpB1hB5zDSV4+532Jpnc4YbNigby6yv3n+H+azf1+fz/ShQ4pW8/aG/xdP+CzSzH/FEvO429vDsoNyn1Q9g1ecH9+++jvfgdq+pSNR3dKhf26JlxgviKqtUBrqIfW9C7rawaT1bH6gW5cOUlFsuZgu6LenjiLfPeIXYDbkUoGBmJGTY7qlUVUFGhclGjfl1Wf78FhqvbrNfVy/rKwT8mpGvtHOvsOXkVaKvO6803it2LoM0Mq7yqixqJdNymRjaiSQLTyOs12JHpsaKFZD65h03k0Pe73h4SsBN1IcdUTjesQphUdDyWI2hyerppb2ZcHVd2qL2ukVVRb6rGIxVm83hu5yOdlbQwVWlwpAk3CxsvIxizMKmYhRRpVwrZgl1uvNZJThqGrrm6q47+g6rN3xl7lztvMdeugqHwq7xbm9nQMmpOUZ5WxjXT1HBQW8uBO0RHMy51IUwWcK8eu2atTEJe3tnTZ2EG0JLSWmhES2ijkZG9Ad9laK0VONzU9Nu9b3pYrgneKZMzNtrHmbxqVUQ5wrlamVQqHlzlUfJ1N2YjlCD5Z2XndgwH2VZ+r5isY4Xm9XdFMPOPbwIzbxx4xYp9Fgyg2/V3icyWID2U+QpK+n46epffDuHbcChs1UOZdEuq+zc7UJMef4DX3JLDLaVT7QikuX6vXRrcLP5fb9HeDs286nmbb2ZF3SVl7dZGM4c7PXTqHom9umKqIseHh2dlPIax5beMSIXqr1mqQnYM7URDdZc0XAaCrBqvu28sQrNRhyBhJ0tT6NXQzeM3s3dy5+9H2IqcLWoD67+BoC3e5Qy5TV4J85V3htJHNBDt2pgzah6VfWWLXmxzrBtjXiGrNlGzdawKrxnb4ZlTcyjGdG76UMxqr3BZysO567KQr2GcbuENZq8odmu77/B7wpEVBOmJ8dqzw6vNcVmsYWIpcnmJ3xU7dsvQBJ2yi60LjyFDyUDmCeOXOqYcyNpBkUJxaqqhf2/Es1amIR0Y0U6y3tr99VK6qiZFO65BT0UW0Mem3eC4jTD4XyuHe1M2O6HNxFWRWZwwiC252uPrt7c4O3sXZJsRcsycbxGWUniOvH3Y9y8FdQYEnWHVUKwyXJV3a3Bb0MtzXWDWdqG1l5WjCczevhmcYxaio6uoaZKFqWcl3LnGlTjYrTlXw4tOw8eLVgNcX0Lm9cob27RqnCF6XeV22qzXmzJlXVupFiJVzO3tcFdXUbFTg3cIhqZeZhd7Wyam7lzKIdzr3Nz+1P5I3Tj+Mwdnjn2fEWbCwUTmNBUrVQGrSqVD7iLoiGoTuo5geVdOzTOPHfIZkLG7vdW4qvbwmjWDhQI8PDoss2iMw1LHVnRbcFBVdvSLxR3VyGCnhe0jnUtHV1zs0t92kbgzlmW6JEyqmyVUmbhp3mqDw8LYb8Rrvbs0apAtUNevs4s8b41M4K+66ttneNPNDHh4O9BxcVcN3mq63bFsNfa9V/fcan2XYqyaNwS95HMsL7NQnUtv7JvVMCzkplViHWMqU75LesXCTlSty1nWkzll6bdHFDoZ0RVuw6H1LbOxyAu8J1OySLXfFfUeMg7qLRDHGXizp919eiDjNqm6sGysxUNZmb1+8PBqYn10nsvlKPdovrHM7rYkwQNU6PK5ZqnxW67PUZMyoO10+pvrFVRnleVK1MSX3a3SOtiUvQSsgmVcbUwpTYEElGhQxXlQ4LVcmaKiBsIpagUSZpkvV13l26RvcOa1LBrcyWLxPbT61nTas0UbUZ0cQmY749dv3h4dTFQXhdrbmZsh3g5SXC+GDTuy8GQ2JKsEoJG8F4yYtZ0VRBvDagPlgWqj6iDQ7XbUO4DtW+hOnpFndYQtCZVA7zqXgLiyodFCDlo8PDdvYqzutcR0W1r3rM5xXLkuGbEnn1C7p9sDlEvfvnli/jk+ldRO4qG3JZUUifGXZBu/lt6ZerZ8UxQ4kcE8UWY4anPZglUSbQrVxrK1psFKcEbvaq04t16Jk50GUvY+V0kFmxIExLGNobB1DFyug93dwYuMgc0eHhut1WRRrHKPSWLpqQxpEVfKrharOZdq+67WEY5Hb5g7WI+xoOoe2wU7OaLMo3mU8Tqbgzat+QtY9NUN45UW76SEMp+KUwrsj4R2cWoQ3Oku6XKSW6fZkx5V9KvBHXYb5umW2fZmXTBwPrzFttZnUmEhRvOqOrpsmAq3hjoit0bnbgKDt315e9YuVmb1nDW7x62uW5l36xcwX1CxUvMTSseHhkbrN6xwI8PDjbo3W2luCnREqE3lQTrQNWhqrbNpbnaT6t6xl5DeUZpd3hxJ2WOy79rkUVlc3pZ72xsTHlhZHaoMo+6xRLeuoPDw1MHEJELjOXW0tWitCPWlNyDspFYbBKlK3Ql5u1Y5a+5bkddSp4aDkvA+nSwuejlQrFQd3cdZeivdruVuF463urMSWTBQdVttZjqqlZd28ZxquKevYuioJaqqsHWxLof0/pw7+Rnfn34/tl63KX5nrsR5atuS7GUgdzLrbP6zq5XtjdeDjHkcO7yHdebb5PS9qddMjSof3mywLIw9qynnZFHdS5MND43t1o7dFdK3GLrHvYUsytNw43eXcARRqgc5B5TTvHC7oW8Yp9m5BWB47OelODIELburzdvBDWjCsZ94eGFrcNvVLBSVkMnWppl2uJtl03dCg9trd193teUILgy+pUQqNErmJliGjKT1lXlUeV31jI6GDcSDeQmO9zKUoiziXTA0NNWRo6etyr6Du5HpNHahZ6ktwyK+mDuIJeUh18WSVTvt1lbZ1NeXBTeuFElLQXfKU+u9674ds4neHZK25Q3NO51d2zBfbqOtoQbVmhuesRAWtRThQu7GaqtiatGibb7E1TyLb5c+x5k6wetTb2XExdIqqoxhde6uw7uzSzQzKvGDZStJcRHFWVA8EnZW3Wbx/tiuUT1DuOVjzCKeNp3EPDwlpyuhVo6YbPrUgNVLOgr8pbSaC/OwSoD0B5+u3NlaO2QfW7MUlZv1TRPt513O5sDfXmRbuS7pWukMmyzWW73fQG+1sHgtuPn67rjkYdalTrfeHg3cFXdYsVu8qiDWdE1j7a2+mHbMewXa9vb15d6cY2bmya9lUxW2N7HUqVaqvoqM5KZ3Kp98WevQ+nXjUIzKNVzxMSTJJnXnKZqwsoEZmHDYmdkt5pmzd3dzTaaGQbdBlBdaKWzFXa7zdSkjcTMG0MH2ZlZLPV9yzKeTTI8rC9buaCNx7eVm1grSKzfVdaKt4PlrKNZfWmFNFIG1Ky3zFNXt9kx6DT4vKveN4j1S67hdmdXKPNrYnk7b43WZW6Y6F44OV5fqDeRdB3BUUstVkvScjv+n9v4lU7LPMyeWsZomGrOHMvqIJ0o8lljEAGnYQmCiFctOJWftaN1TLTftYtcGOcgCk2mJ3Jz+L9JSLAbGIiZoyJGKLDMopESSs0ZkaQ0wNCgkooxqszJiEhMk1J/K6SkUlMZESCYKDZDUiRMggwyBCIIiQmBTGmgwxooak0RkzSE295tsv38vBH49X69emGJlDMYmGQmkJBkkxUSRklI0KSjJLAyEj37pJQJSlGFEyhYUlohkyIaSASZsExEiTGpkxZ67sgxCCaKUYmSaZozMZiRESmppQsEJgGZRMiDGKkkhUlWkxBm/HCt3r0fDjfJXgS3esNbsuoHtbt01iFdW0aIxhl7dlhbsFzHmOkt0LSwjEVK3E3w5RG9u3J3QqWKo11p7QUb7M03gthOZftwNGVvXtbfUIsViOjMns69O2i4rEBmWlqIUIXZj8Ve5Ns84dVtAWLD603hrc2seSpxXbli9nn1XHix6OvG7mCVdCYrB2M5k7ZHXDh13FbUZusVnK2tKtrJi2EeHg8qkhgs05m8dYVQ6UFZLlziKoHKKh3TWiXiRpdopc+2Dla0Xd3mTetdoNt5ShHLMNUQRKxtUpdXjfsyjMhNCLnW8WL6i7WbeB316HtpiVqtb/em/sG0vmoFd/PBLRQP2R5s+C0a8HZrNZS6obMXTuvLK6cq3XFtb2vhvVHR3oc11Sx0nzVmzieh+kxRVr295DeV3RVO+54+C49kpUn14c3uvr28ATKg0ihmDMyHj4kkE+JAJDRdcOMEq7HHDyoPYnuDHDdZkwg+JCNl2kxRkEJ8SzcClZzGVcIdxUKQ4txbFjegpzUt1vw0jGnZb0ENYnVu7mxce7ltiShxvMGrb5ZWbIrSnJ1ZLy3HNzMpCEkkJAkhUgF4kAkgH11GxJLdajELrae6G7ehEkmNaQIC0eQDB8SCfEn0GUNm9HFLDUGbTk87mvH6iCRUl4+z3h4Zjk3Xsp280+7pMGKSSI2UTYSQJJIQqr3sYKhVrc1dwie5O+u707itVWKZGWakP4cdZccqjWD8k6rN9qu8I8PC6GWc7WO69NFGU68jTPHDnVIFo6LuW4Qwduor2rytuihFUj9l6Kg0UuEFl5rtHbdOBXwpTskZ26j0uy4HQXbKjrHSlu5Mecl1YMnPBFpVoKseBQvdJWa3cGUQ8oOGA3ekY2n1Mi6psjusRTC2cgnqcLxCGSkxvOZpZw2WxqTm1VzoI8G9sTV7q0bCTZU752XbrfrumklQbiCj3tPxggu87dp39LqJZuz54RZ+pGfY2xnt1Zkyth7JYAJBIPiSQQSSQCcJIQJk0i+PPEvZ318fPefPz68y+uasfbWEX0zkqPgRN2hVEQkrxOLT7zAIxYLWobLIWiPOVWLxCbDph8QSSVyd5WHTY0cZSurJOmDVdmlagIJJBkUJJGslEC875d568+fPjz38tl5BPEr5Q5eZCT7DrReFBnlL3IPits46Y25ppiUuYrGNqgQr89ExAezBRuzhT4VdR+JUBGwhQ+pGpUOGpKdumMxKTeD267OXjzfQa7R59mFOluUN0arm9s26zeG7gNuePD9SxVDnqlGt0u+q2W82G8apM+p5YY+SoVePboh9uyad3KJcDO7hEQLdqtSvk+7rVMndN0+5i0r2HTl4XDu4d7jzxtRgHKWxZU0mruJ0lIbiVZmdVsjw8NTtgrVuHZ2rdPW672UrmbmoXbiaeNrpTDK3WC0kjjt1lrswPc7QvxWx9pCO/EIsfDGUrivoxmPBu/DehvqcYS552KZO2O8yr3qvb2NFxwyPYdKEc0PbuZhT3NB2k11yILOghUbavbmoZhWJ1iPVlTLwYE+MrMucnamkWYEqeEHxiwRXgtxbMdecPNisd3Y0lXcYSXci8aaTDmvDd27l02Ldkbaq8d7e/t6v3v17+V86SCaZTJJRmjI/HcokhJMmaaIyQIghJAZgRNDSXOUSlhDGaGKaJSppmIhk0qMppSkYpGYNQGGEQAolLNhhsowyQSiaEEwhkCYwFmyZAj8/fy8fF1ea1lLS8GlEoIxiGUUYCNlIpJS0jRBCgyTCgIiJIZESRD+O6bMZQ0kNMoAkiSYosoxJpGaNBTYCRsUpAyMe7miZiMBBSk9X2ptLzykwhSAw3l+vLxIzGQkZ5qssUm00uWyHiRnXBBDp5xHVuNVqw9ImtZwNIqt6vOJSWHCJZdKHNaCCWGdQT9gWJ5Zq05CV0V3WXlzCH0240CMLoubis5lYjV2kkgin6s3LIj921WZromupomnTtVq1Y57sUnbLiym6rY+vfdE6EnXOxZzzKzOrDdLdiyCdJlAYHsyzYeN13D9YPr0Z9x4IGcrn3FMU6cdivptD61srNWWj9KpfZdUDuZSGXNdVgqlBbCyZ3WdvthmlnsV5X13e7AjgovV88dHG6kxZWYqarwqNyJ/HHHRiefX16JK2kGCI7SUGthwE+JBIGCwzIMEgYkCAKkhCVKkhISpULmoZiOuoutwfWs5ajboUx2Om+o8XfZBgE57aogkEElWmfEgw8q1UNnYde8pl75O6Wytxc2JSbpg3sEAN1THh4XXSZdMWOrbFqrLSI56p1jE+0ETLU0+J8CST8USCfEHwJPiQSQAQCSRCdbqzm3zs3hYwJWMtfdMFaMPlfXcBe5pA0i0siEiGRhxMZLrM2UEToMCTVymICRs3bqze1IQRit5Xr59e7yMUkikyGklCBmEwxJDee3eAiPb9fXrz69/r1cPur6A2uvXqqsjJGbDnKB5nagsl52wmbkD3W6s+o52PNrXyFLTBwy7tYQySZXTdF0zgS6q4JhoxzqasTaygttp1daJJogqKrrbmb1R7eNiITrtPdedbao5AZedRGKmKNVWmmZR6mGRhKr2zZhl1XoFfb3XogPUTWjL4eHhmSrNV2IztraO8rSfWmOG8dmc0rReonCgbzjV7aVLY7qZQmLkhjbm6Lq6Em28BmK0q2jnjlO3MgyiO0lx6osV4doXaAZdqycJyXjtSjQ2m/bLO3V6CSSSSSQQfA+JJJBBBBBOvq26Xbp251bdhSknWkZ2jTsqryxKBta2XRCJNtYT2CsqziDTDt7SuxL9y2C1V9QoWrruFUNB89wSDQx4eFOk3LNU9Go3rsqpa6Bs1kzdFRis6j7+zGEyAgzDAzCTF2IipnCJPYdjBx6XdFkA08iIy3sh9niQdI3Ix4eFnuejhnpmHaCqJYeYdLMV51d43l6mK37I0LH6+OA+3fshI5VFcKQKpAyIJvxe27aHV4qtVVbLdq0RRRaTgVQVERHFNqDbtRfHJqqLUtJrlGFmaYq8+LfcJz0iYTdZJidKUthTCxMWKoIoIoiiggUnRJCIcM4e+smDAiSmHH5L9GKbAXMDgo/zdZLWbo8PBX/OLazc6slxDaLmmPDTFGrEizLJvE30l2+ssTDgVu6m06EOzVmdhW03clHReSCQZAzV7is2sjB9jHaMfbHEFhW7cYLxWMN0JNzSptXot5xqYM1YTZs9ylK5LpbuxsimLKvS+pgNtO5a3r6iXXbeqL0DFihbVdc5AVyQa7r3arEKjPQM3xD3F0jk66Lux3HYryDgtXMaM3e2xM7K3KyxrpIVYSudRhbx1y5g4zt3DlxLtslgzuqO74cuGjRQzKEmhBgp1bHGy94jjm9b7q40mPDwWOdVA1WhoHAfEe9NsvpVELqyqsUtNeQPArjS4I3TdvcrdWyY+u8N284dznO+R7NG9kVCGLcvYu4Nkbs4WMJ00ZlSKpTO6QZfW+FjerNqUrHh4Wcy3t2dCPZOrtvW1fYqPa9utEdu+UN0KBFNQi6XXhcCWC+K2tWHTXVYvO6FR47UsKE1TE3leDtvbe3e11y+2BMdw6rq8xK+Aqy72smsxLFebY1lSp6A9Y6UVe7VcarbZXK48s1WQ7vPnpabO5W61CeNlUcqMI3evNbCRznd1s55sakyqEy7Uvr682hLT6ibwJXYrzadiqWAseHhMGQ9VHtSpog97w8GJji2iSN5g1fahXPtMaWCmdy9yu1vdQWcQhYFuDsrNMzj1IXd9jrteG77YMp0s1ERE2X13zcu7pPaYzW8xnZdhVrCEzIa014jrdOxgr1RzOu5TO47w9u9ppmqwbhb914ezrXjp5ZBxRQt5wGk4tojMvbRK4q7qJDEDQx9Zp3ddluZ1vq2mh4eHLwWylVlKs7Jgw40LsbTZy540NjVTJFmZmVF0UgWchNentt2O7TepDhcpSYL21K5HplN5iZmg83mdGZIyTdgMShYanRpQsWcpaUN0jw8DQZFmE7xd2Bko2beeropuPbNs9Q5HmsTMzGKduzVW/SYChSFy8y7yVpoZq9SzKXDFvt0cCTge3sRodu12XADeO8u6x5yxC7uS8QqFYy1W12cQ7SvRQxmzU8Wq3PCkZiWBvApzdVF2W7OpNObR3GD1Nuc6yrTazIqlFULu0e3tvD63FqpDtGwn+j152FVO+V38dshbCTbb+upmTJF2h1end7Djjvh15e+UujKZEl2JtnNXXfRGtras5T01dbi3cF9auLluhOV0Pb7Y8Fqe+7AxloInPgn2KC58hlBfGpzI2lFxXCZahpquDw0LcPi6FZu5p0ukKzhvvDwJy+hNddzjd5wpUnbssdVbVpm4TJdFU5gN3vqwCrFQu8QPGsuquDlK0mr5Vetg1OkuI8hp21iV1ToU787soGXsyWR2CsVbHVl7UhraMp1TISo6NY2yKm2U6oVMmUp9NO8+HcHT7DeX9pqskbN6hPsyY1ZrVMLzuqr6PPdmlcrD2qIY7Sh2nNqOzmYLbvTg3eN5NBw+xCLSgRTu3V4jbuPbN2hewONMQ9U7pDEd7qugeyq3LWnq44c7YhvSK+Hum0lWWSWtLV+ldk2k1b1R0aSJiySxJU+3Rq2TarVwYl3f5+Fj8Dv8JbpnbTtwck9/MhuDCEMtMYSVd+uSLXLKpmuQ25bXLV1wWJSgvpm6N0xyHNpBlKdfbmaM8ogiyHGscaChb2yclPcDsyi6Q6Vbk3CrwIan1DZsXYZuAxaxfTGsnT9OYbBzWRUUlRP6wkl1i2DhbHZbtXNRhzIFhmM/RonDHw4KxpOixvq4ma6rqezskyufXc4ss5mQuVXStKLpbGVj8xHqJ0SiaL52aBFdnbHUAIzmHmWKFHRVU3SNV2DLnoWaVS1XZ6VVUD29sq1xG4rodrzJlu8Zq9TrkJRSp2FUrMvHQjOaMHWmo4xNyBYJLtLMtdLd6EytOyJy5SJt3kZ26JPiZqV0o51Q0Tt3poiXdJrjWqmhEGzVYzlXCcDY7bucq1kg5R0cFO7lI6rFRTw0brXeDbPVGzUEvRRO44hdUclduqgrqo7x3aXV7Jh2BjqyKXSF1Nl4DXci+NO67Klt1j2M2KRZOwu1kVM5fevecqFugcEWE1blMvRl5Kt4sgSNZLhdSRe6qzczr2udvj00lrBMiKMOOtu+l3yKPTl8+5IqryZy+Km1lW9v67qscqQ3RvXegk9V0O246TTpdgpXWR51MRVCBtVMpVaWndlpqsFTM3Ck4Cpc0F1blPtypa0sDbvEopKmQ2RbePrZ2KYaE0VqSntLLp57c7HRyGPQ8Bw5mJ1WXlzLwG4mqPR2t+3BorA8+Ndxrau6LM+ty9eHM3e7nUys6YxKqXdY3UzssEju1ncXYrXO+acMUJsaitKz3cPDwzb7crl01s8czDm0Ro15mIOxa4tuKRXELauk1rJzdTt6Rmzq6tNvpodSRR7opLhrdMipapzqJ9ZaqxSFyXeUoiessSjQ9LSqNEE1hq8LCIjmpxeetKspjYsTOh7znrCr3IicM+rGGxpr+Q3+fqr/ndCuzQ/SGPtfVctt85nCQnq2oQ5DJkkxEM2QuFrpXUQpm1ti8Od5OkHcCGcuxDYr7NNxchBUHR/3nHNNkdVH6CB7/ZfgOmC4hT6lx7GT0qfnKDb+Njku7PE3r5VHnJZFRNJdwvjYxGprO3xeDk27w3gxLZlA5pFPqot559reiwVlblVdq0sIvpVQ05nZd5pZQa3a2r29uDuzMyLDLvLBwvBIrazVzgOR+sburq0jTu43W2C4ahFXpoIbq7NJddzVXvchpsLrqu0EK1Zxldw12dj63tzUb55tF0XHe3u80bw1EererLgqnlp3WYESid69SUoJLVpO0Oe0eqr3eihy6kR674sW8vSTWajVrOgdJZzXa29u6OLcRrHK26peu3Yhl9EKlC8zq21RmPbKnLTBfPSNxOlGJ2G958r0aFW5u2DTlvSFu8O2BdqyZ1dxzePVt50KKxStVBzFS6Zu48SG1jvVuZqCDvYyczMuqyxdhJZVDIuB2way0arUM7qivinXXWhbLhpbaJSlE6Ii5Ouoau8LtLylDrt7csu1eu8wBjVg2+IQn2Oc+ZIl6QSaRPYsQRsi56u0ZYuy5ev+/5W/Zs7RH4nrYOY/imqGMV3Mq9b6MrM63e60Rs3H1Oh4eFOqJgNqpuZnWSjS7MNHSHWwvBcF3xzZZpdyO7XAzipfRLOtaXsV650he4+1btCqg/tW7o0i9futdjo20KCrKGL6Dw8KyjVy/ZRHh4dXZssCsNDjhpX+oGIewyMMfc51gm08h6naHwxi42hkYfdkuoHyxTXivq1+aZ9riNKtv3h4WcRls0we0dz54310HWqqlFMkyiZvNiHNW7WLFTzty8po5tx2Oe919QiwiclvIUZhnY+vRyVo71G62zGKtFVUp8rrOhmtSuDcgfc4Nw5oOXtSkE+bLlipWXrFjr3qq5VOYraa7BY8PB7CDcNora2quodBRCjNVubHu6Rgq6sQsjeQonpXQ7i8PeB3obym6OH0rcMOVkYMazb59oZFRsFNYtjfc7+uxPt3qk7Oi+j3LoBOs1WDVNbON7rvCc05JhHJjMMYnfbx660mNwZEGKFS+zL7c3bdm5J8ZYs4Jd1bxLr40XT6qwLdGRI0rd5TgmZKzcZhe0sviN2y7G8Mt6lNy9QNEXXr6g96PRtyFNZmjaoYL0tHXlVRtR8Rs1xc6rVvbB9JnvtB74Gc6u6TwilODynSQuGfIG1ME3JlncVmUgbUfs48a6svcvvalexdQq1x9ldYqxT7IlmjXt5p8z2E3RvM4cLo9lb9ezeDsN8/hEr5oi1sGGfDE5VaxtxDoOusdutHKSs6CiZVHCKVpIQ3DWrOcPcceZUQQMiCRwyli94eFsiLBgxjLrha2McLjtSqFCJpG+d1uimHZ43EYfZnOiKsVZqzmDsoZVdl5Dc55thg1dit5UKpVDU1f3BP9Z0uswE7RjOZCtBjM5jSIraKOVyrTsTrSaztOUYOygsvL04iO6ruGShNGBGhuG87CrsbvmYtT2mjSvdQST3t648d3IRe1d1pmgseHgww9QbvJPIFrMFyzaXNcj1yZ1xbdczNL1Dc0hXd4ngW9wTg3eUMNVktmXeXSt9cNC6G9gzbODQZZLWUO6JUcHIKqqSO6uw8M22i5kyDpuDuXWcQ5Vndo40xszLOwyBRtcQtiGoXlBfunSU+uE0veHhtL4t1GKz6oMKNS7vTW/VBYyr7FY18KmU4WtU2uwvLpdh7Qs21RxdJkzBXZcqXD3dlctPMVYqXTQhpa/avn2Kt+1lwut+L68H1bBa+2Ti3U2vnKeVe13Utvr6bOpkve0WrerePZBbN45py3OvKuSkm9Yy5YOpsWzavMryu+ke7zmkFT3aH7twW4NoU9tAl2ia42KroLd2aduxmYPuvMtaI5OF9Z+aRraT3YId+mPvbVGKj1BZytTtZ0Es3lS2L9lu6qXnEZV3VsIZbDSdKnYnS8wEm8re0GtRb7ryRbS2PHPM2Fmbs0upN26otnaw0OBy+uzarXV1dg0M2XJcZdacgT4NdWDcuqubx3b2rvVtG7MiwFvb2WM6nfTcFU2XnHsoO961jox8g9Ko1tnx7pXW90KqzBLyXuwK53dCL1E6d6ucEdYHc3EuKRnR5HxTjoTLrhp9lO5VsHWma5dXZVTrti1r7rwMcVZO3OdQKbQd4czMlPFIw7rqmRosZw1x05W1ON3Z3rws51uUllLCsw+nOgQcJBofV0FU72iJ2eyxQlQVJYorPvsrsPY7iFYlgrBMtbfKswWkpUI6rd3b8zyxjdp1kuOnE8NXuYKxh3aUmROGlHeK7XfEX8aoid22LvtN/VnpW9rnGh1rq0+PNac071FnjDgAX49vgzqqqj36yn/fPvkd6/vz6vzrJH7u2pVndofqdOJvwjCyW8r6S12rSea2S71Wc8FlvNsDxkZbSnGZ0hUVFYVVKGtp5eExWV2OtGeHvA6feHhc5wVdZy5483doQ1jsmOurd43e3qzrFTU8zVDxtXTjDXHPbTrtqMldodg7mZcIzaD3V2h5azdJvtdg9wVazSbJxOnnDhtenVTDF7x3MxdbdZdl5fWYMq8rqzO3xXI6tZZqYx4eEW9xXXWLooKu8t6j1CtFQi7tB4QiYdaCe3jXGutLsnPXvb2rrmdBjDBQqvXXHd3+v8/Sjlj86Iyj8/y8z8V5kSGFOtK67SYZPKr43p6giMwzhAbyXMVnZzUfcavQs6lu9tYq1mI3lQnbZ6jYe6rJIMMMu7TNvZbTfUI+zlMJ0nlphmPVLfPsj1c08pNcXbpVHKax7KQ4UoEg5l92w71cMVWU8VJ51KuzcHSPVmuOHNC64kK4wc1zLzFMnKM9sZI2nbo0LosE3J0s90jqFdszYUOvvMkA92BLI3jIy9mXpVdyu3E3uMF6Xi7RVYuHh4KhfZielHdgp6L4nFpvq5Qlnet6yUS3zRl1uXyFFBK1dZtbkYbQxjdzL64z17FeJ3aePNdsJY+QugrYodR20vnXysj7qcr5rh9ct1H8Xqs3fFzpjwiXUbuoZksyPRhi1JLjtIjmzHBFwvule5YuwzZonUkLobVUQfqe9z90VV8N+G4sGsF6Hew5X18d7TWvVcdm0ayqhyuM2+pOtuxAjHDkRs8Zb6obGjRHW4i4Gc3c66eSzui8Iqasut41hNKrzr5sbKPI8w2pana4RW23KZvJT471l19buZ8cNRFfcvoMqssztG1lzVe5371d8yugxdR+QsdVszRlNnGU4M1sYQPlVjNugwMNbkPZhgrDNoaaxPyieXrnEHCHjzVlEWDczrmhVwzLG9PSWFFGazYxrk5g3qiPQK1Ty+27zb/Ov1/Xm8LF4JeO/i0xWpI6xmOzs+3LR0aVdNPdFnNXcSJioGRCs7qPbkoOuoaltHpK2wNwklyXIbrUaW7kKMzebopkMd6LZhwruslVuK9yi4/Zoo3PuutoZ99bpA0/ksI+oq7Tq6Z4rndjTccy6CfPL7XnbrpyY89M7a9K49sBlceRqLDskgopRVbdApO9PHrKiszHWA3mAl09d1TBbvuWUwiZAjBuYJd7t87SzeZm5BNxYrEOUqGZjtWcGLEXJzje7oon1kcom+scVNOby3CrFpxkLU768l0VYeU0Hvx+GmWIp5va9J8e+0/BNG3tPsZrrerBwIwSUMV7jau+xTtNi+EkZGdui6m6RmDazijTwuQM0bs1JeKZjp8NOUK4aOvpkjIeWo4dJq6gqttSbdVtW8kznKxZeNgzcqyKqspyeUqbW7jJu1/a6qnZyuqtn0wM5j+tUcZJyrqmHXK5kuBYSMvd06ZgO5wNUtN+q30ju3vUv0y+nxMhlQSoSVIVJCVJCSQkJKkJCSSBAq9de4mt68c6XglmzSms9ISUxQ2fp34qhRhsWf2ctmoC/sd9sYrbPKp87CcGfG/rGO+3XV0VaEdtXnK8Nvnpokybkkwo6ReUOvCXlM9VXqDp3qLSu04sc6+N1vJV3QelvuWuycEivVHebfZjo0GTdVlJPTExb+3aMzmJ9K4KhlXJd59Yu/a4dwIn7KyqdjrzTe1yQM2tD2zysZW3XkuZwpDtZKBy6ERw9EhVI9HeqpH3ZQzthNx0KwhC3IpZbtHkwJ30+zn18XWjMn3vqqq6Ll6U1VHuYg8PDic9y89oyqlOmbuM6OyurutUnlPbtwqPKj5Ds6rka9VZNbLzbwprcIxnHnN5WJS6ygyQuzh23py+q5t1WPpdVFV92x37s43RJBIRrnjZGuBSCTaZzDlhF1G83JzTiDt5Y6gZoYpWpxKFTVGlUm91d7OvmEtulZAYyp7TKJQEpDJzGiVOk4WayrNvDpHh4bx5lPoCZq6O2kbvM2xXiNyhZiGb21i+36h2rtyZDl79x+f29W4Fqvqe6H3VtZ6462o9086eZT6tdpmnYhlu7eHy55UxS0RBeN03m9yye5WdvbFg3R13REt5ktyXdW9S2hUjt7CTT1msLyVhlbXWsFZB3GhYs3t8MIkbRzuu8dS2Bjum+bvLylkQp9cN7vbmnMIXDE8P25Wr4EjeUtChTO/QOtlqhdB/bVoZV2XkopWrtGziyWIIWVSiB3ZmWG0eeaTl1HdcspEGFwY/bAeVSZMIm6Tu9mcIQhpOI0eMHPrw5wh04zkew77aWJs5Q7M664qhW13oQeSsVWS7KpE3rqac6Lqt929VDlhKOXW1ox2b0Z1p6s7iMy6JsRWNvLJL2HXVkbadY+dasrflwyhWcL/r9Y3LQ/bm7+Wv1D35G04RkpWUcOmpuZ/RC7PfvizS45p81nbpeTsuS3Pl7/wQVftChgKBVEU68fNrX0Phy/CdvwcJs4ag4lkyh4QTuiHgYxfsBnuup0MaxUaeBBhQHgtqcrEhAw/hxAxKeJNGMzBDLLXc5ypuWKV3d33SU7PvA4KZnha4eZEoHelWLcMavmdOS0WeIiVscjEpVWVB57lzk6y3pYIiNqU3Nq3e/HeWntfObVrVLV3EkzGrSKRe8DNKuZNN+PgiLROVuUbMpKIVlV3u0p7a0c1prTm/JrTct7nadWo9sy3cWeL4VKa3e2WOK3qbtuk6x1uY1701WlV3SzTjlYxJmXFJbOig1VjGzSszTtOK5XPT13Ny9FldhqX1gh+E8jYq0YvR52XHKRfeZybLRmGUxvGGhpau2LzSedXv688EKU6WEwqQYVSnXLJ0hJKpecgFjDamoIMTCowaSZAZShe5i5PmmGoypfM6NTavpYBr61u6anaup3nJpsxCCXFAyAwlaEzSSAkBiG0ti+JNFnXZuWyu15bD3lg3ZRjW9W3SLF9HLW4ZLCj2JSvsXJdyiwgvszFpMaW0NaSRqGFVSa8q7NRIyaKFhhOGi5g4SOhQwbNGCRIyWGBhTZIUYxkLEFiEdhFMYzaSw4ew1zNVw4erdu+Onlp28PLtsrdppwpwpTGmkjgxMgYmCnChg2MbMlCDWpNsXWZPLb25N5yze1J1teJYbF+CjTWWilJ7tVY3TLazSeXWsh1Si1WS8zPVLssq0hUVXneheSSMja5izRtX1eHaUnh32utRl1nxV3GJLbFM4zS84q7T3eVLtK651Kktw5XUC3zFYpTi8ihuLuxZecbJp1pHHktuNPV82LxXJyl3tjA9uafO+axiLxnbytKlYkYsrjTViL0tevC2MxRnYxRsazSq15Vsau9bW1WM8zdrzWnGnnU2hl1ne+RXVasctbj85KfJalpnk7lo5LFKVmbW0asztufNYbVcWrquZy1pYZaypiw7YvGpnF5veDMuctPayiIvos+c5vGYnORKWoy9S7GHaU7Bu9t31Sdp5ZYpJ1huUxF7TVYZp21GFzWVGWxq9oLnuMNzeDDUIWOZ1ollFXe9T1FOqz3ke0VlJ3vPTSGHxummWH1Z9q64vucNpWnmjupTMTwSesVnWk13ew5DxLrfMvbl5Z01LYfOK3FpGOERK3FarWLtGeU4WqNwpFpvWpafuuUl1e2VR571sUw7OTW1Qs7l1hZtxYjG4ZeYk5ajDsxN+nGVV2zUUZVazVkpekmXqNzpqc1gnWdyW8Xk1S21qINXbUmSlLHKja5dXWHZXnDX4/JliM5ORMnQi2h+V4u60rW1bmpxSV75w0ZK0ksWajrUpRXWeZNk5xK0wtqNKmK2tmTG8YL21zmtxelWWud1aUlrrO8GJtd+ZtSw9NLEWkpWTCuLZsya9L43KLur3qzXvGXeI37UrSk4tVoh1z1yksvvS8GpimJWXq1oyabWNTxjdNQ+WlRalKdKuLW1l9TxjEmXM3vqtXk73vMJ7xXeqZJSpe8uK5kXWN2hbczacktVsaphpTzuzcXbRnGKOATat6Tm9bS5F+XwoxkyTpTUZgXK4u2SNb0azlcLd8PrLKll2pdVvM3aWq55A06U1zUJW893ZvjMcTka23LtZKrA9OuJeelGuylJY3IWjNWuIJSlbM3XHL0XTdG673Ol2m0SobtLKu1KMzarjbUSihOKFG2s51zDSnNRond82zGCzZbBZXfE72l1uRYzuqwgj8Co6AMEmDG2mQxwQAWdjKiADiVEUN8bgomd4crrOxjkSK3hy7SgvadZY1PlJtOxGS/QqFlSd7K6lsr9LqkktNtJUlKmpSzWWSlppSk01tJUjYskmWWbZSpqSUqPqpiqVFKfbt7zZxsnxNksnm8aR3RCXVeYEAOv+Q1A0XyY2EgTEtjkY2JKuzXB7CmQD74ZDRhFkVMSSmawISGYsvZ7jOFeQ4glBQUUEUJv1uF3MKjnhqNWSnp6webv49777kyjnmzKCMpIzEGl/PXJIpBUUjEhmaYP6OKakoGBkkwRERQyZlGMaRFMxSUmCPO6lhJXpyZmkZokokjMRSYjJMSQgESSUZJkoNCGbWjSFkwMjKaExIPpz7Pv1vb1eoIphBYVKUxoUixBgYh79dIRECZiJiJSSCJIUiWRIpg2EkjEZMNAs5dhJJIYaaRSIUwGQ22iGRUijJFI+HIZrxXEKBmTKISTFEaQSDEZAkYzQyKQhGvv7e9X7Nt7ewX2821vxvVb3qvba1wZmkYY0jJFEIJjKQ+u1wIzRMUwTYsCJEBTFTS1oMAiGMRshtaSmgIiJKIGgwhKEUBPVddMUSUsmaMmKREoTxdIBDNIkkSUkNASNDAiLJpJH736+K3l6RFKJKKUWESkRBEiQsSMhjCWeyuqEBMskiQSBIRo2MGkoIQAkhigkCZAAmhDTJ8d2NK+7rnCRSEgQMQozAxIJMgkCkiUQTCUMMMEBIlBTI3teu8nfXleECJZBiooDCaPZ2SGe/bdIDSSIlBIyBljM2tIMEYNGElmlGEyykprAQoY87lETMptaKmRG1ow2BPW65AURhkpSZiQIIjKSMs2QwIkMQIGMYBIGUkSynvW654uYMl6dpjBu7oSZiEyZKETGaYsiNJBkCEkXt10SDBkN53CQyIZoUiW2mIhI0EYmed2KQpTRDNITKEiZCZigMwkUzGQtLKMZi3O8dikRkoUSSiYTfvNwVIgMpNIsIgUjMZSI2IRCRQS+W3ICIEYUZoySaUCNMpSIhhiKUyTECiUhSgyUwjE8VzBBTEaUgSoJY0AyNELMiZRARLIMSIkEQYlKRJk+PPJq38V83X929/aBNMMWxDNIimGAYhhjC+nTMYmiSMIkUS20zSkUaedu2RGKEtaBpRkhCETBKSIiCMiykyJIZkaaEUkxgAlNDZjCYTYQUhllNkomIhmMMkWQQeduxMLJo/dzE00jKUhBCGIgmZZUpiSiAIZJi866JgzRkifa1puJgSi3/U7cmRMZMYhojPHNLJKISyiKd3QS3ruMbJmSSIpGZlIja0ljNQGCTCAm+3dQCSEZIAFEzGTCMzMwDH67ff9/z7+/tNBYpCmWUBZIzIlgaBtaMmGPldRkhgaKRIUGkpAjGKbG7uSQQ1MJkzEGEzQzJS/DlPr15vAknncxoxAaWUjSNRjIiRIYjJoQIhRGkUiMxGEoz83u/jzzFfG8V8ErOOyndtwjKeFTFmeZcsTnQPAzvlSKn2ZiDENAlxMUQ7XShcuW3iDyjyrXdRUZjVYXc9FdmXRJ7r2z/xN43phgXGQDECIoqDEp71IPcVEDsqDildLXnG1Yw2YsiMsWZIVEQTls9QWijOounhO1dJBudbSDGpgglNFjkBbSAIi76zIi8YL4xxJV2mYi0SouJCbuk1TM2bRxoELNVNvcXGVtCvUDS0xrSZiSJPCqqE4+arxny3zwNRuUtW1+VypRM02QjRFgCTIEUSkxTQlFKQRoQigCZDMmSaGf07hJkQaEtGTJpSRI866JiBJiQMkPWv47XhAEGkYITSzS8puiFAEECMaEZJEKSEJRLABgaYq24k/CyGJFVFUlSaPgrUFJIhCiRHx3SaDUxQRJkfHchioozGjEnNulMBiGkyWjRLDSBpYiZiEylSGjMaDmq3YUo5zQp+bVZcokgIYaEwKaQSE0hjIQL13GgNKZilMHrrpRUmxQe/ve9si9X7dfz5veMDQNjJBI+e5FfPdFLzzvO7kpQiMFhMiIxkvFyVEokJIimJSaWkiClLl0TBkIoaZc5JgMIvz9dvIj2cso0DFkoZojRJAyJBBhpkQZjDJIRpGSSIUAmK/lbiZg2gkMZjMxGKRBBsEhkJSSJZKKZkgTSWYKSYbEpGIkpZjMIaGQR45JhFgkxRCJiBGmxlE3OZTRgwmiJJClSyJEyJJJPnuGEZsiSPfuj9/f4tt6mSk22egRljEoKKIzJGDHw6CJIJGYGkxoxhSJJ89dJEQpKMjMCNIiZhk0xEpMokgkaGQiZkG3q3XJqLNFbSphIIZMGKAyTN1u5JEYkRCMmFJkBK1kZmMsgki+auq2a3m+QFhCMESEGMV20NBG4csjhKV57vq92mZoiImlMMoSZIAjCRGlDIRTMGgiEyxJEQKRAU0SmiBkZKbN9u6JRGWkzQgkSIhERBAiaUlCIZUZQFNRgBpMC5rhI1JhLNKAVCUZoYlcyioSECRy266Djtyl7c1Q3FnRCS1VN5Wr01tvzTWSyyk1krM1ktSlspSy2TbSUt5turYUoqWo6181JJ2LBuxjFmIsJCpOIownd8yN+Xq77tbet/XSNuvPfOyevx4793dfQTFirPJUnttjx19+I2UiBZqlC55buRsw7zNRSzTZsxCBCCsEFEFFRCignE/YKhLQCcxjqM4vy+uuuuuYjEuX5rN+b3rnOECAFGzW6YBAHuO2ABEyOTZVSNRHvrfNvo45TjjcnmcYk4RfL421ANdlTm8tpEQCxk1heONVHBKXV1rqvDbbeMBoGtK0Kt56ZbRVpbXheN7AAqibokt7nKhMnlWFyLTZi97q24qYryY1EQE2KIAgEVlKLTKvGZclS+5VN48EM5x9FdaNV6EFNmUx5+ZatvT67SUzKURkjKFttstY754eTHfe6bK81u37x1KidbYNuNPrEdWsxBTejE2JY/5mm3hex9TlPq6/AG68L45pXbtY8vKq4WxajbJV15TrLGDy8lJ7WnetkHmeDljNKl9cyX6ccjfMUMVrJYtTVb6lIcjkFmHMdGm8nLea93juAJxwqjf266AF6AMhg4rIFbRXcDeOjIBySCm4HMHTPGSVlSVzdHWXv25R2v2QHtg7YKnuA9uuowWnXrPd3tOK7qeqYrfDB5ViuOsNN9ZJ+PnGpqiDLhSi5HYLq6mqHcZy4jCQ6XpGNEh+SqQGmqd1d6d5hbdk5I1Wsuplx7RraXpWz3dezMQMUHanaz46Qqqrpy24WQZDi7dLdavfcwS4oElAHUFwsrXeSIVdjHRhMrjUiM1kVKLg4/OWbkZxqoyPvVSkjGjWyV7kazKMvFd7KspRQ5FamhKQF9CyVr5rjdJYZZm6VImvKl6Yvl7UezWvXAYDgG8WSc78CYo4KFABgxmsehVJ4DHgw327zHXByh549e77nFrOsRdJ3aOWqCVQQ4CDCUzW8MMSuTlvE8zeqppqPC33EUpWbRuJOxiInu7aicZCfL75XfoRR8XFpDktl3W+cRZyTX0db5fe5OxqbRurLPPTxzkrpE9XLStSU4n8itnJT3avgZNdm5XeepToXHIk9i9+l7O8vTiuvEVG+s9vvJCWtD6B+3gLd4dcoW2Kxa09yHo1+EsFemp4GQ1Iv38cXVtnmAogJKcsVs2cXry+Lti+Ol3ug2lKqmiG5fWVXNpJJGWUI+ec5q+IqCZrgEk8jinMlsWnwXNta1hpprerXuZpUd6aMcilgkIlhDTAwgqIhNRDFkiliSqEntcVsUhhZJKWSQqKkJUqKlCqjqePFY0gSFCzpp80oNffJiAFM1nJaljcyu63sMaEDCpEFByYqCCopVAETesE7Y2Y5dDCKIaLNk3usC5YB1ERNRp03NZuYDTbm8ELIGVDJFIokaMMtBGIzEyMYSEv73djEpTSRFBkQIMBJMSQQIikUilJAc5MSYQiNGEoY0gmkwimGZZLnIGQbCShNIGYBImMyZDEmGDYIZGgREIEKGRfr7d5kWtCiNIkNNAkDAmSaYeu5GSYYucRCRMiEid1cmSEWSm1o395wNIUyMzMRgpTCSkkSGITCykxMTMBhhlmM0LAULKMJslJJJNGZCjJMmaGmMYFMmFmYnyupMzFBIKNEbWmkBApkKIoiSQUYheu3JkkJBEgQkFtowpEoJAFCMY0GUSmmaGABjMpElJmkZYkokxYEaYsmRIWtMhtaAFRSLGjSSgZJJYyBEm/S74/V+n4vL29mISIFBETKS1pCRJGEBlE0kTKQiCUg+O4gyGQSMkGUhFmhSaDAwhJEURTQNhINgCUEmJpmzEk2LNkZFIICAMM312uGSRbBSLTSRk2JIl+vr9erekf5PV1BSKSmPjufDda0AZGZIYiYEkwZDMGlMySzAFMjCbCgsI9OwxSWMmLGUSMGyShExhAiPv26IzSUmEZiYpogkhhgxiQoaHs5QppkpJIiZGTGIhY1/Hq/P8+1e2ULBmaFhmRSCkjCGTRYmtoSZoEympNJGe64wlIRjISSUglJBgyYJmYDE0RS1poBEkgkDEYzJZZF3dmmlCS3y155ukkzAgkylJm1pIGoyQY3dzGEpKd3BpRZv5u+Pzq9V4IMkRJKBMmGCZSEiABIohJIkSiSSWYmJKZikKZEyMDESCkxRBRmNEk2YjQUJQSk2QHW7oUkSCggI1FL3Xu8yOdEiSESLuuzSSAUiJlCQMVtBn69rv3+P19v3973+cQZMhJTNGT6dI0K7uDIoMYiIkwpMA0kMwiSJNTJRYiikE2ASijDSSiZNKEGKABB9lypCYwh6r5VdeMQiQShMJJEIzJEmmRsUksYEEsxCGM3t3ImCRSMMmIgS5dgTTUIFKBiAlAIAxjR7d2UlIoimZERNbXLimCk2tMMO64JERAsSzEQ0yESRlAUMFMNKQoVESZBLIxhBTKWWYGNIIaIKSJKESSQiggISgJMed0D7duUS1pDYTIj0roMSRIZCRhRkg00ohGkIYpem6eduNCEbIhBZEjCEiMyaxSGSYkwlShTSmDGbxyRmYMhttAGppIhYFJpIc5o2JlEzDC87mkRZGT8+z3+vnft8V2J4XupEtuM6dYtjoXGsWL9A6jLRdqKZd9wom13Q1RBCth6IafTs4x4tSmKjTZrKGlfNrPrKFXHW9TNY2vfNKCCJkUWWNpCZFCHGKyi9ttWmMTKcWa3uCQ462n4L11YvjJueJyrED5K9HUAXKSxfVKs9Ti6m7Ytdh9Ihel9XsGeqktGkKTiAQhldxduTUQhFRCzGor8eeX1+v3vv69vPe+UKUiYMYikEZEDRpESZCQZSGSggP4dQhoUkmiUhAAmSv56umNhE0sjJk5xJBgojJGYkkJEQiCMYmYmAkUYQIGNCloUmMgUMozTGMiCEiTGmzS+rq/FpWLVJJK8r5/Ht6q9e0YtaQNmCSK2lAEUFDEhC9+3Ywo/uuRmAsJERIAoAAMGwNA2ZJmJibCQlmUEsiYJlMIxvVu4SvldgBPKmukUoYYxSFQ0IyFEMyiwgbzuwpKTEAsmSuXHzX19+89EUSJGkWITMZBEZDSpQSYxohRmDKPbtzEMDYgTAaQSTNQzIygIBEIpEZgImmiTQe3568aEJBKGJTINlIQlCJgBY0UiRlCKAmQFL427WXtXbbXRedWwg2SZlmExjYYmUmGZhkMaKCYjTJYgTLKMzJlbSEJCBiTMjKmE+uuSZEUigiUiXrtyXjosSUiUZaM/HbpJkxTEJRUJHpwkLGSGiLIkaUIE3dyJmDT467RpCElHyui9+9H3/Pmq+qS9+jGCQEIEgWtKUwISQZL57spMSX+T1eedgEjJEQoNMEyGUgm1plpRigkoI0GSaGJMxmAUxMwTExiX5ckoymFGQySZLEzBRhhJlMxMomZRFIU0SZSBhSElVtTck9tNjyN0kalltquLMlWCBFKYQUoRM1EFk3LiDKMhEoxZSZy6MNL2dggjCUSUkoMQlNGaUCRDMSi+OuDEyRF7u0jTQExlmGQgRZoISZgVEE2MWSZRlEjEkmMwShLMtr4lq+y8vo7QSm7h4H1rsoqkR3ZpCzDsDAwilADvJ1ZvZHbv3757TgqI8VkCrIUCixLH1k81NFQ9swsiyFSlSU80xUKqbZEGFkllJS1FLJJnrEdJdu678Vzud11ZJr1ylKKqafPeGqPdJ+RYE0qVSqqoKRZIUppjICq7yPdjQqdKVRipLIirVtIsvjvv13wk4iXdRtutZSSUrKlsrX7sG1OzaGJ160GJurEypOdx81IFEUEMiiJfErbtMUxgdHyQm74imMJNd6KXgy2ru290cdbZHHatBZReZmVuBfkY0ZKmEBLIiRD1fOK2QmTwaCYZ1ThPL7o6gGCopLZLJk3Q5vUygxSW0cpnENLmTJHG1mM63VFS1V8d97TXMbYikk1FiihCBJKkqSpJKkkjmaZd6yd6GGeg71OestqzGJakl1ts5Er4WTDWtJ+WjFtYManv3OtPd7Jvo6OT2YieD7WbqbP32clV+vGmo3jU8lDmmw0qYuS05Oeda8Q28zLjPKCYTxbfQlwgUKhgnv0O2bZpoi558/Tcm/dGTt2rybPppu4NylG5NleejhT0Y28MXs8Zri07ynuSZ2VV7ZlIi7ucds5rebz3SlOE3cZ9wuFN8fTNrFS4BgUBTbIJmeAdM3xhntr2L8fPUD71vMxn1S5SVJUo7FrWo88YnYyKDb4QQ1fZNPA8GK2SSntybNlcsY1fHt9ghISByQ5cYLDhBIgKGdF35myytc5YSbsOPaVOQj8i+CUbztXvbmJ6elrymSllaTJ20uIYxe+ry0l85xu7LXhGcmbmtC1tKoYXeGGmpBWtoYa+TltrpszucfTF85hiHM0zNXbWJvcW4VJ4JnJoEqcOGwRLc0K18aaSJQTLxlszzptxxueLDiFeDwnSbOGmmmmNMkbMd+nK+sX01q3HLmvBu3c46nb1Ct1jUpTHLlTwbsbNFaaPomo04caCFkoMIkh8tE8CkzbbtvL2TehIFEmBu+5FEcprErw9JE4rvccVKGs8xd705qrKbzkvMcgtBtCa1VeZk9CPIYQERD7z4eS+e6+DyAVOgDy1vk2IKEECdHhmBSYpMc7O0qngde2ZiOBKwmiwihIQJKKJ5QMI4gvlnS9u9U3xbY5d73Ywj7txsC9HYiDNepF7UoRqAJIIE5hfV4MJfv63ui2Qf2t/SxZmq6o2FFEq0J06THh4HhihNR50vtpuHe1uR07sZK4lHc3IspBCy9v3RU7pzMx1tnurgk8KVvRjwplpNIXH4ilrd29GbtBV3VU56Ng18OduiVLrcblQZeQHclaNPZopvEDSyOjdyspsbemzxvLxwRlGp07cOO6XF65WdvNdvLZmallc8saRR1dA3fIGCbdwTK5K62mpYRrM4m8Iebmz15uQoviKSGVlqRYqkEzOO26au5q3ICKx67LB5UXZ7hpOLdpYxgR0ggi3XHlKyhp2hTW5NNxK9rDnOXupV18KW1fucW1pOhVdQTo+pZIlygIix2Hmf4m4MSWlda+5wZPsTVZUy92VTDUbJgy5v2EVDO7eFva0U+6X1VxRMc62EDtNOz2S7FSDDkd4MouxVXLUjVtpNXpLvMVrkZFeVfapojTvTnbt6oNFG5XOzyyoVg3cy6OxYSZly49E7BKrSTstTeza3c2uO3j01j0mx2W2aFXdvBThna7IN6VnHgTnI6KoGE9tVBsYON3LfTVuYzajCEcy656Wt3FTVB1e5dtbMV73H61PsnVWdi4MSXdfbjjuVjqpYMJdYCXOVPlggzMy5dB97bgnbeLRMqCKzbQW1QupeyVkYuaTL3usQ9Y12XxLxNkXNlMyK5FBZMsZBpIdUwd+waHlol4z3158FR+GduYIarF2cNvXL683OQqQ5kC66udhiutrLmx9oOVcxpI7dOlAEjqx1he05UfJ/Ph91Yz7e46DaiuqL+lT2CrqnFRpOpZlksrM2mJrth7YiMiT1ca6BYxhJ5CFmsWU5Sybo29mjMtph1TRiFu7laEnXYOMN1qqK+0Vt8TLeMYwuQibFlp1V5wOrEsyMOlVrDuBp6NF5x07efd24hQtjPhwTwMbunLDC+qQg1dbeOB79butWzdQi75YmPDw0HWDaCpUqukrOtmBVuLKGxS1mdU256qNW9h2OnUNbUx1ehQFlZkq9hm4qwPO4tmzi7Ky2DA+ZNdutWEnT3KrpKboX1I7s6qMoiw9jwu3TFIK2NQV9u5VtcT17Ar7rqjsOLcukfdg3Duy3OWw1KZXJ3szOy7ytqbb3raxXPIGkIniTB143fTK11xysjO6VpWk9RrrEKdCwnZF7111wHFdqkjl3a72qGdmVjObkOjHKeMhdlVegoEc1whHzq+uoLcsDKf2mqA+zK9djc1ixdqrYyvmO3akV7XvDweXWplOYtlXjjzuozaUhWhB0VTXZUO3noTID2OntjK5OSq0aelbunpGHDCgulUDOMqtymjjXmxqTzkAu6ZwrnfdF2N2stEq4I63d5B32HkVI8YbiIdFzKdQnHoJNAjLFszCLgK6+0VdcndNd229sHNEl721ttqCg9YqC+5y+t5tYm890ZUnsaFDtC0hGtyw7NYwc8RVDY9KypIo1Gm11khuTVZkOX3GZ1leUVxlaTeUU1R6SNnMsbMqspqs58Nt2auwXk7h0WLK00H5VlEPRraV0hFKptTTmV267yQ9zRO2unFDlFuR6cNLcVdCTCxeijejbpXtDmn6V1ZVMFMXl9IF0eubd8RVZzq9qrrLo280h2+Oc13W83RS3NgdiRRa1u5e6ODHWN3RVVMbl1xOc4WavU9TWrPE5TRnbeI3pigvrGjhTtVLq0+Sy+mV0qTp1ZfWMt3RPY1mEdLzL7acsRgt6Zu2mu3bS7O2ot526dYuOu85861BcE5NZmZS3RcywE54WBoBHlWc9e1M7MifHKoftIn7hft+H+//PzVO0LTd1Vrajs/n0czj186pK9FvSdNAkhTIk8rIc2SdtqtvhQavMy+zNSQ1ZtLfw67x4yMZq6DttGweyl9kWVgrZHtT7UO11L6IxVhx3QYfUOhiLI4aaydims7fVAN9atosJg5O3JeYEY6ConRs6yFCq4LMq6zpWeU8OLFHaUtSpat2J0n8Z99z4XMgh76/q2U6x2xeRq7WDuwG2ptWJt3q250Ug5bd92Bp+bQyQ32iPMuuw4KCCqxWy5pm89vtTSjcWW5XD1o5L5CpisHkSc2htvjour5DlUt97DuLm4YN5pacyId1RRZuzdSvqFXLvZoOR5BQ7XqhQKrDGmnJdoJhOLU623y26HTeTlXw1qRcjh22iMYkS1Un7jVYU22RQ3IVfC/98vbcdlEZ9UC6pXP6hWQ9uv8zKzV3VAT/CufYNrZbP3VWzMn5LJlIHdhTB28Wfndf3dQ5Uy7+iXIhQ2bQpmrkollFBYrrdyOPRiOOtY+3U+1s5SrdDx4NyLnuKsoXVKprlXW7IbulrwiLquURQdHZQvL0s7WZFuYjhWU666pMbnnhRRmrhRR0hdcnNah10K+5WWWHxCKIUYfNjx29JwrtpuVsfR+E9m5orkTSN1cOSk0k7eWzqHB8VNSVKnzc4K2SG5SMVOR4G72eTy5GzTpOXkydlanZwZCbJNqbeTqadmOnRxCbw2kO7NzUnRRViTcyxw5smpNnhiYYxMKMI+IOHSVUUo6Uw2nLliJ5eX3K5OGxptNm5ppKoxKjYyJO255Tg8i1hWqqjaZZrxc8m4zw2eJqdprSNzc4LmmUKqztlhcz41bXqtS7baMls3guChAwwIgE86xevJGTAoXJSjVCZuoGs0XW6Ll3WIvLWV9Fl1ECqzbM1YvTOTnddSV1eKozjUB5xLrw7iK/p17xHh4G4r+fn9Td4VEuq18DfrxVub3c7uEPpl6+cojiOzbzUOs0Txw4r0Q1tTrBaLrMy5Sd9RcNu0COwN9oahIG47hWiyq2uFXwp5tZdvlDKXFOyMNhwYXulUK547VDaF2c0Kwrb3RtJYd3ljiy5g8PDVhiyW6MZR6ruBWlpvTaXYOpO3V6+CPPBFOeLHlg6JQ7LrBeTazNqs7bfDsDg1JZcvl2bxfXpI2tRuS9vcnqNjJLecpV8aMXXcpWKmy0pucekzPUEosrua6u51A2T2ViVEjhTF4zd8VeXxrDdzZiAuZWB1ihZ9rwk3mYdjvcei1to2Dmjkhl0Io+QmpbVBWD2a2KG6CDlb1Q1fOurN3Jhv1i72f23Qz2vs2P3Se+oNJ0FeuZ2pbNsU4o5yvJQvY0Ud14rFWX2h663S9vo6wa728A17ag40b3o8F9mOUMq4yfVXXzqKtx2MTkBUvRUrTV7dJZWDTx/Jf2n7cqfBDmhqmTLd/Xp108syxsuhut1svKuS2hYbEpTsZJoNZu6IM6aLBmMcMB2mw9BG7wLuYIRsTvPXlcoFeVkVVlXtC1cvacemj7au6LDBW9O2gkWq4jhud5q80XMu5dlMLOyThfDZm9WVtmWICDJehQacDw71AnrrKpiJDpmjqF3jOHXQPJyksqqvcTqa7Yw5ry7N0safVGMbRSdrSHGlkNs8XKgu8xi6aJt4zMo3YNisxZvYs8aulh0ZutDHUtJ1w3dYoS/PQbcIvCtcp9UO5nDM2nFVxcjyO5DwKvXskGaGyT1C7rZY3AnI6g1yzDZlI2dq6vIMwFEca7u7RkyQPlyqufxvMXqR+0VxF1cXvjK+lhGrPbeju3FL9t3xGFXO7bdJ5BRxCrtRu6Xbm2oZV6avte2BWXj3Tj7K04Lhk3qqsrbtVtIyseVVvj67W27RystHjkyhDRriu3gJ1yGKytxzGpES7olcOOZfZk3MCwXZwyojUIwq93LPaeu+N5TdZWAtZl8lMrdWx523HVu/XUHh4YVixbodWmjqKOawxisyNnGq1ZpoNqBux1bTFdLxZX31fSrnbydV9SFSB9UO3SBlVYEKhrlfWeLPcDcN5gx81XVVOnl2Q83Vy4c2luoV1UUfYZMWvuNXr9bFDLSBpoypYfVjDn25hPY7g37BK6b8d07l9NcaOpujmZ819eh3nyhYquIo5d78RM0cVu2M3rVq2+XFyugZ2I5HLNWQ5xTGYtuu2giuOI9RWsdo3FgPUXBskqOtDGewu+vVIsbVjw8DkuC3QJD9oW1fH4j40CURJOB1HhucJv12LB1g3kjSn0uBVhG5aF7Xs+WfGvdgODsxqX8GkZbjw5mk8vsmJBfaQ4LZXLrOQH7fLrZFaqzduZhtZKyI9l5d5jjfb27id9d3zV5nDapIqO1O0+klywgCcKXFyOChnN2zV2fSwMv5AU+QO6Jh1mZVtKqkUzNxw56te7eYGpNDF4VbujDl5Kho/xYpo9+L5fd23YlYfr7K3NhsWOEVaHvQbNnVKOkWNqtFXZBNli7c6WW26eOxsyW8zY3j3BYnAfsD2AUACB33w07PvrB+Lrk/VaDt4L7rw6u7aLEt7tXeN3zG2XOJV/i+3ef325Yy69nyyoZl++b7i7wXt0NKrlVV8nttcfvtFnO9pWZVUSOtXZqYsTb+z6qlzfqzTpRt+sg5ZBXXltGRKr3J1aVBMMcp7Vjtl9ST5UYK6rql98KfYcDc+kifw7fs3WhJc0l1T6V1ac6GpqmVSjvp23ZvqyKqNbvt3ezNI0vjEtrLV2RLrr5WwjZs0IW+uFqhrt3Yuqa47lX0xuhIYows6bcqsrd0zFFmuu1MHNzDfJ3YwjlzlimKOVDejMPddV14ZTeVGvU7D3cuoqvr0XukarzXk1UdZ7M3tV1o5qojqgZtOGBxPHnO9yEjGHmyx2HT1/Z3GmNY+rVyFC50Qwj6iMW4orGCtNdFnM4kCGT26IYV1JvclZpyC9Q1a8sY+SEwf1F7Y8PCvo39z76FMqrlUNp1v1ihZwrEMENjw8Jp3aODaTXFwJe7bsVbcitA9VRKld27Jtcm6o7c7aeIOJi3SrcgviMvbLyZUo1QUfAyq2ewZ3WqdRbjDkVTCKzwqztU+WHVVuxV9vEbZRy1IYJbq29g5ahtTsej4ADAhkvMHrk489D+qhgN7SE23xWaXxqoqrrechxhrgnT6zuyZsssLtPZj21zd5XFibY4MUkJHRlLISieGYYj6G8q1Y1bPKkrrTtNYUsWnp2HO7TDuHCOEZ3iR1bRtwu8PTg3xrFBJ24llu9251qWnJXOPXe94t5rgpngPHe9nAMqqEGFTRqJKKq6T10bR03WYWRarb74sDpG9oiMWwzPQgvkWHItGlIWk5Vvxut+xO9UC4ODCVjoXkFxQJgpjEp4syGhVli7W9mYJhlGEpITMEjKZpkCQGYmEyaQyAxIURMf07pUJKiEkkYoZH891IwxEgkk1FDEwwyGEp79y/o7SjSgKIoxJgmiEomZlmFDJJpGKJMUYSkEHpdPs+3m6DMykw0EZgiUImQQyRkpEmTEiaRJpTImTMxClMTIoZkjM3wunt24hNBNJK2glBJQgiGZExkLAvHYZKImEmSIYIiBKWbJmhsJimZhJBMkYyRMSLPa6vtZeAkySgMSFMKJYsJEhMmIhkUgQEaYA0JhIk9dzI01EE2KRlEpAmZQwmTQwhkhTCSMl89xFNNJkJsRQYBM0jIhIoiaZMSRHx12KMIQsmQhCVJIwY0z2AeBqiq9PaevT5Jyc1mI5lyv5FVD/Y41wXWcsYtmVVDN2o2deXVBk6zvpvV38lV82tzTXyByyupXi+OkGnI8cJpTnxktY8CvcCpHM3Vu1e9dypM6dVhzH/OjhJ21hq+7Te1dnN24fI7lrQLVWdd3jNjZRbicCh27uevnKO9N77nn15iG4v7jxVnVg+qp9cYqxgE+vQRb+HKuzCoLtSWvsWL6q5S6y72bxsV+bXD7Mql1l3scQ+7eP3bn0oHlCHVVnfb0rBFvc7aih1ZXbe7muHd5YrteRDOWNET87u1xx7ddLI0VuGORMkyUWL6meRVHSjMDayC5bstDNWK7sPrVTBAwfFxpW7PVHjMfxsEg/fLW1mfCBjHg+yFP7s67NPJnasEzZ12brhVWC0ckrJWXK1XhzQcfIzriNl4emK/TBWjSrMq7uvrXyWG9W7f1Ycyt3x8evb7fHsfUJJGEQCUUJMbCzQERQX16+vn5nz7/Pnt55XuS0aeNy8aySUGrV9MdYVG8FNTKV7JgRQ12g1MfnVsNK7jJ8HgYSuVd7hsby3aQqDnUjbXTa3MecI9UEBAJymCL1bRy9dWuz0kWPXGaxgkkqSQISBRYhCBZEiZL7euu+fO88990MyYXMpOZrd5hBB+SJBJNa2q2CotIFim03G7ZXZwsqvbZFFBFBbD1z8vLz4877Xz69vhvcjKQRaUCGAwIMzMgXdzBG9/PXXoFfdm5et2xg+lQUe70WMwVlXgooXu3K67VOq1FCnEdzJWWrXZmyF6pRdJy8nWYYSEbPVmVfVFndlXNvDsBIvaBsx2UJRZ5I4cdDAz3Y92dmsiiM673NixGBXUleYLcvDHRtP+KVfeoa0fgOKzOVCP72J7Qua2JhpYtYOvdyUiIqEuukvuldupYtJy+JrOHdR2nKtC+57gm3ZjrKzMeQh02K/DW7ickZQuuuzWg5awzoqZ+djBnCZvl2sWM2pdVzcdZc3RCqSujmK76DhI3gJLTLzFluo5XbV+RIBJJBJFJMIjYZkw09/a9er2+LzCHuKQyBDM2Fuud9uYyKs49zXp8fEDipMjk93S6NpKospeI4JdjZt0+1yzSNRKVKbVLNvrzEggpEJeOP2RWIJkj63BE4t61l81JvGS20JIEISQCBJEkHxJBBPgQSfAjjt0rNwGUXWGuPWqTvdxdXdu4hJIj+ddkXmSVRRxIg4hAg/b9cFeIJv6kXseI9Xeke+wp0hREVyzQ8PBUjD0qtJ9YmAq9avewmqqsUFpSXIIuJumnWXpC3XBuVL4VmasW4hSK7AFWKZMdWeCyILaqhDeOHeeIzG4qBXXbzq6d+LM3MfK66UMf3ze9OmPKfbk6PePS60ttjjeLrzdYyVd3pkOdZERyV27Z1EoV3Kqva0x6S2xFtUeJNC6pu+RWnH6znYGJkfnbeFQmxebuVLF1oq+5TDtiVQKt28BOrbglqtJWQhVXMYZbYx6rTGmhfNbq5TGUjVPuVg6eiLqtGSZMzNe6oT1XuaUxdnBail3kJxVWGM3W2pNTSOVK6xDDvVE+XGQasedpd0HK2xeXfCqM8+uTq6R5Dgo3Xl27rrkg7Ns6VMdKbqd7hQmE53EmbdXFSqAwGxnFk5qMVoPbmo3VTBt1bSG6bMeS97ueIlXpu2dmsTaDx0rqIQO0Iv4/vlH3ipIJoTSTSJTTJIlkkREAmMooYYi200yAzIDI1MsAmRPyuoya2gMMUpGzYMSDMlGSKFgSmJTI/Z2ARMpoZNDCYSlFMKFGUIxNiZCZfnOv4+fqt+Pb20kiSQlmRCBCESTJEwxMUJQkmDRptafHdJIohmMIiNSZkhkxLRGJmIUYQpCyjMUGEyVIwFIfb388oTDGUwgCAqKmEMCEIki/d2UjKNKSGYwjGF7duiFIEjxDKHv4A/neV3sYxB/wqpVkMlfznbRlOgn0u40jYR5JyqyxXaamU4urC6nZ1yGrut3IzwNh3W7jyvEE8dOHEbvdy3kuSlh7JWjLODou5OcZUFC8zVGUa2zcs8tbPREJPUGcoL229EzqZorcaW5QWdNp7l33ZXY1t2PPwA/sPDgFR7d+BLuCqQ+LshP7ywOr+klPOnWhoqscoplqxvAXN4diYQXB8rXpGQhgvpVZ3LIKzOqrPY+4q6zLXbu1d+lsHMykbg4YlT0j8u++X3NUMMF07OtCvt+wYocF0WJ2XdnfuotxPNxZ99uvFfwtQuEbP7KXvEzRVLEN8fQIYhIAhkSGGR8QCCT4gEgg+P1XkENYd9Y36r5X3dFTyIewglYU82QSEdUqgqBIBGBaTufkC7szgbpreQjvFNFqwa+4PbRJFgjcXUEAgt3ZlNZDQiWnWY7xLA6WY0cMlvp8/Lz482+JSNlGRQBGHrCi1ldbqbSVJUEcOa16Re0ixTYJ9ESSIwj1tk+I4rLwNpzqI26u7GPtatNKsxvyMhQWXKW2wRnF+YB8SCCfEkkGgkJKMhBKb3+fjzep4gnrTOdj4aeyo9vdonL3FBNp4RpVg1AavR27srJsum8VTtVkGDUsBwVrGM2kQ9e9mRmYw8MslZJVhMwEE7u1ZvEb42Txpit7xv1Pj7XiOYISz4mnZ7KyC7jYZDGDqCLIeUl2PgxqM2lSz+ABw6+xbzsQdCrNj6e+mU437MV43kYuUaol7Wi7qrD7FuGpt4+1GkdwZIP0PrlKr6ntn7Fbfyqs23JbNFVl3e9VbQlthG2Cd27oujdVKNILpHlL2Sqq8e5u6YdNKru6uwDtXzbvW7xbf7CyGZ9sm3VBVPHh8K71LzWvxeuWtdfN7kwmSCGEHwJIIBmrXvPSMZDFodbz7d0Wb6kw5MtYO1oGaWISWruGghBDjF5soUCNtbOYeI1nnqKUQzxi7ZRlZxyV4mupe4FVZXLrX7LOauN4rLH2FXVA9UCF78Uff5+vX1fNKUzIkpGJIR317bmu1nRhZtk7y9XN9Va/QHxITfJcRZFgmnOiVUxoULg7c2kO3NBAI3FcAIO+ZXW7ngwViYct2yth5/JsbxDqj8K4ocKlpHxRp6x3E5JFq3IzMq+1dyMyShSbWjdl0mGZCB5OKTEmHXXWtEYRTEaEmIpKM/dd5d0jMhIhpMpkppIRiTMxJppjESVavCQ6TwlkKsVTlKaiNt5SZAQy/Lcak0SjEKlJEEzGEJoNIgIKFIJYykkiDC9+4H69vfy3qiJNIjIKFiSbCMoFFKEJhfXdSFDEZgowETFDNrRJNDFGChoUiTMMTRChMLIqCSSTH79dCmEQihMmQ0SYUJmEMMYxQyREIszDJIzSYZnvfbzy9/114JGCiAwxJE0IIxJMRQNMyKDIaBCSMoyJkI0khSbRMUJJhhDGKEmAREZGQvv8defXnfH279Go75JhyXm8VzzNLgaQqVJUhIR4bSRICUxCTARiIJpEGAihspExEJOdKDTEIZifx3R9W+fr6v08X2l2Gn2GpexTMrYLj1LBwgVgVUyqIyk1wod1aaqLujiy222l4R6QPCC1W0bRvYzS209+Zmcc7T1z6a44Mk5T6VhTGpFYmLJKYYyLJOHoyaljebsPRZuqaUYDKBKqqmaDwF0PdVYcRvXUnnL7eFeqVZDeKv41tyVy9UGQwaQ1Jhdct0U6baNewZs3j13WBnVICqysu9q6o53pzx9bUodenra4supbnOBS9cZ3qxodok7NotS1WZyVVpHW5TeaMzmzIRR6edHNjN4cdBEHqp+NL7mWfFJHMz5Lsrto1Qu9yqP1ZLobxW2cuOSo33ZsG6lqD2X1OCrpxZjOpJ09Nh2rBYheXX8moUhNctVXx76DCX82MIgVpUVRRkjM2Xd3CLZCcukndx2HKGw2chVyVchTOF2qGir9ek3Id3rpcxfcxd0Ot5nIP9L3hW9h0vhxdXcXUHRmIEAp3sDrfiLcOO2Vd5MGYDiWPd2UViHh4JaqN0W1avMdiaRkHh4VvGblccfdJmFBKPMRaLpVSyxYPYOfXWzakL2g61Ch2kjsBzNrN0WOoxyrtJ9WCg1CNFXuME6Fwyg8KS3K51KELhpfn32wt19mnlWfde2mzeyQaS86nS2+d3ec7d3AtPNSkOEuG9RFa35bioxmVKWjh0rLs1N7UaJjTeVYm5wPKRjV42kDICULFcd7RuQk4erlnbizYCGosUh2bKZR5wkiHZ/XOFi08uhQo/PmpwchODIG6buZf1fm/Uh9r2jn2VJO+5+OPzea23O7rT53LEmdkjLJ12uFMZ2mVx3bTlx1YWl4w18qODcDsIcgurH9Q1fdFSUDJlKn3bt6tV5yVDl160tSErsU3EjDsugbfbgWW7a3+clZi1g7fWfto7v02XqxZfDWap47KKV5hqHxrHVlrLrArV5ZWCtUGs0cvUolsG0dHh4S6zZBl4fYleBC71xVWzR3Y65JcKFbtRB+xy+F525ZvRg3KxZ+H6/k83fjLs4CnRdhDKdu/4qpZ3Povcm5EexbENIaGz8NbEdrqzpYUh1TxV12q7fYNPG3X511R74T4XC0+V/JKlNSBQp1FcUFK0rMEkG2W6yaDNmF2Mbta8prHPnpu1RFnsWqqJ3OXdqqY4ZU71w3GZJiyCg6sUy2wnSr8u+5IvdeQ6CmZDxGOk7K3U7HyNu/zdztbzPu3WGdPmcr5WK2Uhd82NrNoikJkOA8QyCBdR92ToV3326pw2ZKLPF39ktaKjWB3dJhGbnx02JWblVNcPWudTub3jQysiGY1U7my9vjY2ZglDbGzOOp69WetWNtODMdTEpavIkbd5ET27NNYq8eO35vbtLX2Kuu5l6tujL51zfbfm8OfYrGu9+rq5I4mwY6uXlfU7b0GpycGxczBTMYpmXlZqNZoS7LDurqg6ehUhezGsBGoyjlPCgdzy3Esvbw3OS/jXw2g/s+rr+xGQIjjxvKKIYc5KgSabdCstEOsFnONkdl5gQohb1S661K3tduqZ4L8jsffF2dOvPizlmHNtbp+LNnWFeN5zdr0w2MqDUb6t4aESc6zdR7FmC6T5wPLwaONdZQV5LWjkmk6u84xSWuqWffRsluBGfWsYXSyqsCqrQ/j9TmueXtf0V+Eu5fI3bil7d2LDOOpVHGj9sdL7ay9etTE65isNkwRZGZWFJQJUq/oh9L24w5jJN6xcNjjej9eCjVXLyGdbirheXuB/mt9QlsSu0XieVqNCqq+s2MuJXrVGVaqIhEfse8J73htQ/XWuEpfDPr05WRfVnCuO2dD6coO7EazbUFdJfB3RlnaNLaqu7Tu5LwIxOzGpTm6la3StecbjYc/VfOsvYjU4yWDBf2zScq8OjNN5oPXohNhezXrr5yiyJCza++BFI7fbyTVDctTt3YjQRNHePPQ2Gs7MVqiZCnqVTmNO1Rq8u9eh9dyYlUuSS2KQalNyiK6xlPFkBoYO9dA5Xbm46hnbcrYEfPKNYrS7apZqtVVMdy1XzyQZuY5XkpZHWOy6XGtmxBq286Oxd+59FEWza9MOKx5A9a7b11XCMscerPjMEbNQfZNqp9Zu62seBb83U2pVzNYYLclDLcrresTmcqbCr3M6+zAeTHVrPW4OG8paVPcLbPkKp51GpPEHo+qx0WWK7OS1YsyC8sjpxkezEtsaN2DV+h7PvxT78OX1/kZJ9JPkFn4jrgqAZM3lSzjsmVolbry7zJV7Ni10GMOdq2At9fdmWeyiuzLF84daoQIZS2mNG4/z3tquFfbYkJe0/kx9FNyIrN3uElBJUqqTmz2tjJzolrgSloatWd5QtOjBa+ECxgdLJAjiohWFZWezwJSkNECVEBJBpCo0CXSeFWozNO98WzOKyt1Btwn4POVDLyc5Cqr9nujYttZiDYtMo3SNbZ+Pzq7NdrhIrZnXvDaHcc14aEy7vYEofNhBQOkpu1MVHbhgPnheCxGxm1bstXjeI6XVym9t1xdLr6H6mfrdTnCdaBi02FWcF8yM6d0iNzbfvQEF6GHtypiPORo1E+tyfFajzw0YXMIGadN5EznetYnuYzdNLrKznEcV2m8dTdi7DWsclK+LmCey9OmWJVOkpxHrKtOVpvg9pIZKmePV9u/jlUpy6bmPKpubmU8TDjqD6an02Tkac6YWMcnZo0mzy9tjlHKU4cMTtTG54Ndk5NjeNmzwxsWSO08NNFPLdpGlPKlYcODaasbFHk1HTSTlKmzcYYp2Y3NOlTSpw7cuWwp00mJU8NU8tJptG7yadt02SbvBuaaeW7Ddw4aMbKbD0eJ4U2dQXoxGuno0k2QEeH7Cg/g/y/l3x/X7ZV9LNbLwT1acvMyUmQyP3sqNXXacGHToUnV/U99a+cLxlnivj8WCsf0wIWoHdHfSCqpyCXN5XW7ZZLwLS1e4wsqiUNdZKLT043kijx7RjGIRbeIYjsvxzM42KutoVMulKs1PVUboPhbGB7g8PA1Zl6hc2t/tW99mGhpt6oU4qz7C8VOJ5fzi1UJi6mNYdS0PDwUVaay1OTJ5IuyeyC6sXKuSjV1KN11DTlGnlstEdTqQy7Gdyull2UOk3NPFZh4CfUrGrNr65XKrUf15dOaU7xungx1fwByFKaa6szMXVuJw0m701z2kPDwd48VbhKD6DHkly0ouxVXcaHbmLamGgnE4eyy+q9XPtU1kZm2H1aRsuueaczD3ZWrrOCdwd9a2tF925dM/1cz7n3Fy/ped7w8Nej7DmaQ+q7hwb1a4o0OROJl1ufqV9SobEj059ROasm/c2qdXipGulox4FdJbx3O1aYb5bGqx1eHOQqtqVXS2YuKSMVQbyxaGNEFDKrTYtLLQrSrwGnjo0blpt2+Szt2rSyjXUuvdK5DRXdWbWL2tbL11U03qzInjOi2bMyDhmjbXdahvHmTGiHnbVEXqQtM9uKO3Mo8oEqbXjCiOQq82RUsY6F6asYsLv7AsVDmSLn1NOoNqXSaFMxVDh7dfyyJ7xOrcHDiMbpCNhJ+2uY7jVTDmjPtrOfu+En0Pyd/eFadyq1WIhuZNtUsiPy0pBtbNmmtNHc+cP2U7w6KzcyzZFbuxP6rfxHcmxx0yFtpvXjRti1ToeHg24WXdXhHVHNpjIpZWaQjZBGRiCGEwnurYq7RKO2SMJmw3m5Rvd2Fe7BFzaq75NaGkcyxlmBe2WOrTNqhsick283KG1dZyC3MuCjuntBNhbDcypBQN0MuxuXWo1ax61G7EKbYxqte7gpy9PWHhWeNYLuYIGrli+owUsFSxvXbc8anXmalNQ5mpMMPVoXMU5Sq9sUKPLnx4rkce1lZcFnevoZmsEapW4FmVKbjebSqfLs1pVZEyUYK4kvMujKIblKoJRJdXcsNxO7No8/Vvy0RZBt365VlorQVqrMYVbkqunZe1T4dsu4Ru8ep+W9OlhvpeoGtsYCNHXslYLUvAm7WDtI2VmNq3aoEbkvmae05SPbW9ybxb6lRZ1YMIq+IzDmIYsyqkGzsHZUqys3ph0Ht7p153c6qtztGbo1G8hyho6xUCRmdOqPevVxmS8oROhfP1PKJzHkusSRLovjfXfR5qPbMJreOO9svUhGKdGbqto6lva6Vdw580Oc5EYSNj3W0s3brIEjNuu9BFe1UbUxnNrITbqDqqbm8To3MrqvEfCGApW+yJp1DhODVxeS7i3WsVJyy8wsuS6bHh4SXTt4yzSy5cu4bqultezEDEXQO9aqhsBebdzlOVqUiiUelAwqaowUIBOFJwnAQU7JQlff6/f6/f8N1lSnQKpjbG39DKCFcVEctEYoo5ZKSaeCBl0663mscucne7MYd5gmVpw3amvSOy6EzMZ44bCezJRWW8juXtu7d7mbMFxGzt0nbG6t3XJ3D3KtSxy4zfER6WXmI5dy925NpvrMYw8geKKrwHawPG+67Moo754uZ4e/Frb3mpmaesuVfBrd1lbuzScBLway1ob2sEGa+rNXHtUuV2ZhYVtHZeZi2pZ3sWdV3nqgfWtxyqGwm+a4l9t08fblFPJVCKo7xk67p3rxSn/LCk7Zv0vzzFaEzn9lqzydPprAKxtCp2xcSS37adZnbvXkF/OXPQriKDCBOJkwrluhCULK7VWQ44CbU+wTJeUSkaCTUD6dkerbZcPuCGtG+oPjoqyLGun4YmUINyNiyUD1Zl7TsxaNxOENPZ1pD1LfMxc6xvmRCWiuDruIr2gCA2DAVHHqGDQjlwoEjKGZWXGn1hmktLyoM2h2ZTP1djqZVoGxw2typTzJHTsXuVX2aZ3RxMfOaqUM+vH1L7hYUbznsIpnRubmlaON4kl3YOdM7uDppHCDPX1mpMUytfTkSN14lr64sJXu0vdV3d7b7ERDwmBldl903lx2Xe3vC0xR7p4ZS94BXb0IWRdiXpDxBBs1QsbbN7fPzI1cx01bVonOmpKDso7xEzBmpDBMHh4WqEVXLtWnZKqG7tWMzkERqV02tWGtYWQ3qkdShVHY9NNclmcLqOqO2xSy8408j/QHOV1tjtX35evMvLf4xPo69PtWgie97wsdpvXSZ7q2qqWqlmSObRqtgVyu2vZXGxwwGrPXj5TVePzqZZX32SwavbBtF385K+L04qOKZDZvxS0EashutryYdMJK2bu7trB8rHtPEb6tvLU1XjLl51god2bK5ustsolRmGEoqltS5nHRVaWgJB72j9qkb8Vh9FdHCE5abiPLsjcOycrZU+jHJo+LJwU8vSq4VUaTY4lMOUeFk8JXaU3R4hzJNnLy9pwbFbzy6aPJ0VsdlYrk5Nm54pu6Y3jZm8u8YjkTo5NIn1BUx0mPRyuOsT55ZHxsxjdh8bOGNTZibK4btGzcx6HaTpIsVjrjZQrXuTmybGwryYNlQ7ie05eG7y9KhxE4Jg7OUYaanu7STjx7dta9alr0R5bBKrWr5l1ExUGJItGkYsXZVPR1lDqsSZFlmeC0zNwTAadLtjDRcexjcsxdbW5TZhXYLmVCjfHQggqY012ZIDGSEhioJpUywZYaSSGSiYMhGRKDEpGZokgKFR/TuhjZhIQFkzCJRDJQkZGRHdyDSgNAUmhYxJpBQEMkSLJJMkIRMQYMYNEbKqtpVvKVUPeDTz79+0fE9lhiSn0s2NhsamGIxMGIblTTddZfPyRGJIxIGpCTRiSUQpRmJjDGFAgzRMBIJGSUTYjIykZmUY0UAlmffrspGYy0CJJJShQokmCmSIxIURKIBJaQiQgKKIhCSQjlUaBxSqqCKNdt6O3o3BZ62admif3WO/ndW9OkW0rFJZukXgdSxtDP3z4Nbu1k507JrZVXIVLqOpyV5wvDuUDZijWvb2mujFw+LrPalYepTM2bY3N6ZNvey92dv9TlUSRb+T+Uph98t0RGOT93w/Ff2gI/XXc8X2Vopcd2ybohVF5sEafw9RWUHkFDFqknzagbERGUjJUrQRZGD43h5MtYdGHTw7K2OhYOBKqFVHGyLysiqlZwYXx5F1HhG867PVlIyqgNFUUOuq9NB0pjJrqFFJ4VQqOqBCmxlAF6ci80Ia3DmJ5lcqsBTM59ODFcdIrKV15C0N0QbsFGdtllwXgzopO7BLru7KkwqhVnHjl2zt3tCtrteXvaMMUmcrrdddWVOlrNvLFF1mOgS7GQ6pVsY4InuRFq9swoQLnl0/HMggYskgE+J8SSSmJNME0YSIhjL4+StNWE6datPBZSXaSuzqS9dYefPpNHEEkkve9PQpt1dZQCxHFMXUiLqr4+r6g8WfbkqmQp8YT9GWlsysiLoH4W611PZoVZSkl11bxPEGodCIJBIPiT4kg+ByYY0SkkJPqfXx3t6+PXnp3r689sok7YOa7V4J24AlqWm61+TIWY4fQk5r42nxwUVsWyUM2gGKQwjdVV5lC57fb1VbwZMKIpiUZIYiD4kAkgkEEEnxJJquC3s2oL1YL+pG+t3l/V86dB4Pk6LdwXXLGszJdzA97BNPLvjBCSOrcgo2+P0Q8PDbIlzY5EiF8M212K9Rbup9ymPlc0Tm6lXmXMEVfVjTh1Rk6t+unlI7dAEvFnEzr7LOC2Od0aFxnaR9DTQyFBNY4xlcX3WMMjvr0I5w0D3hqs9dDNm1NNnZkqpH2yTKzMNqHr0RWcrMT9uU9vNxwWjbL7DrFlG9dMkJprLeWORk7TnJs1Vaqrpm66p6LG1n1398h9jH286+Kb7IDGd2iiKi7lb+vnz49nzxe9d17pSBDfdukagST4gHx8RyEWH83Sfz6kvzvqnOvmLscZPoWlMgjaFaiS0ZLysRt6IaxllPka7fXs3z1ypVGbYh8QZVRTbxizZ1BHyQ02dei+OrKFWuUlURS61moXM8ly1rnr9fX18DJIyTIjMaaYbL3C08Isymnlq7tpOwggSQcV7bQNCVrW4/WR4+FGc3ddT3nBxmS89SivXfLaKA3ZsW06JdQeHgwY9yKdDyECBmdhCM4eHhWSfb8bXXJ89kFtVQHvDayunxzEVndtmmILhLFqPFsqGDnjhCyXa2Ucxk3lwcVVXDyhVPONfT7soLtevLOM45ZEloX0qQJISUzbadIXgYn2XBoKNKqlDI2dytvtBfobtsNp1w05Ia6VCLzjoe9Ts1lSWUw317YlUnAsrLipDgzT2oTQRyqhu3KN+ekMITpmy84q9KyLYCmHN7JGHetCoOPuquV4Jewt5VekyzgoEjcwvtXOhc3M51Vli645L8zZXGsQs3b1qeGuPho6803ewz2PqSodnPaF4wszo+WxxKdtStRa3Kmvcxw/bbIXV77F0rK4EJ6mTFVZJR+qGrIVuXXJkdj3WdMgrc8dvNd8O0YLROs9LZ5QwhyYM1iijvbd3WGLbFr2npCsoSQkVSSBIUBMpiMRCYJGFMAQpMlEZIUEkiQRGgqYQQJGGRgiJP11cpsgCiUGA1Ey+HGYlkhGxKWJEykBSalMwhMkhJJKE37rmEJSChEhP21t24YMZRGRpkNCJlqxRGNJpGiFMs8dIxSQCKBQkCQEDECyGRJTMTSKhKUzMINbSfKuojETJomEGbDAmZetm7SIjJMSv3XStpEMopslMhmPNWbt9vj+NGBRDg8FBAREJ75Zq5ek3nbETiSzrOHJ0o8FYIFayWsut1RYhRNCzeURelXlM0H6vL0wpQB6RqxZKabO3oNKIk03vkt1lm7Oihqglsl1CtjqejuSbtKltWpl3HAavavcvaTwIeQNF7e7uaCvKsUVZYOXFrw0qeHDKGhMboV4ayFO3To1bW0jVUf0slKhJcCTHTjM6s2tGYlNzA0KQ1RkS7J2pjrBCncyCm0HhQ2S8mZVzRLQKva1ZVO5Dj7t6uHDPD3oW3O6qTw6SQdOyxMvyF1mZfr8JqhHskjYK1IGUqDdSE7tAbdMYYVQLZmCmNtUbqZgkIvCMlbQq8YsSrUV5eixtAe8Lg3V6tCqyRUu6riIaIhN7uihytZlC2vUicqQTXtCDczIiKcWeVNjW8vJRw4gfAe9/Y+A+PvAfHwE+HVmknqLWQBDdhluH5r2G2In2DVeK73dy0a3HkDIubLFrZfqrJt2bzMVhTDII5saqg7ck28d+oRbtWco4nYZula9lnFtXS9DQbWvHqdUgVma7lmO8zWZujYU3Kx2YXWyTBlaWK2kSiKgj005KqGzdE5mWhuarSk04cysZ3zxXTGtCqd6rakUvDuZYOYNRVVl1YuoPDwjIdBnMKbRy7D2JLbuxZGFl0looJVMWUFd54e8MqYdpVlmPSm1i0EfvB73q3Wbyuilo1tu8pgSipSQswr76qINe1hezGo11WQ9vMWE0YIy9nOixt1QfoKSI40ncym8JgotomazHpQAHhgzxtYKpTFlWzSa3VKR1u0MxB171DAppy8r2igg2imJkp3qwrEYQHYjZlZguqXOtuPEd/anb8bYchox+KeVJK0mJCp6YniicDwwjwVyUn228tuA7pY6cze6bFJRSmbT28OtUecod4h5YlYAMiKX7wjV5mRJoJ40wIEahZm8begmlC4oIiighDRh6JyI3TGRCgiDgbnOBwUFEvIAnzRyBy02cQEtYCwXEkHEVCB5cESCdOOUEUA0KUKmwuQKYsrUnw5M0++RLKjIIN4Fh+IXR8yeGkWhjZ1dv6SXbHcSTZAToqyAdpZlLfbk5Z3fvvv23vXLzlanMRq3N4orY5uWh45y685uTPzeeNvi7nV+TtrFN6tKW15bb0o9HOcs9N8dXG+MquGeBvYqjwpVHKKo1uNAsqEFSmFJgpzvxw4NvPKHjztr375fN09JyyTx1JwoqjQovr5pCRysK3Jgs3iMGNZCYk4PY5bOHDIgYen9P+2Qk0ESYZO17Lge74yXla0I1n12xnNszWk82pvbFOdUZRoxK+NHY4HVrA4liQwITedTXs4KsiKpyigx3sQkCEIEIEaWyrYr35+z7+bjSfD57N07UTEvKPbUJ5SZJsnz44e05J12JTl2k39cvB5OJvvEeTmTaSOiqnclPGBu7KxFVVKVKlcPBy7GKcMgYPbg0UN3byp8NJhhj3DcjopHhXSpsjyrDZhhTStScIknSpYskY37NSSsbPDmNGwdpzVNJJUUpKUoqrHJPbwJO1HmBwjZJgm2jZG5unuSe2xsNIAwAqTBgXmaS3OrZyzTYvm1q2FN0zVr3kltHJjt3FKolRbKkzi1rUfecFzrZQsRblNZ1PG7jda81Xu0iaB31juAcA7cqd+5sXK2raZQ50RtDsZmblULzwRrXqvl3aXWuu/Dv33bS+eaIeMZ8Fa05U8atytey1VVZVW007XPNsLFqfNbfg0/PyOdj8/ftyGnIx6ViV+Hxrnbij8olTZKJ0rh6EzJembiCGZmBPPy9OE0FxE50DlAqSHxuz7rMLLfdIsq83wi87jlJW48Zcvq+tvPcN9n+3rmZYrHC3ZWOwQEDoiCiFAYgUkCKQVFTRrJiI9ZzsTW3I90Nm+zxx26McPo4OZ0Ng3kk2iTeStjQrVPCmpCyKVGNilho0wJyk4Ry2dFiahYmKhij7FSqSlbkOHchiVUbhUvoh4Rw06FY3+0NbqcnRGVI3JTIkvB5cHRCWlHaWa8FtVnXezccMw+STTXSv7zHSl9FYvueMDYrjXUygODCOKIoDAyMEpy2TYCaVDAmnJqUywrpDmos2aPM6awlhLg4IOkkPIw2TeJOk9vQbpMVWMSbDDFHxLJhThsa9nEMNlde+/J0dMYkwlJ0acwYsOzSSVJnzXgkCgooTvtgzuwLluuPJrbmy2pbN9tPKYoau0+V3sa0kHxsrMkGQuihgUFGYICBFBZdmmoU0xipMPeMbzJJiq2Yoxu0mKjTZSYUyVs1MS4p7wmNYqVOjDzGyKVNGDow02M+aONdDbnvzvrO+vjzg8lLCpXROnlIfWhhYirEqksqNjDEsg4J1J1qOhSlkcGIUWSKUiyDYrEqblMaVHkrEuiRyK4MGQkrbYYdaJwV6qScF9IcxOSpGx0xgsTTGiphTEwpjFMSrJorBUwFYmlYsnG7NMgqMbGETRUqKIXFEhc53LlNMusyUlNy64g5YobsVNTpTVtFdjFy0cnawiDCiJcFJ9FjUsnmUZKjXjzp8vqt44eevm/0lVLX0TqvMEaqkwQNGQmiIUIEGM4nuowMjpHmSJ7jwBjliHaIpUbN2FRSxJRUk4kSbKhSmGMkhSbHkmLEYpGJtW6byDURL0+PTZ5ckdnpIY0npvuOXBNE1OI8Dtsh4a6vXpk8b9eiNmGkh3EnlNpCdn04SaSvMrr2nRU1W6Gp57+u+vWvsHistYky9YlNNlTEHYp2HrOLYNdaZzj212O3W6zkqfX9Zv6dqE27BgV4dDQpdueK7LFhU7iIioJXvKXbtBOQtGf66MHgROGblhEOwkxJADHMTcUsHxh9GmFV6OSbptHno7LJW0cyGwUbMI3Pb4TEkxrIIyCIsoM2MGZU7aKHTae7naHzJZvra46K35tsN1cxSWZYjS9QhLo3IJhOZTbo4oCgpVuNnOnZdZBOOU0GgkCa5qEDQhZTEb5gjBK+9T4QboOcvLkrvee8LhsyxbHOFhShoU3kQqurKmzBiopv6nfM5c7nZ7OSpopRSVVVPRjFFSo0VinMXTXaGkHGaOQXSEM1LsCuo37dueWclaLNkzhCmknQ00jaSOO6cVtMWGMmEZscHs1j1BXB4QyJ1EqcksjklR9jtzG+Nmjw0WIw8DBkiY8SSYzYpKhN4RuknwcJtC8SbyaeKdG0kdEyPWzUqcqmV64aHQuiFgYgDNZ4ydZOB0NfWl42KDpXeDKiTfdydTYUC2cVkiCAkYYPgoiISUREI0rJwfYw+jbJI/hrylIg82Z24Ps00+lbsk7J48tzSq0qNmLhThXE3YZYYCOiGEDAwPSuGAiFmjCGgRpuaKVN1MU0bU4bMGzwfZhtKm8rhJpRu04YVu2bphvN3tu8TRjtOlkj+Kgm9hI+9SR/HYHR+ByelcsV6ccaccN3D7NPZsbNKnJthWzG5u6V68vBsQPNEls/FkkcSdvu7abPtjHlwv22z3ugPFgS1HFQTpiNxATbARJFXYaFKBcCRQxYT5Y9OFPDsaNNmOl3NmMV6PtwRDHomSSeLPNd/YpSzl6MTRKkcuncqNng0iaRu9HeV72MiSN9zrwo4aoCyBmJRhIbEtwcYgYCLhwaaG5L45ge6bBUk4WSTCpmMksUPMsYsiao6aPTY8Nm02SKw2YxoilUrJJ2eE4U8tKxg4YPpeUOd5Kq91YT5ZJbJDSbpU6fGjDZ3QnFR96SR8otRP6FifLJGrEG9JPpVjnBDpUkb0iBmG0ohCoAhpQlM4B4O8utUjqlSeWXNXNiteff4F10d9do+AcQgSEbVe7w6tFNyVBe9ZGkHrpiUVGIprzbK8oao7ppJIDuq1OyiOzkH0gxQUYAxRZBpCSpAMoZltElTdQoIARRrPAbOHBwgHGKjHhWjtp9NmxU0bFZHLZ8Njs03dVD2rpwxuaTE2StNMeCm5sVtjFY4acqbNm7RuxMFFJTYwqt3r4aieXDJwmFYjE7KarYUYTbhY4DjhcsczSyARnJlnkyKTSJlk2eTHhXvjOhJ5d+O82RoceJtFcu3yGmymyWNEVhLK8RMNjt8MNE0dTBo2cGttntVWKWV0VMpowxZVYwmFVZNhWyPhs4I5AoObxyhjOU2cGcKho2KZFAYQNoiCipEOzYxGyieyviaE6NB5qtnR4csKYxVKlSlilRUqVFSrBUm6aVWMMVNRg86RDdvBsTp3umxUVzEnCSZGjf4xsmyVKjlw2NlWStlHBW7RRGBQwowhAKCiXqF861l56JSZwBEtnK3fzJVopnprcoa11R72odFKWu+TLruebbFoUDTHJ5NO2FId+HC8b3np5+u3R08btJwWRqRwOEmh1JxFqbHInLnaZTFd1e/2ajVXycnmJNRNj6eXad6PJ5J2qHhEeEkelknWzSGnfSqJwYC8FIZhFTJ5pGhduRQrsBoGjQGCSJlHBwxbIpVQmTEWgFVzZ2sivtcO1b8zMRcQWxmeqyliW3gS9cIgd1AEDwogCqg1ESRExq28jdkKHGAq4ypASEU34McaPZoR3SRakkPFaTOufnjiSDmxEefeRBSjinb2h8GpAkCAvGKFkUhYxitO8OTDI5EEwqm0kUqQeKYWEj29vox+GKppoq03myaaUqryr05kI8+HuBO3YpvrO9iqC4BLy6NiigqBAoBydyRSSIiMKFAocd3rfg27aSbz5wlusqcumLZEJCnHL11BGjGmg4UYGBQVRIMpggIcDWxzr33k4zxwkmq9fPnlPKHhXMqE+KT1AgxFa0BslsG3rkbmZ75jNd5QpG1prc5VwaE2K/NlTYTAuoowMD2otyDLSZHAYzS9gZETQRCYuqgl4ukwuiGpc1BXLIGNlMkT5PJkhzU+NmD35508yb/k711E5cJ8USikAk4J5lLE2bcknqjvlWMLvJ1SbSW+RcUOmoZhLScadIvcyTRTAaBQdE6JEEhICQMQYJBI2KEkoE6EGHgDkaugCJy6gnZQROs05aR1vgXgREdA2XQsGRQRI2iZkO1nkIiSKOvL3GxozeyyMF4I1ic+s2tWt9QKMtLK5WMvkpfcwrJgkKiIrqyPvrJmWMTZwJFDeSTjwxBobjti7e5zfmd8+Od9XNVvNaF1paKKTIKW2u8PWe2bJh6hfOmi/OcK8ybii6kgFkTAawgkI8qWgzSc5TrjE1Ksz7c5nXJUOYstLb5LC3njFzkng1RMz7FBryUvXoiDc7mGrnrZCTvbmrz00q8tLqTlsb3R6OpzMpNLBY4PXa2qW4k9WOComBQnLC2uSTBMqVSB6CMWKqTfKKkKbnrMl4/NpJ3QE+iiIg0UY2KdcbO5bzSfFu+mxbmJS6OiUrTWRqODV1afK0fZgzbFrbtQnLe6cLxJ6rpLyVdcjcRHY6vKrC851rMX1Sd89P1UxNyvWd9X0+1jLv9WpkqWU3xtNl9ZVjM40tb8OupsSlR90UtbIz2jRpGMFSZesivNbzV2tJHHMERJSk/j9hb49kk/evbQJ/zp2/g52x0Mp6r2OmV5Ac2RBzYJsKD58/H71+vmPH5+ZpylJHCr7NAJP02IggUUEQWdJmsmzkyAONMArvycruJOo7tZhpACIuXxFn6XFOlYmiIgjeVdxHamMyREQTqHrLU5Yru+otnJKqLTpWlwza2mxm1oFlpERBHhYSnWMYronC9Erypm9c9ceX7/J6UUpVlkVXuj7U0KQWdZc7anVgMHqVo9Jbq+IibWjkpRi2Ct0ryl0sTQNKULq9ytCYVGGECZOCvW74lioiOD09tXttPCN+eM+cLo2+z5y+6E3WRP14YksVIpZBSpIdd9cNoiG/nCRO+b+RTjhqtB0YqaQUTxi7ovMiIVBkQHnN0BQ8YihvICDt049G6X09HLlfRR0bUF5QFJEEeiK1BeMBTERFTdCoAGICqZQFHfEVqKiXFZFCoiJuyNemBFc4qY27rFTEUSznKBEuIia4CkgrUVeOpTgIa9vDXispcJU3IhodOr0i9NKjjingtUkEAjKsSHGG8bhem/Prr2e3Owb9m+zxpNGxrQe5VtjGirTSUFFyAcjzft8c7X6754fVtEwudoiboTK5o09uJqcoYODSFuz7d7bLuCADcpaWYvRXN5m0WtKgITSXFNNML2Xd3L0k2mtONZ4xFqSdatfb05W+VLVrpwpylryLUfcJiLDFABEyIhqSsMRMwgWgnO5NCzbFmV/M+3e3P2c476n1z80GlSNcPnPuIDgsDmagsYxFNDBgir0QRUkaAiqYGIkIilxJBOmAo5RQLgq7Jkv3/G2ePBuiH5U6pA1LJHXrPmkJGEcVbJJC2JMWQ4skYgcLCb+ebvJBzYSOFiJzYTVDQ94vnUJeCrRCp4Ffs8JTw3cDKgFxEwUnRwSYiUmOY0gBQOFLzoyRaVmiMhDSBhKVLViyvhJqSulakr6sQuhj31ijyuoh3sPp6ZulBEV4cE4yzHDthIGoFxUQCNFM+vbE0EWdmouALGR2oXHkE8tvWCqIhCIiQohwO26RTd3nYBgLqMGGL3YWyYtNdUoZdkINuxs1UgkJRUBBK1SXTyejEO+K0H0lpm5RTjtOVqvcUXdDOjPN6KxzmqFrRpp8jbVvsrm2vQmXjJmlpdG+WnOkWd5GOrqiJgUA0uKUfcPHMZKsUXqk1lOww1MlNQztqxw0sROEQEuoIiYZwErbJdlabPR1wRe0JDbjkbGHiBqUtSJ0pVp0pVOW5w08i8zAm2tXhIFfOH4bnS9itllfUcs0oxPGJDk8lrb3fGZNV8TYoTu+9NrWrSelipIaizM1HHm67k2rYlzJy93xS260lQXTZS9dzvcZ7scrZ753ynDl3rucNfFKmTvy7z1h2R5Nnabtxr3C7wLu4xWguJjDt1jadt2ZLHfK2R4qaKr1Z0unHH033etPl25YrfJi5RRIuwnzUG6sOhgydoBlgtCkySQiAgHzVABJqAggryxk1D7oHNV713u/VqcwxZ89jPLTK3Dd+GZLPWp45nMjFrF7NqCiu9bl6RzWL42Z1m4+ZVjW940PLM8mcYXG201i2aYrbDElzeksJXa4dfAueqS6zvrUup3iXCfFrNZyjLV4lrnN7vm4btGS18KTF0lSH31K1im7bnXYujBzjUe27UblqEzVp8zmVzMYlmYw887nOc9w1ovbkni1IvBbLpha5wu4lyHR4IemcUpndsqcvy+jjEE9UHmFDc61eetJWW6Kq2XnIKTmxqtM6ST1PBNOVIUWoAfp8/xQ+ATExQrobO5jeF8zz4L3lUa/k8peWnSjYkw1JWqNip5Er+dLSTHONKdBEEq5Q2eU4c95eMc2p1Y0WWIvtLGVchqM91xOXKYvlacKdTh8nTzUvctnTVdyczDlQNCnxYkxVlUqqfLMLI0qZImKiK5HH3DxnsXbXRJjO+PbRjM3MjW0Ic4TBRAVKObpMx1abSmsyZjmAMCgJIFBGH7C/Nbq8c8nGmGvO2/1w5G5SlVyHP2w6+eeWzXnu0URO+CPbFA5wBTXsoNek268AuqKqGUBQqAPDecrLgirpAUXnBR5G3jpW04ZgJtg8YiKYzq4ogaoCmUETbx04bN3DQQV1RTfFAHbFXwjqfWIHFQN7ESb2RvZ+XXzx5+uCeKgeKkHMqJMoPj1t4+RPoqx4fbURc7lK8+/aizt1VVtQZuu8+POSca5ArKwKKM7TZTzjeYENGruOPXLyVioIMWMuDS0y1vRnWFG48r6DKQol0A2gCIqIga1mQCUqJLSeFJrjnj1fa6vrPUJ5qfSbpVKFX0ZMWcuVTHzj6gk56+QSdeeAlKowGCkBU4byYsDcf42nXC4lw+NEERUMjioiGiKIioiAUYNDRVUFRJAqSTfWUO/IsvREN/Phw55cuWVvQpAimKQpeeWmt1vHLXeKryuhnChhIEA0aUoAF7+UYVcKuEQZAVRBVEVUS2JXs2Ye+cfsxaY/05tnINO1KqT8/3aGkGlZIOZoNj5GXVJyC7LlXc/Efu5WbyRCqrKoIclvX6GoDTHWLd0sRgyKG4+ytdZaRm5UGSmqpk2Ry7BtVKe5YcorGrq910u2XzFOLl0O484X0gPG6MmGlSNU3ZSYky9pXVvdGlzFZs7Od1eQVr3DoVugm8URUAO0ucIIUmcmt3pg7td3umuWS9Yc6jVQvNyYxSMqomsuBqpqumQMCuhcvG3MVK7iF4ex4NwMvBGd3ME0+vZJ5YhgYd4cglxFo1e2FaCNBGtqVSVJ9ZklhllQWrESKyVVlOWQpronKdLW4dYIltaUrQ8RaQpqrc4LKi5GJvq+qGGx55zrStStp0s/RN7V1mdBloJyy6tWRiDZUW7cxJKlQKIKU5V7WbdOY4+tHr3z9CH6rIj8VIOypBZIWff6ySG1gk7VAV54R3tISMSkFiKhSSu/XXfveH6qkDyqSdEEA47mVZBDls2BYoc4qGuKyCL3URyUjV1TKJp0sTHr8fdsJtxVFQRERNwI22REdJi7rzASNwrp1XfGJRzMIQ223JqSpLIOSh3o8fbjxyckKUVU3qYUcQqJDBZIPm2z5v7dDCFBERA24IOCiJjGF8HJVnWbSvJBECZYgs6wIv1edzaCPiyTrbEfX5e73a1KIire9IGK0IZZoAEohjJgeiSzK2BsRHS3ivB65Ot05qZVSaIkVh2JFGludq8xumtYTm3pqTGp105bj1OTbeuZitERE99+jGua3G753WFWXS4RETpBAWl61bhPDR1MbUVL9IiJbaIiXnOnK7zuk80kuKNOl9RKU9bL1OMTzTsYsVnZdY50zyjBwa9WOpU6vOa3/u7RByFSFBUw2NOLjqO1SRJ3pTtyuuTkTvbF546s60kR12wMW1bk4HWH21rPyCjjNzTtwcntZW3OycYjN9Ouq6J73JlpYurqX3Ro5jmSSLPPMvIWuooUpMjA85zuYnS3KUxd25pnjRPczDxWUpF9WlxaW5J5w/RbkNTN67GKNld11RhdS6wY5Prq0ty1nbVzbmGlTccnvGBbYZdVoS09NqucaeZmimGmU41ucvnelvCdFbbJZpavNk8vLJV61XEyhNt1vbmkLSmchnqULv1omRY5ndrQyxa+a4zvktEs6I4u644V02oUpVxjFmK3lieDUh0yuM0ysW4Q5M0X0cfb2mZn/c6/kDt/av/eqVdfzE/6r/q91z+nb/dfZH+v/M/6NeVq2hva6l/yX2J/CbVG7whltMVDGlW/hW21dRYfk/TRiQ6iiYtuPD/0P9v8H6yh9f+E8iSfj/4JKDn+CfNdn18BTRJex3mE1P7RYEVqZD3sxYNsSHtRs+m7SP9of6g5+wr8yoM1J6zV2G4TpY7onk8erHH/h13v1SIeaDpBdIB2RpapJU19ao+H1M8c683rgzpnCNB9aKGgotPuwaSSEhJfX5RPBZIxK0ylx0V6IondSNFe1uJx9piITbh2e4xV81DZEdptBPsXsNfZHvXohXPczrGkIaFTSO/y6nxVGYp/zp77JhnrcPKXxGQ0gZ72RJTcioXh9vOLpRG21phKlLdWLLe7GFqk2Ywx9FQksTFZa4f/VDCyq9J9ef6JJ64ne35pvEm/VE3PCVjSLqft84VfC1pbD1f/JMbvSU0z57rVTyZumWsliGqwM7LJ7QmjJqd5xL/jR9n6ZIQopqtUO3UbZs5Uego6ofH/rxJbFf/OW/2led1jlY23D/HddV6er1iSNhswLUSYqRlSMsJtZbJrlotY08dq0ar/MbFrc1567FRaiFxGRQbiiFku6lZBYBcDEBqIHqNu8Pb65DBHnln4auWjbuo2YNTO/GsQe8sJAqJMzQp3Pnb7YWyp+5Cia5bUz/L3g7oInPh5O/R+gnqu+DVYhtH2onx6Pjv8E5Jp8jw0yY566n9ipSLrH/yz/gF9o28C17oxmp5IJHRjYh4Gp65pNYpNyGWFd1h08dmNLimGfCZFRMYpalYKoTroJSJf6Q4Xz3bczHrBM+v3fd4qKmxKKYWAdLnbnU+03j7Kai1V+3CZQIs6hdScjt7rElqyxr/RU0lBr0KvhyF4WPi81WW+/7iLTFXaoaqZPwaEdGm5p6yGI6GbtYfJH1LwaQYhOzsWqksLkU5Qvy3z9vrD+ny+Hb+PnAKNehyn722iBHI1mZGMY0YxPZQSPRfP2OazMzMZc+n81bN/+efyfm/1jXDt26jXvOTOwZH8hqdj8P2/V/7ifl/yPs/P936H+x/v/3nHaHDjJ+HjT2kOmB1GAlento8hwf6ZuhCbnKh4f2rwazxltjCQm46mjn6UutrMUWUf1/+tAerX+u9hubNQbZlnDKqD0G2jsVCLP0yL7AkkNulj2VmONx94O1xDRIk/xv1/9R8uscB5iPc7XdYcBPw/L+cnO6qoEkkn5MwD03XUpNfUUekIHalBQ4ftPZ6fZ2eqe/IoywfeZvYWHuknbrP8+Eyfj47Gbg9HDC7z92adSmfgdR29uZkGYdkzMByCBgigSEr0YPuyDMoEaB9Rs2W0UVqP/asg8rR0OXyhu5+3M9uZyeJ/8Bl5HVq7cOYaFQ9voCy4SIEnDv4l+2QLD/99Jp0/EEicp6l27DOSLCMPErqIanHJ9+Ow6tgZuIeQSk9NfCWMd+xJR1eT4P0L2/OHDLQ2H/L5DcgeAcilhkmwk+L0BfQW/6fA+WzK3tqQ1sDYoSoSQjxgZUJRtKeqWa1yh/MPk+NTxDNQPjGEhFIQYRCIobfNQfH2157vI45cFP5vQeL7zxTLFlnsy8meo93EoP6JvOwmg94YC4MgH4HoIB2BgxD31GeMkTrwbj01+rv8xNAxNUkkmDz8o/Ll3HbkZ41HgFVDk/+KDbD4545TsVOg78pzKr0tG2GZbEs+b5vcHmWnnr49j1TqDqOXF0/H2Wn5o5BIEOQ+Vqkh2fRZexkkJ7pYfDo6aOMDJ6bcz7Md86TWe81mrnmjy498/R+1/0OkhIhI6GYXXia7jCYEw9T9waAmbGHz7s6qjqLu7iV4dWHAwiY8KzvBcIEn6IA46qmCodccBVDElDR6DMEkj9gek/yK9ZrU2rvx3zP8r+/a7HvL93ncADcNAZqQPiLLXhKZ7Z3BdQiyLOB9RV55ewvdJJJJMocSNQCo1zhUDQ/ZeZDo2p4fwKaIeRjc+GZ06pdvt/Zm7YnXc1GaHT59A+TVqYEXlaNXDP0c6DM0/5emFzmK7IbpAqP5Ct+M24fLWTodMf5X/DdfX1hTRDcxLJqesIgciUj2H7gj9OKaX/CZ8vSEkkH4nup7rrvXNGxmz+qHvBb/AeyeqI85q1lVv+J8b/k2HX4aI/yfP8eU+f81sKL8mZmFBpBlaqdCg6z/3XvDfVNyDYzC9+DLA1ysrndi77ft8MiceenkOq/yWfbN7mf4WU/070PCJ5f0WPDZ7vu+Xdz8JZ0pLzRvlX312GjjCqy/Yit/d/vDOHPcU/Lr3dWfOvGfCw6OnrqXQeuZ9hrKvSHYTSGKr09AJ0or+Jcr+ruzGHOmaVf1Ne+8u9b2PdeIy2P9/9pRVHM+uDmBlqhQVRTs1F129/vDMhZQRQ9FAU6YD/YHGLnJJ56am679uPGe67flL5OqtYU5DvH4UvEv8fXxn+/+Kd1FSzIdlSUN/LQm/8N4ojfOrUYVPwvZV2sf5VT9d8TJlv1/jWU0Wi0Wn8s7QZGUJJpCiQ7pIrnFDDDEceSmiMgGGMiEL918Jqeuis5iHRPsvdlmfuhjGYZSv47M95/A1VnWT1X4w05Madom3T1Fk0jx99y9LTtBiHdu/rJr7ifjrJcWk0Wvz5b1DKp31o9PXSfm+JCDyjSSp4/fmlF+lb6d+eWZZPD1Z4kxrS0123ub3tnZHp0q+RdFRJLTK3SSIx6cnvjrrHi7xrKxJAv3Xdp8hr879vXaN652fWvRftRi/As09pe1Ol+F9KafdNUvkZ+T3hmB23D1nRFbIvu/S/6c78fWX6RpC92PNrsrrVY3W24jnt3BnWpSjNR0eJTR1v4pexA+fvR/TZfwX5454nm6aK8Lt4vzbP28at2RabnFu3XwbwTV/Q6v7zff9cNmy4Z3QRTHCPsK49HVzTO898Vz0QXxI14V2i114c4u+++7iGtJAuCJK2iIvzKipIV2YVVPDsjitv6Qc5P3qQKiresrSNr99NC8rIu7nkh2WtPOy1G+0NLaGYPPEJV6nf1yVm8dt2+KzPhTrvSr5Fz/Sh1XRm5Nc1bWv9EvNdt0J7y3pluzH3xLHlr727V57Y1vc9FEI6+L1LsFg+0a4vdxqwa9eOJAfR+L9U3s1BJQ6h5+seL+Hve8mVvPSfNKaSSV9ezq4c9PHGffTn4Zu187fldX+DDMxEfy39s+XRqX3utz993q/qgRKvcqGJCO3SIfmViR963EhKkYzSgveNpFfHGYt4Pu8g/rbpR+mx2il002JCpAqSPzW4jjo1HQkiOxURVWxjPyq1EJCtfLEw6UPicvCGL9TKZF9SnE9Jn5k54m27+h5GWn7vue6Wp8kzuzKQvidU/cxgvGKa13mln33OmfNnWV5R7tE3cL90rV36Sy/LaUYYoqpCSEvoTBIVp466XaxghUJbbQfP8sq0BaEkVVVVJMN+Ku7CrhuhS1GwsTDCz43dV+eCt5b3xS/V144zzJ0WAqNzxd4mhAvawZSiHRiiIm9VBpJTr5m7tUhC4jvKxL1ZaUYZGUzyH+bMomWG9L/h1fkwk7bqMIoqqiiyMy5FT4xlk/e49P1M9/P65ati1Vzp4vnEhIUEJIZufkKOZ56szNuwweiJ69dfRN5DPbkhxJJ9A9GEpr7y8r0379fjz4l+Xf8y9C2j7O0hcPtm3bTnDsmkLkmyrth/GuU1ct153TxgPl4Y8cBNQjDMzJ/S2HJczTkik2opNV8UrOJHSjWlpbSE9zsq+1ecZbTFk8SzpPw/iVNHEcd+2z6cfjCsFqN+pmOKVUSgumy9Va18SKH1+zJ+kvEO95qirNU/e/pdvzrPrVf0dVlHSpX8mY+XpOAsufT7XLrZow/lMVZiGJL8LrzGJX8GEQiKmH3FQ0JHVHhevtOOQ57u+0C4lxH2xTv3dWzvhyzvhWcmUojx7TicvwVvP0aP78/osEV/Byy5ZvaTKv56vE5Rt5e3naa0gQZPvRBsfl+XPr9visqWYp3b7KE6qTylZJB8JFPcvudD6/wh/k7VVKHyYniHl9mf9O2LTic3O45zt2JBOY6zPLpw9obzX6WZbHlTJyWczqSkIyQrujJ9jjWdV7J7MuqXEhwDWGOD0bHPFBu7Kkeyf2fjyNTyhI6f2HPzensL2o9csf+Slfj5edLz/q//DyzKy0+Xw+Pxr4+PwqR5rKtyWNTosl8ns0TX9dfx18r/7PnMtBwNKn1isHt9rJZ6q+SrwfbXz4ZFoznn+WvgeBS4IqbtHZY6sQoXE/3f/XbaYgjw1Sg4xkkGtUk7ctv/e7vfpafzB/ByP0H86/w4PdNWj8RZse5guUeTCSSBtjOFeEKvj+bGgB0T25SgwhcM4UsQgLbKDS60ZCNxDKB8X1qhvgEZyh0whVN/uIUEQigXGEWpNJ9M1bR3CeU+wgwMBSJqCjOt1WCZJgMup/WGp/Yf9mUtSBKSC/JuA2B1nkDcNGf6t7pAnRw1kxxiZwDJi5lOd3EytKWossKWg+90ExqMxrNzoPkNgeACddQQ15JIpITeOsOr5Q3H1Dy4Js8hqHf0+JponlM5GSBJDjxpCoIag7AL98kAxCRTmbHrLMjlqDWJ8owPX/GqquAd2fqGzAq57iqItAaIYYFXzRAxjH5IMzufAWvuCbNYw3n8x/Pyd4zROQaX0bTB5czr0JJN0JV1KbbYwUoadcvkQkI4l+XD5BI/3syvUKp5D+h6t1MO8Y5HLSnj5YmQG8oJ6aGs4eAdKQ84D47MHFTy8qJmSG5hTTLMx6Re0aTb9TOCPur+Ris7VJ9H2n299rejMlqrLw8fpOywW6LIww/1PCTJ4njE+jXXuSQm189sgcIGWrUjwKbCfPgTt4mlqVCRCne7ko3O4o2hmvRFDRVwPbvNLIHpD+Z46PJ106j9dz4TgVKaip5TD9b6dYZDoRU6NkPPLDuCiAfIQAsQ2rA8RIG4dg8r4O3dmJkGeMZjL6wsOYx8OFPYHMNescunYhseOHPNkK4eBt6h5VKg0f9iho/3fJ199dvupPSrFnzswwiVJe26im8Uar2hgI7JPA0lpbkJQedQ9oWfGxNsCRO9m7+BrTwIj3/CTSNVMBx87nUapqZlkSMkSQlGbFZCEPYB6ANR5fEMhDWB1hbbmxksj8pxGH8T9v3feuPauK76/gNjl6U4WJxmd9aTUFlt4xilNT6po0WkP5KBbfVG/g0SL55IGkhIRfP7Py/8wv828wf4Z0Af7v7h+eLfuecdmn/lP95PJbX2xasnP7ucSVz76mP25tzknpFjNDKIiiKCgBKU7u+DN7mJaeWrytoqxTZc8/0KlAiWxS2XdsZvmVDU7114GL0xSlSHbtooVLLxu2cUS0JbfbS9b1Wl8bLz6m02uV529VXgiQ7UgdqgOnv6YPwxiGFSqCpp3ERHBREwyMCJRn337xPk16odmiLRJdjavcErovK1O1E5nj7dwq4EWuPOA0Z3ZKOKwhoUKNy/JvjwVyYa2jWL4cYpKjRTdSVXJSXw1r0tKU7XnaGfs0ObFEwKNJR+sDyW7MqKqkQH+WyGYUz7DhusZFve4fuHIN/kZf38/xNpopBubCvds0Xp8ULiggHWFUgWanUdQx1nnRbVl6TmSwC33hetY1vEzGl2Z5vlDmGiWuZRKwT1SHnUv0pzZgjlLS6lSz1vUrhYAzgrj+0iom/ftw+1GVVF+vN9YdSSer1177nHF3trqGpywzXcREtMBGQQq3Ml70oqm5jXkTUW+SmKurFnKuk9tIEL53d6EJIcWlauImWUYNmHsak6RKbDnT4Qru1qTi1NC3nJuLcaK0YZ6ba7xEuOM9WW2F1BLdK3peHk2Kcoi0bVFdnws65zQkslOZ1aXJXUyQpvdNLab7JTfe3spje5aIoGuUTCm3jKyalHUsbrYnJVMV1Lc2L3no5xrVhL+fFNVYElO16VBDddc63zkPe8sCIl+ZeKdFOTrqNZwOstYn6CHwgQ97/F2Peqi+XlW+Dyr5eN2WnfvJSnqRMwd/JmLDwZg3Hn57IospX1icPgW8abOXz1PNRusM+OEcr1fNF+CCZuiSn2d79nu20XcUnnp2s0gYk/ZnvNibHZmxep1Q110IZlENfvx/T6D3zu78fj5jt47diksS799Wj0O5c+4uyMifUsIj4PPdxQwaPmXqwxiJy38dh3Pd1VjPLr0o0Ds1dItank9m3T2pWir6NdD0nb1nzYxy+m9xKaeJeaH6+/fx3gGvPMupDPkdHSbumunYXYn9MhBSRBIQWRADUpOG1/WUbwgkUhAUs7T/Vj4f7ntcnOlo8tC2B2IfsQ+nADf2+/9l+2B+bpfsHlXV1d38d5eSlzVdjFiY2ynz+eVPtafy+34zp9lD6Dypf5qMQfUMHztSPo19KQmqTIqStfiAqgqiFlYePgbnvGfC4b7lVVBCJq/wT+mokcc/B8sKlWrZVoc/X8097N4qrVREYFFFH7S8zXa3hGXNSXnuh5XYueFFzjNUApPRSsqwYrjqZmM23CyfdEg84nGmy+r7MxbYq7fUblZpPE7VnG57K34tcyMRu9qxNqOLa8ijWgveFisiqQ86aIkStO+YtrTQiSlbErLcf54prDWkjYzlrYu6vLGVutBTyRPuD1UVQb+A9AVFBL03H5WA1cqVM13XGV3+V/180zdoySEAjPyDSVISJ/cUjsvwqiiBCtGqJBDwwqFwHzYTeCfwPKmrM0komiqRRPzm0/5A9/6KsgqjbsjZCXdOi8QHqSqQs0xdlWhGrKwGXHbCtgzP2Hv/iS6WiBq0oSfC7Mezye8vBOyBcdTDBWj9jVXXBuijeUUE4NQzaXMs9R3ptSIAYQx0oCf9Ith1JOokZPmI2kIMe1NADkz8BXqW1cjRsaoyZla3XV0UhporxaIRikGRkGH0uCU3rwvQIcML3kBIRNCCH8xAnX91WyeSI/TlSf1xTVq7hJtCDuZFMHqLS0hYPdCPJ1Byc6DWSA6/AjqDEMkD/Q2KccnBPEUmC2iu57DeIeZeKBiBIIHEqjMOSnqOT65Eo2o+mSIZRYQc9th0InHI/aQgQ5nUGs/CSAQDtjWSmcZJGJOkhmCSefp/mKKANP+iZ+lHqGjJ6w5gP/UIo9AxSCSIMrJ88TevMqUlRkemA5pohy3RkV2Gh548WdiRQtIiUsQ4hihgR0jlLDaLmq/hh7dcObVUSRiRieCpbbVSpTUpGiiJBZmqm1/fChAxmPE8qDGi1ZZC0LCoih3/Bb/kZ+XunzVEiEiBI/nYVGw9f8uNjMQaA7aCuiNEJET1hwsOSFQWopIrzo9ORM2nKGSBSDdnwPy4vmLO32VlYfm+9v8GZQui9giHRyrGNimbt9uG50bzCo4I5m8MLzN9FbaMmylyJ4GdO0yo0NWTHVGQHIWzvH0QkARkHQ3/2xSw01ps27p+4rCUU5QxUWKu6MXa7SUNFKxQ1bJHbcVXSOKESGisqJmOqK9Jaoa6ukNRDWelVgHxgbADTt/1+BREr9oYfJB4d4bSKEiVQFnB4p9QReIh9UBwQ+LEiv1lU2B0olFh5Nfd9qqfFPnT2k6wlOfzJ9a1X+gCuAP8It7XHpdflEVmgYyDKxIpmVtwfd9qHdAN+qkBfw/D0n4erIAA1wfw1mLFXZ/KUIhrgj+MTZqpVNVlFnZD9tlhI/qkif1T0OiTFOTGA2xS9pXUYdgWuvNjQKOg7orsjFWlxUdefWUb4PSqmXh4/xdu4HbVkuXYlvpXN9+qEE5UZnTtWw4cVOnYSfbLlMDGM6rqQ2rOaqwVwxJVVIvjEbmssGrydJ/l3dWrLgciCMWDEOZQFCQoKKKFbcGr1UOrRlaOrzZt7LXtUnzJi/WcdigobSzzzvCYYs4lZ82Xr5SnjJypdBLX1GyQBaJMsrlwlqxii0wuHEfmKZ4ZXWsSWxBZIlcRM0uQIJNQIkdSm8aXQI8UeQt5yKtOgEzU9zbHTqcQ1RlwyBtXlbwXNioFumFQW+XeTMKOxZeEw3rUiqi1YWzCnCTsz0a81oppc2Vbby+plVwXzeYuc9FazldJaeQMVwsFNQmbONo21eqads5BCVsVw0qQS5fE8sNcvYZ8lxR2zmKlTEliKkjkyZm6RhZVuxu2dwX5LFK1k9qqaCqjCAKIoln1IaHtrG13qgDrkzkSUO4hymzVqS/OMiW4CanyIZiUW2oqxoMWYoqLMjEAXSptxNoiiCFd0bBbVW00JTkrhUMUWo+55lSJCa6hBJc097z1A+cSi8siUvNwNXht5qRZrppuFLki9LQhrlXWebVLvs2aeMY5LJWY8l5j9xfqa9WLjVfTS5ngq7GvaW6NOrdx6OQiIgnU6UHiVhuuaZLyhdVafHtGNRuU537SUifWjFcU/vJqWHGu+150XORFL12MvQup2JybtOivHZX6k0o3K2JYlWyFA+fmDJ8lT64FUk3xj6fU6r/ZaQUDAjl1VfrX/JRk/1kmY57dj1XOWaXwNePWnt7TI9pRmizRqvJ7YFnP3RLEqLF5HxvnXv+xN1p3oIih/QorajTrhqnHfjfOXDgfSPuYhOJKaILKChf8bCuycvZ91kkVRQU+8BedU9D/Cd28m9T3Ky94aB6+9vSlPW1JlbetS/v9lS3DN3wuoQy4vL5ruxJOuUzLaxvUcoW91NFJNfNqcjDq4+9QupHMu+KdcxfMsHMZw/JZ2ZZZXI1vZduW2ts3TEy01Wcnnw1h1l+cKbIpOl+mFJLfTT5O16LneNma8Zc6xH6EJXpKZ2y5aXUsHRks95aWmOu4CH1r3vjIt+FVmY6bE+T51LvJxs2sSkV1OFZ4q8Vt+BY71mWsvX+IClqeJ98rDtbvvPVte9UR+0sl1kgLmOnaZJAcVPNEQVExFKz68PryesQdnG6i66WrywWOLfPa1rak08rFoeo1crKpfrU1GxJ7dyhemFy0svbOc4IpzFKLFc8id6tnO/2L7R/N/qZytDF9eFqjtP5bX81ej79Xt8jMn7mLpVwxxqW1b5kz+s7n2Cn/Yw3/Rve/zCoB938n0A/uW+K/DQ0/vdW4oUot/fzvG5LRgwQ1KmPuNuWT9w+zZlNfYPwEOI6lzDT6em/q8jmvqHmon0H5DaaoE3iTq1ImljnOyCG6X2iQq+7+ruzuI6+TtJlmucDKvgz+j9Ibr9qs0o9XK27KUWWAoiH9owVPv+z7/vx9/5A4MsvynESl6r+VFaP0Xa86QzQ87y/JtElf41Hf2nSr4fKLBsejLiANy2Likkppc13f9D//6bMz6mVLBfUpw/FrF0pMRV2uobW2J0JzpSwtsPPVMUHG1Tp6XL16zsS2qqNuryLjvbckTIpYi95SIvZqQgGqVld81s84MOjlhrSqrg9cYriDG9WXOqSbcIhhdDYxs+uk2UU6FTCTmxEyItWSllVKpVUpCm5iRiykoVSrBSqpPLEwpSR2phYkJq3KXfObiVOYci+qcrda1wZvZZWvd1/WPeR1Ka1mTgwmy9CfLsG61EWguqPTk8BgUFDZgC+lKcag9AA6IVcrumjqILkW6gOp6CbPss50uUliS/PezWur31jsYqRWzdgumKr1fJOdaB2R2EaKO79s8cs9RTz6SBUElsacEUrBlr0bseRpHsQmOkkIW5IX2V8WeL12TFnOFa17SE3Skyco1LkmlJZGq6hhMEZzO5QK6vhN4nx4nQCQ4ou8FnWjE0TEnvOivsR6ElAMm6PGozzeH5ydbamZqZdLXBLbyVKakSM61nW4FrsJ5pVcoNnRvRXmp2rUNhhQYIpN9xGhpTbS7pgnzBUMAoKCKG2YFBS66ee23plJmWmOgBjGHEMzYL5q6IiRLsLGby3x1HUScb4X7WZHO/nSQmbYI+uLiT5x7dL39b7c11x0I2LElKVUQ+3p6Z48617e/l6kRpSM+31nRzRwO/W7y3g+e+UJmcGZ8w6IiJYyh+wrOAJIF2C/HQSNWoRutd1E0oCQTXd6SQKqgjTBlTHGcESVqDOgHIjZVtsVlslUAV8Y6w0q32UK8XfYXaPR9TbXWnx02cCIiAGnnNmks7ubaRbBGFtXFLqWw2zkq0xNSzIySexBTRjMLzj5oTrDT61OLVlOKRajRrTWvJqtaxY6lQtqut9I+iazdhlkqK8jdnFH5Iq9JfxoS1GlJFczM7OdUF4Tx11NRX5u7TTdNXtXU5dUoTKE6hPbRIz/Qp8vmrfL4EEB7yQVtYzg15y7ea17WGi/hH8ptJFXOM4v5UvBW1SQZ8qbK28Dr26jG/P4ier9cfWSp6vvhdtSAf6U1CS6kNxk1QvbtX/R9dW9NU/w7U6kqJ7a8a8Ma4SbpfP2PQUjylP2r6+/3qoofM7HdFSEGSheyJglkiHVUIsiEntWdRqM46iQkUGZkdIFUVBU8r44/OKvjx50PjJG8rGYi1YIh0rKGU9GofGmvWcQur2WTSxP12ano00pVnV3uzK618/0fc39CgY2lcZg+4iW866PF+0yQq3tSUTRvKfZ4l4hleVmL+WqLO/nzu3dVO1L17XVtr371XS9bO9MFcddyP3CBNlNUnP1QxQ8qV9VI7t2V1ib9Q8tz7kSXvxLXk0rlid827WlqmonegxSzLItPq264vOdaqmy282JZl08VlRaan+sT708KHvVDAKKoJDKgwKOqM15msJjPjt1RyCIOz93bqkrd6dSe3fwsXpiZE1hbXtyDK1xLOS85w2rlXwtV7gUO7Ih3Exs78H5ZbCIskWxrtLa9HCmGnEbxLMmeySD0yLdD5QF5ZJvIQhIySAmOadhUKR7uvoORnl28XnQnPz7W8NEidIotZVZ7/Cvj0oTsYwuhoPSLN6yruhhd4mY4XunIHu+7Ip643iL3IUvPVNmZkRYlreZY1jjQqXnLe23O/6vofpQ8kVD4HsJ9FVFWEPrIGsAEgnrsfuiF+Zh+XMH37XBkSEhPTt873dAfEHqybyIG2QkiQjzuwJdRiQpaRoYQIKkwIxbsf64bPq2i/9IJYcOjo8QnXyM6LETps0+QaonUnzvtvQjkBIMH9MKI4++gucDtgjMH2hg7Nf32dxEadWUIzKouJJkWXk4QyIhZH8pBKS5OHMG1Nz8KzEiZUtGu6CJ5n9TkM7TA5CfsNASiA5j90sIQGLEyqUdPhRgiYMxU76iP98DAp1B/4DIPswf/PurYLDiSkOAVVGstdhuiqVT6wwwAr7vW0UUFRYeESiF3NzShNFqlSSilOtVJKX9cMQrSTT9xthsfzGtRLA0Q5+02lHG3OvK6a8J6ofNG5ryo3vLvhjBJpkaFQLEIbLdfsOg9NGgyhsig7ojEFOIRFcLIbjqKkDaVFygYRNMmZZne3WBLgKlSOkZWJjELeQLbJt0NoYNBGNNoUpgYoAikVcdVLZI0yVTFoouqYrlF1ZAVGJCMcjKpdeXSldXRCqZLTTWoyqVIS25GlVt6NBiaJSsGwg4EQhIdrUpqreWmuzYYOK7tsSw6skX1Kf3NVfeDQ7CE6g7j6RiC4+1jqsRYCKtA6oz4n2F38n95ssEL9v8a/v/d/G/8H8TKv8VJWP4/5ERn/k/o+FaxXH+y8fxrjWbaktE64qrgheqt9NhwgZhL6sNdJVrPGJwujD4vdtmo1DGtUXT1Un7motjvI3jC2mVx0zy5Vtb42ymuacipE3iznRbDGDGqTMNwxy/MPVp8lQUB0wLpbOnSo0o8BOE00gs2NpJSk8bMDTEYw2NMaFSoUoVRQGHFGSRAjCjEAwForixYlFl3sYe9lTVdGsldSeVa4/nJ0K5UzOpUWz9QiTmMYuUgEkoGv5Ber55aghgUTQGol0We5QKooLVGGDDFUpXjl69/STjWvKTVLpVcZpcykWous0svbeX63fLbo2oZowZfbXu0+Tnadd7tbZZaE6KaqrcWnANpitcIITK1YAZYkwppgiSPE/wkRy3pcDIHH9DrdoLR+6ekVaJJT5vfC9R5aK8tfC5ut94mSOUjO7SRaNwjea0ziV92KUKrvFbUMZjgylZkrghJNjIIPFMlg1LTbtya0cpG3zF9GHbc57ExUkWttrrIxnnNTpBB0Ytgvww+K0xFxSWBgdq2lHODFxKBUBBL0dxAkoB1olVJY42+idkEAZaklCT5muYhuIt3J41ZIQRQUMrUmcGk95NSMvFsN1w336r389dSeVUpCq6V9U+m3jTFkQkCoIJpayaCt5RUkMAm2GnRdZkIxGp8w1IYJybRydYEnyS81kzJUoNyV+M1J2TRXmd2JFnMj2WS47F8W3XqWJVtizrqfRyS5nyWsVjnSmCU7bscVylie81RntLZjPQ0GLdYjZo6GmUpjCtC9d84kcH7dbyIgmMwSxIQLl+drbeuKSx102pUa1qMazHK8c5a915NYq5QPXTfJezCKwgrDIHjZXjVTyGiaGCFKTD304TQgZDHVPT5aldcfxmh0RseEdHdRuUqptY1GAwjoMJgj1FQVO3p5+XgeLUp5R6T86VF5P09VostE1kUcY1O8ltzaITtFb0Z6J6i+xg1q51itqIqkrdns6EeAe/uez2WfLH4eW7c9cD45bqINMQxKl163xgVFgfnDaUH37ZkfHmZXj2Z0QoO7znh3efvf3S9vm7i/MpT4ny+ZK0hoal7Pb5/VbVVvHv8vIFPl5M/sHM9la+MP3l38dFJVXzNHvPTy8ht055T63TXD0l11qvZbxO1muuarimZYu/oXei1bOhayrPUtO+NW3iuSmfMz2T2+cud/BiOdpRzc68XkQbGniO7eU0FPZgQt5+QzXYtnVOlzq3n2V0nl4+GLV77IjwiiofktFGYpbJclFJCS2DurFmIlwKVqFhAUVEZQcRUcBWANdeK7ydt7jtWatEo5Lp+iTXoQMsxlqRJrWraphyktiHFTgCgnSgwgDgoMDDDrGG1rx378PcQG/vOx6WJTDSt7KFMT5pwQ59nqCw7tvT07Dhp3epEK++kaqb7hNzf3+3oc7z13hPLx5oJi86c7ilU1CVSDKp9OvrzD9kfE7uB9m4yfiIemGzs4R7CHmsIUGSHzdxPcQKFkQIZh70W0yfKHfRvN/xH9Rg7n3NdHnr900lx4IE3R7PNPN6p4e71V6nf6fh917fV9WYxD0xbCzp+BfElvF5VmlhcW+H2QW5Td8Mss4rm963rvGtXybjlZbpJSsW1dYeUyaim2yM8yGoSL6rx6kuk8Knb3t8n8nSFJS/IPhCTGZlVRp8UO/I8KKC84JR7wr9C+U9Z0z2F2Z0UYhcAt0U+Y/GFGcD6yA7PPS0yfHEqPuADAV8kAKX1bVPkzQN5/IEDGX+9/429RsTd8nbZ3EMB8wVRIEgQCyMjoBFKe/yWayB4KKR+ci9c1GsdLA8mCEOumidBcbCSyjGTGD897xf2tRpf89X6t47ZDvYskOiSBIhEuEi4pMoTEnr0X1/f18z5Q8om/9OJM/+FaVS1VM/LvsZpUGhXH2EkbhaD+gbI7sR3GUM5wbVZuvrXBcvwm76PBmzHpqk2t7rZ4njeTRtSIt0bREduOiKzjIhcYMR3prFlvOsloitQfL4QCkxf1E4g4pF/tMLBOhUqQVdKFwmLbS6HGFSpif23tkwqkLQmM2ZxFGU/sdBrlHUyphcYGsoXMsnWWV+TmVNOFP822RDGxkKYq+FtLYSfCwOUZCu8BCiWJrJWjsFnJjG0GlURXSqn0xC2i0eEV/PmivGlTESIR2aYslSdyT7zN16DtUo7j2nEn32KsW6SoxiO/Bm159pNmcF0vBYbWKxJJBdmVqtEZWuChjFCZrS1pXRgKKFVSZ1NkdGp4HAwleu8bIqMyiqwDOLOqqKmZlJkyRRicFzsxpKXxCJUNSSIFZZmYQEnGDFCRhUNwW9w7XTw7oZdMTdvXNnf0pmbNXW4ZhW4gY5FNHB32BrivOLomrR32WbHGOBlLqXEFlBORdXKVehXqeIJCijw80fRSkuhjUsLd9SsZuYHwKjDz7OEUMsXJDVSW2GsE2hDkVaYxFMHfnYWLXWl7NkPbOvGdGuKGVgKiPpCyY8E6fTdh5ssn3085xLsgdu8i0ultxhGqgNgV1ulvzxYrMurqXVrNNHE6HmwoQajMxjdDtVQxDQlEYqLEQhaFditd4FIL9fkU1jYhtp3KiLlsbLHw+GFi/am60AtXQ60dQhvTWxlhsyGzMNFyVG92a1SB1owNCI/WzFvx33y8rvDUxIBKl3ukhJYaYs3yyUlC4nKywv0le9XpLSNFb2ccuzloJadyDspZUB5grWwyL+3XM1nesVaioOjuxEAi21TZpPTaVS7QujE1prvzOYdTz59Kh+rHMH579PNN0vvdwMoK17Gta0UQV/vTM12uc3rrMxszt0rrpeNMOmd0ShipP1hUO9qLO9+l9mD0C4nvQyDxKQi5GSjE93nYMvUBWarBGu8LjsYOceksTYn2UitEmoO2LRDBUIWm8624JP84vFKv69Uw4inPJ7K7MMtfqRpd2yVZJBSoeR2VC+UYgFFehCzsozww/HOt5m9WeohNKFEGEkiR4MFxOi7pzek5NKW1K8z0XfezcyQ62cMTJg5wqFg/h/X+5f2r8CO7N/B6wv7/gVNW/hK038iyZK5/h3qHbcTtabfhk5bFXjP8pdBEQcUmCgKCMMB0bizcY/ocXXbfV1WmSVtzXTbte3bo/Qf3zvXHfvVGtbxSKtOcsizpvazbqjUOut4rmuYa9CuNDE5diz3zNsYNPyWc8K7Md1LPa98UkThTUqTvKXXUj80qPpTT2yDRXwVRhRZibSMMJFEYo+VMVDYlkmCpMVIbLIiroVhhiMVvvWus9cN2p08oMUjbl12pKknvWHlqzphuYLZ1Fo1qgJqH2vr0jc8MYYsmEqYmHnT3n1Jj+kN0nzE+cmx0YqlikfX38ecvEevPRCoKAqKAIYWlS/britNBYGzLteEjcThAl2q487DvZ+UWmNrmVMDram6YEqRPNJVMuyPuy11utKUqBReVIW9E1imbrWm3EWthEIuAc3wmO8gGcFqLIQjwmUbicIhVZVY3DGStdRMLE2SrMqgqiGaO6FVIVEhTi62t23Zrqs2xhv/0cY2W6x1aG5QxUrKRFheo0SVpzwTN8aDqeQ0q1otFYz0Ttpp8pYiK0il4ptWLca62xIZa0eq25StKTvlM8gWudpW8q4oWnlbYxW/NTk3BNkn5taTpITCKb5sqAWIRqk0AUFAvdiLUrzNKAmrowiBl7mCWJNLeHrn4E3REQQXdmuedQk5EsglUU883DUGumtNVIxSVU8fS0JNQ4fbT1txAa227OuFc9WJabOovXQITJ4YR41m0AkgZUKiIMBgwyzd9qu6BoizrOGvThzzEODwpV10lFKUlWFR6259vn19d7eOuWzxBC4oiCWzYgSEAHa2GgQUUC0ZSb5xyoJvPa5W0ou9AL829wsTqRc3ikq5tPUrsuTWGpeNelrpguxp+pZH4+dVyvNFZSy4u5yoYxnqeulzh6VuNGszqsrFB9Vw181JSWls8tIfnK3MtDPnS6aNcpzXJU1LU5lwNcOPJzcmlRdW9B06FxVrbfrFqf9m0tNc37Phcmadc7UqtPXzPq97X+/5OyoSQZXUWL76ghJwTFT+Lt1q/p+qEEV0LqMElO/WK8SsxjcELlsVY3VWycdrkZczL77f4Lw6Re1ViS7MZwY8GN2M4eIffVb4/tId/PSbfjUIwRPIWJzzRh3t2Jo7o5xgcrsZZzOb1tuLO85kr4K9tHg/kOuu+DSvXlmClPwjULuuu15sVbiFpCecYmX+OueUjixS0Xe8whS6zpP7owq9mxZZs3bcltOTSRxycz8mntJ/pXSXL9DKcfwYBXOBfjX5wV0/s07991PDOorbSVf57OkTdUhUxgJUadAmhipVWxwmxHg+84jSYeE3HMcFWlSxj1OU3SepvMFSkVaH0YWfdTtPEncdHiSNOiTYm6bHTaSMNk0NG8zRiNfrmRj0xODtVOhtYENYhFcEDXtC/A9B3+Tv8nj5zV4Xjy7PNszPK/1k3ti8qrL6rZtb6xfOWp1hGbTVpveuT3l28Ih48lgHvihLqQW5lyLsII8KFN50m+03QA9vZMf+a/IA+SSAJiTURjv3xhujuSU7ePKH8yCzv6JTyX18q5x7bpdnepLfpMxOr5am8YlSM0zDzrJ8VzdhEw0EYKVlrNrldzKSMyrUo3mIqf5wVPB/Qat3x2THUWod5Smd+01rTvOVPEWl38EnYskWyUup4V5nYvh4VdyNoGHvdrdK+eZOdRSC+UPUtbZemjl2h3qhmPWTzCn88Qu5IEJIRkIJFWlle2jj/nfwVstZKmXxk2iUsoI3CFU4IqRtA7+RcPIxNVVsGkkuZn2hKlX6f1Phs/WaL72+WaZAei0vswZf1UznDYKXnzEPPNqsFTqzxg6sVdxUQs7GQcDZkmLpkkIQKc8XKqo4iHI6vHPd5/Dw0MeQ+D2+opeSlXvabrX5/NXefzZbPQysvDGG1nO9JPbjRu7xB59J3bv5QCMIuxT7TzhHXisCZCzCfTUeDqphQ7xTpiXR4Jv5D0n6b+4PxGFSp7z7o8B5SVHVBfsFQ4t/Lw3ft2HPJj4THLJ3+FJQ5HwWfrE6LnpcULVY9bfeMyjqvsktJicS6efXl5G71OqTdeu/fffO9rSTHV1OeBfplBVBXPcfJRvxNIIiB91ji4bhzvT07nbo9oPD+rZLaxA/rKo8StWua522959Z5zy2o1beeDUpmK32BklSEbKtgld8WnopS5Wk9K9omacxyWxVuZwOTN6kT+NT2fyEqHsJ0P6qKqJ4PiUfYMA0To3Flx2EE+/H/lap6z0HANPLBoAQDL7zV+nZTzPScpXD5DA+6yxT/iEHahDUJ/ZEZBfqdou8Def0/rx0D0RCHvDdE4zkHkeJTCiMpCSAEAcvkHwOo8hnnombojpCQUZEMdDpSa3S6IXcgFNiFU7Y0BeCmn5tmIlJLJRUSghECEY2GKZLVYxULUkz9Be39ufz+XJHUJD+S0/GVK6aNQZOoCD4f1/SAE3PBQ9aw1EOZ1de49aczHTDLrmvIkhTgv0UCZDnUrBcnoqZoyuzvt6n9Y5a4frzo/o75upbDaCV1BsS3dxYuakKhn4G/9Me/XJqTMYKP2LJAtIY7/ISbpyn7jgnKxz+i/yeT6/tz5NM+9XxCLPgfR81WZLHBEZj3ft5UWmWzd/Al1ly7C8GM2VBVTaXgO1fRVlJ49BA5gJA8H9Nx5KkGsKXssAUZcjhbykCFDfVQOxsLugsRnGa2978eAVp8d5YgPJ6NlOSzf2D9cZHmZCpJ1yyzdC8LqILkxNi/xsmo4ahMDoRU/Obq7aafSU1Dk1E6LKMmiDBMQaqw6oJ4fu0us181kqgJCmSmSMKqlDR1dh0PRwOowlTMzkasTkj/aRROiQEDrZsbXEa6u7yZzG7ux6Z+/1Dmb2ddZaLmsNTQy6g+CNl9iA68M0Kujch/OFdvsJVh32OTtyfWxi8enndToioulpU0klXciDcSO29SvRYuGozVsp+H+CHfuHefV1aR052CuqNjqjZsrdFbuUmnb5N2TbpwZWaSSYMR3XFo0mq8a9e3bVwZ8X4EIKWWdJ4cSNKh4shxXVTKlVbAEKGAFbsJ+gh2TjZXbDjLIlwoZItYWwu4iSKBIYYlWI0sVkiBBLpS0gJpF8/uozImYqGXJbHEAw00NQwh7FkIsIwSSQIqQioffnsWhhuIRlFY9v/OwyT4yBRmZUWEUgkWflLlkWdKxbIu1DfbYVSaVH4L6RSz0hGwDHZlnkdjkj/tISMAIjInIWGMuK0Pqvwt/5d7g6CGkFgvVAEJBGMzTJ957ADAH0dJ5In7yBRDyx/eEGQcQ5Ftauvye7juzCOUDIH/jHrUwncQ+aLo7A3hKORxH4J9f/f+us00m1fpNru+kyqJmHWSBKMJi4q4xZh+eSsYmUw/bD8Vag9oARczC0h51d3/ZpRkFD5z2d8dml+/4wPlPnAry+TydmK8KPmzpdOCKTWJTCighRDoyYs7d13dd37+dXi7SuVnWtx6dV/N47023prQmkudK2uJtubll1u2KXdtyFNbSzJCWLju51q6v/s87iNdSplUKjIESyqG42RLhTEoPVl5DK7ktYSR/NLs/1F1+apRT1g+JE2McsG/ZRTwgOqLUFZLqNySThhDEE0gvRAS52EEC4KLIihlFQhFF3mhqWxBygLu6sfu5VfozPxA+Mm5WVVVBJGMJFJJBhEUYEIwUGQZ+sr7/x/G8o5yQ/kn7C8rM4B5gciv93837td/zR2VnX/56r356+3P+HeyQkkJIxT/E7gf4NPUt3bCvOTrN5+Xis1BlOvIKul+7Aqy7xSzyKKlVSUeBXdfDtIu1u8rEImF+hZor5SXkr3bKkrFqvA67W2cD5dssxToYtaroqiGbsVXUNhLVzumL0Wz5lO7a5rPOMZnnd6UcrAXUCi4oxxSFmoq5VNcY0pKjTuycW65ZqKmVC8TzFbMhtR11lkaG0KTlD4FLVZEzdjAo0ndDgSqOi87AaR3bqqoEgI8WKG/ScXffQduWmLme2jZUvqm9ZiuZVzTLYK8tLi21ExUwYDdYHUtDY0273duO67LoFTUhlLNRwKqhJYWjtewl35xkoSxlaSJ145taijqhSGhaqKAkMMCqChRV5lX0tlmkmR1zJtzSeiMrdRSfIe5a/G3fdM73S2OSLTJ8as5akhhURrMrXfii1h80GoyqxheHDblWnSIViXclGiTdYd4uvFHVFs1K9GUw7PJ10qqg2g0Kihq1xF+jemUDR4XWmeiWbcrtbQi0Mm7s6UWW2J7klijJivSJWzGQVJmZvh4TIo69DFaSxnm6RzdLtOzTWdamuKxqS0XeGqLZtPjLIXmrFFvhj17s1o2bvyg3x1iOI3u4NBnl18bYEFzpnUmJXUs6dcMdGOmndSbMbFSxDv1BUcVYWxcrkfc57vWV+tV5bQ08S3K9I4vJUvuqvWF4qVWJ0dt5IWpEeRUxEVHjbflncQhEWl4R3WFEipQHopK9HS6pJVnuIHQN6ZA1AWLF9Tb29cpSG2+2Y02JZEoK59b7NiUk+Swq8a8SZ4fT12/FfVdblmtJ21fVdritcwpWXNWzjF95E1Qoo6IgoogJkyKiMPNYbTuGEiOSNmRMC4ICNUQZG5N+mZh3TZwme+5Md9O7x4cQpKVOJyt5Z9X1uGNvnWjpI2omJzTxyT1UN0lRY9mIbaN9GWJMefHGw2NyLZMSTN7MQkqwJpJUEySrTYrbbZ3fr3trt3nS+t/AbEbdXurZ3sSN5Gt61DioxABCMB+jIEQwo6094aNnk35zvc1nMXvTXJWxWiznrW6S48nGepWTV5uJbXcMNbWowvNYjDFHtE8ZxLk5ZHis6c4wrG0EUkt0VxEUM7zSQ9Zsk0iRwoYNJiaKOm22rAGN1rpXUqhY6rtBoyeOqHLv0zReqm4gwqI6Io87UIK8Y4KFRXFJKcU5hm1J0VcXYMrSjJvLHBScm+Ap1nlSEmsjJqlus6GXV92lPNOSlKUOqxOL7XGNXm+q2t1NccFtNOTrQq/M33WJRBWKNx6WnLmd3Y27o6oypucRCKrKMpsWuKjmFujtRRp33BCqoGqnQ5JdiwqJzhqHrLeZKarJumJYZOOwNSY8NZyUmrmjp0uVZTyu3sdDQehwZzp832zNzz3vnGnVJUJUJAlo2JMUJFSG33b8OvX1eX7IiM6el7FXF0uLv0wLR3VHZBTRruzjDmoOKctNx5tm06EOqF1Le8BPq/we8+pIY033n7PkDlZLT7J/VD3G86uPIs6O6g7Jxj5OuiHcFHaaXnWXujNLrUa0qy96zVKMwlWGTK/4zdn96l1ThKro781AzSd5aceSbHEVUPxATuqIhm8HSlVjOLnN+eUNN/lmmDo4H5H99MYh9ciGXil9gHMxCHRM8y+u5QjqXmva7dlyq3IByh5keU9POVvJ80aVm4i1VYtqr4/Vbt+vl1NPumLw3T9GHovOOkp5wzk1Mzy4aVMKVfT0UeTWoxeB1xuVH0qPt2uVZeZR+ZZHVLrCmhdlUrqCk2gMDDGjd6TqTim6tieGh8S5zNpznC0Xig6k1aHf6CzWFMKOumu469dNsXBbWYMCi7bCmyzXJMXUojarAt2vRsCmDrq+1rOioykkTbcNknngZCGbbtZQWmawllypQmcDZQyKMcwRh7wbObh6Vtrmp7phtDUlrK2HeVt3qRrm4so60WFuoovFK+WG9zl66eLembXECXlHovRG1XpH6eU60LFBUaimMVvEo3eLYay53WqY1NRWkyU5DTGZx8zFHLClyhM0cJjBU1zd102NjEsLS5TVtU1KT6VV5nerapm1aZfE50UeVmo7TngpyVl3ibys1McpLFqJRTSmV4pqlZRxU1tjCptQnJhlQuLgXikNRJaneiNnj1qzcJTnnXDBRjF7K/xCjPn5jVN3419/vnvjK9/XvX+43D9CUVP61KtpABtcb6ftHh2WariV4dUdTyV408Cp5LSCZ2MmCwpkqQQdFShIwKYKGQoEyRQuaLkhW1HaT1XMlWl2lXTNmtWVjeJtrW6yJTNba1bPcaq2FWej9Bvz3QNbYyKrsb4/TkTWTaN3knRJiy4lJ0rdms1hTinZZqiXVYm8LpSFuKG421FhpNVUoqYaWNSNXYSvcDYDAObNHC1+TOE6JlVat5xL6N5+qLlEPgB/KHgU/v7z2Y1fD454+XpaxMUahAqHpg/hAITIiSBtpEP1/L9dFyhUJ/k82eKQxnr+G79lmLuPSsei8eCR4LKtTWWrGIo8CCy7QQFQg4g/PNKD/IFqlmZCDCMdso9+sy2wyXOKUQuFEGOs59GHQDt6y9v95KYySMSAQZME1kLjBQHkdt+UpCguZ4Qc/3qgcVIUkerIzBxD+2papWj/kVH7cwmompQ/33qH7P3PXTOKncnFxGlP7fSRWqKQaOQIqtsitVVQVwfZV73q5k6wMHKB5TMphuGuggffAPP3cL6f11z3OLeqWMOzSy+BtKHnHEOnidcbm4MRZ1zsyzzpJnQUTMzKdR7j2rtD7TtA9c39xrnjXJg+SGkf5J8h7j6D7uoDSQIYorhKyoxdInIiBqSWGDBYNxFKgjSxgMdo1RJKllr0LE/xVPDxNL+DaGucNjmaNGLhKBYdGKWoxksZTKpsPdr5/EpV9KSD4KsocwiSBCRiiwoxOoKIei/+evtwZYrmZh/PDw+D7m0n5WHE7sqUzNgzSqsumgqERpoiVBuLfm15lnSh0OsDltrc2J0C6J27qlJWAzHbe+1Sl8PHg25AzoJJ6Oqr+P0WQkj1yroK6pRigikVIqQatnSlCj0GRjYcggQIIyKMIEcUg8WWd+uBx7LbhNUuxqHyMGYtKbK/wZVzbRd3ZLm7Nq6lsP5pTuw2FIHbnUuoU9ZKthGKxSqCG/hQQmpclKN9hdqJg2kDz264XtqVCZW/JZUCWRfTLGEBgeMJAo/s4J+2VSUEqn9pGWpNW7kntNNlFfEYLUykloYXLG1dnNQNXXZMZloybbG0u7XTVkq5ukVHVCAvnCKtEFA8d23Vy3AlcYcv+utkAhACRfkNDAmQmgw2r5U5FBE4w5kSrfsSTTNbp7+onXXcpr1m/ja5gybhlmfOepcsAavCf3TnA2pkZqbCYPT6Z2WGpJ0+b1fJUw9Q5tfqz0sdzuZCEGSRIQkSRFTMkSyWS0m03f1fve35QvOCQUcso0KOMAH9URkYyLihBMDoEVkQhDKB6V6jPy8Xl8+Mn6+h6MHmP7fS8pDToZ8QGmQ34O6SPkH+f2dD/YfgipskOQywzYmynB6SsBDP3hkfx9/B8kAqNtsr6BT+Mcr5KSCsOn6q+szrMkg4H29ZF/1AXjM7BHIPsB1QIEkBL9B2eT6e3x0Cr0cspACoVFKcE7iBZ5t3E6UiadkOzpiH0HUh0B+c2VJp0++rPqLh978n5JLYhY/xFu3E6tL9xCEVYNUxrP8LVUzQJISSJieaaszzDrcqQkmrH+Rs8Ki8gpmeHxvjd6qHKn4IgIvG7XVjoK0mNt85qYhJY+ycaS+461rAO6tS2kKOhoSaaEqpJi03i7RotGKqEknq+9zKspWZnmYTMnmVTzA+ID2cwhQSh6QPOLgDu+fL+qJmPtXyobXc+7J3BsOAP2BoQF9bH9i8pFpP+2ySZUg/o2GlBHEVuCKJz9OyKkn8F/8zWGrKJIE20r2e88Q6cxAf7IPDv+rMoDOYT8hPjTAh+gyKhUKPRDwqMENGYONyEGYMLEomUxjBtg1TLRF+GwYYrg8cQRsv7JA+wypOVVfK4N2qUYFPqKeiIJICSCe6AZQBKhIEgIfbAuCHikcow+Kp8C4qT00hHGySHsyCiXE1wKQYIfR6x0PWes9aY3EA7w8kNm5ihyK3a1K6omRCj73P2ZHheefkiU/tvuT5Uj+vS2HtGrE90NSRNh8Ihpu2V7oPxnR4+rww2wNmV+3jKyJlpa76q3VqOoX480Rc7Po6wPofzrPoo6c6JuoRivz3mi+65/Ed9Ozt5fp0ujbjNd0pQECHjzym2Nb06IGQWOZBS4TeYCxYGVZkWqz6u3qF7D/4TqHIGL3hE9sqIXB3KQNGHlDfuIMCxStLJJD6ljKki2dsyTMwGZh+Qq8nEY/2lUJiCQNiUUmMD2sFokg8w61MnqZNdcWVLISMfDBeaByiSKEVlNQ0kTaMyZAFqjWJMbGqZVZtNklNDAkiLE7Nx9gVQL/Ef/4g0Pe+ax1F+RIZKhXWqHzQJBD4G4gG8HtwKHgKH5r1t/vrav7TS1JWiRUrSNtpjLSo2mWQmzBNBRg/8jXXlDaayDDzEWB5VfOQISl4QKNFNwGZ/wujyiUvzHsD4mBIlEk4eYXTnkLoWRYRGEfNwKzyJSTUBYkIx7IYMbdU122zhSmyo5n6mVIyOch4qf9XKeeFId74Hw+PI7B/VKqiam727wE7kQPkIh8hE6MR49D0nQ4TkKJ1Cergew4VsDaC9k2hbrrRqO38KwmJrz6hov8j+reG1sileOSOyirgsn5/h3caPJIn6ij5WAQWEe8ANpplfMDr3nt159LYoNmEHUpBSRRw2MwxKoyoo0WpC7ilr6qJiQkl7kt7GAkGALkbPToHCEijsChMlS4gJmYPznJIUHxcGohJIxgT1FNN7wPSfmekOif4zT836q1OvJjx46zpD7D0hgVwax5dFBhwzUQgCn+9EIZCCPPz93qn3zJ1U/F0k0xiIKL/NXcRNKMWaFJsKMLUwEkjIT6KKj1NGJuJis4SV2hzEkdIZEVdKiKoIQ2xQVbRUECQhIf2jogtJ9nWIvq5ZceFnMdAx0qZAdMfOnZxNyFfPt6Yw05fFy+Dwv1Nc0CNI55VPOOWteDe7bho7d0IY13PNnRzXV+74+KI3vXUk9sKJAVIfRkPOYVfkZCsEClIt1qFypcWJpQWY36H8q9BRn3H0BmL6Cj1wIEB4+vaaQOCHsEgLqFz/JHfv6/h/3f7erJZTMpAaWUtqVFO3tNP/z8PoDL4vP+jT/KB5s8sYel4AnIt6TqbRMgs5Hijk9OpDtgSaoEgGRhMKdndL89yjOvXer/k+XecsndOiK7rjiZL7yjCM0IZlMASAe9QP0FgSJDFUEcxRa9iuu9N4tUaL4lrru8V4erk7umSJZ12sXC7NYp3aLnFe66QKiePjeUs8zXtkU3a9ebC6TqdzO27ly7p8/Hv493JteLJ71Ta62RKRkRzVMgqzv/vQwRhyN48HWaqNkoPi9ueap/6/263zxX5Z6IrcPKEdpGBzUOpKqCkIhyCLUOS9Y8HICMk6jIsAQDrPnMdVBkwY/HLz+nUPZPR+b+hpf5WLf7C/1mzZVoIlFwJBhFr5/RjMM3kyLsO1dUmqh0XPmU9sT2ZVIc0Hr6/ORd1pUGZELlqRjCQSRO6VIxxMRqqsintxVxxF7GVNEMFl4WI6EQhD/AjgYu82Gvk/rsuyiHY47YBgYELC+0wGHM7dLAs+LHVYYMtbo+w8DxNA791DGQmkkpcrTqD3VkeiGs7Xq7Q8wGUDk115ECvxmwLchyUTtKA6vV2fXOe8l9zx22VpJls2xCrPWX9NjWmbb+kUoSKLFQih4G+KOUQaYOBCJg2aWgtqDWiLQoWGivNca8g6tc73f0kHdNi8/hGRfWYwgh0IxKpU2OnYfW9RIVlGRufRQyn02adDfzq3by8OvlgccrRHVg+4Fa8ZlXb+XkyNieHThrorErdYXMkVOkW+DD2r15htOO7hGWnBRQWlXwzuu47CNO4H6K4gP75K4IpkFZE61dykke1pIMKDl+BIEyfGenzyZ29MMOQfQtlTOGEgFBrWnx3u9MLiCZ0Ps+c6izyHfU9dI4SHNOtP5kmya/r/u1+fZKPyrkEu7uTdLl3UQ02kulFF1W5aubUbJTWxcncmFc7S1ZaPRTbZqPEpx5sBsBPR1YGwwTsCQIBFM20tTWWbaGoGt4Hsol5FqY2Tou1nWdpVOVZuhCD1d2TlCHHMrd3CHAL7HX571sxE3B19Yp90E3COwcldehQMhvORYYmGR85yLeqHoqjwMzlEzx8pDueqkPUlqgdsC4PacyA9DoENiy3RWhKUX+6IoFJnoGTaIWj2GG4apXM48PbDf750xz6LSywuVb9ly1OcjE7ZnJDmRsNdVti5kNUDEGReLSeTzDjzHLTpr/BFFFnUcIXY9XLPfhNCALHaR+Rjz7c69c4RJAqECVUHy8GhuLSq1QqFTwLmCeYF06AzD9EK0Cwq9WhhrH8K0PAbSLRpUxFtm1UFeTdKVrKM/QIGYJ3UKpLFTqy2flVVFiGMBUkM2dlqYYSFAkbsauqtZdVKvFhdJUuUhk4XBgogQ1lZlmFqLG6uBQ0VaXjeTeF4rggmst7+eem9IajkjqCuHYUKVLRepEzVmjWVESlFgtDYI1aNVdBcyRJExCwVGLd3lghC9aqEHbYh26iRG6KSu2BQ5RD7pILdZ3cNN7VpkJIFEQwRAuJLpoRFVEMQIkxVCXTWhsSLqyBAVDpMaSB6TLI7Xc9le4Lu3usfs57VMpeUVzjtWlm9TV9fKuNWNpUxxiZZGnHJo1ITGKRZDgpMUe84xJSbjXD2FUEj5YYnRZPEpjPGeZYfzbokOq1Y2oW2z8K1y8XMmuW+Fbmi1Xk9NrygoOL6itXuMzMiSKGEHkOi5gYXGC5NFTSGRgrb62aWXtmWmsNVptvuNs4eC14w9RsDSLGLIkgQiWZPWQaIlTUUVVH7tDTIyzQrqiDJIRknlwUPUdd8eURiuRftqc/jgSZboncqVVhjsAbEfKZDevNXSRDESiKGcaYFGwpUsxSD45UpgiZMoyHCRSEKhCQhMI0StsKjSLhibVo+05mG3SSWOCwac6ZMahhKxq6WTCVqwsskUySiUaKjaNJjY00lGDAkEIAZEUsgrTVLbxBsQrQTd9TgfvqOd4iyK9W13UqKqNwUZJEEdAddIMI4z9PTU+yjgf/ZrJ/JzuWXqQn0froqqV5/t/c868rJMiiAQCIHKAt8XlADKhtOfk4eKGQfwYkfMvLaSKsnSwYkAIlbjr6UqPyUHx3e87vRgwSyHmhZe5bokCCh3kSEQUkWEe6VAfND5evN26BZk/XI5DkFmqSUQ2FZRbq5V/dlzJNWPatX5+qsH4J+jyEDuHxCNQoo7bIUUHYUlSJUCMBKuhzLzMjDaVRKVKIgWxG/mgzNS8ryazZmjUtVpabLS1o2slo1JajFhzJbq9p1BiQISotUCQaaQpKWqUtj3mDFeXa+PXr16TRmeOaMTCVKUGKZBQbNjz6JQzjKOsmpDLlaHVHXtGCbibn0Wlh6jSp7Tqwj6Ihjz1cSqo0hUQf8wkhCHxfkmlWt5M/nE4LR9J/fuyuwkCEJGmG0CVFXSrFdfjI4efunja/LnpZ8WMvkwFrrd+dbe226cxZT3hg9wH9xUslLPyjQcGG07x4NUOFTuv4p6SeXHiUX7TWWH04v5Zi2GvNssNnN8IEkYHLioZpkHa2DkiZgfanaRJAAifOv+gkgaz6vLE8spLMsFDMnO1lSalL4rfjzKHcG1HRUeyCHccTipyQ3bEF/kP3CB6D7XAhwOl8SMEhvKARpgHQplChgSQhEjAjBHB+/0JHM6jJOWjmsDJ6oVMZLrQGzqAyscJRlIMQn5Ia3IwqP8ypI/lhsUWj3ZIxLcuTF4KljprxVc6ltddXd1urmaRZVjVWydrEjb8mEYVVSRvYbR/A4tHJQgdsLCKuoE6IL7FDUa6EgSu5kiNWA1mI3l3kejaH9ex1Du1SBohnvh0Gyi4oQgkhknIyfyTzdoHX4ESOo0HYWWdPIEykFPPyA2EHSLC6TJ0xm31oGSuQY3WVJSZdtljggkSBhgEn7YJeKAuN0FVFcRD1RKhCJligyUmzTyai5qd2vZeS89FReMZUlKvdGLT88N5tOyRh0x06HzA7Q+cRf9CDCDRgpxloHYQoLAtivhl/nkjc3DgsmF4Tb9nuOqthbIj9IJ+FQH2USGCohtPdRDiZk93vokKn7vp+af+2D5IaRO775cLgRqLTItraxGLqy0tyj9P1yfsfajMMGZBD9nLwguA79IiHmYieuEIi3FDsP8KADEVMJmxHIv0J3fSQiwdguohMpIXak2rlWcLr9p+defF/hv8UmSRIQiwZAgRSnz7RkHzwKImYePoST/3IV2EYFA7rNiu3cZFiBYT530qAbgT3LpxPQfz/TYSCmISHBppoh4nzmP4zFwkqIz7WkqKssK/S0pfkPf8toVD4thVT8eYB3cJIemJkYX6IkghRZ5DyniUFVVaFn13UgVKBuA4tFC1MUlOfRCfWaVFimkIZDqMfd1/nMiHhH2wMFWgyfjHNmq5lCNuMaq44vQbrab2Pqzylg2ds3kYrwi1HgdWSps0Z28Dk6q7JY4JjhLwhqZ+2U/V+xR/BH3WfoUwVC9h9wGOJwa09unyEgEYQMHI8gkE+cssiONyV6oez9YV+XD6ZDo1VkfbtK9UkJeXf8c3kemHdTCsGImQKQigVcuLqMzvsuPWbLrqxdnCFBsQ1LXCHeKdKPeyEAjI9ryEf5BGgweALXkgpCagh0yTWjIXQ5Jcc+gbNE3u3Vyh+T7OdvbDKJZ/waOiHvO3K4R694dzsp3l5i9k9OD1Q9zudKqcJuaF/r4tHSSpQFMHF7DsKWQMBBe6ZIOFHDwHVR/NCTIOjk/G027lhs6W2rbBaLUKUSzKxtSlbGsaRWtSExUszbDUWJNJo/y/i979p/T7r+fDzHTiXXTD+Wyy6hKmTA/X5Xq6KBaJOqiiyFWTm5kOsoOhI8ONBghroGg9BHJy8v7cFsefe1NCllykhL/J/anFpNFRL/BxJCUskJGlEnxyd/lp16iT6xiZh6KEmcnKrAQb0qTQshq23RaSIhqsOzOyOytCrtzctpbp0tuxA/zV2ho/6ZMRxYhrEVzB2jOFbXVizKaQsut69rRQVBpgEFhB4kWK0I0d2FJX+08vX19fsUtLBO4HETa2lNLs2yk3TZTF61b1v8v6/CaVur5SF0wohWAkCWrhEMb0KWE1lAQi0wSZhjyjDzzERcg+HLL0AZBUTL2j/Cj5nGJ5JoJBgyDIT4Q+N76MTZCp3zTKChD+UGOtZngsNFHbxPqFoXY6fVmnmLC/bOpvIh7WTfqv1wvBTyngP74EJAJ2r5fjLQyHVy6LU5yXwskJE3EZz5l16zfC8M14sZB2i4DtPN5U5VS5XPc3Xx5NUVVEfomJMJymjiZjCyhl5IaRGiEjCQId0oxSSn1eSnaXXnnljSLLeOm6bp69n2zbfcrltzvvBuoyxKK1LmpkLZItbu2NcxpddmUlobzt5K8QxDiiqoelVqTEepAoe+h6LBfflSlZTFopcFqmLKMQalSglR0LAuJeVFODJejPAn78YjPG+KGLcGrsvwXeboxpeDNxM87w5xAzSClEM4GUGyzDaSvHqV1d0LQ0ubDhlGJJYw7oIFjdYCMoIeSndcbLG8UKaYhB5VXBiZ8Pt31N5VN6UrryYnRTaUaf1Ff5pUf2iMImge9E/EgCGgAeG56eNHZJMcj58ZfL1a03AbXm9YXANwZJ2C0nL8BTAIaEIMImCu4klkgDqJRCQh7k258PX4Peia87TpDwDwZWSCtkUrDLiaNDEOfAurEWrjSRlwbFAlEbLpuDBQgJAyCExSlR853yO4IaKwIO6qqu8WjQp9o2x5C+agC5dFEi0MD7Dyp0gGQ9fyJ3dODiRejzySKQgvLkUnNlZayefd3k3khkTaaw2ak5xPQTqAy6vDFJIfJCeqyw9lND6Sny7K7DclHx6VD10NRSGkogB31eNejZHDpoFEjsicDIORQd5KP3qYTJz5/jzSH1TE9ExRZHnJnFat2zNmSlzGTFxW2Ge8M1hlUptkns7MT2/mrOSy/WuGoa5zJt9Rtl6qrAMiTYEB82o89d5gqwujfj7IFVQUwNsMMjGeAa7dNtc4v6YU98OHfhDxV2EVCNYnKAcJGSMlI+WPz7mX2YVutMIKmihLF7HIcQfSB264i8bb/cy7VM+NjERIVMGnkn6UDtf3qKNNNtJ1TRghxyOtKr+cv+IPjrdGxF9wJ7Wg7T0PsCg9KIvxhDEy6LMs190L8kE/o2nG8j9u9zxMmVdZiW1bYqxMlJhSGwUEMFCBsVD5UQ/9GEnmP3aB9wwNQBtF2xYbV+eKEGKMg/EjgpAg/t+sE4gtsbGWSSLQs3BnKVP8c1g7QYaooVCMVCSEB5fAEf52HJ+nyanjJPP4PmvEMSu3cHeqp0n6en3B3nScXaG2dethP7NSdxH6RsrWykq0tFhatk0lreedhJmgnreby7+5dJ6SS3LueeFbs25cWbUrr1ct1pSZiCiT3ukNzayWWNqkzMS1tFtzWupXddV20trJbEaR3Rbup2jWxtaxGddUrGSstmLGJYUwWUwixan7aiMFVCywsNT9D9slQsJaS0hsOHvafpivOESDcfUUl3TB7Sit4bOJE9mOBwJMFUVU5XYcQ43cJAyI04UKojCFwh+2/vCf5c/sRfPgn9m+5/uXXk4fsPqzFr2cs/TdkmtssjCuM3FtJiHVlKu7pRXL5v/q+2dft+7Rg9m7TzHxdGvFQy5BRDbQbLK104naT9vgK0odfdq0eq1hbKIq9es4Zmj53Km9uki0V8p9V+tjGrCp+F0SZ/Yl0mWQ+3L7pXfvqA9hkSq60yigxGpsO2zNQ0y2/sNMlTXkLpiq12S3dqORmZsw18ZaPQvaDwtiUN6Nh6GOtc8Q6reG01VRUGtGruoKJCiqUqAIIRS8DOQGXCscbfaXY2nixWnPLY3MMtd5g90DqJ+UJqcDrQVEypYWi3XwVLDpGmKNK8DKf2aaW1fxPXdnBysujqlWXUFyswwbrPOXWjQkYzTzfxh6/gJK6sjS0+cLbt/HhnWOV7PEPbSJ9fuPXmDVcXPNJDSnG1TRu91NqWypqv0r3G2CPB7mbFVQZuq1ZZodPgup4W+N7mm72KVC/yEjR89+mrpVEPv0LCcWLVSadHQqPmu9RAYv13HLGSratXVZjwZTGML0p/F7Q5NmMFAKyFky3eeISMRSzJIMUo86KfPzwCKhB1fNYxHWjPrAH04DCf8AXli3zaR+ZNTGabtTR2WvGrW71tWNPKK9RH8fk/3a0NJtp6Ny0WcWhswgUNEMnYmvXyN2GEVcnorUkhzr8GxjffubFa6L4iJ41hSe/vNDBqNoUECG/3R3usvHXlRI4gHKC07mOmnPtMZm9/qiHm95r69oe42GBnZRZsrq5dScHu8tVSVpnoLdiSuCjwpJ0IvHf7GhKSnQlYSWtMMlM+ipCvunc6ObwR8SYkLFSSTpL4fgd9XWb5ohxMVIQlWdzN2I5qQ9mn3qw+SMXWfD5e2lZrte95y9aSXm5O6Oo9HCLoFl3odWkiIWJBGYITJBro4n2H6WE35hqO4IMB2Y+8mBSPNGt3O1XD87HzTL3/ZZ2GgbjnhPb0FHllw/LHNdv1WSSKUCQ3aFDkHH3iqq8eRlO6qkNcDCXYqExViG0MdoQ3BwVGEHC8REH5K+Gi6LodEoiGdvddSTFSmZKvi7vV3amXx3JIjLyArrZRHCGmRlchiK1FMTA4BzsCoXKzWGQEWgaGg1nveRTIh1dFFt0He+vV2kDWcqd5KN2cslan85yK+shoaBSbyEAR6qTfY0/DFEl9d3cajULI1Vaz/P9dJ7et1ntYyTd1cXKZb0nTdUkDgxoSapITY3TsZUT+gb/xDNCZlVWgiFf0UrtF0RFRpaGNIQkncC1bkHTY8X4pVzWr0rEkY5KPzY2VZkNTFHEQuwItQt3dVFUFUX10XWXcGmU1UykpMBHEH03k2SSMxdlzHYB4vedMTfnZ2j09UoRx3vZGEBXXHJ2QoXIHUZRCQoKarw9FbpDz2eObpM5ndWtrCef52Jsv80JPaT3bqxgOo6nUukS2RWi1OB5ygTokk7eGdQkfL45FzMqFEkZJGZVngSs8v98uQxMzTPIznToQhNNryE3RWERiWUszkiPEOOKKKgxgQLC1OtALgtDnSHSarwekTV/L0zVkbDwnDQxuQmRbkHrkJEiZMNsU/gG9ixvWbnJ1tSHmgXE8kCjs9ZR3HTWdNGUKR0rEsh4M1E2ik8/Qb0Hbg36xMHCppW6vRHTJRyWEkIMjICRigk+IU88r+161/zJet611kYrFymVEUkpRQsqBV84FSRJMhQpbQspSlh9ZfbCXGgxHtDOUBxilpImKXKTLO2o4IYi0SAM9eeLziHcklvO5udTWeTm8RNUMsGXWl1qEbrENWbUqStNUDBgGZF5FAOuPCy3HFqyElQrfTO+njDEJkh69XpNR1uMTVVGoLYOSGrMdi5629jbOit0gZuhxJJISx0NVSSHodXj2usy3Vc+UnvvV2I9dcl0n3fzvsfCyODicP7PuRvUkN9loz4hm1Pf7SvpAhr0J4SRNfIynLK6MJUC6OmGafZH67DW2GJIXZhcYVoDQFyMyHQGiHAGMjIrejP1Sp4w8gz0hOBNoMbePdjJmWwAX47gXoGg871QsI+EJxaKKTulkUPT/ECKQIIHqq3z6HPz/kZhiF4ESiaRHTHLTnkXYXEKYPKeTo9HGdHf15YyOlzrIxdk6tKuTKeQx7H4TTlr2/NcYaytkMfgVoi6Wrp21BYNHS13vHqXRaCmch8S9u9GlzKNn5qAdeuGoeQAVGCo3UeHrAt3l1z2iNnCaDKC9o1h/HoYiaQkqmisRlLtVZzmQRPwmubyG2EOnxDfYlM77hKMECJCCn62GGy2YaKXMwhMvJei5IsLp6OUGwXCBKTRRRjWAzXMH1dHJZFRtAePC11sxeHdrvzhN6aBjromVul41ok8VsN1qhM3zrowyueb2LXfheTHxknV7WPXxhc40vbPWsWSp53lEO+sKwyebNdlZouHKFrbL8UdQlCorxWQS31MbIVrMsT7UisRU6krxhoXcyNIUoVI4OOlWgxUOu76uC12ZgcVTphssIIK8TSjS4w+4C+hMGHNTDHhnJ+uz/mZaYwXMVWRv21jRTRiMIqpRASoIbRFUx169xogdFnGKcEN6blXSNiEkDHbhRBmUEDlsJjqjiqqNbdWYOldMZWJCMJWLFURq3QZSFbQxNC6R0qrkVnNVLhm0apFVBVXFiowMOteztrrMPc6L4ELVD0qUKf55IF3QRhi1M/uK8GSwxW++sPCxgVAjKf6vjY9guT0eIevV3kBkRKjUM3KzJErMSLws4EV51zTMFDlHU02srw5vWo36x7EOikzrumc3q+ITNo0KhUWWc0uYssdunOSTbZMmjN6WrKTapZjDVT8zbZVT2y1s0rCjd7ThzA7lKqp0UqVIq67WJpuLY10oXG62XWbfpSHh2qLL1bmE8Xr49ZZ28R8zreTbHreevWywjWRVky2nUVs3MhNkTYlNCFVUqqYEpiouUB2rciyrV0uZN6zRBYIJr+iR9xFUjmBiEUTAhxotuTMK3vXH5/vedcueVt189HkpODE8FiX1yauZGm+b8+ykMim9W9/f23m8oStbLGnE1umkujeRUo3bJvGmNksnE9mj9n6f4T5n4RvO48q+SH0WKttKWDJAOXP/x0jx3eo8vr54Myq1QwQ6WJzDMrKFROB1pmWRUp7VEgNh2CGQ3FD+D+eT9wd2edG9qpJahOI8NNJ23c/jgyXpTqekHDqNDWaKhmRQKIKOmhN9aqhBoXwHTlMbFRGQhcd0qBiVWqYvLuVKk83dd5rtXXbpqY2NgdLy7xJruvWyry8bemu7vMGoLRspqIRLG1stQ1prIGhtrA9jx0dZ69tsI+GZlLxK5UVAkxVBGEkoowRYI3TLQqEeW7LbgElQ0dtFdjjDwgEgK13dCo+c5RirYv2VlWmbfiFnAsLNK23jL3wb7Uw+9Xhkc/Xotr8ssvbjp299xvXxxV9S0X/BpiXGTMX134v+H6xpbar0wgQIwhAoGSij2TsypxkVbVEYF99UQMAEwxXvkjbGErwK6ZEgsHBwFjs6sFjNcnVYmMFWmjlJDs5HUbDM5gJQwA/NERoUqIiUTzxaQ1CoBqs0oxZZVKYEwf+dGEyxOtwKBnYo2KO/Abo15uznhyDKhdWzg+ECoNnblpeCJmAObzx3lMeBq6U2yzPAfOevxDRQ0DLQDj3WHFUUQkVRUm4qlCyTSCL696aPjztBAskmw8W4bMnGZP22Wzi6hqDMbK1GZjQTqMcVUREkcoip0AkRNCqUkkMWSqTfbNKlVWIbN9GKWbbLI1EMYhgW8JiyqI3TpVhcBrwNhv29h1/t5+MNJGq98EqZhcYxIU/oXvRgrTWmqS1CUT1I+xSepPvIkfoVH5bmXZ/SBu6M5Ag9kN8QXrgAbQDdR2ySSST4dRRgQkIoSFlVv66iQ1pmEr8KMW1+s8bhgux+/kzMhvrLbVtseVUYxVH5K0PYhSfKtJR7jqCvANW3bidtb2SYlwz9xvUdYQS1HbKLF8MzQ1wruDzKawTrwbIYKFJsUqWLTfC3iv7L/rX29f0LN611wHj9TEbyiPpFSJ+9TpDZP7lfo/M7k+g/kyOrx9VbpLYURqSQu5N2CWSip6D0esl0spNGDIIF7rtXdDElRwJUiqAkkC4qdvUqBaKSC0TAaIhskq4BEkooi4jMIQcOUocpCpWKU6qK37ezZrNaHvPAwEwESQaBafJVWTipSAV8icRN4PcGBcbpzQbBUuCkgaARPcRteYHXySzTf5a52BUCjv8pmVRCGlF+asEsPTs7OxBcBuTBi06Rx9ftVKTqWQnfCNr5FBz74G16a88ANcM+kIo7BIbLSitlnm9661dUxYokzItXvLlIOUKqqjHIYhik/zYQiJIiOPZqIh3EXixsIZCfPDUBq8g4yROIjvRD8rtAK3E5ag2InlijAhIsPsKVHIOdQtiZ9ywf3e/gn8do2kcHUMif3nE85irakqrjGVMZiKzJPzYn2LD/RUoQND7DJA9cj8KlB8lWPq9dMTzykkH5s6+T1WWGyjIheoklUVi6+zlzSLCLcxxsZPbJB9LJ/KMExZtg5kTZPEDtALvRgHuCEYpg1Cr5GKAeS8yAaq8rAJLWDgqyRDuXCwNfZ11Nt313ZbXCiFHw/oO4yygdF2F52UFN1Uzu4xCPAxuFF/bCcsDzBOZNXmrQnaU0R8TeekdEiw6eiucDkEUMnYda26onmC9xyfT+qeqj4ugcwAzh/UUtSSYOLtyXOXdbu686rojYoyaRkSCR0gMFrJoCkipFG2FyDPWcXd2buX4EEIQ1gmrMr9Xjaef4uq5m14ndR+ef2TdP5x7Sw/qFC2E5cfwP4vCl9bD86SO6hoPqTcO6qoqqPGFSRGEZALGoZYswxDI9Z+mzSg4/bZ/neWNV4v4lcSDqPRRkEV8JCqSTkk+/7aPswGSceJk7JEY6dwh0BgcIHBjud0G12Ylc6qBYVAkEkeOs9wWOrXpRZ+JEM2BqGk0WxEYnx++/qk6PNh+y/xnc7P5DtvIaO5hj+mtUrCxMjEh+y803VE2L+c8Yj4kf1/Q/m/m7r7+8Qp/Vk6Wt3KtFbUTXpQHwoYkPYPBR4pQFkZqmWlLlzMFLVxsp5ELR/2EMXSRIHn+mw2hrqu06zzhweXHh5PM5SUsfGQkDFO1hdScizQ1YyDRDAW2HpYnr0lE1s1Sm2Foq95q1y9llsh1QGMkkAkVCQHER9r5q3WNCfqhZ97KpM4lQrVV9j/NGwYDLW/v9BlWI6O+n8k4dt5tiPyiP0G5KC9uudeDNvQq6/SOofcbtA1wMaqz2PwInKGOMpyLP2G9cXWubCUtwdI0Zc9tkiZEKgSYmYYplkKSMttgN6EGDZ2n6ZqGjZKdukqpex0lTsylV3MbYzTnqbzeb2j00X7psbiyevzJgfFWjkiex/PD0+xPRoA+qIr2c0frgEgcdfN6Pqsie20SrETIo+87fp9nSRNj+49arqIgc/X2HP0dny2duD1W/FCTwHgYLnfQEIf5R+u6fjjqgTifoDGDI/MJ+er/STVE2RcTQNMAOIEpH2inp9h6Kgyn5v/H/0x/6f+voUrT9JXJc+f1pmh2sYuv5vuyWujIf4yrLYl+JYwLsP+H/r3eUg9fAmFRf/6h/uPo+T/Of/4u5IpwoSBMnaQAA'))) \ No newline at end of file diff --git a/irlc/project2/r2d2.py b/irlc/project2/r2d2.py new file mode 100644 index 0000000..624158b --- /dev/null +++ b/irlc/project2/r2d2.py @@ -0,0 +1,210 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import time +import numpy as np +import sympy as sym +import matplotlib.pyplot as plt +from gymnasium.spaces import Box +# matplotlib.use('Qt5Agg') This line may be useful if you are having matplotlib problems on Linux. +from irlc.ex04.discrete_control_model import DiscreteControlModel +from irlc.ex04.control_environment import ControlEnvironment +from irlc.ex03.control_model import ControlModel +from irlc.ex03.control_cost import SymbolicQRCost +from irlc.ex05.direct_agent import DirectAgent +from irlc.ex05.direct import get_opts, guess +from irlc.ex07.linearization_agent import LinearizationAgent +from irlc.project2.utils import R2D2Viewer +from irlc import Agent, train, plot_trajectory, savepdf + +dt = 0.05 # Time discretization Delta +Tmax = 5 # Total simulation time (in all instances). This means that N = Tmax/dt = 100. +x22 = (2, 2, np.pi / 2) # Where we want to drive to: x_target + +class R2D2Model(ControlModel): # This may help you get started. + state_labels = ["$x$", "$y$", r"$\gamma$"] + action_labels = ["Cart velocity $v$", r'Yaw rate $\omega$'] # Define constants as needed here (look at other environments); Note there is an easy way to add labels! + + def __init__(self, x_target=(2,2,np.pi/2), Q0=1.): # This constructor is one possible choice. + # Q0: The Q-matrix for the cF-term in the cost function (see problem description) + # x_target: The state we will drive towards. + self.x_target = np.asarray(x_target) + self.Q0 = Q0 + self.Tmax = 5 # Plan for a maximum of 5 seconds. + # Set up a variable for rendering (optional) and call superclass. + self.viewer = None + super().__init__() + + def get_cost(self) -> SymbolicQRCost: + # The cost function uses self.Q0 to define the appropriate cost. It has the same meaning as the lecture description + cost = SymbolicQRCost(Q=np.zeros(3), R=np.eye(2)) + cost += cost.goal_seeking_cost(x_target=self.x_target)*self.Q0 + return cost + + def tF_bound(self) -> Box: + return Box(self.Tmax, self.Tmax, shape=(1,)) + + def x0_bound(self) -> Box: + return Box(0, 0, shape=(self.state_size,)) + + def xF_bound(self) -> Box: + # TODO: 1 lines missing. + raise NotImplementedError("Complete this function to specify the target of R2D2.") + + # TODO: 3 lines missing. + raise NotImplementedError("Complete model dynamics here.") + + """ These are two helper functions. They add rendering functionality so you can eventually use the environment as + + > env = R2D2Environment(render_mode='human') + + and see a small animation. + """ + def close(self): + if self.viewer is not None: + self.viewer.close() + + def render(self, x, render_mode="human"): + if self.viewer is None: + self.viewer = R2D2Viewer(x_target=self.x_target) # Target is the red cross. + self.viewer.update(x) + time.sleep(0.05) + return self.viewer.blit(render_mode=render_mode) + + +class R2D2Environment(ControlEnvironment): + def __init__(self, Tmax=Tmax, Q0=0., x_target=x22, dt=None, render_mode=None): + assert dt is not None, "Remember to specify the discretization time!" + model = R2D2Model(Q0=Q0, x_target=x_target) # Create an R2D2 ControlModel with the given parameters. + dmodel = DiscreteControlModel(model, dt=dt) # Create a discrete version of the R2D2 ControlModel + super().__init__(dmodel, Tmax=Tmax, render_mode=render_mode) + +# TODO: 9 lines missing. +raise NotImplementedError("Your code here.") + +def f_euler(x : np.ndarray, u : np.ndarray, Delta=0.05) -> np.ndarray: + """ Solve Problem 9. The function should compute + > x_next = f_k(x, u) + """ + # TODO: 1 lines missing. + raise NotImplementedError("return next state") + return x_next + +def linearize(x_bar, u_bar, Delta=0.05): + """ Linearize R2D2's dynamics around the two vectors x_bar, u_bar + and return A, B, d so that + + x_{k+1} = A x_k + B u_k + d (approximately). + + The function should return linearization matrices A, B and d. + """ + # Create A, B, d as numpy ndarrays. + # TODO: 4 lines missing. + raise NotImplementedError("Insert your solution and remove this error.") + return A, B, d + +def drive_to_linearization(x_target, plot=True): + """ + Plan in a R2D2 model with specific value of x_target (in the cost function). We use Q0=1.0. + + this function will linearize the dynamics around xbar=0, ubar=0 to get a linear approximation of the model, + and then use that to plan on a horizon of N=50 steps to get a control law (L_0, l_0). This is then applied + to generate actions. + + Plot is an optional parameter to control plotting. the plot_trajectory(trajectory, env) method may be useful. + + The function should return the states visited as a (samples x state-dimensions) matrix, i.e. same format + as the default output of trajectories when you use train(...). + + Hints: + * The control method is identical to one we have seen in the exercises/notes. You can re-purpose the code from that week. + * Remember to set Q0=1 + """ + # TODO: 7 lines missing. + raise NotImplementedError("Implement function body") + return traj[0].state + +def drive_to_direct(x_target, plot=False): + """ + Optimal planning in the R2D2 model with specific value of x_target using the direct method. + Remember that for this problem we set Q0=0, and implement x_target as an end-point constraint (see examples from exercises). + + Plot is an optional parameter to control plotting, and to (optionally) visualize the environment using code such as:: + + env = R2D2Environment(..., render_mode='human' if plot else None) + + For making the actual plot, the plot_trajectory(trajectory, env) method may be useful (see examples from exercises to see how labels can be specified) + + The function should return the states visited as a (samples x state-dimensions) matrix, i.e. same format + as the default output of trajectories when you use train(...). + + Hints: + * The control method (Direct method) is identical to what we did in the exercises, but you have to specify the options + to implement the correct grid-refinement of N=10, N=20 and N=40. + * Remember to set Q0=0. + """ + # TODO: 10 lines missing. + raise NotImplementedError("Implement function body") + return traj[0].state + +def drive_to_mpc(x_target, plot=True) -> np.ndarray: + """ + Plan in a R2D2 model with specific value of x_target (in the cost function) using iterative MPC (see problem text). + Use Q0 = 1. in the cost function (see the R2D2 model class) + + Plot is an optional parameter to control plotting. the plot_trajectory(trajectory, env) method may be useful. + + The function should return the states visited as a (samples x state-dimensions) matrix, i.e. same format + as the default output of trajectories when you use train(...). + + Hints: + * The control method is *nearly* identical to the linearization control method. Think about the differences, + and how a solution to one can be used in another. + * A bit more specific: Linearization is handled similarly to the LinearizationAgent, however, we need to update + (in each step) the xbar/ubar states/actions we are linearizing about, and then just use the immediate action computed + by the linearization agent. + * My approach was to implement a variant of the LinearizationAgent. + """ + # TODO: 6 lines missing. + raise NotImplementedError("Implement function body") + return traj[0].state + +if __name__ == "__main__": + r2d2 = R2D2Model() + print(r2d2) # This will print out details of your R2D2 model. + + # Check Problem 10 + x = np.asarray( [0, 0, 0] ) + u = np.asarray( [1,0]) + print("x_k =", x, "u_k =", u, "x_{k+1} =", f_euler(x, u, dt)) + + A,B,d = linearize(x_bar=x, u_bar=u, Delta=dt) + print("x_{k+1} ~ A x_k + B u_k + d") + print("A:", A) + print("B:", B) + print("d:", d) + + # Test the simple linearization method (Problem 12) + states = drive_to_direct(x22, plot=True) + savepdf('r2d2_direct') + plt.show() + # Build plot assuming that states is in the format (samples x coordinates-of-state). + plt.plot(states[:,0], states[:,1], 'k-', label="R2D2's (x, y) trajectory") + plt.legend() + plt.xlabel("x") + plt.ylabel("y") + savepdf('r2d2_direct_B') + plt.show() + + # Test the simple linearization method (Problem 13) + drive_to_linearization((2,0,0), plot=True) + savepdf('r2d2_linearization_1') + plt.show() + + drive_to_linearization(x22, plot=True) + savepdf('r2d2_linearization_2') + plt.show() + + # Test iterative LQR (Problem 14) + state = drive_to_mpc(x22, plot=True) + print(state[-1]) + savepdf('r2d2_iterative_1') + plt.show() diff --git a/irlc/project2/unitgrade_data/R2D2Direct.pkl b/irlc/project2/unitgrade_data/R2D2Direct.pkl new file mode 100644 index 0000000000000000000000000000000000000000..eb3973b93e24e5cfcc9b5ca7c2289a3a1d3a71e0 GIT binary patch literal 17340 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 literal 0 HcmV?d00001 diff --git a/irlc/project2/unitgrade_data/R2D2Linearization.pkl b/irlc/project2/unitgrade_data/R2D2Linearization.pkl new file mode 100644 index 0000000000000000000000000000000000000000..1977f1e9fe2e3c37bbcd85d178b77df83561e8ed GIT binary patch literal 10767 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 literal 0 HcmV?d00001 diff --git a/irlc/project2/unitgrade_data/R2D2Problem15.pkl b/irlc/project2/unitgrade_data/R2D2Problem15.pkl new file mode 100644 index 0000000000000000000000000000000000000000..ba6d982fc7ad02f136ba25a1dfa8984db6233555 GIT binary patch literal 5640 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 Z8puZvMS*;g!I%LO8f_rcuz_5v2LOtMvfTgx literal 0 HcmV?d00001 diff --git a/irlc/project2/unitgrade_data/R2D2_MPC.pkl b/irlc/project2/unitgrade_data/R2D2_MPC.pkl new file mode 100644 index 0000000000000000000000000000000000000000..b3670d7e508ed0fda0dd3ecd811d09893c3234e8 GIT binary patch literal 10904 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 S%FzMOoK(=*IaLNcOZ5P>yVENG literal 0 HcmV?d00001 diff --git a/irlc/project2/unitgrade_data/YodaProblem1.pkl b/irlc/project2/unitgrade_data/YodaProblem1.pkl new file mode 100644 index 0000000000000000000000000000000000000000..e8d95ca14e3032826dca52c996e197de4ff290d5 GIT binary patch literal 1139 zcmZo*nVP}E00y;FG<tX<^HUN7it>|kQgaQb^l%lYmV_2K=Oh*vPidRd!%~u&n>wX! zio3ni4zQLC#vYE6)Z&tO$9N}@0=C5B;?$y&DQ#0~r)YRH^oZt_<`z`yCFd8V>gAT^ zlw>9r6(v?q>EVelN=?qsD=sN2O)i--c}fo}SmBf&_Pi8`lF3uN8Cs_}GbT-GpAs}h z!<*5Y$(yNdN(NsKYf4FFK`KZSQ<}w;&JKt?a}T4<6hA*dumAu5{|6J^3?);NI-M23 z4uumR?9ZM#bLLEs#{rnol#(e)-i#T%83G_1GlU@Kf$U>!o01{b=_~+K`442aeZB)& z2NO0OAQwtuv2#g*E!XwM#;A5OV>1EWPKezu5Ib40>A+>@ZSys?hi@sO+R2K|1av!} zn8dG6Z&!fW$%ah_E;~U1^uOK`)lPP7CZOAi61E)Jbl|cx4GdIJ?c~H}0=k_jVatV0 z2QE9i^>)2j)GdT+CpR_|(CtJH+tLii47Ro@87!b2)yS9tat}nPha)+^EVU>x9hBQ@ zr}T(s7Ud-C7Zl}Zr6!jc=~w2bB<dAZPN|*JqnVPLrjVWr&Vd@~3RVhfIr)htIto5; zR<5mqo}s3d!W3_=o>~P31%)CdB_##t{M>@ll2nC~j8uh^@_dEd#FC=S<kVsXM;!$x z1&!j=RE3zL)B>aGLPI^nT1|zF)S^^{#Jm)RqSTVoqCAkkTs<z3aUmJ02;IdQ`K382 c3Q4I7;0&z*&CbPo3Q9^!Q`)8!7nkY*0Q3}C&Hw-a literal 0 HcmV?d00001 diff --git a/irlc/project2/unitgrade_data/YodaProblem2.pkl b/irlc/project2/unitgrade_data/YodaProblem2.pkl new file mode 100644 index 0000000000000000000000000000000000000000..472b8f3f9d46e309fb44636e16cab8ed585b5894 GIT binary patch literal 1991 zcmZo*nYxFa0Ss!VX!P(z=BFeE6y+!7q~;n;>ES9)EeS1f&PgmTp3*j@hovMlH+4$e z6nA^R17Ix~j6Linsl_Gnjs_rkw#4G%)S{9pZBuHeXm~U9h~|~%7F6mb=NF~w<(B4@ zWF{6BC00)9;fXIwP0r6NE-5NaE}1fUN)Ibo;glZsycCF%$y2-;TBkTOCQWId5;R4_ zo6(!eo2hL|244?rN=aowDo7Jkn#GjP4v0K+52MW#KR-XO|NsC02NT{5B~y|*ofW|D zWcXk|YbFTnv`+&AA&C1KKG;twnUdtqn8BMN0J1Sd2x1=0KB-P;1@*P=d%nMVVc+rV zZP~PS+wBE;s#R-P1rMk}#la>p;WGi%4JV;)P(pPBGd>d(#3MY~El=Ce@Xfe$rQnc# z=liRF44b45z{J6BV8LessvBV8z=Y}sR(vLWyY+C>wd6PUOw~5^4hwhKXH^tOKikZB z045H00~<aQP~89v2ei0g$7h0_l5O6-_(%48*1hTbaPz3Wj&;dd&rJRUFmbROIPjT( z>V}>65WWa%IB?=KLGhwa)tlfK_CNn0O#Rxj-Tqg9{r3CuLI+^tU^j5#GXY{JEKQz- zx<Lii4cz!l*iz8a_U-Fo`#qxi+tVH%wEsHMvd-Xx^no2vaj+YB@R@+>23R<-pt^w< zp9ulA(QF!`Z|tMyUDbTsy~BRn<8>Z^y37asq2gdS@ZmE7)eW$4K#L20d?s|WZROYS zdT8Hc%g(c^>!`ixiqxASR|F39K*d3BD9vEZU~8L_!2&9{npwdm0z{~XBRRh;wJ0$i zRH)TX=@HE=%1PEQD9X=DO)fFgugp(L)GMe26=pq}DXD1+>8U00j`2<!=?Yc~X*v0c zB{~W|a8|CZfu5nJmBJKnuAW*21qFp7B_$;V=ltA)(vnn#l8jV^lJb0o+{BWi%;eN! z1xFnPCk2h-)KrC-qSOMT>Ow<3!&*&+jMSo3g~YrRg`(7w(xN<&zFa*nkZ~aysR-T0 z8Tq9-DGEuc3gD7c0a|Vr>nSKHDS?V&dysn_<5Np>Qj3t>>w|E)OKMI@B8;o4plhd) zSD*(q2jmOUo_>(ED87g($;?Sft#+)9H&D=U1(~gol3AQwlv<Kml~|IQpQov#faE13 zJ;Pc(F0ku8GV@A`t-wr>samkGR7g(DQz%F+%1A6IRwzy^OI4`MFI7lX$jQu0Rmd*_ zg&D;AP=DD#{gp|cr{sIifviXIlq1+P6$SZusd*)ti8%zlgu_Rm2r4c}O$Hf}R+^U# z3J-<Uih^8?2u+1#NIED6MJOa1D?oB^J5%E#^b~?qAqgcXHMyj;C{-aZza+I-AuYd1 ZAveD$RUtDkEx#xi9L~sLQd(T92LLH(v*G{% literal 0 HcmV?d00001 diff --git a/irlc/project2/unitgrade_data/YodaProblem3.pkl b/irlc/project2/unitgrade_data/YodaProblem3.pkl new file mode 100644 index 0000000000000000000000000000000000000000..7cfd67e961d93d87a739c9b7d69d5c97da114a0b GIT binary patch literal 3483 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 literal 0 HcmV?d00001 diff --git a/irlc/project2/unitgrade_data/YodaProblem6.pkl b/irlc/project2/unitgrade_data/YodaProblem6.pkl new file mode 100644 index 0000000000000000000000000000000000000000..9978ddfe8f3a4fe1b09c0b73a0025163862b742d GIT binary patch literal 635 zcmZo*nOeZa00y;FG<tX<^HUN7it>|kQgh9w^l%lYmV_2K=Oh*vPidRd!%~u&n>wX! zin~3>0<e}0#vb94)Z&u(3cvW&(wx+y_@w;OycCdHw#4G%)S{9pZBuHeXm~TY+yAk= zb+vo3n>VAo1Iw)Y`*&rfcr&>>2&=r7SmvSa&Ft==t?zry_{>9Z7I*uvmm8dB#*})q zy4(M{u^{l(w(H((?hdRT{oU=UkG<L59Ypfxc{Kjc^yYB4|C@4Ej(6iRZ%%gyHtzY? zx?DrNx!fH@PTbLRvTXF`c6ZR%^>R%PbN1$OxBnIs+En}Tk~gor{qN6Nk7e`Ry!qT6 z*cQx7tG7Pu&F}6Y24R+FFlMl|P03&Z`89tA)UP0+9**Svvecr)bWk|dPU#WNEXqmN zFDS~-N=+^?(yz=<Nz^N-oKicb$1^20O`*aM5+ab$(MVUYQb^0mPb|?<@PRX3QgccY z;XFSDD}~Iw5={kNJBU&%g(==<J*O2E6cmb-l#~>l^K%PIOHvg|3kp(;6u{xFke{be zQxWf1qfnlanx{}&oSB!d;0lTlg_O+V<f7D)%&Nqa%=|nZh2qpyg_xq$0;B3eBR$hv zJuZ;BAsML(X{C9|ASDXL8Tq9-DGFJo#U%<wsU@XFc?yXNd8N5YsYQBRVC5c}c_qbG zU?xbnmO@BIW--Em(&E%&g~Xg3h0MHy(h`NlqV&?-)Vz{nh+RrbN>kdV6c?B30RZVz B;kN() literal 0 HcmV?d00001 diff --git a/irlc/project2/unitgrade_data/YodaProblem7.pkl b/irlc/project2/unitgrade_data/YodaProblem7.pkl new file mode 100644 index 0000000000000000000000000000000000000000..e7d916b7cc20fd28de12c5da4fc1ece4dfd4be80 GIT binary patch literal 693 zcmZo*nYxOJ0Ss!VX!P(z=BFeE6y+!7q~@AW>ES9)EeS1f&PgmTp3*j@hovMlH+4$e z6nA@$2VgB3j6K37sl_Gn6@Kxlr8%iZ@k#lmc_|>ZY>CCisYNAI+NRV_(eP$)xBmdv z!Qjn^U@{??%m^k6g2{?tvLTr42qp)D$%$ZcA(-3<CJ%zii(v90nEY^NX$E5kTicWj z7LZ@_y&FJIhY0m>B<Gi<7A2;G!l8Cbk7#C5PO^SMQGQlxa*2_CWqwMcUP0xQ+9^FQ zDXD1+6@HKqiBHYcNVif*%gIkH(eY7$v0PGfN)q8bKLsm=%)Am!1zkIcN-Kpa-VPD$ zj0_A43JMBEN=ix!&iT0or6s8fr3D44MGD~1R>;p&sHuqet5GP=NX=6yEzZnKS4gcW z$j?j7E6GgEQAo)wPA*C<$*f8&$;{8wQ7BGLRfs7{EikGsG}1Gx)#Ks<8SjyqS5j;R zW`ej{3LzPp#R_SqdC4GM3Mu)i#R`7@Aqu6%sS1fXISQG11*IhliACw9xv6<2#d_#E z%QJIw6p~UEN-|OvG7^hYQj1Fz3Lq&<p(J0SI6tQ>RYxJIv;?doHL*AoqylbVNxnj6 XZb42e$Z&|+N=iyo+NKm2m+Aokd*#c1 literal 0 HcmV?d00001 diff --git a/irlc/project2/utils.py b/irlc/project2/utils.py new file mode 100644 index 0000000..355be7a --- /dev/null +++ b/irlc/project2/utils.py @@ -0,0 +1,53 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.utils.graphics_util_pygame import UpgradedGraphicsUtil, rotate_around +import numpy as np + +""" This file contains code you can either use (or not) to render the R2D2 robot. class is already called correctly by your R2D2 class, +and you don't really have to think too carefully about what the code does unless you want to R2D2 to look better. +""" + + +class R2D2Viewer(UpgradedGraphicsUtil): + def __init__(self, x_target = (0,0)): + self.x_target = x_target + width = 800 + self.scale = width / 1000 + xlim = 3 + self.dw = self.scale * 0.1 + super().__init__(screen_width=width, xmin=-xlim, xmax=xlim, ymin=xlim, ymax=-xlim, title='R2D2') + self.xlim = xlim + def render(self): + # self. + self.draw_background(background_color=(255, 255, 255)) + dw = self.dw + self.line("t1", (-self.xlim, 0), (self.xlim, 0), width=1, color=(0,) * 3) + self.line("t1", (0, -self.xlim), (0, self.xlim), width=1, color=(0,) * 3) + + + self.circle("r2d2", pos=(self.x[0], self.x[1]), r=24, outlineColor=(100, 100, 200), fillColor=(100, 100, 200)) + self.circle("r2d2", pos=(self.x[0], self.x[1]), r=20, outlineColor=(100, 100, 200), fillColor=(150, 150, 255)) + self.circle("r2d2", pos=(self.x[0], self.x[1]), r=2, outlineColor=(100, 100, 200), fillColor=(0,)*3) + + dx = 0.13 + dy = dx/2.5 + wheel = [(-dx, dy), (dx, dy), (dx, -dy), (-dx, -dy) ] + ddy = 0.20 + w1 = [ (x, y + ddy) for x, y in wheel] + w1 = rotate_around(w1, (0,0), angle=self.x[2] / np.pi * 180) + + w2 = [(x, y - ddy) for x, y in wheel] + w2 = rotate_around(w2, (0, 0), angle=self.x[2] / np.pi * 180) + + + self.polygon("wheel1", coords=[ (x + self.x[0], self.x[1] + y) for x, y in w1], filled=True, fillColor=(200,)*3, outlineColor=(100,)*3, closed=True) + self.polygon("wheel2", coords=[ (x + self.x[0], self.x[1] + y) for x, y in w2], filled=True, fillColor=(200,)*3, outlineColor=(100,)*3, closed=True) + + dc = 0.1 + xx = self.x_target[0] + yy = self.x_target[1] + self.line("t1", (xx-dc, yy+dc), (xx+dc, yy-dc), width=4, color=(200, 100, 100)) + self.line("t1", (xx-dc, yy-dc), (xx+dc, yy+dc), width=4, color=(200, 100, 100)) + + + def update(self, x): + self.x = x diff --git a/irlc/project2/yoda.py b/irlc/project2/yoda.py new file mode 100644 index 0000000..dfb70a4 --- /dev/null +++ b/irlc/project2/yoda.py @@ -0,0 +1,97 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from scipy.linalg import expm # Computes the matrix exponential e^A for a square matrix A +from numpy.linalg import matrix_power # Computes A^n for matrix A and integer n + + +def get_A_B(g : float, L: float, m=0.1): + r""" Compute the two matrices A, B (see Problem 1) here and return them. + The matrices should be numpy ndarrays. """ + # TODO: 2 lines missing. + raise NotImplementedError("Compute numpy matrices A and B here") + return A, B + + +def A_euler(g : float,L : float, Delta : float) -> np.ndarray: + r""" Compute \tilde{A}_0 (Euler discretization), see Problem 2. + + Hints: + * get_A_B can perhaps save you a line or two. + """ + # TODO: 2 lines missing. + raise NotImplementedError("Implement function body") + return A0_tilde + +def A_ei(g : float,L : float, Delta : float) -> np.ndarray: + r""" Compute A_0 (Exponential discretization), see Problem 2 + + Hints: + * The special function expm(X) computes the matrix exponential e^X. See the lecture notes for more information. + """ + # TODO: 2 lines missing. + raise NotImplementedError("Implement function body") + return A0 + +def M_euler(g : float, L : float, Delta : float, N : int) -> np.ndarray: + r""" Compute \tilde{M} (Euler discretization), see Problem 3 + Hints: + * the matrix_power(X,n) function can compute expressions such as X^n where X is a square matrix and n is a number + """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + return M_tilde + +def M_ei(g : float,L : float, Delta : float, N : int) -> np.ndarray: + r""" Compute M (Exponential discretization), see Problem 3 """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + return M + +def xN_bound_euler(g : float, L : float,Delta : float,N : int) -> float: + r""" Compute upper bound on |x_N| when using Euler discretization, see Problem 6. + The function should just return a number. + + Hints: + * This function uses all input arguments. + """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + return bound + +def xN_bound_ei(g: float,L : float,Delta : float,N : int) -> float: + r""" Compute upper bound on |x_N| when using exponential discretization, see Problem 7. + + Hints: + * This function does NOT use all input arguments. + * This will be the hardest problem to solve, but the easiest function to implement. + """ + # TODO: 1 lines missing. + raise NotImplementedError("Implement function body") + return bound + +if __name__ == '__main__': + g = 9.82 # gravitational constant + L = 5 # Length of string + m = 0.1 # Mass of pendulum (in kg) + Delta = 0.3 # Time-discretization constant Delta (in seconds) + N = 100 # Time steps + + # Solve Problem 2 + print("A0_euler") + print(A_euler(g, L, Delta)) + + print("A0_ei") + print(A_ei(g, L, Delta)) + + # Solve Problem 3 + print("M_euler") + print(M_euler(g, L, Delta, N)) + + print("M_ei") + print(M_ei(g, L, Delta, N)) + + # Solve Problem 7, upper bound on x_N using Euler discretization + print("|x_N| <= ", xN_bound_euler(g, L, Delta, N)) + + # Solve Problem 8, upper bound on x_N using Exponential discretization + print("|x_N| <= ", xN_bound_ei(g, L, Delta, N)) diff --git a/irlc/project3/Latex/02465project3_handin.tex b/irlc/project3/Latex/02465project3_handin.tex new file mode 100644 index 0000000..b69b431 --- /dev/null +++ b/irlc/project3/Latex/02465project3_handin.tex @@ -0,0 +1,74 @@ +\documentclass[12pt,twoside]{article} +%\usepackage[table]{xcolor} % important to avoid options clash. +%\input{02465shared_preamble} +%\usepackage{cleveref} +\usepackage{url} +\usepackage{graphics} +\usepackage{multicol} +\usepackage{rotate} +\usepackage{rotating} +\usepackage{booktabs} +\usepackage{hyperref} +\usepackage{pifont} +\usepackage{latexsym} +\usepackage[english]{babel} +\usepackage{epstopdf} +\usepackage{etoolbox} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage{multirow,epstopdf} +\usepackage{fancyhdr} +\usepackage{booktabs} +\usepackage{xcolor} +\newcommand\redt[1]{ {\textcolor[rgb]{0.60, 0.00, 0.00}{\textbf{ #1} } } } + + +\newcommand{\m}[1]{\boldsymbol{ #1}} +\newcommand{\yoursolution}{ \redt{(your solution here) } } + + + +\title{ Report 3 hand-in } +\date{ \today } +\author{Alice (\texttt{s000001})\and Bob (\texttt{s000002})\and Clara (\texttt{s000003}) } + +\begin{document} +\maketitle + +\begin{table}[ht!] +\caption{Attribution table. Feel free to add/remove rows and columns} +\begin{tabular}{llll} +\toprule + & Alice & Bob & Clara \\ +\midrule + 1: Optimal policy & 0-100\% & 0-100\% & 0-100\% \\ + 2: Simulating a finite approximation of the optimal action-value function & 0-100\% & 0-100\% & 0-100\% \\ + 3: Analytically computing the optimal action-value function & 0-100\% & 0-100\% & 0-100\% \\ + 4: Extend solution to all states and actions & 0-100\% & 0-100\% & 0-100\% \\ + 5: UCB-based exploration & 0-100\% & 0-100\% & 0-100\% \\ + 6: Sarlacc rules & 0-100\% & 0-100\% & 0-100\% \\ + 7: Escape the Sarlacc & 0-100\% & 0-100\% & 0-100\% \\ +\bottomrule +\end{tabular} +\end{table} + +%\paragraph{Statement about collaboration:} +%Please edit this section to reflect how you have used external resources. The following statement will in most cases suffice: +%\emph{The code in the irls/project1 directory is entirely} + +%\paragraph{Main report:} +Headings have been inserted in the document for readability. You only have to edit the part which says \yoursolution. + +\section{Jar-Jar at the battle of Naboo (\texttt{jarjar.py})} +\subsubsection*{{\color{red}Problem 3: Analytically computing the optimal action-value function}} + + Using that ... we obtain + \begin{align} + Q^*(0,1) & = \cdots \\ + Q^*(1,-1) & = \cdots + \end{align} + therefore... + +\section{Finding the rebels using UCB-exploration (\texttt{rebels.py})} +\section{Individual contribution: The great sarlacc (\texttt{sarlacc.py})} +\end{document} \ No newline at end of file diff --git a/irlc/project3/Latex/figures/your_answer.pdf b/irlc/project3/Latex/figures/your_answer.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d8c092974e20aaaf1165958a53bdce3a2ebdbf8f GIT binary patch literal 6498 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 VQc;we#${$?V9cee>gw;t1pvtyz)}DJ literal 0 HcmV?d00001 diff --git a/irlc/project3/__init__.py b/irlc/project3/__init__.py new file mode 100644 index 0000000..8794db4 --- /dev/null +++ b/irlc/project3/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This file is required for the test system but should otherwise be empty.""" diff --git a/irlc/project3/jarjar.py b/irlc/project3/jarjar.py new file mode 100644 index 0000000..898d4b5 --- /dev/null +++ b/irlc/project3/jarjar.py @@ -0,0 +1,44 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import matplotlib.pyplot as plt +import numpy as np + + +def pi_optimal(s : int) -> int: + """ Compute the optimal policy for Jar-Jar binks. Don't overthink this one! """ + # TODO: 1 lines missing. + raise NotImplementedError("Return the optimal action in state s.") + return action + +def Q0_approximate(gamma : float, N : int) -> float: + """ Return the (estimate) of the optimal action-value function Q^*(0,1) based on + the first N rewards using a discount factor of gamma. Note the similarity to the n-step estimator. """ + # TODO: 1 lines missing. + raise NotImplementedError("Return N-term approximation of the optimal action-value function Q^*(0,1)") + return return_estimate + +def Q_exact(s : int,a : int, gamma : float) -> float: + """ + Return the exact optimal action-value function Q^*(s,a) in the Jar-Jar problem. + I recommend focusing on simple cases first, such as the two cases in the problem. + Then try to look at larger values of s (for instance, s=2), first using actions that 'point in the right direction' (a = -1) + and then actions that point in the 'wrong' direction a=1. + + There are several ways to solve the problem, but the simplest is probably to use recursions. + + *Don't* use your solution to Q0_approximate; it is an approximate (finite-horizon) approximation. + """ + # TODO: 6 lines missing. + raise NotImplementedError("return optimal action-value function Q^*(s,a) as a float.") + + +if __name__ == "__main__": + gamma = 0.8 + + ss = np.asarray(range(-10, 10)) + # Make a plot of your (exact) action-value function Q(s,-1) and Q(s,1). + plt.plot(ss, [Q_exact(s, -1, gamma) for s in ss], 'k-', label='Exact, a=-1') + plt.plot(ss, [Q_exact(s, 1, gamma) for s in ss], 'r-', label='Exact, a=1') + plt.legend() + plt.grid() + plt.show() + print("All done") diff --git a/irlc/project3/project3_grade.py b/irlc/project3/project3_grade.py new file mode 100644 index 0000000..46e8b69 --- /dev/null +++ b/irlc/project3/project3_grade.py @@ -0,0 +1,4 @@ +# irlc/project3/project3_tests.py +''' WARNING: Modifying, decompiling or otherwise tampering with this script, it's data or the resulting .token file will be investigated as a cheating attempt. ''' +import bz2, base64 +exec(bz2.decompress(base64.b64decode('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'))) \ No newline at end of file diff --git a/irlc/project3/project3_tests.py b/irlc/project3/project3_tests.py new file mode 100644 index 0000000..a50927e --- /dev/null +++ b/irlc/project3/project3_tests.py @@ -0,0 +1,142 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import UTestCase, Report +import irlc + +class JarJarPiOptimal(UTestCase): + """ Problem 1: Compute optimal policy. """ + def test_pi_1(self): + from irlc.project3.jarjar import pi_optimal + self.assertLinf(pi_optimal(1), -1) + + def test_pi_all(self): + from irlc.project3.jarjar import pi_optimal + for s in range(-10, 10): + if s != 0: + self.assertLinf(pi_optimal(s)) + +class JarJarQ0Estimated(UTestCase): + """ Problem 2: Implement Q0_approximate to (approximate) the Q-function for the optimal policy. """ + def test_Q0_N1(self): + from irlc.project3.jarjar import Q0_approximate + import numpy as np + self.assertLinf(np.abs(Q0_approximate(gamma=0.8, N=1))) # TODO: Remove abs. This was added due to typo. + + def test_Q0_N2(self): + from irlc.project3.jarjar import Q0_approximate + import numpy as np + self.assertLinf(np.abs(Q0_approximate(gamma=0.7, N=20))) # TODO: Remove abs. This was added due to typo. + + def test_Q0_N100(self): + from irlc.project3.jarjar import Q0_approximate + import numpy as np + self.assertLinf(np.abs(Q0_approximate(gamma=0.9, N=20))) # TODO: Remove abs. This was added due to typo. + + +class JarJarQExact(UTestCase): + """ Problem 4: Compute Q^*(s,a) exactly by extending analytical solution. """ + def test_Q_s0(self): + from irlc.project3.jarjar import Q_exact + self.assertLinf(Q_exact(0, gamma=0.8, a=1)) + self.assertLinf(Q_exact(0, gamma=0.8, a=-1)) + + def test_Q_s1(self): + from irlc.project3.jarjar import Q_exact + self.assertLinf(Q_exact(1, gamma=0.8, a=-1)) + self.assertLinf(Q_exact(1, gamma=0.95, a=-1)) + self.assertLinf(Q_exact(1, gamma=0.7, a=-1)) + + def test_Q_s_positive(self): + from irlc.project3.jarjar import Q_exact + for s in range(20): + self.assertLinf(Q_exact(s, gamma=0.75, a=-1)) + + def test_Q_all(self): + from irlc.project3.jarjar import Q_exact + for s in range(-20, 20): + self.assertLinf(Q_exact(s, gamma=0.75, a=-1)) + self.assertLinf(Q_exact(s, gamma=0.75, a=1)) + +class RebelsSimple(UTestCase): + """ Problem 5: Test the UCB-algorithm in the basic-environment with a single state """ + def test_simple_four_episodes(self): + """ Test the first four episodes in the simple grid problem. """ + from irlc.project3.rebels import get_ucb_actions, very_basic_grid + actions = get_ucb_actions(very_basic_grid, alpha=0.1, episodes=4, c=5, plot=False) + # Make sure we only have 4 actions (remember to truncate the action-sequences!) + self.assertEqual(len(actions), 4) # Check the number of actions are correct + self.assertEqual(actions[0], 0) # Check the first action is correct + self.assertEqualC(actions) # Check all actions. + + def test_simple_nine_episodes(self): + """ Test the first nine episodes in the simple grid problem. """ + from irlc.project3.rebels import get_ucb_actions, very_basic_grid + actions = get_ucb_actions(very_basic_grid, alpha=0.1, episodes=9, c=5, plot=False) + self.assertEqual(len(actions), 9) # Check the number of actions are correct + self.assertEqual(actions[0], 0) # Check the first action is correct + self.assertEqualC(actions) # Check all actions. + + def test_simple_environment(self): + from irlc.project3.rebels import get_ucb_actions, very_basic_grid + actions = get_ucb_actions(very_basic_grid, alpha=0.1, episodes=100, c=5, plot=False) + # Check the number of actions are correct + self.assertEqualC(len(actions)) + # Check the first action is correct + self.assertEqualC(actions[0]) + # Check all actions. + self.assertEqualC(actions) + + def test_bridge_environment(self): + from irlc.gridworld.gridworld_environments import grid_bridge_grid + from irlc.project3.rebels import get_ucb_actions, very_basic_grid + actions = get_ucb_actions(grid_bridge_grid, alpha=0.1, episodes=1000, c=2, plot=False) + self.assertEqualC(len(actions)) + # Check all actions. + self.assertEqualC(actions) + +class RebelsBridge(UTestCase): + """ Problem 5: Test the UCB-algorithm in the bridge-environment """ + def test_bridge_environment_one(self): + from irlc.gridworld.gridworld_environments import grid_bridge_grid + from irlc.project3.rebels import get_ucb_actions + actions = get_ucb_actions(grid_bridge_grid, alpha=0.1, episodes=1, c=2, plot=False) + self.assertEqualC(len(actions)) + self.assertEqualC(actions) + + def test_bridge_environment_two(self): + from irlc.gridworld.gridworld_environments import grid_bridge_grid + from irlc.project3.rebels import get_ucb_actions + actions = get_ucb_actions(grid_bridge_grid, alpha=0.1, episodes=2, c=2, plot=False) + self.assertEqualC(len(actions)) + self.assertEqualC(actions) + + def test_bridge_environment_short(self): + from irlc.gridworld.gridworld_environments import grid_bridge_grid + from irlc.project3.rebels import get_ucb_actions + actions = get_ucb_actions(grid_bridge_grid, alpha=0.1, episodes=30, c=2, plot=False) + self.assertEqualC(len(actions)) + self.assertEqualC(actions) + + def test_bridge_environment_long(self): + from irlc.gridworld.gridworld_environments import grid_bridge_grid + from irlc.project3.rebels import get_ucb_actions + actions = get_ucb_actions(grid_bridge_grid, alpha=0.1, episodes=1000, c=2, plot=False) + self.assertEqualC(len(actions)) + self.assertEqualC(actions) + +class Project3(Report): + title = "Project part 3: Reinforcement Learning" + pack_imports = [irlc] + + jarjar1 = [(JarJarPiOptimal, 10), + (JarJarQ0Estimated, 10), + (JarJarQExact, 10) ] + + rebels = [(RebelsSimple, 20), + (RebelsBridge, 20) ] + questions = [] + questions += jarjar1 + questions += rebels + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Project3()) diff --git a/irlc/project3/project3_tests_complete_grade.py b/irlc/project3/project3_tests_complete_grade.py new file mode 100644 index 0000000..17fda11 --- /dev/null +++ b/irlc/project3/project3_tests_complete_grade.py @@ -0,0 +1,4 @@ +# irlc/project3/project3_tests_complete.py +''' WARNING: Modifying, decompiling or otherwise tampering with this script, it's data or the resulting .token file will be investigated as a cheating attempt. ''' +import bz2, base64 +exec(bz2.decompress(base64.b64decode('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'))) \ No newline at end of file diff --git a/irlc/project3/rebels.py b/irlc/project3/rebels.py new file mode 100644 index 0000000..951a543 --- /dev/null +++ b/irlc/project3/rebels.py @@ -0,0 +1,58 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc.ex11.q_agent import QAgent +from irlc.gridworld.gridworld_environments import GridworldEnvironment, grid_bridge_grid +from irlc import train +from irlc.ex09.rl_agent import TabularQ + +# A simple UCB action-selection problem (basic problem) +very_basic_grid = [['#',1, '#'], + [1, 'S', 2], + ['#',1, '#']] + + +# TODO: 21 lines missing. +raise NotImplementedError("I wrote an agent that inherited from the Q-agent, and updated the self.pi and self.train-functions to do UCB-based exploration.") + +def get_ucb_actions(layout : list, alpha : float, c : float, episodes : int, plot=False) -> list: + """ Return the sequence of actions the agent tries in the environment with the given layout-string when trained over 'episodes' episodes. + To create an environment, you can use the line: + + > env = GridworldEnvironment(layout) + + See also the demo-file. + + The 'plot'-parameter is optional; you can use it to add visualization using a line such as: + + if plot: + env = GridworldEnvironment(layout, render_mode='human') + + Or you can just ignore it. Make sure to return the truncated action list (see the rebels_demo.py-file or project description). + In other words, the return value should be a long list of integers corresponding to actions: + actions = [0, 1, 2, ..., 1, 3, 2, 1, 0, ...] + """ + # TODO: 6 lines missing. + raise NotImplementedError("Implement function body") + return actions + +if __name__ == "__main__": + actions = get_ucb_actions(very_basic_grid, alpha=0.1, c=5, episodes=4, plot=False) + print("Number of actions taken", len(actions)) + print("List of actions taken over 4 episodes", actions) + + actions = get_ucb_actions(very_basic_grid, alpha=0.1, c=5, episodes=8, plot=False) + print("Number of actions taken", len(actions)) + print("Actions taken over 8 episodes", actions) + + actions = get_ucb_actions(very_basic_grid, alpha=0.1, c=5, episodes=9, plot=False) + print("Number of actions taken", len(actions)) + print("Actions taken over 9 episodes", actions) # In this particular case, you can also predict the 9th action. Why? + + # Simulate 100 episodes. This should solve the problem. + actions = get_ucb_actions(very_basic_grid, alpha=0.1, c=5, episodes=100, plot=False) + print("Basic: Actions taken over 100 episodes", actions) + + # Simulate 100 episodes for the bridge-environment. The UCB-based method should solve the environment without being overly sensitive to c. + # You can compare your result with the Q-learning agent in the demo, which performs horribly. + actions = get_ucb_actions(grid_bridge_grid, alpha=0.1, c=5, episodes=300, plot=False) + print("Bridge: Actions taken over 300 episodes. The agent should solve the environment:", actions) diff --git a/irlc/project3/rebels_demo.py b/irlc/project3/rebels_demo.py new file mode 100644 index 0000000..923c69f --- /dev/null +++ b/irlc/project3/rebels_demo.py @@ -0,0 +1,50 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import numpy as np +from irlc import train, Agent, interactive, savepdf +from irlc.gridworld.gridworld_environments import GridworldEnvironment, grid_bridge_grid +from irlc.project3.rebels import very_basic_grid +from irlc.ex11.q_agent import QAgent +import matplotlib +import matplotlib.pyplot as plt +matplotlib.use('qtagg') + + +if __name__ == "__main__": + np.random.seed(42) # Fix the seed for reproduciability + env = GridworldEnvironment(very_basic_grid, render_mode='human') # Create an environment + env.reset() # Reset (to set up the visualization) + savepdf("rebels_basic", env=env) # Save a snapshot of the starting state + env.close() + + # Create an interactive version. + env = GridworldEnvironment(very_basic_grid, render_mode='human') # Create an environment + agent = QAgent(env) # This agent will display the Q-values. + # agent = Agent(env) # A random agent. + # env, agent = interactive(env, agent) # Uncomment this line to play in 'env' environment. Use space to let the agent move. + stats, trajectories = train(env, agent, num_episodes=16, return_trajectory=True) + env.close() + print("Trajectory 0: States traversed", trajectories[0].state, "actions taken", trajectories[0].action) + print("Trajectory 1: States traversed", trajectories[1].state, "actions taken", trajectories[1].action) + all_actions = [t.action[:-1] for t in trajectories] # Concatenate all action sequence excluding the last dummy-action. + print("All actions taken in 16 episodes, excluding the terminal (dummy) action", all_actions) + # Note the last list is of length 20 -- this is because the environment will always terminate after two actions, + # and since we discard the last (dummy) action we get 20 actions. + # In general, the list of actions will be longer, as only the last action should be discarded (as in the code above). + + # A more minimalistic example to plot the bridge-grid environment + bridge_env = GridworldEnvironment(grid_bridge_grid, render_mode='human') + bridge_env.reset() + savepdf("rebels_bridge", env=bridge_env) + bridge_env.close() + + # The following code will simulate a Q-learning agent for 3000 (!) episodes and plot the Q-functions. + np.random.seed(42) # Fix the seed for reproduciability + env = GridworldEnvironment(grid_bridge_grid) + agent = QAgent(env, alpha=0.1, epsilon=0.2, gamma=1) + """ Uncomment the next line to play in the environment. + Use the space-bar to let the agent take an action, p to unpause, and otherwise use the keyboard arrows """ + train(env, agent, num_episodes=3000) # Train for 3000 episodes. Surely the rebels must be found by now! + bridge_env, agent = interactive(env, agent) + bridge_env.reset() + bridge_env.savepdf("rebels_bridge_Q") + bridge_env.close() diff --git a/irlc/project3/unitgrade_data/JarJarPiOptimal.pkl b/irlc/project3/unitgrade_data/JarJarPiOptimal.pkl new file mode 100644 index 0000000000000000000000000000000000000000..efc6383731dea50b9985335b11ba3c5bb47cc889 GIT binary patch literal 606 zcmZo*nHtQ*00y;FG<x{G5{tYNivlwJ3raF`6LY5Ya22PPgcdmGBo-G>X`9l+Qj(dQ zI;CxjyS?TCu&xZo9?p`~;*$7+%y>hP3bw@J;?$y&DQ#0~r(`f@u(eIeU;(L*e+^X+ z66)bd&M!+XN=yftRXe3eJhLb#S-+qtKPxr4#8^Kou_!CCNUxxBO6`;$g_P7Zg@VlZ ze29}YiWRIBGV@9_6?E-Dw3WgXZ}y&G1qB5KB_$;V=ltA)(vnn#l8jUZs1AjK{G80> zN`<uiA_cF+B3-Y<B88;PyzF8<1(*Ch^%4b;Q%W*2^Rg96GBS%5^7B#^L1s;9n^Ihy z!PvtM^Iu|4&Xl$(85|(5X?QbuGlC(LH={SRH={R;H={SJH={S3H={SZH={R)H={SF zH={R~*Z=?j|9f*oC>{vK3!(TR6hDL#fKY-EN(fAqW-w-m!NRa&Q3EItp+bBhcMRg7 HE7b!4*~s5D literal 0 HcmV?d00001 diff --git a/irlc/project3/unitgrade_data/JarJarQ0Estimated.pkl b/irlc/project3/unitgrade_data/JarJarQ0Estimated.pkl new file mode 100644 index 0000000000000000000000000000000000000000..36e3c87cea22839893c43b95665bde11a166e771 GIT binary patch literal 1252 zcmZo*nR=6j0Ss!VX!HnrB^G%l76lr(7MEn^CYGe8OzGh&PAv&7aL!3AE}qghrH7>? zGdFcg+Z1<uz6D@?8H_z#C8@<F@qq^Meuf|=Y>CCisYNAI+NRV_@n+}|%`43<sMJf& zFG|(REzK#(Oe`u&ten!rR-BxelUOum@{}G{u#zb~tSKdx1*sqrrZkHwogM8{f~IJA zGxspsO!4#c^ZNh)|9>#y%}_EW$(aLeKLZ29l(s2BQ;IVfGuYauWUzqT=6wt-2NCMw zNX{=yElNxWxx02sk9cNLPO^SMQGQlxa*45iR$@_BVv$}!<&@efJ*FwCX$pY`@reZm zMfnxrFwjU(%*{<yuu@3N$xkfNQSei+Qpn6J(Nxg2g9uqEO!4OJ*{`6WprE9rq!5%^ zQd*R!P?C|Vppgm<M@@zNG_Xj10VrT|6cUq5GV}9v%Mx=+Qx(!m^T1q%z&I@p106$6 zg`~vd)D(sMJT8!-Ad}KEi;7DW{1l2(%M*)IiWN$WGxO3F5*1Q1i<9$9^GX!b5|c~v zi$K<ZovWwdmtT?!wz4=gH!~-(D6^zep(GzHlBZi-l3JhubzFXt9?0EO+NKm2qeQ0B zl(s1u9FSPd;LQ+r=197@c2ecXulDc&SAhk%#|v11gM?&2nnuGJZ#eTHGL3-&Mo34B dNS(N_M8E+a(x&i`7J-E{NN6;q38d&!Jpe|%xitU) literal 0 HcmV?d00001 diff --git a/irlc/project3/unitgrade_data/JarJarQExact.pkl b/irlc/project3/unitgrade_data/JarJarQExact.pkl new file mode 100644 index 0000000000000000000000000000000000000000..0b7858760854f8e7e8dff5061a15a650a295130c GIT binary patch literal 4156 zcmZo*nQAD&00y;FG<tZv5{tYNivnFM5|c}&^l%lYmV_2K=Oh*vPidRd!%~u&n>wX! zin~3#16WH2V-IIZYH>+?V0^IwNCjJBadB!<$&|J!wNo^_8Qc#r9+xRRE>q;q2xAtM zW-w;3wN1%j0htqY7-|kksD~ptzbv&VF&$(_?UWwz%%YrR{eq(WtkmQZWBsheqO8Os zy@JXqwNrXbQ&Q6u0^?Ib?$jt&uu{m(E73`W(hBK`xw#-tT26jqiKc?CodTF;HN{&# z!jXxAK|w)5K}ku83q%K{mXsFdDU@WSDu7K>$S)|#%uUQuNK7ut%+J#;OUx-vRY)t% z19KGu<Fqu2brLldG9h}r5{q=b5{ncHit>|kQgijdW_l_Vr6%X+=BDPQD5T{lmlkK{ zr7Ps;DHLbs7UZNVBqtW97AvG>78RH1C={0_XDB2VgB?&(o)49TnvP;>NJeU&LP=4j zLP@?tPJVv2LSl(RPGV7dYLNoik;Mx6X$r*(8fp1O3YmGuC5d^-sX7Y9wnmyd5X%%G z4uN<KWMg89f_g!IW?l)*H$|E086^rSnMJ8!->NHUBr4b{=o)H*y_J}k0&->^G-#kE zpctTDUX-7gu8uH5A<@=Qj|;3lBqOybRUxq`RiQW)6wf&d<%yNWAm0?{=ai*_jD`iH zjzUst30MFUWW^;4nZ;nq#H1W>0F)M|f&#g;s5mn}uNZ2BmP>w~dWn_-NU}1&v`C>i zKc^HFiy%t^4dN3E3X1Y8GIJA4Qmqv-!Dc4rDIkd|XryK4WtODsX5<%TR^{huB1vZE z=RsmuNl9r++mzyB<kW9CrEN+E2RzxcSv>Bucsv1=>{XgQOqx9$yqVnh|BnZO6i^Nj zgXe%ASPlRQ@qtVjP57zcsD@{!(S%==pES4<z96jFk1xnC&Me6+1C`l`46y%q?zY>x z+irj|0F$T6Bu|wo-c0TXctL`<^Sqhe4~T;VCwY3axF1kh3lhHL&FX$YtqH8yo6Y@z z&O?YOyZZsdD@!JMs!a0ca6e!gU!A+{cAht<`vFV#IbcyP_X9RZw}M5v-48f;sc@=H z^7Q6$Kj36Oo9%Y)c5hzy11_3dTtT9I?g!lD-Hkz_{O$)l#7onjO!D*=a6jNBID=O^ zce}Ts`vD(bBhCktJiUe75BPCDZO_Qv?k((oAb@$B&~Z&wP~KI6<=w(<u)GTr8qK?- zmDZ4`w78&oH!&v%wblx1oN)dPYcwd+1~Q%K6OFqK%Cvz^Vp$W|RY92+nh8LeHlPWl z0Gw%IxrELAfIoYVYG072H#;I5akwAwg=Qm8L_XtkKj00`XWWR4$m4#%6Pgiu5jmC5 z{eU|(r}87RvVi*mS7=riMC5fL_XEz*ye^C=3`E=yI6?~pQABAW=6=9#iiZ%WWD!Rc zClc-ltf0k-B%-{Laz9`WEpMa|1(J;W0b^)^B#S7q<lGPFuY{Ci@`xf$!To>+v`AA# zlzB?-2b7>?o-(3PRB=Bb84W5yw|lE1N=-HQ1AJg(Cwr^AAAl9B8t(AIRujg&<*kKK zppDR`gD^}NVTB&TVts^j3=obqL^$0D;UQy$H%$<pH$?=A86u#}5y5AH2vkc%P+K7) zz#0)PHi*cwMMR+;B4X_k(d~dp1dfQL;e<#q&WL2>f=FDhh$QERNQmx;<mrJ(w4R8h z?1f0+-iT!HgQzlm-4DRBh#$Q6@b-5<0L@OIio^(3kxV!M?t^78W`Kl7E0WQQWbjuc GrFsAxNykwD literal 0 HcmV?d00001 diff --git a/irlc/project3/unitgrade_data/RebelsBridge.pkl b/irlc/project3/unitgrade_data/RebelsBridge.pkl new file mode 100644 index 0000000000000000000000000000000000000000..06affd8ab0a70532880f475bd1455f6f96f5da5b GIT binary patch literal 14048 zcmZo*nR?ZX0Ss!VX!P&|r6#536gw4VrlhA%>ES9)EeS1f&PgmTp3*j@hovMlH+4$e z6nA@B1F)71#vbXC)Z&u(B(R3~)V#9HqWrwv)Vz}T{5+7-9=62d;?$y&DQ#0~r)YRH zcr$u4#!m5ONG#1@%wTJqlEDHpuDsR(WFADQha)+^EVU>x9i+c@N{@JEQBJacK~a8I zYI2FOei7J(dIgmr1ABxra|`l|N)+-+a|<dJ5{nh`3Z{4~^e}*&o0O88rjVXm5?`8} z6rY$}l9``ZtdWygnO|C>V5N|gSzMx{keE}Dk*Hv$kd~95SfZnlj9{h~WESVAq!ue! zDP-oA=qMEA<d@jGCFT^TYAWd3fwfyHO!2mixXQ%9prD|jproXv5R_U{T9l_yl98%V zoLX3#nwOlake{XiwHz#-n4X$fqEJ$lnOdxn2~mm^YzpO>B^h9K>6vAzc?uBc>K2z2 zW#*+TlxL*oDU=i?X6B`)D1ZV<K^^8ybp;qpj|=3QkbH&YqSVBaRE5Mm1tbe}6e{ye z6_OM46iSOz!4~CY=A~M3fi>BIR4UjixEE!nl;;=aq_`p?6dH1x5S78HsS1fX#ra?p zQc`pCb<;9)QuQE`AsML(>Y(sa*DXjaO3Y0yNi9;yELO-b0L4LKjx~xKGD{Rn@)Z(O zQWVNEi%S!8GOH3n$`neAL0(Q&0J%@0xHLIKA+Z?h&dfA$bXb8M4f1VjUKxI8>nIeZ z=B1<-#pmXyq}r-yl;$SpsYCtZUj%ngR%vmGLS}kieo?AIW{IAHZ(??;LUCzPD#(dN zh{!D|D$PqyEJ;m)MlCowC}<R?LV^^MM&m)@qE}D}4jP60A_Zs~R!B)LPA<v>2Zkmj zwmkC`@=G#OixkT9i&Bbpz@ZAYt}HR9G*zKEBfm5!MIk9wAyFYGKQA3(VSXAYZKkHD z78NTb=NA>F78m5_rGSDB6rzw64+$h#3ba*-HqcQp)KM_fQP9)V12c`mJVPA?1F%>u zI8>FCl%}*zDJ{mA#Y@Wbr?gGU;DF_AW>DUSWO9a7PzINRW$*^^1ZV~a3Gst8kdv=7 zMBAqHjArZ6Y+V8^jYhLIsHiMfASYYP;;OleGxEU|HX>tdA!TfDCU0g)J?_l_W;1&; zf@wx?W^WK1LNb7PAQg<DI^P?@2g#vea513`D<&2$y#OsHKtiL%#Axk5TKf-l?Jt9? zm;g0HkgI>+B4L^p6X3!GrQje@1X4s1YXYPwBUUx2(4(#S5SM@oQV5H9l6arsSBXs) z)jc2;<YPu~l>!P$5C(M<nY>9i4dfzJlR&1Cia~Kny4~oufJ{Iaql6Fg8#!Tu&rWK) z5oQ;)%?0@#lIB4slZQdNVD2M^#-|=x4(2wH7<m|yVi9^lsUMOC5n{x+7^DW|8VCmQ z$id{=jBXdm?dW2Z@Ik%;rGJpQlw*(yl(+_)UTT^N@+~DPo)otr)Pj5k<H6}v4RBqH z>>>mkp##DK>4M2Z*dTFIFeo=b)PqQfSrC&zT?h~hCJyR|AoD@uq+o>EAYBL^$V}2O zD9?b*0L2){9MW_{bfW43nF0|9kq92DDv%s07^IsN_2_C5?f}Ukcp!60#|ZuSOv6+) zI7C3M7{#L@Fd71*Auz;3AXNiABsaudJ?iGs5Eu=C(GVC7fzc2c4FS{;7_HG!!()^; z8UmvsFd71*Aut*OLo)<MYxJQRZ=<dr4S~@R7!85Z5Euy|0A9Xo16#iOPIh4f0|P?_ XV+KfQbouJ&^3~Dhs{^`xwNwuPO&=zz literal 0 HcmV?d00001 diff --git a/irlc/project3/unitgrade_data/RebelsSimple.pkl b/irlc/project3/unitgrade_data/RebelsSimple.pkl new file mode 100644 index 0000000000000000000000000000000000000000..3ca65445fc193f3aca2915c4959db9eb9afacd79 GIT binary patch literal 14306 zcmZo*nR?xv0Ss!VX!P&|r6#536bEPK7UZN(>ES9)EeS1f&PgmTp3*j@hovMlH+4$e z6nA^h2VgB3j6ISisl_Gn#b6EbY5Ao^@u>xw#rY|zU>&R_nI$<OEj<<?sl_D<B^jv- zX_-aEB?=&=3NWP#nR#F-h%pN3MVToI1x5KuIjOmNQ!*Gc*xIJ_uq753rxuk=X`50z z#hW2^iiS6XH={R`H*;z+L`4P*$Yo{PP?v!<aU|!Lr4}WogPc%1rAIuoC?{FJpeR2p zHMzuCzX<GEy@JXqAioP`<`(1^l_=zu<`z^cBo-^=6-@C~=wSf)JSinLO(8wCB)&8` zDLyf|Br`v+SR*H~GQYG$!Ac<~v$#Y@Au*>QBT>OhAuT6Au|!898Nq~m(@G&TuS7?o zASb`X)-5roI8{?Y*AA@RN@0q(WyDn`1_lKM1qCG~C552WlF}k*u%s52rsgH5D&(gr zKrIIcS7Lf<UWr0UQD$l}ECf^Y$})@c^KwBF<(VZJV0G!4WvO`z5a;R^mlS2@r7M(Y zq~<A<6eVWnrKTu=0!cv~=1g^Xyy$U(ToaP7kX)3SSdyxcn5TebfsR6DeyKuoVxB^2 zaVprNoXosbD=x4mJCI5RTLt%`%#`x{qMQ_0gv+2IrwLIRoSLeTm{Xh&HX$W7H(xg` zGbdFKA{mmAs-O-EFLm95#G=I9)RNR9h0J1w`~pxMB<5J7xFNGdp(I}+F(pNzEVH;Y zF(<Ps5u{9^v>4>&L<Nxh6pBleGZYewq3+B~14oAy*wG;0rskF5ceai~QEFaFYEgV{ zeoCsXdPZq(VxBtGFaAYv_hgk8mndYW=j9irDrA=EDflL4rz#Ye7NvrmScHh&lA_YQ z<iwKH6lm0flY@draVjK8A!#%o6fSxNmEfRJ$S(rr4p16aNJ%YDF3JQ4h9)GoJo6Ot zOEOZ66w339Qi^rJp$fIGEHS4vRiQW|zceRBAt_ZMQ6VQkFCAiGei|rkrlzMB6)Pm? z7Zs%z7v$%qfPxJaqL3612_#qwv{i^U&`~hdQ83a`(9_ccGmXJKLmdSJuvjcORF#yJ zrnF5dEk-Xb@-p*MkxPpVj<zWn<pf9(JUzlvIj(X-u5C&N4@Ln2D=54f!9@i~5xA%* zt%nsAAR%FpK5|Nk49T`BJ);H0XaP|IE!Rd12vDJ0tUyiyA&%UfK&oq|z;ZUI+E4Lj z^k(p8LTUpbvN%Y>n;D`2FAX*VMFk_0E)bg-%m8YEc;ixuT^5UIYH0>zhEdxTNE>G1 zoCBbe2`V&NFpaicMq4fe-Ex5xOi4wVDe0;4I0`1;B4KYvSg8cb<)A(atfT>zN=)Dq zhZ%`v@CNZfsv)Hagbxy<E(Z6Nz;+R1E+f$@A*O-c4)Pm>N0=nle29r4TOcgrN#bq7 zuM(Rqs(U~x$j6{mg3t|0H%#6LJ}B)FgF!ArHHjEq=xRV|g><_yO##Ic<>tW51^JDf zFoEgEMuS|3O`K9OYMTr4J18_MaTlp>!lxct4(2wH7<m|yVi9^lsUMOC5n{yp9ON1Z zCRPW!I&y8sGzS!8r27Ef92g(uD^U8Uj)@>sU?x+Grly%7--5!AT(^<p7KB=mZ7?33 zPSpU{hR7~Lun{^SERZgkEQAdbCk2CY14KQDgqQ^}3Dh<Kv0&n$8W))l5+?;C%m(Q~ z@IYpghCz7-WCke4K<1F98=@0c56BdVIEX~>P*s8CNWmc8q^L(%i*N@>2EhZFOFBmA z$7dR*s=*-wa>Xbf4S~@R7!83T76PdnILGXUm`_IiF&YA+Aut*OqaiRF0wXyDMr-tu z9Q&hw9}R)g5Eu=C(GVCuAuw8_51+Uk^~q=mjE2By2#kina0>zO%2j9B%GD3;??Fpf YGZ-^KLZd5JM^~<nu3R0^m8+$C0DI?Z<^TWy literal 0 HcmV?d00001 diff --git a/irlc/project3i/__init__.py b/irlc/project3i/__init__.py new file mode 100644 index 0000000..8794db4 --- /dev/null +++ b/irlc/project3i/__init__.py @@ -0,0 +1,2 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +"""This file is required for the test system but should otherwise be empty.""" diff --git a/irlc/project3i/project3_individual_grade.py b/irlc/project3i/project3_individual_grade.py new file mode 100644 index 0000000..f88cec9 --- /dev/null +++ b/irlc/project3i/project3_individual_grade.py @@ -0,0 +1,4 @@ +# irlc/project3i/project3_individual_tests.py +''' WARNING: Modifying, decompiling or otherwise tampering with this script, it's data or the resulting .token file will be investigated as a cheating attempt. ''' +import bz2, base64 +exec(bz2.decompress(base64.b64decode('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'))) \ No newline at end of file diff --git a/irlc/project3i/project3_individual_tests.py b/irlc/project3i/project3_individual_tests.py new file mode 100644 index 0000000..3bb6f83 --- /dev/null +++ b/irlc/project3i/project3_individual_tests.py @@ -0,0 +1,61 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import UTestCase, Report +import irlc +import numpy as np + +class SarlaccGameRules(UTestCase): + def check_rules(self, rules): + from irlc.project3i.sarlacc import game_rules + # Test what happens at the starting square s=0 for roll 1 + self.assertEqualC(game_rules(rules, state=0, roll=1)) + # Test what happens at the starting square s=0 for other rolls + for roll in [2, 3, 4, 5, 6]: + self.assertEqualC(game_rules(rules, state=0, roll=roll)) + + # Test all states: + for s in range(max(rules.keys())): + if s not in rules: # We skip because s is not a legal state to be in. + for roll in [1, 2, 3, 4, 5, 6]: + self.assertEqualC(game_rules(rules, s, roll)) + + def test_empty_board_rules(self): + rules = {55: -1} + self.check_rules(rules) + + def test_rules(self): + from irlc.project3i.sarlacc import rules + self.check_rules(rules) + +class SarlacReturn(UTestCase): + def check_return(self, rules, gamma): + from irlc.project3i.sarlacc import sarlacc_return + v = sarlacc_return(rules, gamma) + # Check that the keys (states) that are included in v are correct. I.e., that the return is computed for the right states. + states = list(sorted(v.keys())) + self.assertEqualC(states) + + for s in states: + self.assertL2(v[s], tol=1e-2) + + def test_sarlacc_return_empty_gamma1(self): + self.check_return({55: -1}, gamma=1) + + def test_sarlacc_return(self): + from irlc.project3i.sarlacc import rules + self.check_return(rules, gamma=.8) + + +class Project3Individual(Report): + title = "Project part 3: Reinforcement Learning (individual)" + pack_imports = [irlc] + + sarlacc = [(SarlaccGameRules, 20), + (SarlacReturn, 20)] + + questions = [] + questions += sarlacc + + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Project3Individual()) diff --git a/irlc/project3i/project3_individual_tests_complete_grade.py b/irlc/project3i/project3_individual_tests_complete_grade.py new file mode 100644 index 0000000..8cfcfa7 --- /dev/null +++ b/irlc/project3i/project3_individual_tests_complete_grade.py @@ -0,0 +1,4 @@ +# irlc/project3i/project3_individual_tests_complete.py +''' WARNING: Modifying, decompiling or otherwise tampering with this script, it's data or the resulting .token file will be investigated as a cheating attempt. ''' +import bz2, base64 +exec(bz2.decompress(base64.b64decode('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'))) \ No newline at end of file diff --git a/irlc/project3i/sarlacc.py b/irlc/project3i/sarlacc.py new file mode 100644 index 0000000..55e2463 --- /dev/null +++ b/irlc/project3i/sarlacc.py @@ -0,0 +1,120 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" + +References: + [SB18] Richard S. Sutton and Andrew G. Barto. Reinforcement Learning: An Introduction. The MIT Press, second edition, 2018. (Freely available online). +""" +from irlc import savepdf +from irlc.ex09.mdp import MDP +from irlc.ex09.value_iteration import value_iteration +import matplotlib.pyplot as plt +import numpy as np + +# These are the game rules of the sarlac: If you land on a state s in the dictionary, you are teleported to rules[s]. +rules = { + 2: 16, + 4: 8, + 7: 21, + 10: 3, + 12: 25, + 14: 1, + 17: 27, + 19: 5, + 22: 3, + 23: 32, + 24: 44, + 26: 44, + 28: 38, + 30: 18, + 33: 48, + 35: 11, + 36: 34, + 40: 53, + 41: 29, + 42: 9, + 45: 51, + 47: 31, + 50: 25, + 52: 38, + 55: -1, + } + +def game_rules(rules : dict, state : int, roll : int) -> int: + """ Compute the next state given the game rules in 'rules', the current state 'state', and the roll + which can be roll = 1, 2, 3, 4, 5, 6. + The output should be -1 in case the game terminates, and otherwise the function should return the next state + as an integer. Read the description of the project for examples on the rules. """ + # TODO: 4 lines missing. + raise NotImplementedError("Return the next state") + return state_next + +# TODO: 19 lines missing. +raise NotImplementedError("Put your code here.") + +def sarlacc_return(rules : dict, gamma : float) -> dict: + """ Compute the value-function using a discount of gamma and the game rules 'rules'. + Result should be reasonable accurate. + + The value you return should be a dictionary v, so that v[state] is the value function in that state. + (i.e., the standard output format of the value_iteration function). + + Hints: + * One way to solve this problem is to create a MDP-class (see for instance the Gambler-problem in week 9) + and use the value_iteration function from week 9 to solve the problem. But I don't think the problem + is much harder to solve by just writing your own value-iteration method as in (SB18). + """ + # TODO: 2 lines missing. + raise NotImplementedError("Return the value function") + return v + + +if __name__ == "__main__": + """ + Rules for the snakes and ladder game: + The player starts in square s=0, and the game terminates when the player is in square s = 55. + When a player reaches the base of a ladder he/she climbs it, and when they reach a snakes mouth of a snake they are translated to the base. + When a player overshoots the goal state they go backwards from the goal state by the amount of moves they overshoot with. + + A few examples (using the rules in the 'rules' dictionary in this file): + If the player is in position s=0 (start) + > roll 2: Go to state s=16 (using the ladder) + > roll 3: Go to state s=3. + + Or if the player is in state s=54 + > Roll 1: Win the game + > Roll 2: stay in 54 + > Roll 3: Go to 53 + > Roll 4: Go to 38 + """ + # Test the game rules: + for roll in [1, 2, 3, 4, 5, 6]: + print(f"In state s=0 (start), using roll {roll}, I ended up in ", game_rules(rules, 0, roll)) + # Test the game rules again: + for roll in [1, 2, 3, 4, 5, 6]: + print(f"In state s=54, using roll {roll}, I ended up in ", game_rules(rules, 54, roll)) + + # Compute value function with the ordinary rules. + V_rules = sarlacc_return(rules, gamma=1) + # Compute value function with no rules, i.e. with an empty dictionary except for the winning state: + V_norule = sarlacc_return({55: -1}, gamma=1) + print("Time to victory when there are no snakes/ladders", V_norule[0]) + print("Time to victory when there are snakes/ladders", V_rules[0]) + + # Make a plot of the value-functions (optional). + width = .4 + def v2bar(V): + k, x = zip(*V.items()) + return np.asarray(k), np.asarray(x) + + plt.figure(figsize=(10,5)) + plt.grid() + k,x = v2bar(V_norule) + plt.bar(k-width/2, x, width=width, label="No rules") + + k, x = v2bar(V_rules) + plt.bar(k + width / 2, x, width=width, label="Rules") + plt.legend() + plt.xlabel("Current tile") + plt.ylabel("Moves remaining") + savepdf('sarlacc_value_function') + plt.show() diff --git a/irlc/project3i/unitgrade_data/SarlacReturn.pkl b/irlc/project3i/unitgrade_data/SarlacReturn.pkl new file mode 100644 index 0000000000000000000000000000000000000000..3ead9ae290d76fb309b7f682728dac309b6606f0 GIT binary patch literal 7307 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 HD%Ar30sMFc literal 0 HcmV?d00001 diff --git a/irlc/project3i/unitgrade_data/SarlaccGameRules.pkl b/irlc/project3i/unitgrade_data/SarlaccGameRules.pkl new file mode 100644 index 0000000000000000000000000000000000000000..da00e5ccb061289943675d09fd862f10675071ab GIT binary patch literal 3332 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 literal 0 HcmV?d00001 diff --git a/irlc/tests/__init__.py b/irlc/tests/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/tests/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/tests/tests_week01.py b/irlc/tests/tests_week01.py new file mode 100644 index 0000000..812c8fa --- /dev/null +++ b/irlc/tests/tests_week01.py @@ -0,0 +1,132 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import Report +import irlc +# from irlc.ex01.frozen_lake import FrozenAgentDownRight +import gymnasium as gym +from unitgrade import UTestCase +from irlc.ex01.inventory_environment import InventoryEnvironment, simplified_train, RandomAgent +from unitgrade import Capturing2 +import numpy as np +from gymnasium.envs.toy_text.frozen_lake import RIGHT, DOWN # The down and right-actions; may be relevant. +from irlc.ex01.pacman_hardcoded import GoAroundAgent, layout +from irlc.pacman.pacman_environment import PacmanEnvironment +from irlc import Agent, train +from irlc.ex01.bobs_friend import BobFriendEnvironment, AlwaysAction_u1, AlwaysAction_u0 + + +class Problem1BobsFriend(UTestCase): + def test_a_env_basic(self): + env = BobFriendEnvironment() + s0, _ = env.reset() + self.assertEqual(s0, 20, msg="Reset must return the initial state, i.e. the amount of money we start out with") + + def test_a_env_u0(self): + env = BobFriendEnvironment() + env.reset() + s1, r, done, _, _ = env.step(0) + self.assertEqual(r, 2, msg="When taking action u0, we must get a reward of 2.") + self.assertEqual(s1, 22, msg="When taking action u0, we must end in state x1=22") + self.assertEqual(done, True, msg="After taking an action, the environment must terminate") + +class Problem2BobsPolicy(UTestCase): + def test_a_env_u1(self): + env = BobFriendEnvironment() + env.reset() + s1, r, done, _, _ = env.step(1) + print(r) + self.assertTrue(r == 12 or r == -20, msg="When taking action u1, we must get a reward of 0 or 12.") + self.assertTrue(s1 == 0 or s1 == 32, msg="When taking action u1, we must end in state x1=0 or x1 = 34") + self.assertEqual(done, True, msg="After taking an action, the environment must terminate") + + def test_b_always_action_u0(self): + env = BobFriendEnvironment() + stats, _ = train(env, AlwaysAction_u0(env), num_episodes=1000) + avg = np.mean( [stat['Accumulated Reward'] for stat in stats] ) + self.assertL2(avg, 2, msg="Average reward when we always take action u=0 must be 2.") + + def test_b_always_action_u1(self): + env = BobFriendEnvironment() + stats, _ = train(env, AlwaysAction_u1(env), num_episodes=10000) + avg = np.mean( [stat['Accumulated Reward'] for stat in stats] ) + self.assertL2(avg, 4, tol=0.5, msg="Average reward when we always take action u=0 must be about 4.") + + def test_b_always_action_u1_starting_200(self): + env = BobFriendEnvironment(x0=200) + stats, _ = train(env, AlwaysAction_u1(env), num_episodes=10000) + avg = np.mean( [stat['Accumulated Reward'] for stat in stats] ) + self.assertL2(avg, -42, tol=4, msg="Average reward when we always take action u=0 must be about 4.") + + def test_b_always_action_u0_starting_200(self): + env = BobFriendEnvironment(x0=200) + stats, _ = train(env, AlwaysAction_u0(env), num_episodes=10000) + avg = np.mean( [stat['Accumulated Reward'] for stat in stats] ) + self.assertL2(avg, 20, msg="Average reward when we always take action u=0 must be about 4.") + + + +class Problem5PacmanHardcoded(UTestCase): + """ Test the hardcoded pacman agent """ + def test_pacman(self): + env = PacmanEnvironment(layout_str=layout) + agent = GoAroundAgent(env) + stats, _ = train(env, agent, num_episodes=1) + self.assertEqual(stats[0]['Length'] < 100, True) + + +class Problem6ChessTournament(UTestCase): + def test_chess(self): + """ Test the correct result in the little chess-tournament """ + from irlc.ex01.chess import main + with Capturing2() as c: + main() + # Extract the numbers from the console output. + print("Numbers extracted from console output was") + print(c.numbers) + self.assertLinf(c.numbers[-2], 26/33, tol=0.05) + +class Problem3InventoryInventoryEnvironment(UTestCase): + def test_environment(self): + env = InventoryEnvironment() + # agent = RandomAgent(env) + stats, _ = train(env, Agent(env), num_episodes=2000, verbose=False) + avg_reward = np.mean([stat['Accumulated Reward'] for stat in stats]) + self.assertLinf(avg_reward, tol=0.6) + + def test_random_agent(self): + env = InventoryEnvironment() + stats, _ = train(env, RandomAgent(env), num_episodes=2000, verbose=False) + avg_reward = np.mean([stat['Accumulated Reward'] for stat in stats]) + self.assertLinf(avg_reward, tol=0.6) + +class Problem4InventoryTrain(UTestCase): + def test_simplified_train(self): + env = InventoryEnvironment() + agent = Agent(env) + avg_reward_simplified_train = np.mean([simplified_train(env, agent) for i in range(1000)]) + self.assertLinf(avg_reward_simplified_train, tol=0.5) + +# class FrozenLakeTest(UTestCase): +# def test_frozen_lake(self): +# env = gym.make("FrozenLake-v1") +# agent = FrozenAgentDownRight(env) +# s = env.reset() +# for k in range(10): +# self.assertEqual(agent.pi(s, k), DOWN if k % 2 == 0 else RIGHT) + + +class Week01Tests(Report): #240 total. + title = "Tests for week 01" + pack_imports = [irlc] + individual_imports = [] + questions = [ + (Problem1BobsFriend, 10), + (Problem2BobsPolicy, 10), + (Problem3InventoryInventoryEnvironment, 10), + (Problem4InventoryTrain, 10), + (Problem5PacmanHardcoded, 10), + (Problem6ChessTournament, 10), # Week 1: Everything + ] + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Week01Tests()) diff --git a/irlc/tests/tests_week02.py b/irlc/tests/tests_week02.py new file mode 100644 index 0000000..f8c474c --- /dev/null +++ b/irlc/tests/tests_week02.py @@ -0,0 +1,270 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# from irlc.ex02.graph_traversal import pi_inc, pi_smart, pi_silly, policy_rollout, SmallGraphDP +from irlc.ex02.graph_traversal import SmallGraphDP +from collections import defaultdict +# from irlc.ex02.chessmatch import ChessMatch +import gymnasium as gym +from unitgrade import Report +import irlc +from unitgrade import UTestCase +from irlc.ex02.inventory import InventoryDPModel, DP_stochastic +from irlc.ex02.graph_traversal import SmallGraphDP +# from irlc.ex02.frozen_lake_dp import Gym2DPModel + +def gN_dp(self, env): + for s in sorted(self.env.S(self.env.N)): + self.assertLinf(self.env.gN(s)) + +def f_dp(self, env): + self.assertEqualC(self.env.N) + + for k in range(self.env.N): + for s in sorted(self.env.S(k)): + for a in sorted(self.env.A(s,k)): + from collections import defaultdict + + dd_f = defaultdict(float) + # dd_g = defaultdict(float) + + for w, pw in self.env.Pw(s,a,k).items(): + dd_f[(s,a, self.env.f(s,a,w,k))] += pw + # dd_g[(s, a, self.env.g(s, a, w, k))] += pw + + # Check transition probabilities sum to 1. + self.assertAlmostEqual(sum(dd_f.values()), 1, places=6) + # self.assertAlmostEqual(sum(dd_g.values()), 1, places=6) + + for key in sorted(dd_f.keys()): + self.assertEqualC(key) + self.assertLinf(dd_f[key], tol=1e-7) + + # for key in sorted(dd_g.keys()): + # self.assertEqualC(key) + # self.assertLinf(dd_g[key], tol=1e-7) + +def g_dp(self, env): + for k in range(self.env.N): + for s in sorted(self.env.S(k)): + for a in sorted(self.env.A(s, k)): + + # dd_f = defaultdict(float) + dd_g = defaultdict(float) + + for w, pw in self.env.Pw(s, a, k).items(): + # dd_f[(s, a, self.env.f(s, a, w, k))] += pw + dd_g[(s, a, self.env.g(s, a, w, k))] += pw + + # Check transition probabilities sum to 1. + # self.assertAlmostEqual(sum(dd_f.values()), 1, places=6) + self.assertAlmostEqual(sum(dd_g.values()), 1, places=6) + + # for key in sorted(dd_f.keys()): + # self.assertEqualC(key) + # self.assertLinf(dd_f[key], tol=1e-7) + + for key in sorted(dd_g.keys()): + self.assertEqualC(key) + self.assertLinf(dd_g[key], tol=1e-7) + + +class Problem1SmallGraph(UTestCase): + @property + def env(self): + return SmallGraphDP(t=5) + + # @classmethod + # def setUpClass(cls) -> None: + # cls.env = SmallGraphDP(t=5) + + # def test_N(self): + # self.assertEqualC(self.__class__.env.N) + + # def test_states(self): + # # for k in range(self.class.model.S): + # # self.assertEqualC(len(cls.model.S)) + # # self.assertEqualC() + # for k in range(self.env.N+1): + # self.assertEqualC(set(self.env.S(k))) + # + # def test_actions(self): + # for k in range(self.env.N): + # for s in sorted(self.env.S(k)): + # self.assertEqualC(set(self.env.A(s, k))) + + def test_f(self): + f_dp(self, self.env) + + def test_g(self): + g_dp(self, self.env) + + + def test_gN(self): + gN_dp(self, self.env) + + # def test_states(self): + # for k in range(self.env.N+1): + # self.assertEqualC(set(self.env.S(k))) + # + # def test_actions(self): + # for k in range(self.env.N): + # for s in sorted(self.env.S(k)): + # self.assertEqualC(set(self.env.A(s, k))) + + + +class Problem3StochasticDP(UTestCase): + """ Inventory control """ + def test_policy(self): + inv = InventoryDPModel() + J, pi = DP_stochastic(inv) + + # Test action at time step N-1 + self.assertEqual(pi[-1][0], 1) + self.assertEqual(pi[-1][1], 0) + self.assertEqual(pi[-1][2], 0) + + # test all actions at time step N-1 + self.assertEqualC(pi[-1]) + + # Test all actions at all time steps + self.assertEqualC(pi) + + def test_J(self): + inv = InventoryDPModel() + J, pi = DP_stochastic(inv) + + self.assertLinf(J[-1][0], tol=1e-8) + self.assertLinf(J[-1][1], tol=1e-8) + self.assertLinf(J[-1][2], tol=1e-8) + + for k in range(len(J)): + for x in [0,1,2]: + print("testing", J[k][x]) + self.assertLinf(J[k][x], tol=1e-8) + +class Problem4DPAgent(UTestCase): + def test_agent(self): + from irlc.ex01.inventory_environment import InventoryEnvironment + from irlc.ex02.inventory import InventoryDPModel + from irlc.ex02.dp_agent import DynamicalProgrammingAgent + env = InventoryEnvironment(N=3) + inventory = InventoryDPModel(N=3) + agent = DynamicalProgrammingAgent(env, model=inventory) + s0, _ = env.reset() + self.assertEqualC(agent.pi(s0, 0)) # We just test the first action. + + +# class DPChessMatch(UTestCase): +# """ Chessmatch """ +# def test_J(self): +# N = 2 +# pw = 0.45 +# pd = 0.8 +# cm = ChessMatch(N, pw=pw, pd=pd) +# J, pi = DP_stochastic(cm) +# self.assertLinf(J[-1][0], tol=1e-4) +# self.assertLinf(J[-2][0], tol=1e-4) +# self.assertLinf(J[0][0], tol=1e-4) + + + + +# class SmallGraphPolicies(UTestCase): +# """ Test the policies in the small graph environment """ +# def test_pi_smart(self): +# self.assertEqual(pi_smart(1, 0), 5) +# +# def test_pi_inc(self): +# from irlc.ex02.graph_traversal import pi_inc, pi_smart, pi_silly +# for k in range(5): +# self.assertEqual(pi_inc(k+1, k), k+2) +# # self.assertEqual(pi_smart(k + 1, k), 5) +# # self.assertEqual(pi_smart(k + 1, k), 5) +# +# def test_rollout(self): +# # self.assertEqual(3, 1) +# t = 5 +# x0 = 1 # starting node +# model = SmallGraphDP(t=t) +# +# self.assertEqualC(policy_rollout(model, pi_silly, x0)[0]) +# self.assertEqualC(policy_rollout(model, pi_smart, x0)[0]) +# self.assertEqualC(policy_rollout(model, pi_inc, x0)[0]) + +class Problem2DeterministicDP(UTestCase): + def test_dp_deterministic(self): + model = SmallGraphDP(t=5) + J, pi = DP_stochastic(model) + + self.assertLinf(J[-1][1], tol=1e-5) + self.assertLinf(J[-1][2], tol=1e-5) + self.assertLinf(J[-1][3], tol=1e-5) + + self.assertLinf(J[0][1], tol=1e-5) + self.assertLinf(J[0][2], tol=1e-5) + self.assertLinf(J[0][3], tol=1e-5) + + +# class TestInventoryModel(UTestCase): +# @property +# def env(self): +# return InventoryDPModel() +# +# def test_gN(self): +# gN_dp(self, self.env) +# +# def test_f(self): +# f_dp(self, self.env) +# +# def test_g(self): +# g_dp(self, self.env) + + + +# class TestFrozenDP(UTestCase): +# @property +# def env(self): +# return Gym2DPModel(gym_env=gym.make("FrozenLake-v1")) +# +# def test_f(self): +# f_dp(self, self.env) +# +# def test_g(self): +# g_dp(self, self.env) + +class ExamQuestion7FlowersStore(UTestCase): + def test_a_get_policy(self): + from irlc.ex02.flower_store import a_get_policy + x0 = 0 + c = 0.5 + N = 3 + self.assertEqual(a_get_policy(N, c, x0), 1) + + def test_b_prob_empty(self): + from irlc.ex02.flower_store import b_prob_one + x0 = 0 + N = 3 + self.assertAlmostEqual(b_prob_one(N, x0), 0.492, places=2) + + +class Week02Tests(Report): + title = "Tests for week 02" + pack_imports = [irlc] + individual_imports = [] + questions = [ + (Problem1SmallGraph, 10), + (Problem2DeterministicDP, 10), + (Problem3StochasticDP, 10), + (Problem4DPAgent, 10), + (ExamQuestion7FlowersStore, 10), + ] + + +# (SmallGraphPolicies, 10), +# (TestInventoryModel, 10), +# (DPChessMatch, 10), +# (TestFrozenDP, 10), + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Week02Tests() ) diff --git a/irlc/tests/tests_week03.py b/irlc/tests/tests_week03.py new file mode 100644 index 0000000..403e29a --- /dev/null +++ b/irlc/tests/tests_week03.py @@ -0,0 +1,88 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import Report +import irlc +from unitgrade import UTestCase +from irlc.ex03.kuramoto import KuramotoModel, f +import sympy as sym +import numpy as np + +class Problem1Kuramoto(UTestCase): + """ Test the Kuromoto Osscilator """ + def test_continious_model(self): + cmodel = KuramotoModel() + x, u = sym.symbols("x u") + expr = cmodel.sym_f([x], [u]) + # Check the expression has the right type. + self.assertIsInstance(expr, list) + # Evaluate the expression and check the result in a given point. + self.assertEqualC(expr[0].subs([(x, 0.2), (u, 0.93)])) + + def test_f(self): + self.assertLinf(f([0.1], [0.4]), tol=1e-6) + + + def test_RK4(self): + from irlc.ex03.kuramoto import rk4_simulate + + cmodel = KuramotoModel() + x0 = np.asarray(cmodel.x0_bound().low) # Get the starting state x=0. + u = 1.3 + xs, ts = rk4_simulate(x0, [u], t0=0, tF=20, N=100) + + # xs, us, ts = cmodel.simulate(x0, u_fun=u , t0=0, tF=20) + self.assertLinf(ts, tol=1e-6) + # self.assertLinf(us, tol=1e-6) + self.assertLinf(xs, tol=1e-6) + + # Test the same with a varying function: + xs, ts = rk4_simulate(x0, [u+1], t0=0, tF=10, N=50) + # xs, us, ts = cmodel.simulate(x0, u_fun=lambda x,t: np.sin(x + u) , t0=0, tF=10) + self.assertLinf(ts, tol=1e-6) + # self.assertLinf(us, tol=1e-6) + self.assertLinf(xs, tol=1e-6) + +class Exam5InventoryEvaluation(UTestCase): + def test_a_test_expected_items_next_day(self): + from irlc.ex03.inventory_evaluation import a_expected_items_next_day + self.assertAlmostEqual(a_expected_items_next_day(x=0, u=1), 0.1, places=5) + + def test_b_test_expected_items_next_day(self): + from irlc.ex03.inventory_evaluation import b_evaluate_policy + pi = self.get_pi() + self.assertAlmostEqual(b_evaluate_policy(pi, 1), 2.7, places=5) + + def get_pi(self): + from irlc.ex02.inventory import InventoryDPModel + model = InventoryDPModel() + pi = [{x: 1 if x == 0 else 0 for x in model.S(k)} for k in range(model.N)] + return pi + +class Exam6Toy2d(UTestCase): + def test_rk4_a(self): + from irlc.ex03.toy_2d_control import toy_simulation + w = toy_simulation(u0=0.4, T=5) + self.assertFalse(isinstance(w, np.ndarray), msg="Your toy_simulation function must return a float") + self.assertEqual(type(float(w)), float, msg="Your toy_simulation function must return a float") + self.assertLinf(w, tol=0.01, msg="Your simulation ended up at the wrong angle") + + def test_rk4_b(self): + from irlc.ex03.toy_2d_control import toy_simulation + w = toy_simulation(u0=-0.1, T=2) + self.assertFalse( isinstance(w, np.ndarray), msg="Your toy_simulation function must return a float") + self.assertEqual(type(float(w)), float, msg="Your toy_simulation function must return a float") + self.assertLinf(w, tol=0.01, msg="Your simulation ended up at the wrong angle") + + +class Week03Tests(Report): #240 total. + title = "Tests for week 03" + pack_imports = [irlc] + individual_imports = [] + questions = [ + (Problem1Kuramoto, 10), + (Exam5InventoryEvaluation, 10), + (Exam6Toy2d, 10), + ] + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Week03Tests()) diff --git a/irlc/tests/tests_week04.py b/irlc/tests/tests_week04.py new file mode 100644 index 0000000..b032c0b --- /dev/null +++ b/irlc/tests/tests_week04.py @@ -0,0 +1,131 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import Report +from unitgrade import UTestCase +import irlc +from irlc.car.car_model import CarEnvironment +from irlc.ex04.pid_car import PIDCarAgent +from irlc import train +from irlc.ex04.pid_locomotive_agent import LocomotiveEnvironment, PIDLocomotiveAgent +from irlc.ex03.kuramoto import KuramotoModel, f +from irlc.ex04.discrete_kuramoto import fk, dfk_dx +import sympy as sym +import numpy as np + +class Problem1DiscreteKuromoto(UTestCase): + """ Test the Kuromoto Osscilator """ + def test_continious_model(self): + cmodel = KuramotoModel() + x, u = sym.symbols("x u") + expr = cmodel.sym_f([x], [u]) + # Check the expression has the right type. + self.assertIsInstance(expr, list) + # Evaluate the expression and check the result in a given point. + self.assertEqualC(expr[0].subs([(x, 0.2), (u, 0.93)])) + + def test_f(self): + self.assertLinf(f([0.1], [0.4]), tol=1e-6) + + def test_fk(self): + self.assertLinf(fk([0.1], [0.4]), tol=1e-6) + + def test_dfk_dx(self): + self.assertLinf(dfk_dx([0.1], [0.4]), tol=1e-6) + +class Problem3PID(UTestCase): + """ PID Control """ + + def test_pid_class(self, Kp=40, Ki=0, Kd=0, target=0, x=0): + dt = 0.08 + from irlc.ex04.pid import PID + pid = PID(Kp=Kp, Kd=Kd, Ki=Ki, target=target, dt=0.8) + u = pid.pi(x) + self.assertL2(u, tol=1e-4) + + def test_pid_Kp(self): + self.test_pid_class(40, 0, 0, 0, 1) + self.test_pid_class(10, 0, 0, 0, 2) + + + def test_pid_target(self): + self.test_pid_class(40, 0, 0, 3, 1) + self.test_pid_class(20, 0, 0, 0, 2) + + + def test_pid_all(self): + self.test_pid_class(4, 3, 8, 1, 1) + self.test_pid_class(40, 10, 3, 0, 2) + + +class Problem4PIDAgent(UTestCase): + """ PID Control """ + + def pid_locomotive(self, Kp=40, Ki=0, Kd=0, slope=0, target=0): + dt = 0.08 + env = LocomotiveEnvironment(m=10, slope=slope, dt=dt, Tmax=5) + agent = PIDLocomotiveAgent(env, dt=dt, Kp=Kp, Ki=Ki, Kd=Kd, target=target) + stats, traj = train(env, agent, return_trajectory=True, verbose=False) + self.assertL2(traj[0].state, tol=1e-4) + + def test_locomotive_flat(self): + self.pid_locomotive() + + def test_locomotive_Kd(self): + """ Test the derivative term """ + self.pid_locomotive(Kd = 10) + + def test_locomotive_Ki(self): + """ Test the integral term """ + self.pid_locomotive(Kd = 10, Ki=5, slope=5) + + + def test_locomotive_all(self): + """ Test all terms """ + self.pid_locomotive(Kp=35, Kd = 10, Ki=5, slope=5, target=1) + + + + +class Problem7PIDCar(UTestCase): + lt = -1 + + @classmethod + def setUpClass(cls) -> None: + env = CarEnvironment(noise_scale=0, Tmax=80, max_laps=2) + agent = PIDCarAgent(env, v_target=1.0) + stats, trajectories = train(env, agent, num_episodes=1, return_trajectory=True) + d = trajectories[0].state[:, 4] + lt = len(d) * env.dt / 2 + print("Lap time", lt) + cls.lt = lt + + def test_below_60(self): + """ Testing if lap time is < 60 """ + self.assertTrue(0 < self.__class__.lt < 60) + + def test_below_40(self): + """ Testing if lap time is < 60 """ + self.assertTrue(0 < self.__class__.lt < 40) + + + def test_below_30(self): + """ Testing if lap time is < 60 """ + self.assertTrue(0 < self.__class__.lt < 30) + + def test_below_22(self): + """ Testing if lap time is < 22 """ + self.assertTrue(0 < self.__class__.lt < 22) + +class Week04Tests(Report): + title = "Tests for week 04" + pack_imports = [irlc] + individual_imports = [] + questions = [ + (Problem1DiscreteKuromoto, 10), + (Problem3PID, 10), + (Problem4PIDAgent, 10), # ok + (Problem7PIDCar, 10), # ok + ] + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Week04Tests()) diff --git a/irlc/tests/tests_week05.py b/irlc/tests/tests_week05.py new file mode 100644 index 0000000..4a7f813 --- /dev/null +++ b/irlc/tests/tests_week05.py @@ -0,0 +1,114 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import Report +from irlc.ex05.direct_agent import train_direct_agent +from unitgrade import UTestCase +import irlc +from irlc.ex05.direct import run_direct_small_problem + + +class DirectMethods(UTestCase): + title = "Direct methods z, z0, z_lb/z_ub definitions+" + + @classmethod + def setUpClass(cls) -> None: + env, solution = run_direct_small_problem() + cls.solution = solution[-1] + + def test_z_variable_vector(self): + self.assertEqualC(str(DirectMethods.solution['inputs']['z'])) + + def test_z0_initial_state(self): + self.assertL2(DirectMethods.solution['inputs']['z0'], tol=1e-6) + + def test_zU_upper_bound(self): + self.assertL2(DirectMethods.solution['inputs']['z_ub'], tol=1e-6) + + def test_zL_lower_bound(self): + self.assertL2(DirectMethods.solution['inputs']['z_lb'], tol=1e-6) + + +class DirectAgentPendulum(UTestCase): + """ Direct agent: Test of pendulum environment """ + def test_pendulum(self): + stats,_,_ = train_direct_agent(animate=False) + return self.assertL2(stats[0]['Accumulated Reward'], tol=0.03) + +class DirectSolverQuestion(UTestCase): + """ Test the Direct solver on the Pendulum using run_direct_small_problem() """ + @classmethod + def setUpClass(cls): + cls.solution = cls.compute_solution() + + @classmethod + def compute_solution(cls): + from irlc.ex05.direct import run_direct_small_problem + env, solution = run_direct_small_problem() + return solution + # cls.solution = solution + + def test_solver_success(self): + self.assertTrue(self.__class__.solution[-1]['solver']['success']) + + def test_solver_fun(self): + self.assertL2(self.__class__.solution[-1]['solver']['fun'], tol=0.01) + + def test_constraint_violation(self): + self.assertL2(self.__class__.solution[-1]['eqC_val'], tol=0.01) + + +class PendulumQuestion(DirectSolverQuestion): + """ Direct solver on the pendulum problem """ + @classmethod + def compute_solution(cls): + from irlc.ex05.direct_pendulum import compute_pendulum_solutions + return compute_pendulum_solutions()[1] + + +class CartpoleTimeQuestion(DirectSolverQuestion): + """ Direct solver on the cartpole (minimum time) task """ + @classmethod + def compute_solution(cls): + from irlc.ex05.direct_cartpole_time import compute_solutions + return compute_solutions()[1] + + +class CartpoleCostQuestion(DirectSolverQuestion): + """ Direct solver on the cartpole (kelly) task """ + @classmethod + def compute_solution(cls): + from irlc.ex05.direct_cartpole_kelly import compute_solutions + return compute_solutions()[1] + +class BrachistochroneQuestion(DirectSolverQuestion): + """ Brachistochrone (unconstrained) """ + + @classmethod + def compute_solution(cls): + from irlc.ex05.direct_brachistochrone import compute_constrained_solutions + return compute_constrained_solutions()[1] + +class BrachistochroneConstrainedQuestion(DirectSolverQuestion): + """ Brachistochrone (constrained) """ + @classmethod + def compute_solution(cls): + from irlc.ex05.direct_brachistochrone import compute_constrained_solutions + return compute_constrained_solutions()[1] + +class Week05Tests(Report): + title = "Tests for week 05" + pack_imports = [irlc] + individual_imports = [] + questions = [ + (DirectMethods, 10), # ok + (DirectSolverQuestion, 10), # ok + (PendulumQuestion, 5), # ok + (DirectAgentPendulum, 10), # ok + (CartpoleTimeQuestion, 5), # ok + (CartpoleCostQuestion, 5), # ok + (BrachistochroneQuestion, 5), # ok + (BrachistochroneConstrainedQuestion, 10), # ok + ] + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Week05Tests()) diff --git a/irlc/tests/tests_week06.py b/irlc/tests/tests_week06.py new file mode 100644 index 0000000..a724638 --- /dev/null +++ b/irlc/tests/tests_week06.py @@ -0,0 +1,147 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex06.model_boeing import BoeingEnvironment +from unitgrade import UTestCase, Report +import irlc +from irlc import train +import numpy as np +from irlc.ex04.locomotive import LocomotiveEnvironment +from irlc.ex04.model_harmonic import HarmonicOscilatorEnvironment + +matrices = ['L', 'l', 'V', 'v', 'vc'] + +class Problem3LQR(UTestCase): + title = "LQR, full check of implementation" + + @classmethod + def setUpClass(cls): + # def init(self): + from irlc.ex06.dlqr_check import check_LQR + (cls.L, cls.l), (cls.V, cls.v, cls.vc) = check_LQR() + # self.M = list(zip(matrices, [L, l, V, v, vc])) + + def chk_item(self, m_list): + self.assertIsInstance(m_list, list) + self.assertEqualC(len(m_list)) + for m in m_list: + self.assertIsInstance(m, np.ndarray) + self.assertEqualC(m.shape) + self.assertL2(m, tol=1e-6) + + def test_L(self): + self.chk_item(self.__class__.L) + + def test_l(self): + self.chk_item(self.__class__.l) + + def test_V(self): + self.chk_item(self.__class__.V) + + def test_v(self): + self.chk_item(self.__class__.v) + + def test_vc(self): + vc = self.__class__.vc + self.assertIsInstance(vc, list) + for d in vc: + self.assertL2(d, tol=1e-6) + + self.chk_item(self.__class__.l) + +class Problem4LQRAgent(UTestCase): + def _mkagent(self, val=0.): + A = np.ones((2, 2))* (1+val) + A[1, 0] = 0 + B = np.asarray([[0], [1]]) + Q = np.eye(2) * (3+val) + R = np.ones((1, 1)) * 2 + q = np.asarray([-1.1 + val, 0]) + from irlc.ex06.lqr_agent import LQRAgent + env = LocomotiveEnvironment(render_mode=None, Tmax=5, slope=1) + agent = LQRAgent(env, A=A, B=B, Q=Q, R=R, q=q) + return agent + + def test_policy_lqr_a(self): + agent = self._mkagent(0) + self.assertL2(agent.pi(np.asarray([1, 0]), k=0)) + self.assertL2(agent.pi(np.asarray([1, 0]), k=5)) + + def test_policy_lqr_b(self): + agent = self._mkagent(0.2) + self.assertL2(agent.pi(np.asarray([1, 0]), k=0)) + self.assertL2(agent.pi(np.asarray([1, 0]), k=5)) + +class Problem5_6_Boeing(UTestCase): + + def test_compute_A_B_d(self): + from irlc.ex06.boeing_lqr import compute_A_B_d, compute_Q_R_q + model = BoeingEnvironment(Tmax=10).discrete_model.continuous_model + A, B, d = compute_A_B_d(model, dt=0.2) + self.assertL2(A) + self.assertL2(B) + self.assertL2(d) + + def test_compute_Q_R_q(self): + from irlc.ex06.boeing_lqr import compute_A_B_d, compute_Q_R_q + model = BoeingEnvironment(Tmax=10).discrete_model.continuous_model + Q, R, q = compute_Q_R_q(model, dt=0.2) + self.assertL2(Q) + self.assertL2(R) + self.assertL2(q) + + def test_boing_path(self): + from irlc.ex06.boeing_lqr import boeing_simulation + stats, trajectories, env = boeing_simulation() + self.assertL2(trajectories[-1].state, tol=1e-6) + + +class Problem7_8_PidLQR(UTestCase): + def test_constant_lqr_agent(self): + Delta = 0.06 # Time discretization constant + # Define a harmonic osscilator environment. Use .., render_mode='human' to see a visualization. + env = HarmonicOscilatorEnvironment(Tmax=8, dt=Delta, m=0.5, R=np.eye(1) * 8, + render_mode=None) # set render_mode='human' to see the oscillator. + model = env.discrete_model.continuous_model # Get the ControlModel corresponding to this environment. + + from irlc.ex06.boeing_lqr import compute_A_B_d, compute_Q_R_q + from irlc.ex06.lqr_pid import ConstantLQRAgent + A, B, d = compute_A_B_d(model, Delta) + Q, R, q = compute_Q_R_q(model, Delta) + x0, _ = env.reset() + + # Run the LQR agent + lqr_agent = ConstantLQRAgent(env, A=A, B=B, d=d, Q=Q, R=R, q=q) + self.assertLinf(lqr_agent.pi(x0, k=0), tol=1e-3) + self.assertLinf(lqr_agent.pi(x0, k=10), tol=1e-3) + + + def test_KpKd(self): + Delta = 0.06 # Time discretization constant + # Define a harmonic osscilator environment. Use .., render_mode='human' to see a visualization. + env = HarmonicOscilatorEnvironment(Tmax=8, dt=Delta, m=0.5, R=np.eye(1) * 8, + render_mode=None) # set render_mode='human' to see the oscillator. + model = env.discrete_model.continuous_model # Get the ControlModel corresponding to this environment. + from irlc.ex06.boeing_lqr import compute_A_B_d, compute_Q_R_q + from irlc.ex06.lqr_pid import ConstantLQRAgent, get_Kp_Kd + A, B, d = compute_A_B_d(model, Delta) + Q, R, q = compute_Q_R_q(model, Delta) + lqr_agent = ConstantLQRAgent(env, A=A, B=B, d=d, Q=Q, R=R, q=q) + Kp, Kd = get_Kp_Kd(lqr_agent.L[0]) + self.assertAlmostEqualC(Kp, places=3) + self.assertAlmostEqualC(Kd, places=3) + + + + +class Week06Tests(Report): + title = "Tests for week 06" + pack_imports = [irlc] + individual_imports = [] + questions = [ + (Problem3LQR, 10), + (Problem4LQRAgent, 10), + (Problem5_6_Boeing, 10), + (Problem7_8_PidLQR, 10), + ] +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Week06Tests()) diff --git a/irlc/tests/tests_week07.py b/irlc/tests/tests_week07.py new file mode 100644 index 0000000..1f46427 --- /dev/null +++ b/irlc/tests/tests_week07.py @@ -0,0 +1,62 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import Report +import irlc +from unitgrade import UTestCase +import numpy as np +from irlc import Agent, train + +class RendevouzItem(UTestCase): + def test_rendevouz_without_linesearch(self): + """ Rendevouz with iLQR (no linesearch) """ + from irlc.ex07.ilqr_rendovouz_basic import solve_rendovouz + (xs, us, J_hist, l, L), env = solve_rendovouz(use_linesearch=False) + # print(J_hist[-1]) + self.assertL2(xs[-1], tol=1e-2) + + def test_rendevouz_with_linesearch(self): + """ Rendevouz with iLQR (with linesearch) """ + from irlc.ex07.ilqr_rendovouz_basic import solve_rendovouz + (xs, us, J_hist, l, L), env = solve_rendovouz(use_linesearch=True) + # print(J_hist[-1]) + self.assertL2(xs[-1], tol=1e-2) + # return l, L, xs + + + + + +class ILQRAgentQuestion(UTestCase): + """ iLQR Agent on Rendevouz """ + def test_ilqr_agent(self): + from irlc.ex07.ilqr_agent import solve_rendevouz + stats, trajectories, agent = solve_rendevouz() + self.assertL2(trajectories[-1].state[-1], tol=1e-2) + + +class ILQRPendulumQuestion(UTestCase): + """ iLQR Agent on Pendulum """ + + def test_ilqr_agent_pendulum(self): + from irlc.ex07.ilqr_pendulum_agent import Tmax, N + from irlc.ex04.model_pendulum import GymSinCosPendulumEnvironment + from irlc.ex07.ilqr_agent import ILQRAgent + dt = Tmax / N + env = GymSinCosPendulumEnvironment(dt, Tmax=Tmax, supersample_trajectory=True) + agent = ILQRAgent(env, env.discrete_model, N=N, ilqr_iterations=200, use_linesearch=True) + stats, trajectories = train(env, agent, num_episodes=1, return_trajectory=True) + state = trajectories[-1].state[-1] + self.assertL2(state, tol=2e-2) + +class Week07Tests(Report): #240 total. + title = "Tests for week 07" + pack_imports = [irlc] + individual_imports = [] + questions = [ + (RendevouzItem, 10), # ok + (ILQRAgentQuestion, 10), # ok + (ILQRPendulumQuestion, 10), # ok + ] + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Week07Tests()) diff --git a/irlc/tests/tests_week08.py b/irlc/tests/tests_week08.py new file mode 100644 index 0000000..340d69c --- /dev/null +++ b/irlc/tests/tests_week08.py @@ -0,0 +1,278 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import UTestCase, Report, cache +import numpy as np +from irlc import train + + +def train_recording(env, agent, trajectories): + for t in trajectories: + env.reset() + for k in range(len(t.action)): + s = t.state[k] + r = t.reward[k] + a = t.action[k] + sp = t.state[k+1] + agent.pi(s,k) + agent.train(s, a, r, sp, done=k == len(t.action)-1) + + +class BanditQuestion(UTestCase): + """ Value (Q) function estimate """ + tol = 1e-2 # tie-breaking in the gradient bandit is ill-defined. + # testfun = QPrintItem.assertL2 + + # def setUpClass(cls) -> None: + # from irlc.ex08.simple_agents import BasicAgent + # from irlc.ex08.bandits import StationaryBandit + # env = StationaryBandit(k=10, ) + # agent = BasicAgent(env, epsilon=0.1) + # _, cls.trajectories = train(env, agent, return_trajectory=True, num_episodes=1, max_steps=100) + # cls.Q = agent.Q + # cls.env = env + # cls.agent = agent + + def get_env_agent(self): + from irlc.ex08.simple_agents import BasicAgent + from irlc.ex08.bandits import StationaryBandit + env = StationaryBandit(k=10) + agent = BasicAgent(env, epsilon=0.1) + return env, agent + + @cache + def get_trajectories(self): + env, agent = self.get_env_agent() + _, trajectories = train(env, agent, return_trajectory=True, num_episodes=1, max_steps=100) + return trajectories + + # def precompute_payload(self): + # env, agent = self.get_env_agent() + # _, trajectories = train(env, agent, return_trajectory=True, num_episodes=1, max_steps=100) + # return trajectories, agent.Q + + + def test_agent(self): + trajectories = self.get_trajectories() + env, agent = self.get_env_agent() + train_recording(env, agent, trajectories) + self.assertL2(agent.Q, tol=1e-5) + # return agent.Q + # self.Q = Q + # self.question.agent = agent + # return agent.Q + + # testfun = QPrintItem.assertL2 + + def test_action_distributin(self): + T = 10000 + tol = 1 / np.sqrt(T) * 5 + trajectories = self.get_trajectories() + env, agent = self.get_env_agent() + train_recording(env, agent, trajectories) + # for k in self._cache.keys(): print(k) + + from collections import Counter + counts = Counter([agent.pi(None, k) for k in range(T)]) + distrib = [counts[k] / T for k in range(env.k)] + self.assertL2(np.asarray(distrib), tol=tol) + + + # def process_output(self, res, txt, numbers): + # return res + + # def process_output(self, res, txt, numbers): + # return res + # + # def test(self, computed, expected): + # super().test(computed, self.Q) + +# class BanditQuestion(QPrintItem): +# # tol = 1e-6 +# tol = 1e-2 # tie-breaking in the gradient bandit is ill-defined. +# title = "Value (Q) function estimate" +# testfun = QPrintItem.assertL2 +# +# def get_env_agent(self): +# from irlc.ex08.simple_agents import BasicAgent +# from irlc.ex08.bandits import StationaryBandit +# env = StationaryBandit(k=10, ) +# agent = BasicAgent(env, epsilon=0.1) +# return env, agent +# +# def precompute_payload(self): +# env, agent = self.get_env_agent() +# _, trajectories = train(env, agent, return_trajectory=True, num_episodes=1, max_steps=100) +# return trajectories, agent.Q +# +# def compute_answer_print(self): +# trajectories, Q = self.precomputed_payload() +# env, agent = self.get_env_agent() +# train_recording(env, agent, trajectories) +# self.Q = Q +# self.question.agent = agent +# return agent.Q +# +# def process_output(self, res, txt, numbers): +# return res +# +# def test(self, computed, expected): +# super().test(computed, self.Q) +# +# class BanditItemActionDistribution(QPrintItem): +# # Assumes setup has already been done. +# title = "Action distribution test" +# T = 10000 +# tol = 1/np.sqrt(T)*5 +# testfun = QPrintItem.assertL2 +# +# def compute_answer_print(self): +# # print("In agent print code") +# from collections import Counter +# counts = Counter( [self.question.agent.pi(None, k) for k in range(self.T)] ) +# distrib = [counts[k] / self.T for k in range(self.question.agent.env.k)] +# return np.asarray(distrib) +# +# def process_output(self, res, txt, numbers): +# return res +# +# class BanditQuestion(QuestionGroup): +# title = "Simple bandits" +# class SimpleBanditItem(BanditItem): +# #title = "Value function estimate" +# def get_env_agent(self): +# from irlc.ex08.simple_agents import BasicAgent +# from irlc.ex08.bandits import StationaryBandit +# env = StationaryBandit(k=10, ) +# agent = BasicAgent(env, epsilon=0.1) +# return env, agent +# class SimpleBanditActionDistribution(BanditItemActionDistribution): +# pass + + + +class GradientBanditQuestion(BanditQuestion): + """ Gradient agent """ + # class SimpleBanditItem(BanditItem): + # title = "Simple agent question" + def get_env_agent(self): + from irlc.ex08.bandits import StationaryBandit + from irlc.ex08.gradient_agent import GradientAgent + env = StationaryBandit(k=10) + agent = GradientAgent(env, alpha=0.05) + return env, agent + + # def precompute_payload(self): + # env, agent = self.get_env_agent() + # _, trajectories = train(env, agent, return_trajectory=True, num_episodes=1, max_steps=100) + # return trajectories + + def test_agent(self): + trajectories = self.get_trajectories() + env, agent = self.get_env_agent() + train_recording(env, agent, trajectories) + self.assertL2(agent.H, tol=1e-5) + + + # def test(self, computed, expected): + # self.testfun(computed, self.H) + # + # class SimpleBanditActionDistribution(BanditItemActionDistribution): + # pass + + +# class GradientBanditQuestion(QuestionGroup): +# title = "Gradient agent" +# class SimpleBanditItem(BanditItem): +# # title = "Simple agent question" +# def get_env_agent(self): +# from irlc.ex08.bandits import StationaryBandit +# from irlc.ex08.gradient_agent import GradientAgent +# env = StationaryBandit(k=10) +# agent = GradientAgent(env, alpha=0.05) +# return env, agent +# +# def precompute_payload(self): +# env, agent = self.get_env_agent() +# _, trajectories = train(env, agent, return_trajectory=True, num_episodes=1, max_steps=100) +# return trajectories, agent.H +# +# def compute_answer_print(self): +# trajectories, H = self.precomputed_payload() +# env, agent = self.get_env_agent() +# train_recording(env, agent, trajectories) +# self.H = H +# self.question.agent = agent +# return agent.H +# +# def test(self, computed, expected): +# self.testfun(computed, self.H) +# +# class SimpleBanditActionDistribution(BanditItemActionDistribution): +# pass + + + +class UCBAgentQuestion(BanditQuestion): + """ UCB agent """ + # class UCBAgentItem(BanditItem): + def get_env_agent(self): + from irlc.ex08.bandits import StationaryBandit + from irlc.ex08.ucb_agent import UCBAgent + env = StationaryBandit(k=10) + agent = UCBAgent(env) + return env, agent + + # class UCBAgentActionDistribution(BanditItemActionDistribution): + # pass + + +# class UCBAgentQuestion(QuestionGroup): +# title = "UCB agent" +# class UCBAgentItem(BanditItem): +# def get_env_agent(self): +# from irlc.ex08.bandits import StationaryBandit +# from irlc.ex08.ucb_agent import UCBAgent +# env = StationaryBandit(k=10) +# agent = UCBAgent(env) +# return env, agent +# +# class UCBAgentActionDistribution(BanditItemActionDistribution): +# pass + +# class NonstatiotnaryAgentQuestion(QuestionGroup): +# title = "Nonstationary bandit environment" +# class NonstationaryItem(BanditItem): +# def get_env_agent(self): +# epsilon = 0.1 +# from irlc.ex08.nonstationary import NonstationaryBandit, MovingAverageAgent +# bandit = NonstationaryBandit(k=10) +# agent = MovingAverageAgent(bandit, epsilon=epsilon, alpha=0.15) +# return bandit, agent +# +# class NonstationaryActionDistribution(BanditItemActionDistribution): +# pass + +class NonstatiotnaryAgentQuestion(BanditQuestion): + """ UCB agent """ + # class UCBAgentItem(BanditItem): + def get_env_agent(self): + epsilon = 0.1 + from irlc.ex08.nonstationary import NonstationaryBandit, MovingAverageAgent + bandit = NonstationaryBandit(k=10) + agent = MovingAverageAgent(bandit, epsilon=epsilon, alpha=0.15) + return bandit, agent + +import irlc +class Week08Tests(Report): + title = "Tests for week 08" + pack_imports = [irlc] + individual_imports = [] + questions = [ + (BanditQuestion, 10), + (GradientBanditQuestion, 10), + (UCBAgentQuestion, 5), + (NonstatiotnaryAgentQuestion, 5) + ] + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Week08Tests()) diff --git a/irlc/tests/tests_week09.py b/irlc/tests/tests_week09.py new file mode 100644 index 0000000..ca5d4ae --- /dev/null +++ b/irlc/tests/tests_week09.py @@ -0,0 +1,314 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import UTestCase, Report +import numpy as np +import irlc +from irlc import train +from irlc.ex09.small_gridworld import SmallGridworldMDP +from irlc.ex09.policy_iteration import policy_iteration +from irlc.ex09.value_iteration import value_iteration +from irlc.gridworld.gridworld_environments import FrozenLake +from irlc.ex09.policy_evaluation import policy_evaluation + +class Problem1_to_3_Warmup(UTestCase): + def test_part1_average_reward(self): + from irlc.ex09.mdp_warmup import expected_reward + mdp = FrozenLake(living_reward=0.2).mdp # Get the MDP of this environment. + s0 = mdp.initial_state + ## Part 1: Expected reward + self.assertAlmostEqualC(expected_reward(mdp, s=s0, a=0), places=5) + self.assertAlmostEqualC(expected_reward(mdp, s=s0, a=2), places=5) + self.assertAlmostEqualC(expected_reward(mdp, s=(1,2), a=0), places=5) + mdp = FrozenLake(living_reward=0.2).mdp # Get the MDP of this environment. + self.assertAlmostEqualC(expected_reward(mdp, s=s0, a=2), places=5) + + def test_part2_v2q(self): + ## Part 2 + # First let's create a non-trivial value function + V = {} + mdp = FrozenLake(living_reward=0.3).mdp + + for k, s in enumerate(sorted(mdp.nonterminal_states)): + V[s] = 2 * (s[0] - s[1]) - 3.5 + + from irlc.ex09.mdp_warmup import value_function2q_function + + states = [(0, 1), (2, 3), (0, 3), (1,3), (1, 2)] + + s0 = mdp.initial_state + + q_ = value_function2q_function(mdp, s=s0, gamma=0.9, v=V) + self.assertIsInstance(q_, dict) + self.assertEqual(list(sorted(q_.keys())), [0, 1, 2, 3] ) + + self.assertEqual(len(q_), 4) + self.assertEqual(len(value_function2q_function(mdp, s=(1,2), gamma=0.9, v=V)), 1) + self.assertAlmostEqualC(q_[0],places=4) + self.assertAlmostEqualC(q_[2], places=4) + + + for s in sorted(states): + q_ = value_function2q_function(mdp, s=s, gamma=0.9, v=V) + for a in [0, 1, 2, 3]: + if a in mdp.A(s): + self.assertAlmostEqualC(q_[a], places=4) + + def test_part2_q2v(self): + ## Part 3 + mdp = FrozenLake(living_reward=0.2).mdp + from irlc.ex09.mdp_warmup import value_function2q_function, q_function2value_function + # Create a non-trivial Q-function for this problem. + Q = {} + s0 = mdp.initial_state + + for k, s in enumerate(mdp.nonterminal_states): + for a in mdp.A(s): + Q[s, a] = (s[0] - s[1]) - 5 * a # The particular values are not important in this example + # Create a policy. In this case pi(a=3) = 0.4. + pi = {0: 0.2, + 1: 0.4, + 2: 0.2, + 3: 0.2} + self.assertAlmostEqualC(q_function2value_function(pi, Q, s=s0), places=4) + +def train_recording(env, agent, trajectories): + for t in trajectories: + env.reset() + for k in range(len(t.action)): + s = t.state[k] + r = t.reward[k] + a = t.action[k] + sp = t.state[k+1] + info = t.info[k] + info_sp = t.info[k+1] + + agent.pi(s,k) + agent.train(s, a, r, sp, done=k == len(t.action)-1, info_s = info, info_sp=info_sp) + + +class ValueFunctionTest(UTestCase): + def check_value_function(self, mdp, V): + self.assertL2(np.asarray([V[s] for s in mdp.states]), tol=1e-3) + +class Problem5PolicyIteration(ValueFunctionTest): + """ Iterative Policy iteration """ + def test_policy_iteration(self): + env = SmallGridworldMDP() + pi, v = policy_iteration(env, gamma=0.91) + self.check_value_function(env, v) + + + +class Problem6ValueIteration(ValueFunctionTest): + """ Iterative value iteration """ + def test_value_iteration(self): + env = SmallGridworldMDP() + # from i + pi, v = value_iteration(env, gamma=0.91) + self.check_value_function(env, v) + + + +class Problem4PolicyEvaluation(ValueFunctionTest): + """ Iterative value iteration """ + def test_policy_evaluation(self): + mdp = SmallGridworldMDP() + pi = {s: {a: 1/len(mdp.A(s)) for a in mdp.A(s) } for s in mdp.nonterminal_states } + v = policy_evaluation(pi, mdp, gamma=0.91) + self.check_value_function(mdp, v) + + def test_policy_evaluation_b(self): + mdp = SmallGridworldMDP() + pi = {s: {a: 1 if a == 0 else 0 for a in mdp.A(s) } for s in mdp.nonterminal_states } + v = policy_evaluation(pi, mdp, gamma=0.91) + self.check_value_function(mdp, v) + + + + +class Problem9Gambler(ValueFunctionTest): + """ Gambler's problem """ + def test_gambler_value_function(self): + # from irlc.ex09.small_gridworld import SmallGridworldMDP, plot_value_function + # from irlc.ex09.policy_iteration import policy_iteration + # from irlc.ex09.value_iteration import value_iteration + from irlc.ex09.gambler import GamblerEnv + env = GamblerEnv() + pi, v = value_iteration(env, gamma=0.91) + self.check_value_function(env, v) + +# class JackQuestion(ValueFunctionTest): +# """ Gambler's problem """ +# def test_jacks_rental_value_function(self): +# # from irlc.ex09.small_gridworld import SmallGridworldMDP, plot_value_function +# # from irlc.ex09.policy_iteration import policy_iteration +# # from irlc.ex09.value_iteration import value_iteration +# # from irlc.ex09.gambler import GamblerEnv +# from irlc.ex09.jacks_car_rental import JackRentalMDP +# max_cars = 5 +# env = JackRentalMDP(max_cars=max_cars, verbose=True) +# pi, V = value_iteration(env, gamma=.9, theta=1e-3, max_iters=1000, verbose=True) +# self.check_value_function(env, V) + +# class JackQuestion(QuestionGroup): +# title = "Jacks car rental problem" +# +# class JackItem(GridworldDPItem): +# title = "Value function test" +# max_cars = 5 +# tol = 0.01 +# +# def get_value_function(self): +# from irlc.ex09.value_iteration import value_iteration +# from irlc.ex09.jacks_car_rental import JackRentalMDP +# env = JackRentalMDP(max_cars=self.max_cars, verbose=True) +# pi, V = value_iteration(env, gamma=.9, theta=1e-3, max_iters=1000, verbose=True) +# return V, env + + + # return v, env + # pass +# class DynamicalProgrammingGroup(QuestionGroup): +# title = "Dynamical Programming test" +# +# class PolicyEvaluationItem(GridworldDPItem): +# title = "Iterative Policy evaluation" +# +# +# +# class PolicyIterationItem(GridworldDPItem): +# title = "policy iteration" +# def get_value_function(self): +# from irlc.ex09.small_gridworld import SmallGridworldMDP +# from irlc.ex09.policy_iteration import policy_iteration +# env = SmallGridworldMDP() +# pi, v = policy_iteration(env, gamma=0.91) +# return v, env +# class ValueIteartionItem(GridworldDPItem): +# title = "value iteration" +# +# def get_value_function(self): +# from irlc.ex09.value_iteration import value_iteration +# from irlc.ex09.small_gridworld import SmallGridworldMDP +# env = SmallGridworldMDP() +# policy, v = value_iteration(env, gamma=0.92, theta=1e-6) +# return v, env + +# class GamlerQuestion(QuestionGroup): +# title = "Gamblers problem" +# class GamlerItem(GridworldDPItem): +# title = "Value-function test" +# def get_value_function(self): +# # from irlc.ex09.small_gridworld import SmallGridworldMDP, plot_value_function +# # from irlc.ex09.policy_iteration import policy_iteration +# from irlc.ex09.value_iteration import value_iteration +# from irlc.ex09.gambler import GamblerEnv +# env = GamblerEnv() +# pi, v = value_iteration(env, gamma=0.91) +# return v, env + +# class JackQuestion(QuestionGroup): +# title ="Jacks car rental problem" +# class JackItem(GridworldDPItem): +# title = "Value function test" +# max_cars = 5 +# tol = 0.01 +# def get_value_function(self): +# from irlc.ex09.value_iteration import value_iteration +# from irlc.ex09.jacks_car_rental import JackRentalMDP +# env = JackRentalMDP(max_cars=self.max_cars, verbose=True) +# pi, V = value_iteration(env, gamma=.9, theta=1e-3, max_iters=1000, verbose=True) +# return V, env + +class Problem8ValueIterationAgent(UTestCase): + """ Value-iteration agent test """ + + def test_sutton_gridworld(self): + tol = 1e-2 + from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment + env = SuttonCornerGridEnvironment(living_reward=-1) + from irlc.ex09.value_iteration_agent import ValueIterationAgent + agent = ValueIterationAgent(env, mdp=env.mdp) + stats, _ = train(env, agent, num_episodes=1000) + self.assertL2(np.mean([s['Accumulated Reward'] for s in stats]), tol=tol) + + def test_bookgrid_gridworld(self): + tol = 1e-2 + from irlc.gridworld.gridworld_environments import BookGridEnvironment + env = BookGridEnvironment(living_reward=-1) + from irlc.ex09.value_iteration_agent import ValueIterationAgent + agent = ValueIterationAgent(env, mdp=env.mdp) + stats, _ = train(env, agent, num_episodes=1000) + self.assertL2(np.mean([s['Accumulated Reward'] for s in stats]), tol=tol) + + + # + # + # pass + # class ValueAgentItem(GridworldDPItem): + # title = "Evaluation on Suttons small gridworld" + # tol = 1e-2 + # def get_env(self): + # from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment + # return SuttonCornerGridEnvironment(living_reward=-1) + # + # def compute_answer_print(self): + # env = self.get_env() + # from irlc.ex09.value_iteration_agent import ValueIterationAgent + # agent = ValueIterationAgent(env, mdp=env.mdp) + # # env = VideoMonitor(env, agent=agent, agent_monitor_keys=('v',)) + # stats, _ = train(env, agent, num_episodes=1000) + # return np.mean( [s['Accumulated Reward'] for s in stats]) + # + # def process_output(self, res, txt, numbers): + # return res + + # class BookItem(ValueAgentItem): + # title = "Evaluation on alternative gridworld (Bookgrid)" + # def get_env(self): + # from irlc.gridworld.gridworld_environments import BookGridEnvironment + # return BookGridEnvironment(living_reward=-0.6) + +# class DPAgentRLQuestion(QuestionGroup): +# title = "Value-iteration agent test" +# class ValueAgentItem(GridworldDPItem): +# title = "Evaluation on Suttons small gridworld" +# tol = 1e-2 +# def get_env(self): +# from irlc.gridworld.gridworld_environments import SuttonCornerGridEnvironment +# return SuttonCornerGridEnvironment(living_reward=-1) +# +# def compute_answer_print(self): +# env = self.get_env() +# from irlc.ex09.value_iteration_agent import ValueIterationAgent +# agent = ValueIterationAgent(env, mdp=env.mdp) +# # env = VideoMonitor(env, agent=agent, agent_monitor_keys=('v',)) +# stats, _ = train(env, agent, num_episodes=1000) +# return np.mean( [s['Accumulated Reward'] for s in stats]) +# +# def process_output(self, res, txt, numbers): +# return res +# +# class BookItem(ValueAgentItem): +# title = "Evaluation on alternative gridworld (Bookgrid)" +# def get_env(self): +# from irlc.gridworld.gridworld_environments import BookGridEnvironment +# return BookGridEnvironment(living_reward=-0.6) + +class Week09Tests(Report): + title = "Tests for week 09" + pack_imports = [irlc] + individual_imports = [] + questions = [ (Problem1_to_3_Warmup, 10), + (Problem4PolicyEvaluation, 10), + (Problem5PolicyIteration, 10), + (Problem6ValueIteration, 10), + (Problem8ValueIterationAgent, 10), + (Problem9Gambler, 10), + ] + # (JackQuestion, 10), + # (ValueFunctionTest, 20), + + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Week09Tests()) diff --git a/irlc/tests/tests_week10.py b/irlc/tests/tests_week10.py new file mode 100644 index 0000000..b5dd4e6 --- /dev/null +++ b/irlc/tests/tests_week10.py @@ -0,0 +1,132 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from irlc.ex10.question_td0 import a_compute_deltas, b_perform_td0, c_perform_td0_batched +from unitgrade import Report, UTestCase, cache +from irlc import train +import irlc.ex10.envs +import gymnasium as gym +from gymnasium.wrappers import TimeLimit +from irlc.tests.tests_week08 import train_recording + + +class MCAgentQuestion(UTestCase): + """ Test of MC agent """ + def get_env_agent(self): + from irlc.ex10.mc_agent import MCAgent + env = gym.make("SmallGridworld-v0") + env = TimeLimit(env, max_episode_steps=1000) + gamma = .8 + agent = MCAgent(env, gamma=gamma, first_visit=True) + return env, agent + + @cache + def compute_trajectories(self): + env, agent = self.get_env_agent() + _, trajectories = train(env, agent, return_trajectory=True, num_episodes=1, max_steps=100) + return trajectories, agent.Q.to_dict() + + def test_Q_function(self): + trajectories, Q = self.compute_trajectories() + env, agent = self.get_env_agent() + train_recording(env, agent, trajectories) + Qc = [] + Qe = [] + for s, qa in Q.items(): + for a,q in qa.items(): + Qe.append(q) + Qc.append(agent.Q[s,a]) + + self.assertL2(Qe, Qc, tol=1e-5) + + +# class BlackjackQuestion(UTestCase): +# """ MC policy evaluation agent and Blacjack """ +# def test_blackjack_mc(self): +# env = gym.make("Blackjack-v1") +# episodes = 50000 +# from irlc.ex10.mc_evaluate import MCEvaluationAgent +# from irlc.ex10.mc_evaluate_blackjack import get_by_ace, to_matrix, policy20 +# agent = MCEvaluationAgent(env, policy=policy20, gamma=1) +# train(env, agent, num_episodes=episodes) +# w = get_by_ace(agent.v, ace=True) +# X, Y, Z = to_matrix(w) +# print(Z) +# print(Z.dtype) +# self.assertL2(Z, tol=2.5) + + +class TD0Question(UTestCase): + """ Test of TD(0) evaluation agent """ + gamma = 0.8 + + def get_env_agent(self): + from irlc.ex10.td0_evaluate import TD0ValueAgent + env = gym.make("SmallGridworld-v0") + # env = TimeLimit(env, max_episode_steps=1000) + agent = TD0ValueAgent(env, gamma=self.gamma) + return env, agent + + @cache + def compute_trajectories(self): + env, agent = self.get_env_agent() + _, trajectories = train(env, agent, return_trajectory=True, num_episodes=1, max_steps=100) + return trajectories, agent.v + + def test_value_function(self): + # for k in range(1000): + trajectories, v = self.compute_trajectories() + env, agent = self.get_env_agent() + train_recording(env, agent, trajectories) + Qc = [] + Qe = [] + for s, value in v.items(): + Qe.append(value) + Qc.append(agent.v[s]) + + self.assertL2(Qe, Qc, tol=1e-5) + +class MCEvaluationQuestion(TD0Question): + """ Test of MC evaluation agent """ + def get_env_agent(self): + from irlc.ex10.mc_evaluate import MCEvaluationAgent + env = gym.make("SmallGridworld-v0") + env = TimeLimit(env, max_episode_steps=1000) + gamma = .8 + agent = MCEvaluationAgent(env, gamma=gamma, first_visit=True) + return env, agent + + +class ExamQuestionTD0(UTestCase): + + def get_problem(self): + states = [1, 0, 2, -1, 2, 4, 5, 4, 3, 2, 1, -1] + rewards = [1, 1, -1, 0, 1, 2, 2, 0, 0, -1, 1] + v = {s: 0 for s in states} + gamma = 0.9 + alpha = 0.2 + return v, states, rewards, gamma, alpha + + def test_a(self): + v, states, rewards, gamma, alpha = self.get_problem() + self.assertEqualC(a_compute_deltas(v, states, rewards, gamma)) + + def test_b(self): + v, states, rewards, gamma, alpha = self.get_problem() + self.assertEqualC(b_perform_td0(v, states, rewards, gamma, alpha)) + + def test_c(self): + v, states, rewards, gamma, alpha = self.get_problem() + self.assertEqualC(c_perform_td0_batched(v, states, rewards, gamma, alpha)) +class Week10Tests(Report): + title = "Tests for week 10" + pack_imports = [irlc] + individual_imports = [] + questions = [(MCAgentQuestion, 10), + (MCEvaluationQuestion, 10), + # (BlackjackQuestion,5), + (TD0Question, 10), + (ExamQuestionTD0, 10), + ] + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Week10Tests()) diff --git a/irlc/tests/tests_week11.py b/irlc/tests/tests_week11.py new file mode 100644 index 0000000..1fc1087 --- /dev/null +++ b/irlc/tests/tests_week11.py @@ -0,0 +1,199 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import UTestCase, Report, cache +import numpy as np +from irlc import train +import irlc.ex10.envs +import gymnasium as gym +from irlc.tests.tests_week08 import train_recording +from irlc.tests.tests_week10 import TD0Question, MCAgentQuestion + + +# This problem no longer exists. +# class NStepSarseEvaluationQuestion(TD0Question): +# """ Test of TD-n evaluation agent """ +# # class EvaluateTabular(VExperienceItem): +# # title = "Value-function test" +# gamma = 0.8 +# def get_env_agent(self): +# envn = "SmallGridworld-v0" +# from irlc.ex11.nstep_td_evaluate import TDnValueAgent +# env = gym.make(envn) +# agent = TDnValueAgent(env, gamma=self.gamma, n=5) +# return env, agent + + + +class QAgentQuestion(MCAgentQuestion): + """ Test of Q Agent """ + # class EvaluateTabular(QExperienceItem): + # title = "Q-value test" + + def get_env_agent(self): + from irlc.ex11.q_agent import QAgent + env = gym.make("SmallGridworld-v0") + agent = QAgent(env, gamma=.8) + return env, agent + + +# class LinearWeightVectorTest(UTestCase): + + + +# class LinearValueFunctionTest(LinearWeightVectorTest): +# title = "Linear value-function test" +# def compute_answer_print(self): +# trajectories, Q = self.precomputed_payload() +# env, agent = self.get_env_agent() +# train_recording(env, agent, trajectories) +# self.Q = Q +# self.question.agent = agent +# vfun = [agent.Q[s,a] for s, a in zip(trajectories[0].state, trajectories[0].action)] +# return vfun + +# class TabularAgentStub(UTestCase): +# +# pass + +class TabularAgentStub(UTestCase): + """ Average return over many simulated episodes """ + gamma = 0.95 + epsilon = 0.2 + tol = 0.1 + tol_qs = 0.3 + + def get_env(self): + return gym.make("SmallGridworld-v0") + + def get_env_agent(self): + raise NotImplementedError() + # from irlc.ex11.sarsa_agent import SarsaAgent + # agent = SarsaAgent(self.get_env(), gamma=self.gamma) + # return agent.env, agent + + def get_trained_agent(self): + env, agent = self.get_env_agent() + stats, _ = train(env, agent, num_episodes=9000) + return agent, stats + + def chk_accumulated_reward(self): + agent, stats = self.get_trained_agent() + s0, _ = agent.env.reset() + actions, qs = agent.Q.get_Qs(s0) + print("Tolerance is", self.tol_qs) + self.assertL2(qs, tol=self.tol_qs) + self.assertL2(np.mean([s['Accumulated Reward'] for s in stats]), tol=self.tol) + + # def test_accumulated_reward(self): + # env, agent = self.get_env_agent() + # stats, _ = train(env, agent, num_episodes=5000) + # s = env.reset() + # actions, qs = agent.Q.get_Qs(s) + # self.assertL2(qs, tol=0.3) + # self.assertL2(np.mean([s['Accumulated Reward'] for s in stats]), tol=self.tol) + +class SarsaQuestion(TabularAgentStub): + + + def get_env_agent(self): + from irlc.ex11.sarsa_agent import SarsaAgent + agent = SarsaAgent(self.get_env(), gamma=self.gamma) + return agent.env, agent + + def test_accumulated_reward(self): + self.tol_qs = 2.7 # Got 2.65 in one run. + self.chk_accumulated_reward() + + +class NStepSarsaQuestion(TabularAgentStub): + title = "N-step Sarsa" + # class SarsaReturnItem(SarsaQuestion): + def get_env_agent(self): + from irlc.ex11.nstep_sarsa_agent import SarsaNAgent + agent = SarsaNAgent(self.get_env(), gamma=self.gamma, n=5) + return agent.env, agent + + def test_accumulated_reward(self): + self.tol_qs = 2.7 + self.chk_accumulated_reward() + + +class LinearAgentStub(UTestCase): + # class LinearExperienceItem(LinearWeightVectorTest): + tol = 1e-6 + # title = "Linear sarsa agent" + alpha = 0.08 + num_episodes = 300 + # title = "Weight-vector test" + # testfun = QPrintItem.assertL2 + gamma = 0.8 + tol_w = 1e-5 + + + def get_env_agent(self): + raise NotImplementedError() + + def get_env(self): + return gym.make("MountainCar500-v0") + + # def get_env_agent(self): + # return None, None + + @cache + def compute_trajectories(self): + env, agent = self.get_env_agent() + _, trajectories = train(env, agent, return_trajectory=True, num_episodes=1, max_steps=100) + return trajectories, agent.Q.w + + def chk_Q_weight_vector_w(self): + trajectories, w = self.compute_trajectories() + env, agent = self.get_env_agent() + train_recording(env, agent, trajectories) + print(w) + print(agent.Q.w) + self.assertL2(agent.Q.w, w, tol=self.tol_w) + + pass +class LinearSarsaAgentQuestion(LinearAgentStub): + """ Sarsa Agent with linear function approximators """ + + def get_env_agent(self): + env = self.get_env() + from irlc.ex11.semi_grad_sarsa import LinearSemiGradSarsa + agent = LinearSemiGradSarsa(env, gamma=1, alpha=self.alpha, epsilon=0) + return env, agent + + def test_Q_weight_vector_w(self): + self.tol_w = 1.4 + self.chk_Q_weight_vector_w() + +class LinearQAgentQuestion(LinearAgentStub): + """ Test of Linear Q Agent """ + + def get_env_agent(self): + env = self.get_env() + alpha = 0.1 + from irlc.ex11.semi_grad_q import LinearSemiGradQAgent + agent = LinearSemiGradQAgent(env, gamma=1, alpha=alpha, epsilon=0) + return env, agent + + def test_Q_weight_vector_w(self): + # self.tol_qs = 1.9 + self.tol_w = 7 + self.chk_Q_weight_vector_w() + + +class Week11Tests(Report): + title = "Tests for week 11" + pack_imports = [irlc] + individual_imports = [] + questions =[ + # (NStepSarseEvaluationQuestion, 10), + (QAgentQuestion, 10), + (LinearQAgentQuestion, 10), + (LinearSarsaAgentQuestion, 10), + (SarsaQuestion, 10), + (NStepSarsaQuestion, 5), + ] +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Week11Tests()) diff --git a/irlc/tests/tests_week12.py b/irlc/tests/tests_week12.py new file mode 100644 index 0000000..17c6c62 --- /dev/null +++ b/irlc/tests/tests_week12.py @@ -0,0 +1,64 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import UTestCase, cache, Report +import irlc.ex10.envs +## WEEK 12: +from irlc.tests.tests_week11 import TabularAgentStub, LinearAgentStub + +class LinearSarsaNstepAgentQuestion(LinearAgentStub): + """ Test of Linear n-step sarsa Agent """ + tol = 2200 + num_episodes = 150 + gamma = 1 + tol_w = 2.5 + + def get_env_agent(self): + env = self.get_env() + from irlc.ex12.semi_grad_nstep_sarsa import LinearSemiGradSarsaN + from irlc.ex12.semi_grad_sarsa_lambda import alpha + agent = LinearSemiGradSarsaN(env, gamma=self.gamma, alpha=alpha, epsilon=0) + return env, agent + + def test_Q_weight_vector_w(self): + + self.chk_Q_weight_vector_w() + + +class LinearSarsaLambdaAgentQuestion(LinearAgentStub): + """ Test of Linear sarsa(Lambda) Agent """ + tol = 2200 + num_episodes = 150 + gamma = 1 + tol_w = 15 + + def get_env_agent(self): + env = self.get_env() + from irlc.ex12.semi_grad_sarsa_lambda import LinearSemiGradSarsaLambda, alpha + agent = LinearSemiGradSarsaLambda(env, gamma=self.gamma, alpha=alpha, epsilon=0) + return env, agent + + def test_Q_weight_vector_w(self): + self.chk_Q_weight_vector_w() + +class SarsaLambdaQuestion(TabularAgentStub): + """ Sarsa(lambda) """ + def get_env_agent(self): + from irlc.ex12.sarsa_lambda_agent import SarsaLambdaAgent + agent = SarsaLambdaAgent(self.get_env(), gamma=self.gamma, lamb=0.7) + return agent.env, agent + + def test_reward_function(self): + self.tol_qs = 3.1 + self.chk_accumulated_reward() + +class Week12Tests(Report): + title = "Tests for week 12" + pack_imports = [irlc] + individual_imports = [] + questions = [ + (SarsaLambdaQuestion, 10), + (LinearSarsaLambdaAgentQuestion, 10), + (LinearSarsaNstepAgentQuestion, 10),] + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Week12Tests()) diff --git a/irlc/tests/tests_week13.py b/irlc/tests/tests_week13.py new file mode 100644 index 0000000..a405795 --- /dev/null +++ b/irlc/tests/tests_week13.py @@ -0,0 +1,76 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from unitgrade import UTestCase, Report +import numpy as np +from irlc import train +import irlc.ex10.envs +from irlc.tests.tests_week11 import TabularAgentStub + +class DoubleQQuestion(TabularAgentStub): + """ Double Q learning """ + def test_accumulated_reward(self): + env, agent = self.get_env_agent() + stats, _ = train(env, agent, num_episodes=5000) + s, info = env.reset() + actions, qs = agent.Q1.get_Qs(s, info) + self.assertL2(qs, tol=10) + self.assertL2(np.mean([s['Accumulated Reward'] for s in stats]), tol=self.tol) + return stats + + def get_env_agent(self): + from irlc.ex13.tabular_double_q import TabularDoubleQ + agent = TabularDoubleQ(self.get_env(), gamma=self.gamma) + return agent.env, agent + + +class DynaQQuestion(TabularAgentStub): + """ Dyna Q learning """ + # class DynaQReturnItem(SarsaReturnTypeItem): + def get_env_agent(self): + from irlc.ex13.dyna_q import DynaQ + agent = DynaQ(self.get_env(), gamma=self.gamma) + return agent.env, agent + + def test_accumulated_reward(self): + self.chk_accumulated_reward() + +class Week13Tests(Report): + title = "Tests for week 13" + pack_imports = [irlc] + individual_imports = [] + questions = [(DoubleQQuestion, 10), + (DynaQQuestion, 10) + ] + +if __name__ == '__main__': + from unitgrade import evaluate_report_student + evaluate_report_student(Week13Tests()) + + # class DynaQItem(SarsaTypeQItem): + # title = "Dyna Q action distribution" + +# class DoubleQQuestion(QuestionGroup): +# title = "Double Q learning" +# class DQReturnItem(SarsaReturnTypeItem): +# def get_env_agent(self): +# from irlc.ex13.tabular_double_q import TabularDoubleQ +# agent = TabularDoubleQ(self.get_env(), gamma=self.gamma) +# return agent.env, agent +# +# class DoubleQItem(SarsaTypeQItem): +# tol = 1 +# def compute_answer_print(self): +# s = self.question.env.reset() +# actions, qs = self.question.agent.Q1.get_Qs(s) +# return qs +# title = "Double Q action distribution" +# +# class DynaQQuestion(QuestionGroup): +# title = "Dyna Q learning" +# class DynaQReturnItem(SarsaReturnTypeItem): +# def get_env_agent(self): +# from irlc.ex13.dyna_q import DynaQ +# agent = DynaQ(self.get_env(), gamma=self.gamma) +# return agent.env, agent +# +# class DynaQItem(SarsaTypeQItem): +# title = "Dyna Q action distribution" diff --git a/irlc/tests/unitgrade_data/BanditQuestion.pkl b/irlc/tests/unitgrade_data/BanditQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2c5a18391d06f2648ea043f218bd0c21e42e5bf7 GIT binary patch literal 96266 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 W1!*?{Y|%b=L%|fa2_P4g>Hz@qg(O1& literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/BrachistochroneConstrainedQuestion.pkl b/irlc/tests/unitgrade_data/BrachistochroneConstrainedQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..f89ebd0b17dcf615ea283960334caa2a4c4a402d GIT binary patch literal 7561 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 literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/BrachistochroneQuestion.pkl b/irlc/tests/unitgrade_data/BrachistochroneQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..f89ebd0b17dcf615ea283960334caa2a4c4a402d GIT binary patch literal 7561 zcmZo*nOY~y00y;FG<rl_GK*4^OM>%r%2JC0OH+$WGV}AM^l%lYmV_2K=Oh*vPidRd z!%~u&n>wX!io5->W7j}>GZ=e>OHzwV;)}r=<BLm^lT#sT*%FJ3Q;SNbv`wj<lEIk4 z);1-BrEQA4-9?Z-28ImA9)4t<X{C8n+NNZ1fRuYP^oZt_<`z`yCFd8V>gAT^lw>9r z6(v?q>0v8QPRvOxnlgDx4=Y&7lpfZUlFEWqkO)(n#gxvD_9;PAG`yL67;UEb`T2SM z|Ns9#nDAyOnUdtpQP8{Q*|$Vnhbe7Sf~FK_FlO*VU1qPQ0CrjiV~-@*Wy$$@#U(|F znRzAgWtsUoiQphXxG_VphbO)$6{4y%xn#=ZDH$R??0G2=r%s;Y&Coi<nK5Y!#6gVS zEZ$6QQ!*qwogEk$7#cR*`nZ>YfuYGGvvVH<1B21*oB|NNe@;)M9RtIGlL?a=_c1UW zFiluE)sBHdfuHeI(LM%-h9`2{r`Sy?nUVx@x+2W!N+2T{7<vQ(Qu9(ub4qjJQJ4X; z6BO_c7GfVKFfcG=7=hyg9MDiUNE#k5M&JMeOM5e92xmw-bNGjIYw_K)h6Nc!1xS;< z<_<`Z8D)T+0@I|Hp#k!Hh8E1{{!pJgeP98rf2HYm&6a_IK_ThncM!efP{Df;ZD9C^ z9~1~btWCdy_%(C(8iDu=rri4s;xCcZvj_1D?)rh%FL|&R%vU(O8qEK}^b)N8#q_^F zK<XRr#<7FccijHPYRAC9AR)X%2Sndko+JpO4FZpwg6JB>9B~jm$KahVh`uvvt2BsC zu;q{e(Gkxh<Uq88L5>KB)+kAr2hj|Fr!s=*3G6RqLG+giq6#4UVt9=uL42jsO?n{y z20>*Z5PxP%lp2VC;^`x15I;qv?JXz~Fx17L2Dx|F=j&o1@c_<zCXl+SmYwP#{vGui zVGv(>$}@8iKg0Zr3@9-Kd^U6j@jopuPy)$Ex9NL;_!gNjRY80X%jaGoev$tf4G{nS z<_upD-|ysaEfC+TEW{tg-=SEh12V6NLnQ#jFVhUr1@Zkh2!r{1F0BOd8Nz1pg4L_3 ztOE0|o&4wnQt$U55zIfo!`~ak_YXJ<Ht+taP_X?w@}Fpf?7NZO0d`-C?+1|m4I*3j zxPsLG{P<fFB(EU74D27-iZ>wlHl#2-b^^(N=-j0aa!=u`V~!xc;rvc;IClOmvj_1- zp5}r5yEvJ}2F(8vtO7D`t2(c>9Rowd)m>`JApW_ZT2>(WGYWqcLFPTFSqciz2EO!H z;CN&C_saw%-=A_)9;Du)#u&_JZCfh~;xm_gHwMYC;+`fA($DcW-3Y{geQk{-NWQ?? z$pFOPY5QCp#DDtou^!0&%I)%EApWdPC%}A}oLCVMzfgN4C_Of;Q9L39;)fkp)CB22 z7#}PM;;T$^1IK>}|80H{|D4imHIV#rPgPzJKdi<;6=Z&^&Mq#Hdzdt>l|cN3m*;bU z<oydg6hP|P4z6Yc$zS}g2THdMDbKI4faE_I#emaywWkF$NM6iPP6DKU3-dijki6f| ziQx3^7O{x|#CLgC0#3)05+VOV={Au=T>xaC&fn>OL40w6%UmG+N!q4=Kzzw(_rUq? zO|!&r5PwB)9TP}>z)JOBApYcIi3}k1dyTz*g7^ZF?*Bpg;7(%Z4-o%b&`%J*!PT?m z`(6fy24!|BaDL;z>HQ7FPm?*!0xB%8$E^7RQg8R-D-VbtGso={NWLk#2<-mp>+gc{ z*@4cUJ5nI~-z2|&vX_BjLG;;GiXi(1UqxI5>HqU2L<7X<PZPgr%fRqJrkmdo#NTyq z+6P+(289`?^DOKb7#1}6ih<nG@hZ+9lpas;>w59pF)$STxzgZn$H36Cf>9gf&klva zow55Mg*Bvv1Q(j>FTjOhkBD<(QAt65PHISIZYq`n+v~vD98iJni&S7k*dSx<&Vfx~ z$neE1urI~WW=uKo#eNE;j)SNGX|mT40PD)|#b02%db5D5DyIb;VD$_P8*c3Zv$lkS zB8Y(@;}L|PngHQ5oVEeW_h&-*1^2-GhWug({|zUYZs;ii(+vHhV7eiv9!xXnD}d<( z=G9=DAw?TZA9&OPrWxMofN2HY1~A=l-U3WJOzHsB4QZxe`oXnEFwKzb457=rz;wfI zYcOrFt_e&x9Q6Xz0mj{6nqi4On7(lcBG0hK55#{^?hlo3gvg8VK;_lFLGlbAwnNR& zu?6!r`l0Sqasu-i_&Oo9JVbthO)Z$;pk@rF59GE%Xjum^-SE8vOf&3L2Ga>*&0zXK zCd5AvCPBlmR0%BZz*+~U8Q!}?Xw?D;t*8&C9h{-+5BY%k43X&&+S?LLH&iEr=><mu zz%)a5447W<$q`I5Xa|8Z1_Q(UATa+yFT`IDg4`hd2gP9dhDRY_egdNhn6L2I1I%YQ z)&%AsSQiH7U$9LC^AoZ?!F+-49x#7_Lj;(g!JiA}U)T%r&yP8i!F-0wNU*%jiV`q? z!xl(*G{nvX^B06if#pwZtpf88e6j-bJ!0pB`3wF-<X`eOfcXb*tAOPbwk!hkA54!1 z^Ka;Y-RoeIsQ?y#v1TclPSApcOTw0BFyFx622B5$u>wppEQ81|nA`&92YiHtgGBLa zFkj#<L|)+)L|z~i60QN3>%j60Y9aCuu0iA-93#Qvck(uXX@f+F`x<y5@&{fefW;f; zZ3NR5fspWd@SqXQe-M`jrX?CSfoTS2NccBILBb~>4HC`|wnOCCu?K?v&+sx1to}eO zBwhuoA?6<_hJ^Ql4V7SZ2ewv%)m_Mf_>V!370eG{oD7z4P=~nVK=CZFc)}w;Fx`={ z04%@aR~wk$aJC)HU$7sNE+Whpg82z^`oQuA{~-JW9Qj~=gGnuzmQb4lrX4PJfoTiB zaxi`7-vKZk&<jZyQ*=&&`2v~{efzYog83PtbHQ}c@_S%<1_M~$!QlBFFrTAt4v0Q5 zrSc(&W>B~aPIn0*ir2vWie*#5^sW!*!1MueNPK-r-v#DR&~F9PGI#eu{1cG`rVY|o zfN2IbNd5_Wd<4u7$byuU7u*(s`5%HI<=6xNHDGf#%qs(n8z@84;{_o|xuRtPuDBQ& zrb6=h1&f_v^%~G}%f#zCm~U|_AFN+u)ow7q!v|7sxhO&OOYBPp%a=Ub4wh#qfy7JJ z=7V7V14&5wTJdNLn9q?6DVG<lfSC8;0;IfHa}|<aK0JoFe~bNAuzHJQ#$Z~(7n0sD z+<=t(kK!Te+hTbDSpLA3m0<eA`5Lf$q&gw|fF)62aRJL^VERH^6<B`1?h-IRVi_d; zyhvLN<`+DJl%w^03&8vfRjFXwz<VK>o^Zb$tlz;Al1>6lGr{5qZbQn84~-CchP;Vj z@q~FfV7fsXl5Ps7K;#>4LEQDBJr5$EGXqQ;q(S8OoS6WzrxPN7BN<|z!(woJHi)v$ z0?Qv@gXBjJg?h052KQ31c*~^eVETh@7Fe8NB_tjh93biC!DUGO;2;ah?-4B!`vfu| z^+3ZmNIJZ56H;D0@R<WPFTosAPZvypgipiO5U}|Ie2c;I2U6m}w1e;}u((6IGnh_L zo(dLcsPYBV38wSF;tW$D@yqZ)7|d@t1*z{C6l5X%kJ@0Gq2W2C-Jl7nuNfE=!Quz5 zK+0PNhEtGsgNG*Ae1--=uslNo8-!-q0+wgEBmj|T__znsz=E`Bz>OSLNJk#gz;ezn zF2T~kGI*&d0%~AoAT_WcY>+YV237`U1FKN_e#Nox&afUaL<LBby;cIa8I+NMzk#I= zYhXQq^oSW480JGf<^c`3hPjY{s(@5v3=9bnzJn^%;}anKTu8)%Z3T@hbU`u#1H&A! ze8W6Qg~h;705Lzu3mTBi!2AObAQd75Ljgqn|9+_XYrygeCm{tk%={~xS3>1Cg4H)U z?}zds=4&Z#h4N>B^&ehw0?LQT|Ki<(!ne2xDIlTtH>|dq1eIR_Hh)6#38;G^E;#TT zT0k)@0-Mj@`vNKtF~3jYER^2^mS=YY_aqn?7{KmnP-KHt01ONpK;}2(T7Y{xppXNp zZ*bmr1*(4qh|gdu1MZ14Ffc3tsb~1ab__*+*Bx-rg@J*g0<50F2wK21>;S88$%a%Q z5Z8mOISBP1MC5?dUI>2zBt95s!}LQEdO{g2JePsZd$1OgVHp@EfbBD2hcsYd_CI(9 zsTdg;wt&@d$XNn0pJ4%5{h7Ov3YCEY625QqK|LLiTOj<*O&g%<A^x8<=>e1v(eDxu zsi0u`KfJsPm7fB(k6~vXln-&=jo-(i{3&4j8F;}BYX$}eNcuHMS`H0QNc=6RfE1h{ z7lE+B^Sw~{1c?6a&;~5S46uC>E}Nn9ePBMrB1lC9(hI@~osbHXfgu8{-$5)J>YffT z-y<JVz%d*s2J2riA5xLR+&5?XTB!LgVD%2Wb5Qh82!S>L83Mri83fd!>LLEA2!J$z z7#Lc>@(XgH1vx_lm|tL43RMru-w#S46#)Z71K2);w}nvqGQfO>2N6*95d92&kb;_l zApk7D;D#MkJtVvo5@7a0^-qK}yg^|D!Uv8*8deMp(D)I8l`jzYFlfN+n+$d@Ly0of zeu#Yx2N)psDXaq9&#-_WBA;*!qFzAU7E(Y%N<?rWskQ)QHA9cMQ&D1aMrLtIesV@p zejc_?u<#<g51=x-8L5nhut6r-T>u-zkkO1;M!&s!F^+H7BUmRGq5`DJUgH5+S4K1b zGFsM~8PW;f!30(xbx(LM$geibCLaR%QKzEO05mF6Q#T)+XL(L+x&#t`z;qcr8g=1& z*b|WYJN6sEqaAMdpV@-c_v~H<8cksE@w)UMq+a6nd<T$tUUB9NkotfQo~I!3lnIZ) zqgE%LUbznvU!YQZ5+r_MzBYLD=K#~KLm=^n+1-#v97EVYko=b_4e;pc6OU!!QJX6> zR)R*;7|wd069$cDoV}z99&P$#vl{H4ylKtKAaPYkCsEKSkYbjb3&=eRC1#+}5(c#= z?|4A`FNd=&_AxLx^dvn5jmkBA=UQwG65nXh8v&v#3ao-aqbtU*1D!zT6f9>=-^akP zAjdF2(2jv2K}fdM5ya<H6ix-H|C6^BG`gs;HuX5j{|f@$!;(SfpAb3@9wq#;t;Z6? zKWOnJ8f0Eh{WkDuo#=(<ApbOIGj8_;ne!;!6*TI_aC7Bvu)iigQUJTF#ib84I>a!e z<05FZh#|yB2;@J81=s(B!&6`}?*&kJJ=nVV9f(di_5L0xJRh(#p9k?9Ud(?3q8Y3X z-vWs%?3n~9`-AR01Bu_r{{<dJUgN(7Jo*&E!z=-E&zGsH;BYPoWCD#sF|^E@1rk4S zkbP<}D15dFKLCwVJ5;-@3jnFNX{!Q>D_Ebs3ld-O`Rinmc!U2@MbKzdLod4yc(gEX zyBug#vtdq7lBFF3gTw2sQXu~{q#a%Y5@$%`TM4$8L6>hc$h}L7yq@oc<UL4AX93OJ z=vIIebB_{Q-gAb{cBH0YX(|cW?F2QdGUg#=LkJsWsNH3-nG6~82xdcw3XmpyofBYP c8S_T7At)J)X2W5h4IwEVocL8C1FNNa0G|{UqyPW_ literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/CartpoleCostQuestion.pkl b/irlc/tests/unitgrade_data/CartpoleCostQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..f89ebd0b17dcf615ea283960334caa2a4c4a402d GIT binary patch literal 7561 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 literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/CartpoleTimeQuestion.pkl b/irlc/tests/unitgrade_data/CartpoleTimeQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..f89ebd0b17dcf615ea283960334caa2a4c4a402d GIT binary patch literal 7561 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 literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/DirectAgentPendulum.pkl b/irlc/tests/unitgrade_data/DirectAgentPendulum.pkl new file mode 100644 index 0000000000000000000000000000000000000000..0c8ed034d34e4f1249429c51e84cde358e9e0c53 GIT binary patch literal 230 zcmZo*nR=T60&1sd^a#6T7NsVaIHsrOl?0^brIhBB=1%G1Do!m4EpX0BEH0kXHl>H9 zBr`X4O4}57dyWNQtr?6xyd|l{CGiC?Ep1bJ*b<A2Q;SNbv`wj<;?2+_npc`zP^p)k zUzDnsTbfgnnOIbmSUIJKtvER`C$VVC<S9L@U?o#}SW`+W3sONMOlcNVIy>5@1WnQK zX6|9Mnd0Z?=k@>p|NmgZo1tV%k~7DR*Q@FqzxEuM(l#Y%N^u5b23y;d43@Sj?ha1> LqB9s67)td3nj>9? literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/DirectMethods.pkl b/irlc/tests/unitgrade_data/DirectMethods.pkl new file mode 100644 index 0000000000000000000000000000000000000000..7807f4c5c34901502f48afab8f9e4b5368ddb9c7 GIT binary patch literal 1352 zcmZo*nQF_*00y;FG<tYlGK*4^OMFvHGV)W3r}S_Yr<Q~kIOil57f)%M(!)}cnVUML zZHl}7eJyX0rVPd&v69r{lK86lvc#gy#H5_m__EaGlKdi&a<;_c;?$y&DQ#0~r+72; z6h>FX8^jyvD1azK9feXD&k!PL7!MYN@{AyYMi4<L&ln<T3=xF#Odx_L5J51n#6U-( z#4UD8aRy@sTicWj7Lc2z3qVe0$YAUdg}B)uJ~J<~Br`E5zPKc@1mv*{4v1T0r)czu z=9T6aRO%(?7p3aumgbaXCKeSXR!-?*D^5<#Ni3Q&c}fo}Sjm(g)|8UUf>e+QQ<}w; z&W`peK~prmnR^&*rug~!dHw(Y|38@UW+<7G<jldqz>x4;k<(#H+mxUw8KN1|U?H&M z2nu!7++-q4W5RF6pY{Ze$Kr^D--<8E(ul<@yh7d#8KM~yJxpmPh#<_6!4iNh3=9pB zFh~VOFdr;}ji!Lj&tU8khD2~^d}%>JYEgVreraCHl(s2I(VHQf;p@zDo8J>+5QGcT z4hte*XOK1ZNZi}}Cs7qQAj>i^pm1rY7{iea3`mYda|VWD<bVr-1)Q!0NF69=Km*Pv zJ}1ANqJaC4<fhyFCl4TT85kOnWzo2_Qw;JWiZjpy4%Jm?vJ8+s08Vjzuz*wX02#_q Gss{i`ExC&T literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/DirectSolverQuestion.pkl b/irlc/tests/unitgrade_data/DirectSolverQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..f89ebd0b17dcf615ea283960334caa2a4c4a402d GIT binary patch literal 7561 zcmZo*nOY~y00y;FG<rl_GK*4^OM>%r%2JC0OH+$WGV}AM^l%lYmV_2K=Oh*vPidRd z!%~u&n>wX!io5->W7j}>GZ=e>OHzwV;)}r=<BLm^lT#sT*%FJ3Q;SNbv`wj<lEIk4 z);1-BrEQA4-9?Z-28ImA9)4t<X{C8n+NNZ1fRuYP^oZt_<`z`yCFd8V>gAT^lw>9r z6(v?q>0v8QPRvOxnlgDx4=Y&7lpfZUlFEWqkO)(n#gxvD_9;PAG`yL67;UEb`T2SM z|Ns9#nDAyOnUdtpQP8{Q*|$Vnhbe7Sf~FK_FlO*VU1qPQ0CrjiV~-@*Wy$$@#U(|F znRzAgWtsUoiQphXxG_VphbO)$6{4y%xn#=ZDH$R??0G2=r%s;Y&Coi<nK5Y!#6gVS zEZ$6QQ!*qwogEk$7#cR*`nZ>YfuYGGvvVH<1B21*oB|NNe@;)M9RtIGlL?a=_c1UW zFiluE)sBHdfuHeI(LM%-h9`2{r`Sy?nUVx@x+2W!N+2T{7<vQ(Qu9(ub4qjJQJ4X; z6BO_c7GfVKFfcG=7=hyg9MDiUNE#k5M&JMeOM5e92xmw-bNGjIYw_K)h6Nc!1xS;< z<_<`Z8D)T+0@I|Hp#k!Hh8E1{{!pJgeP98rf2HYm&6a_IK_ThncM!efP{Df;ZD9C^ z9~1~btWCdy_%(C(8iDu=rri4s;xCcZvj_1D?)rh%FL|&R%vU(O8qEK}^b)N8#q_^F zK<XRr#<7FccijHPYRAC9AR)X%2Sndko+JpO4FZpwg6JB>9B~jm$KahVh`uvvt2BsC zu;q{e(Gkxh<Uq88L5>KB)+kAr2hj|Fr!s=*3G6RqLG+giq6#4UVt9=uL42jsO?n{y z20>*Z5PxP%lp2VC;^`x15I;qv?JXz~Fx17L2Dx|F=j&o1@c_<zCXl+SmYwP#{vGui zVGv(>$}@8iKg0Zr3@9-Kd^U6j@jopuPy)$Ex9NL;_!gNjRY80X%jaGoev$tf4G{nS z<_upD-|ysaEfC+TEW{tg-=SEh12V6NLnQ#jFVhUr1@Zkh2!r{1F0BOd8Nz1pg4L_3 ztOE0|o&4wnQt$U55zIfo!`~ak_YXJ<Ht+taP_X?w@}Fpf?7NZO0d`-C?+1|m4I*3j zxPsLG{P<fFB(EU74D27-iZ>wlHl#2-b^^(N=-j0aa!=u`V~!xc;rvc;IClOmvj_1- zp5}r5yEvJ}2F(8vtO7D`t2(c>9Rowd)m>`JApW_ZT2>(WGYWqcLFPTFSqciz2EO!H z;CN&C_saw%-=A_)9;Du)#u&_JZCfh~;xm_gHwMYC;+`fA($DcW-3Y{geQk{-NWQ?? z$pFOPY5QCp#DDtou^!0&%I)%EApWdPC%}A}oLCVMzfgN4C_Of;Q9L39;)fkp)CB22 z7#}PM;;T$^1IK>}|80H{|D4imHIV#rPgPzJKdi<;6=Z&^&Mq#Hdzdt>l|cN3m*;bU z<oydg6hP|P4z6Yc$zS}g2THdMDbKI4faE_I#emaywWkF$NM6iPP6DKU3-dijki6f| ziQx3^7O{x|#CLgC0#3)05+VOV={Au=T>xaC&fn>OL40w6%UmG+N!q4=Kzzw(_rUq? zO|!&r5PwB)9TP}>z)JOBApYcIi3}k1dyTz*g7^ZF?*Bpg;7(%Z4-o%b&`%J*!PT?m z`(6fy24!|BaDL;z>HQ7FPm?*!0xB%8$E^7RQg8R-D-VbtGso={NWLk#2<-mp>+gc{ z*@4cUJ5nI~-z2|&vX_BjLG;;GiXi(1UqxI5>HqU2L<7X<PZPgr%fRqJrkmdo#NTyq z+6P+(289`?^DOKb7#1}6ih<nG@hZ+9lpas;>w59pF)$STxzgZn$H36Cf>9gf&klva zow55Mg*Bvv1Q(j>FTjOhkBD<(QAt65PHISIZYq`n+v~vD98iJni&S7k*dSx<&Vfx~ z$neE1urI~WW=uKo#eNE;j)SNGX|mT40PD)|#b02%db5D5DyIb;VD$_P8*c3Zv$lkS zB8Y(@;}L|PngHQ5oVEeW_h&-*1^2-GhWug({|zUYZs;ii(+vHhV7eiv9!xXnD}d<( z=G9=DAw?TZA9&OPrWxMofN2HY1~A=l-U3WJOzHsB4QZxe`oXnEFwKzb457=rz;wfI zYcOrFt_e&x9Q6Xz0mj{6nqi4On7(lcBG0hK55#{^?hlo3gvg8VK;_lFLGlbAwnNR& zu?6!r`l0Sqasu-i_&Oo9JVbthO)Z$;pk@rF59GE%Xjum^-SE8vOf&3L2Ga>*&0zXK zCd5AvCPBlmR0%BZz*+~U8Q!}?Xw?D;t*8&C9h{-+5BY%k43X&&+S?LLH&iEr=><mu zz%)a5447W<$q`I5Xa|8Z1_Q(UATa+yFT`IDg4`hd2gP9dhDRY_egdNhn6L2I1I%YQ z)&%AsSQiH7U$9LC^AoZ?!F+-49x#7_Lj;(g!JiA}U)T%r&yP8i!F-0wNU*%jiV`q? z!xl(*G{nvX^B06if#pwZtpf88e6j-bJ!0pB`3wF-<X`eOfcXb*tAOPbwk!hkA54!1 z^Ka;Y-RoeIsQ?y#v1TclPSApcOTw0BFyFx622B5$u>wppEQ81|nA`&92YiHtgGBLa zFkj#<L|)+)L|z~i60QN3>%j60Y9aCuu0iA-93#Qvck(uXX@f+F`x<y5@&{fefW;f; zZ3NR5fspWd@SqXQe-M`jrX?CSfoTS2NccBILBb~>4HC`|wnOCCu?K?v&+sx1to}eO zBwhuoA?6<_hJ^Ql4V7SZ2ewv%)m_Mf_>V!370eG{oD7z4P=~nVK=CZFc)}w;Fx`={ z04%@aR~wk$aJC)HU$7sNE+Whpg82z^`oQuA{~-JW9Qj~=gGnuzmQb4lrX4PJfoTiB zaxi`7-vKZk&<jZyQ*=&&`2v~{efzYog83PtbHQ}c@_S%<1_M~$!QlBFFrTAt4v0Q5 zrSc(&W>B~aPIn0*ir2vWie*#5^sW!*!1MueNPK-r-v#DR&~F9PGI#eu{1cG`rVY|o zfN2IbNd5_Wd<4u7$byuU7u*(s`5%HI<=6xNHDGf#%qs(n8z@84;{_o|xuRtPuDBQ& zrb6=h1&f_v^%~G}%f#zCm~U|_AFN+u)ow7q!v|7sxhO&OOYBPp%a=Ub4wh#qfy7JJ z=7V7V14&5wTJdNLn9q?6DVG<lfSC8;0;IfHa}|<aK0JoFe~bNAuzHJQ#$Z~(7n0sD z+<=t(kK!Te+hTbDSpLA3m0<eA`5Lf$q&gw|fF)62aRJL^VERH^6<B`1?h-IRVi_d; zyhvLN<`+DJl%w^03&8vfRjFXwz<VK>o^Zb$tlz;Al1>6lGr{5qZbQn84~-CchP;Vj z@q~FfV7fsXl5Ps7K;#>4LEQDBJr5$EGXqQ;q(S8OoS6WzrxPN7BN<|z!(woJHi)v$ z0?Qv@gXBjJg?h052KQ31c*~^eVETh@7Fe8NB_tjh93biC!DUGO;2;ah?-4B!`vfu| z^+3ZmNIJZ56H;D0@R<WPFTosAPZvypgipiO5U}|Ie2c;I2U6m}w1e;}u((6IGnh_L zo(dLcsPYBV38wSF;tW$D@yqZ)7|d@t1*z{C6l5X%kJ@0Gq2W2C-Jl7nuNfE=!Quz5 zK+0PNhEtGsgNG*Ae1--=uslNo8-!-q0+wgEBmj|T__znsz=E`Bz>OSLNJk#gz;ezn zF2T~kGI*&d0%~AoAT_WcY>+YV237`U1FKN_e#Nox&afUaL<LBby;cIa8I+NMzk#I= zYhXQq^oSW480JGf<^c`3hPjY{s(@5v3=9bnzJn^%;}anKTu8)%Z3T@hbU`u#1H&A! ze8W6Qg~h;705Lzu3mTBi!2AObAQd75Ljgqn|9+_XYrygeCm{tk%={~xS3>1Cg4H)U z?}zds=4&Z#h4N>B^&ehw0?LQT|Ki<(!ne2xDIlTtH>|dq1eIR_Hh)6#38;G^E;#TT zT0k)@0-Mj@`vNKtF~3jYER^2^mS=YY_aqn?7{KmnP-KHt01ONpK;}2(T7Y{xppXNp zZ*bmr1*(4qh|gdu1MZ14Ffc3tsb~1ab__*+*Bx-rg@J*g0<50F2wK21>;S88$%a%Q z5Z8mOISBP1MC5?dUI>2zBt95s!}LQEdO{g2JePsZd$1OgVHp@EfbBD2hcsYd_CI(9 zsTdg;wt&@d$XNn0pJ4%5{h7Ov3YCEY625QqK|LLiTOj<*O&g%<A^x8<=>e1v(eDxu zsi0u`KfJsPm7fB(k6~vXln-&=jo-(i{3&4j8F;}BYX$}eNcuHMS`H0QNc=6RfE1h{ z7lE+B^Sw~{1c?6a&;~5S46uC>E}Nn9ePBMrB1lC9(hI@~osbHXfgu8{-$5)J>YffT z-y<JVz%d*s2J2riA5xLR+&5?XTB!LgVD%2Wb5Qh82!S>L83Mri83fd!>LLEA2!J$z z7#Lc>@(XgH1vx_lm|tL43RMru-w#S46#)Z71K2);w}nvqGQfO>2N6*95d92&kb;_l zApk7D;D#MkJtVvo5@7a0^-qK}yg^|D!Uv8*8deMp(D)I8l`jzYFlfN+n+$d@Ly0of zeu#Yx2N)psDXaq9&#-_WBA;*!qFzAU7E(Y%N<?rWskQ)QHA9cMQ&D1aMrLtIesV@p zejc_?u<#<g51=x-8L5nhut6r-T>u-zkkO1;M!&s!F^+H7BUmRGq5`DJUgH5+S4K1b zGFsM~8PW;f!30(xbx(LM$geibCLaR%QKzEO05mF6Q#T)+XL(L+x&#t`z;qcr8g=1& z*b|WYJN6sEqaAMdpV@-c_v~H<8cksE@w)UMq+a6nd<T$tUUB9NkotfQo~I!3lnIZ) zqgE%LUbznvU!YQZ5+r_MzBYLD=K#~KLm=^n+1-#v97EVYko=b_4e;pc6OU!!QJX6> zR)R*;7|wd069$cDoV}z99&P$#vl{H4ylKtKAaPYkCsEKSkYbjb3&=eRC1#+}5(c#= z?|4A`FNd=&_AxLx^dvn5jmkBA=UQwG65nXh8v&v#3ao-aqbtU*1D!zT6f9>=-^akP zAjdF2(2jv2K}fdM5ya<H6ix-H|C6^BG`gs;HuX5j{|f@$!;(SfpAb3@9wq#;t;Z6? zKWOnJ8f0Eh{WkDuo#=(<ApbOIGj8_;ne!;!6*TI_aC7Bvu)iigQUJTF#ib84I>a!e z<05FZh#|yB2;@J81=s(B!&6`}?*&kJJ=nVV9f(di_5L0xJRh(#p9k?9Ud(?3q8Y3X z-vWs%?3n~9`-AR01Bu_r{{<dJUgN(7Jo*&E!z=-E&zGsH;BYPoWCD#sF|^E@1rk4S zkbP<}D15dFKLCwVJ5;-@3jnFNX{!Q>D_Ebs3ld-O`Rinmc!U2@MbKzdLod4yc(gEX zyBug#vtdq7lBFF3gTw2sQXu~{q#a%Y5@$%`TM4$8L6>hc$h}L7yq@oc<UL4AX93OJ z=vIIebB_{Q-gAb{cBH0YX(|cW?F2QdGUg#=LkJsWsNH3-nG6~82xdcw3XmpyofBYP c8S_T7At)J)X2W5h4IwEVocL8C1FNNa0G|{UqyPW_ literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/DoubleQQuestion.pkl b/irlc/tests/unitgrade_data/DoubleQQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..338359a9b6b0183a8855b431d00c4230184b6531 GIT binary patch literal 278 zcmZo*naa(`00y;FG<x`5@=KF)QUe1^Q;SP7^Yf<ka22PPgcdmGBo-G>X`9l+Qj(dQ zI;CxjyS>l_u&xZo9`TaY;*$8p<mA%a(wxMS)Rg$5)bhll6p(th#Ny)AqLL|XQ);JZ zcr$3Y@BjaX!%*#I6$Ycn{Q#e`s>S~sH6>HL8GA(YN^=V;^^)_8QuT66b4oH3i;5B} zr}VHDCnx447EPHvrH2))WJ(WfN=aowDoBJW&0<PtNBfkZDH`6)J&ZO}{QUg9{{R2~ yA53^NluSu-=8*rA6IQ#9>A;k>DM3?8GZ-`2+NNZ%v`uk$U^uDZz`(#zss{kXD{x!@ literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/DynaQQuestion.pkl b/irlc/tests/unitgrade_data/DynaQQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..881f7e8445a02d321d4c116613de9ba2555be5b4 GIT binary patch literal 276 zcmZo*naat?00y;FG<tYlD)SNp14~njOEUBGru1+Xr<Q~kIOil57f)%M(!)}cnVUML zZHl`+=K-*u48|VulGNgo_{8Mo(%jOV#FEsM_@dPE#G(|CdbY&k;?$y&DQ#0~r)YRH zXt?kH|Axa*?PV1nM#&U!#vakU(%gbdz2y9&RK48NoRZAMqN2pgDLrh($%#3MMN=kE z>0t#cnbO0WQc_uv3KC&TvzXG^(LN<;iiS6H52MW#KR-XO|NsC02NT{5B~y}|Irhz$ m(!Z<1bYM!`l%Of48H^chZBsH>+NQWWDAcoFU|?V<)dK)7uy7jy literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Exam5InventoryEvaluation.pkl b/irlc/tests/unitgrade_data/Exam5InventoryEvaluation.pkl new file mode 100644 index 0000000000000000000000000000000000000000..9fdf18dc7fa643011b14ff9347ca6e4d145fe2b1 GIT binary patch literal 217 zcmZo*nR<=^0&1sd^hmf?B<7lW=9Q)9mE;#yx|Sv8lqQyB=I2f6;VMoo2`zBWNh~g& z(l(`sr6e;qbxPY5cYDqTu>K6j9_5nM;*$8pcrcY(QIMKklA02qS(2Jt9G{n3Q4*h$ zSP9b0mRMYzT2wNnZA$Hw48{z$wka7bAd^&opqi9K$fOJos1dv{Bg7QIMwIFS0D2}) AU;qFB literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Exam6Toy2d.pkl b/irlc/tests/unitgrade_data/Exam6Toy2d.pkl new file mode 100644 index 0000000000000000000000000000000000000000..1670e52ae3c857948adaa2e31f95386afc7141ed GIT binary patch literal 282 zcmZo*naa<|00y;FG<vvPD-v_fLh>t(Ql|896{nVj7C7f578g%xo6^Hll9`)2rEQA4 zJ$nLJLk43HS4nDdNqkYZNqizm30q=uacWV?l(s3gQ@j~^MDt2>3o7-J^NUjTa!Yec zG82o65-X?luoWjK<|GzPnLMS36|7`R4{J(EWkD)PgelEpN@qv=l%OdZ-poCWHdFlk z{Jj4E|NkFMcr%ntNpj{$XMAhaX7|N@O52p6Da9F#8EkD+GFU)vTlnz=$Z;rcOPbO) jC4&Rvs0`i=VP}r>_fI6vO#O|}FAdYbK*|H8zf=zZS^8|` literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/ExamQuestion7FlowersStore.pkl b/irlc/tests/unitgrade_data/ExamQuestion7FlowersStore.pkl new file mode 100644 index 0000000000000000000000000000000000000000..cb028ef6008443edeaf2d59477e056c3f5c3435b GIT binary patch literal 182 zcmZo*nYx+*0&1sd^hml^B<2Q|rWTiE=I5Ea<>Z&A78M7V<QJt*>ES9)EeS1f&PgmT zp3*j@hovMlH+4$e6nA^}1z-a*7<&XuQj1IC6XVlUOX3Uib25`FK`Pl2i;Gi>N~W|; vshyI+n8DUIC4&W|&%p^*Us8NQQGQZ<YHmRZNM8mAR0A(egG2yWL#ZAB=72v) literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/ExamQuestionTD0.pkl b/irlc/tests/unitgrade_data/ExamQuestionTD0.pkl new file mode 100644 index 0000000000000000000000000000000000000000..8058414ea4d73d7348da513847bf99750505a346 GIT binary patch literal 468 zcmZo*nR=3u0Ss!VX!P*ARwU*ImZlb$Waj6ExEM_7;VMoo2`zBWNh~g&(l(`sr6e;q zbxPY5cY8swCWZ{g9=4Ly;*$78kThFjadB!<$&|J!wNtzqVy9@h+kb$lLooKkL?99j z3<xO)sE|9H0Tp0yhcn>XVJ4>*XE0{4wN1%j0Xd630jv`4tfVPzQ!+Rp?x~%k;mzo7 ze{F$K<h<)Aycyi>PtF8^S>8<U`wu)#aO^bq@%sP&|9|)Wi}I%T`ro(lW^uQ_QuWY% zok+DetGoR@Q~R2?6EnP--R)~@_j}Zz?k@#d&Ihxc@d2vk$(WYk1X(z97MkTycR(x$ fo58@q0J0pWoYmbP#$<+v1=w;?xa9}H8cX#6HFA~} literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/GradientBanditQuestion.pkl b/irlc/tests/unitgrade_data/GradientBanditQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2c5a18391d06f2648ea043f218bd0c21e42e5bf7 GIT binary patch literal 96266 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 W1!*?{Y|%b=L%|fa2_P4g>Hz@qg(O1& literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/ILQRAgentQuestion.pkl b/irlc/tests/unitgrade_data/ILQRAgentQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..e59b83ccdc4b3f776c5a856eec67e5fd46e7d7d0 GIT binary patch literal 325 zcmZo*nQFzz00y;FG<pO*eFB3V(^K<G0!veiOEUBGru1+Xr<Q~kIOil57f)%M(!)}c znVUMLZHl|S`~|SS48|V*lGNgo_{^NbqWDCRW{^6z#Ny)AqLL|XQ);JpGxUh&mF5;y z>LuqFrRwFD=9FY678NB{PU+!^FG@|$&nqq|Dork#GI>f5D_G%_9`?Kxh?2=uyct@j zI5Q?qX`d1_MZ=rXo1=9~244?rN=aowDo6`cn#GjP4u~vs52MW#KR-XO|NsC02NT{5 zB~y|*ogKQ_7W;iTsp;@Ncw+HC1@;4za~mF8ozQe}kJ!@qSe^YqgBaWM-1<iQWb1R< xyVy(j_X!6s+sIXF|H%36qtu?p{ZmS&Bo${cX0WwQ$zTEb|GmLcPym$b0RZsngh2oR literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/ILQRPendulumQuestion.pkl b/irlc/tests/unitgrade_data/ILQRPendulumQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..4f0c03f218e5d0b490f478d91439da34bd99266e GIT binary patch literal 297 zcmZo*nJUM~00y;FG<rlleFB35Qu9(ub4qgqOH+$WGV}AM^l%lYmV_2K=Oh*vPidRd z!%~u&n>wX!in~2$0$6JXV~<2hYH>+?W=>&Id}4ZPUP*ib)D(~gw#4G%)S{9pZBuHe zcr)~f=9T6aRO%(?7p3aumgbaXCKeSXR!-^Ri7!e`&d)0@DJo4anKF4w4=Y&VlpglH z6o`_^Q@j~kr#LevO=+JJG)2Rk(VMw-N(NsKYf4FFK`KZKQ<}w;&JKtya}T4<6hA*d zumAu5{|6J^3?);NI-Mozd{cDo?92CO<||s>`~TkFAkm_={#%Uwl#(e)#TkqlY;99A PSU?_pZIB4^VW}Pf4G?s* literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/LinearQAgentQuestion.pkl b/irlc/tests/unitgrade_data/LinearQAgentQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..b33a50f38070a14eeec2fae6b109a09352122a5e GIT binary patch literal 28763 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 D$RZFR literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/LinearSarsaAgentQuestion.pkl b/irlc/tests/unitgrade_data/LinearSarsaAgentQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..aa697f66dfdc784268f10c345ef0eedd1d3aec6e GIT binary patch literal 28767 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 DlVa_# literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/LinearSarsaLambdaAgentQuestion.pkl b/irlc/tests/unitgrade_data/LinearSarsaLambdaAgentQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..ac6a2adfc3d2faa7e4931cd49899e28973477304 GIT binary patch literal 28773 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 literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/LinearSarsaNstepAgentQuestion.pkl b/irlc/tests/unitgrade_data/LinearSarsaNstepAgentQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..8488e90d29bc64d169076721ebc84563b582102a GIT binary patch literal 28772 zcmZo*nHpKZ00y;FG<sxxGV@Xsi-Hr2iWB{cOHvCQ(^K<G0!veiOEUBGru1+Xr<Q~k zIOil57f)%M(!)}cnVUMLZHl|SQ~=nF48|U@lGNgo_`vw`)XemZlK8UJ<dXcN_;QeP zw#4G%)S{9pZBuHeWH4s1wN2?^b4X51&PbioBa)n-TToh(8edYBm<868nOZ!hhcm4- zFS#T?Kc{#~4_CZLVsS=lN^ol7l*v;x8>jfyPU+#yNG#4MOUx-vozlfoEwf7}?%GQK z;<hPC?Ni#O#7^nq&n(JG)=RB0Fw{!~`DIEER|w38$|;klXv9v@=n>5;%`K?ZOU^G! z)ypl-DalMMDoU)J(!	l$xBMS6ot5np`qv@{}G{u)--l?0G2=C6lLkGqg@|W=xvW zJ|$?1hBu>ThI|ieN=aowDo8z3rp1)b4u}+U52MW#KR-XO|NsC02NT{5B~y|*ojJfk z$H2farDRG{hFpds$jA(3h%QFW46ROQ4o0XNJW7}dD`6(AgoUsYR>Dfy2rFSHtOOP? zcs$KX*c2|pO1KFt;UTPqm#`8(!b<oFD-j^9M3Ar&A;L<82`dpHtVEQs5;4L`#0e{r zAgn}^uo5Z4N~8%Zks+)^maq~z!b;=`D^Vb<M3Jx(CBjOS2`f<{tVETt5;ej~)Cnum zAgn}_uo5l8O0)?p(IKovm#`8&!b<cBD={Ff#E`HOBf?6I2`e!nti+VC5;MX|%n2*8 zAgsiauo5f6N~{Shu_3I)maq~#!b<E3D{&yK#F4NPC&Egc2`h0Sti+YD5;ww1+zBi3 zAgsibuo5rAO1udx@gc0lm#`8)!b<!JD}nSC@V0jY37Zl`SV=HpB_V{Bgc4Q~Mp#KW zVI>iSl|&L&5=B@^G+`w%gq6e+RuV^8NjzaC351m-5>}E#SV=NrB`HWsQe&rRVD#6# znOdi0sP{0XnIL+88QNI;eIFSF_JfSW+P?vrlcmMPz|iT;k*Y7Szw(^rE`kcPyae{o z(Y~>hph8yxf&E9PW>^tanB2&}zxpAcH9>{(5BT;UW>zGuFjtRn|LRYMgcWA2<K3Ua z!a!J|dm``tJx;R-d#39M&wi)9GK5WxxyilXS~r`p!ls2>`wQRBCamyA0_Xl~AqxmA zJSNGpe|N`X!V0|v*!LUmYay&K!HsSIikF^*6;@lZ?!Wb^m9WCu@0j;*dcTyg!jsFG z_9wk0!ZYQmjQiVH5D`2Ax(xe!jpq=y`dQPzeJ*o}h{9tYfA{$a$Pza3^YY*OY%&7~ zE9_bPbKgzLM#2iS?7#18;Fw8Rp+581eXIHU2`iNS{Api43lWLJc-qH(-lckkO=Nrj zVV{QXa>AMGK=p@x9$jgK724T;*f*8ymnFd><<W-s`&46k2%EU=`n!E+wQmwuShe%r zzU(`Ngssj9d%y4T+c|_w-0-y@_8FFI?<VM(l@_1&6|Zz9tg!g&=Y1Da;s`4YiT%2- z^Mf&Ag-46O@3WfIN?73;lVAIGI&L7WP-FJrecz_tB&=|8AH)7F?GFemw1{Hb-*f6I zVTF;enfKdFI6+t;vpws6!K*6?E8KgPZNFITX~GJt)^O}!9`~BC!p-}+_M4t#*+Vc< zJU+>@pR<RFutMeIeETQQ|3}zrsUm^>bE>ZrRygap;QojMs|YL9^$^}~>Un^$!tWnM z_Fqf6LRg_!t=RsVn#Tw$w0b4J->YI9VTDqrlKZ#jFD0z-lcd!CRX0)yE0mlrwO_~Q z7vTb6tDf}!+&SWeO<a3ldVjzV1HuaR(`EL*Ze%B{(Ef<bejbHggxzTPO=kb}WA20% z%I%ifztuB`a6wusEVEx`r8?p2qrO>sf8jTN!V2Aar1#G%ct_Z3#ayZV?W*#GO*CIF zxnJp(D`AC&RTBGklcy0@$oNuh|Ay@+2rIn(Rb)TU<e!8U?o$`u@5lF?utJvq0{bWE zaoG?oQjXX2?e{+~Pgr5_2k!kZ?kE#h*dNNdpLwGiVTDZJ*!J5!7ALGwBba4>|27T6 z3I&Q7_kVS@Agr)y!=HT@irok+3>E*jZ>ef9VTH~s-tV(|<V#p#Oa9A!*TvllD}4F; z@xJV0J;DlCgx}vM*dan#VOsa?eX|5U6HYx$Gp_IZaN`eQh5K7B?<>n-B5bwvo%8!1 zX}ltA;<hDc_J!O$OITs(lau>QBsLIMcuwZ{zI6{b5?06;d}JSQ!6w2A|8yVR*Lj2p z6Q^C;zi-c`7{Vsr(cHgp-L4gcOS8ND`}Z|`_6N5}LE{PD4Bm|1Ox{f1jNXji4BiZ2 zHYyJ!gG~-34$=wI1u_L>4l<hwY#vMo!UO36sl&wsnFo>s(IB-j_aIyZ5dq0T%mJxp z@MZ-01!HVP6Fe}2G$oE>U<5QM!ocuhKi0xdGpm;cJSsA(YBVHZizG%vVl*Vs7tV~P ziP1DMnkGhTQP={z(U2Go3C7XZBYa`$X#F@^KaSRq)UOplUEkU%!v&_6Olh2wh|!hz zW#DL?0x3b97#tWFO#Z!obT#w!{<#ykAN|SvasPpyAAA1ndbU5QMJ#qh&b|HDCjZtg zTXc8-r-_++Esj3gZysEJWykK%`^7vLp0h6hynkxp_m0`sulLWBH~i$P`(gi%mh)j} zuRq=I79GW17w~Am#j^0m^4oX!o5dcL;B|ktpM|YvO~<6K`#a*97<L$b-LJ;0pDS_Z z&3<*!oanDUANJ1?6PYaV=H>n#%Q?o;OCRiSy0ymg)|!X=Ymdh?$xM5+|Hjgyv&WBq z-Y=)N!)VjO&-=MvafUoua(}<Uv)VHA{ZIGL%Fk6&zVLAWlS5~?<@?|6pT1J=L5bhT z{mO@C9f_-Zw_nX6Z_-k;m;2xTFS+6W_4$5Nk&4ZE@1F198hqBlV9N3R&Np<X^KQ7Z z|3${Wm@PX`?6;U-pq-ujeE*rrpQ^gcp6-v8s{gus?z8=CZ%MICn00yo4E0)G)`IK% z#ga>B-PO6ge-4{??CscF`!|$itxNuLV?Tp_zZy%!wf#nFudho#ySKl{?z6n^&)fT* zG#~A`v-HOP^98T3?Uy*eKj9@y&+U~b_rLwQlc(|h$^9vxP8-kRxw!vL>S4ckmDl#a zTC-t}!0pTXU;GWo>sq{Y|CRH73HfTL_bW)P>rLZ4y#H#D#SWd5NA_!Ki|Yv_UfKV1 z?uW`d$ItAaA@P(uCVB7v8x8XNG>>1{pHkQ9(_L|Pzs<|0<fZfX@Bbn8iy>Qa&HfEv zO8HodcI<y8rQ$t7?$Z8?Nr(P+$DZE*`Ib=r<YO22bBn#qp7{O@T>O2>Ps3|shr#P$ zKm$5|K)WOUuiqcAxO2ii-d+1|G$+3AelTOd!O2Coi$#{e)fw+w{_xHI3;Q3>naF%? z&YAr!UzWZ(9dr^d4>F5^VgLS+CA-&tG+MjAX=>y3ub=nqKW3@SzQ%IbekJ{u>0LXv z!^L6tKHKZWvvuEYG;<)Pjgq4wFd71*Aut*OqaiRF0;3@?8UmvsFd71*Aut*OqaiRF z0;3@?8UmvsFd71*Aut*OqaiRF0;3@?8UmvsFd71*Aut*OqaiRF0;3@?8UmvsFd71* zAut*OqaiRF0;3@?8UmvsFd71*Aut*OqaiRF0;3@?8UmvsFd71*Aut*OqaiRF0;3@? l8UmvsFd71*Autp|0CZGe8}wGc3>MIpfXlan@3Sb?0|1gDh%W#D literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/MCAgentQuestion.pkl b/irlc/tests/unitgrade_data/MCAgentQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..713e0329e51abbb76d789ee80671d47f60c6f853 GIT binary patch literal 4712 zcmZo*nHnp^00y;FG<x`bogLFt^GX6sQ;SP7^Yf<ka22PPgcdmGBo-G>X`9l+Qj(dQ zI;CxjyS?ZEu&xZo9{!Tl;*$8l__WfzWU!{TDLrh7#l@*bB~#j_)K1A@%wPivIV2}0 zXQWQ)5lPO^EhsHXjV~!m%t}oz$uG)GEuPZD3D%#VpHn=ghb!JAu{a|&B{;Qk%H%1U zjZ^$;r}S`UBo=3sCFYc-PU+&Pmf58fcWtGAaod!n_9<;sVyE=*XBOoo>!ns080sa0 zJTaw*D+Fdk<&?=&G-9V{^oZt_<`z`yCFd8V>gAT^lw>9r6(v?q>EVelN=?qsD=sN2 zO)i--c}fo}SmBf&_Pi8`lF3uN8Cs_}GbT-GpAs}h!<$hvL%xSKrKGYT6{Mai(_%_z z2SkdwhtXz=pP!%C|NsC0g9&ejk|{}@&K%${V_;yIQZgkeLoP!RWMqaiL>HrGhE}ID z2P0Gs9wkhKl`s=l!a`UHD`6#Ugq5%pRsstcJf7wxYzh})CESFS@DNtQOIQgXVI};8 zl?V`4B1l*XG>79$b;5*A5h1KZl&}&p!b-#mE0G|qM3S%)DZ)ym2`iBytVEWu5;?+3 z<dKx5#)66<Z^pJM-i+Q1ZBx7%KxD?*jI-VhU{MJFJc{ha3^0VMU<9jU^kxF<29Xdp zL>y)cLYxV#5~2peX7Xlko8rw3CLwG_Fq;8H_V9(I7UgE<CFUp;mn4>?P60ca38Xwj zriZOKIWZ@(Xv*X%8CuR9@B*!EN)X5^AXSVYl~By!&6x2Fq!1bc3{$`gnY|gkK}s3C z8NETu89_dSD1?`PP=(Ci3?Tb)l)0dC8ier_KOkuk9#w)`U4g;`gh#_=G+a192?2zM zPhvoBje!b~+9^FOxrxQuQ!q*rZ<f|68R|VunTE*iz#6RWKo&+uMn+H|71vJ5>SJVJ zz-n67R7M7dPUlg@jG(X`4GmZUGa4EUtyAE=rqR$CxuF5=Nf-O2mP~1!l2|)MBja@K z6b)|%_XEP}myh(S{{Xdry_wt(2>(cV+>k!Qo7w$<;0GI~JM$)$W}E>l1+^Ky8N8Xi z89<W4-|A!%8tY0k&VnV~4+y`_^UtYy;mzoNK=}6VV)@5k!Nz@5<q10#0@m?Gc5%hR zyQLZDpgII|yqPB-GXv`g=D$$z<``JVi<6Jt=O}qIdoz?~TmdTu+3bFR|5H}B?&)lh z8llLOvmbBb1DPuH@x;~*g<nfEt|BQFT4(iGrmqO%R**Tj!IJI=I9$tbh8B85JPYv% z?|W9(pLVXL8TY_yAa=2YT|K|*>^z78?)yLW$7p;#)L)wM5UvIu68lfi1c4c)8INkG qcr&=$e}J^Ti!<(HQT*?wSi3e8Pibizbhsyj1vE(1Hw~<*R1W~hGgZa_ literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/MCEvaluationQuestion.pkl b/irlc/tests/unitgrade_data/MCEvaluationQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..f4f0406a0c565589ce80ec15300a0a6fb8a40aa2 GIT binary patch literal 2394 zcmZo*nd;BU00y;FG<rmQon6Zkb4n9SGV}8SOH+$M^pqa1;?$DR0_U8>;^HZ7Q+ilR zGILX>v`ulh7nlInn!(s3T#{N`5)aaw8lP60mkid}Hl>FxvA8(3sANjpl-em7j2Ubo zA&2C|<c!oQJtE2Zxdo*qsqrO6iCL-1CHX~}sl`)zIKle!^K*))^l-&{Bo=3+rUa)J zPMJJKvvG=F?UWwQjKty$uvJsKII3lK>BL=I>0jJ7C8>Q%+mzTTJ^YzPImvpd6$XZS ziRr0%B~yC1LSQyjPMJJKBX){Lk7!<LZb7A9a(+>&UT$elNoHbEQDWtk9-jE3)a3lU z;*z4$<dP|qr}VIb6;A14&r5+QnLNdtp>>KgW73rNDM3>-ycsn!<a=0CN-7IdLF$<@ zEv9sKK%|&^7;UEb`T2SM|Ns9#nDAyOnUd7$%mEHJ1_p*HB~y|z<T4aNMrJ5ObTMjX zXmvVsFhbSfQNl!62{U0OEQFP?5>~=SSP45}C9r_O<7sGm#TRs3ge~GGtb~WK5?&-F zsj;BM;LX@J#hcNa2~0ABNf4U}Dgt6Ng4HlVNrtv58I|4;9y3^s*_)wlN)KO1YEf=x zUSf_yaY<rH>J*Ui88SU=#mR{|iA7T;Psz|iN=9u{f~I6N;1Gf*6ND;w;z9_)Qwl<e zIE`3TVG)9c6vGsR@mL%|NFz8Du;&+09s^-KNe3hi!lO!1iyBavfH2L&1s>xiQ<6YY zSv#eNB{#7+dkRJw=*`kPB}2W3Dbo<SG_Ao}nzAr5GBSePUR*mR;|+GBK6g5gDudQ9 z;IJL^0RpWZi~UkdrZi4T>=6W4>!l@`ImLR(`MJ6Ic~g3LQc}|rOLIz6GLuV;K(#MN zQfX#RNoHR0lpfZ!ocu&k72XP}rZZ~X?LR=upp0tw{U>LFz>JJa_X8|pSI@6HJ1?Wc z{Q!q+`OVNm?~GFS1N@(|vUN{qXB4|15X|vro_x$KqsaY$;0GI~JM$)G6uKV}iaa^{ Y@g}~~HfXyhg9X$gDvUn>vZPcG031S9(EtDd literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/NStepSarsaQuestion.pkl b/irlc/tests/unitgrade_data/NStepSarsaQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..c98a9b05f5d8467d392af2386aa023b3f1b6751b GIT binary patch literal 281 zcmZo*naan=00y;FG<t;mf=f~hf)k6169Y?Ai%T-|^QQE06{nVj7C7f578g%xo6^Hl zl9`)2rEQA4J(mMmV+Lc7cu8t;Nqk~*a%pa9PGU)FN_<gjd16rtNIhF(adB!<$&|J! zwNo^_88qAvus9z#{HKuSet_jIgFwRXf9?mEmwcYuQBv=IfH`i<%9-ttOQv`;_K4<{ z<`z`yCFd8V>gAT^lw>9r6(v?q>0v8QPRvOxnlgDx4=Y&7lpfZUlFEWqkO)(n#gxvD z_9;PAG`yL67;UEb`T2SM|Ns9#nDAyOnUdtpp`B<rd!9AZfhlcMf~J&aFlMl|P03(s Ro8s=kV;}f{fq|h^4*(Z*a2Ego literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/NonstatiotnaryAgentQuestion.pkl b/irlc/tests/unitgrade_data/NonstatiotnaryAgentQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2c5a18391d06f2648ea043f218bd0c21e42e5bf7 GIT binary patch literal 96266 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 W1!*?{Y|%b=L%|fa2_P4g>Hz@qg(O1& literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/PendulumQuestion.pkl b/irlc/tests/unitgrade_data/PendulumQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..f89ebd0b17dcf615ea283960334caa2a4c4a402d GIT binary patch literal 7561 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 literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem1BobsFriend.pkl b/irlc/tests/unitgrade_data/Problem1BobsFriend.pkl new file mode 100644 index 0000000000000000000000000000000000000000..d78b291c68506ecf4fd989c63798af420f4a6796 GIT binary patch literal 170 zcmZo*nL3{V0&1sd^auqM<tOE&<{CQXCl$LDWv1q(OzGh&PAv&7aL!3AE}qghrH7>? zGdFcg+Z1<u0|&6q48|UTlGNgo_{8|syt4SD#Ny0kkV3Y^;^Nezk|}LdYNuo{X0WwQ i$zTC#6D)vf<3-X|YA~g3N(Kj1F)vIp_X4ouQau1*UOAWm literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem1DiscreteKuromoto.pkl b/irlc/tests/unitgrade_data/Problem1DiscreteKuromoto.pkl new file mode 100644 index 0000000000000000000000000000000000000000..92cac8fbf95496ae843852ed47ffa0126de01034 GIT binary patch literal 569 zcmZo*nX1Rc00y;FG<qZgit>|kQgaPmGK-UoQcF_3ON;Vz^Goul^l%lYmV_2K=Oh*v zPidRd!%~u&n>wX!in~1@ST{okV~=P_YH>+?a(-S(W?p7~X>ojReoAT%NHtqxadB!< z$&|J!wNtzqdW4EAa|<f<lJkpF_3}z{lTwR{r}VJ8<>V)pOqo1I!<(UpH_gO6#UL%& z%)-#jAZ?1*+5i9ldz+L@X`NC#rH8YiC^b2=I5R(QinnR;q$$N2j2UcgQ!-dU&Iv03 zyC;LOhYjqUv?*;<GB}_Xi{_QWEzT{?DalMMDoU)J(!	l$xBMS6ot5nhbJ64=Y&V zlpglH6o`_^Q@j~kr#LevO=+JJG)2Rk(VMY#N``C?Yf4FFLF$yrQ+k-vET(jJKxCPF z7;UEb`T2SM|Ns9#nDAyOnUd7$%;8>S_4s|@H~T3iQ<6aL7K6DvAQk3rc8I&PksO{O zlOYeXKSL2>KE!s-PG^p)rMY6ttuNu`8NkeIoW1~LU<P9kH`u(CwCwnl3jAhzGqz31 a0GaCR>@F;t{tj-c4b0S{qy~_wrFsB<+trW& literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem1Kuramoto.pkl b/irlc/tests/unitgrade_data/Problem1Kuramoto.pkl new file mode 100644 index 0000000000000000000000000000000000000000..be8942b1ca5a38b7fc7729522a74b70bfb9ff86f GIT binary patch literal 3013 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 F2LOgYc5DCu literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem1SmallGraph.pkl b/irlc/tests/unitgrade_data/Problem1SmallGraph.pkl new file mode 100644 index 0000000000000000000000000000000000000000..457e6cfae3680e41113fb761612b2d6549e0f33a GIT binary patch literal 3834 zcmZo*nfjiO0Ss!VX!HmL6y+!7q~;n1=O*UlxECcBWK8MdDo!m4EpX0BEH0kXHl>H9 zBr`X4O4}57dyxfTjTwwRY$d71CGlw>X|}}T;?$y&DQ#0~r)YRHc(ZsjdNX=6c{8<7 z@n&+j{{Ys);LYsK=*{fS+&;yd1tG}l&FIbI&C))_n++kz?#<}U>do3d#hU{m$mz`l zGPiw-Hy1*X+nWh$CJ#c8*P97yCLcnO-<t_)rT{`v5bP+%_9@;%2ti?QW~k#u5Q3uK z%uqAM5Q5^~%uq8W5Q35r|F=)^mO=<hd$T~zltBo}db2<sFNYA6_hx~bselkv^ah0! z$el_EL1k}NsF^AVK~-;7sF`XAL3M9dsN*#df|?*}z=5oV5Y&c8oDM=z7annX2tj># z#2Fw24dD@Igb*}_N1O>l&=ekVW(YxZc*I#C1TEnaXN3^7hDV$YLeLf-adrqndw9e- zAOs!Z5$A*ubcRQq3qsHp9&v66L3en>c_0Km;SuMB5cGyeoDV|K7annb2tj{%#04M( z1K|-Dgb)mdM_dR(FccnfVF<x+c*I2@1S8=Q7ljavhDTfsLNFE{ad8O2czDDmAOsWP z5toDzOom5X3PLay9&u?1!E|`UWgrAI;SraG5X^>0Tn<7o7annW2*G@K#1$X}3*ix0 zgb*x-M_dU)uoNC~WeCA?c*Ip81S{bYSA`I)hDTftLa-Jdadim6dU(V&AOsuX5!Zwe zY=%c%3qr6J9&v35!FG7Wbsz*g;Stw`5bTCWTn|F97anna2*G}M#7#g5PJ~C?B!u8( zc*IRX2u_7Z+%$yXba=$gKnTu+N8Bug;B0ur%|Qsxg-6^xgy4L5#4SJwE`&$iB81># zc*HG12rh+3+%kmVa(Kk8fD4vpFlMl|P03&ZRf}zW4?vY1yjo13(l#Z716Ch`>O!{m zDc+25&EWW91{c1}2tiQ2$pWr5SrLM4;0Oj)rR)en4zK|rGdU50T%ZVcw+Fj~fuVhh zH#b6#2OQ6!8kH9z$On#R_Vy{>{0Kn-a6E%l3L*rBK=F)hv@k+W1RUL<x=9ovC<c#i zafF}*IJ!YzkwgeefukE_pEN>H1{~cWGi4Eia^UC&wIAdWf(qd12AQdd5L5z3H^^hk z2tgHabb~BXMF^^aqZ?$VIzmtb9NnN0)I<nsf%7RS$h8rII^cW?GE)~Js0YrcASdY~ z1P$QPXowIrf=8n<LeK;~8ch*$X7Fe<M+jPYgIYEq-&!IBt>DpUjS#d!k49UBoE<zG z?Gb_w@Mv^I2s*)|(HSA=0*^*lgrFNd8r>0s9`I=NL<oApqtP27=mU>NUxc6^JR1EG zf&uVo3`7V9!J{!4As7OW#!!S{7(5!o5rPr$XpBS%M!};o8X*`1kH%PpU>tfh#v|ks z;L(_f5KMwcV=_W81s;v52*EV;XiP`QWx%5`6Cs!dkH&0-U=BPQa}k1h@Mz3O2o}Jj zu@E6x1dqmIgkT9g8cPv^W$<V$M+jEHqp=bpSOt&9YJ^}7JQ`~ef_3m{tVakoz@xDd zA=m_u#%6?I3p^TI5rS>-XlzFacA!UNCqk|Z9*x}y!5(-t_96uP;L+HR5S)M>jS~@a zli<-f86h|Y9*t8Gg45v9I2|E410Ibt5rVVe(Ks6+I0qh$a}k2`;L$iAA-Dh@jSCTi zi{R0?7$LX>9*s*8g3I91xEwABszVcDb!h7faLtv$*uxI)TBiFUSEBCqA3!xM1A{js ag2{wnG9#EQ-V7jvcf$;}xd7H#ss{jdd2!kR literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem1_to_3_Warmup.pkl b/irlc/tests/unitgrade_data/Problem1_to_3_Warmup.pkl new file mode 100644 index 0000000000000000000000000000000000000000..5fe4c1c222730aae3e22f3624738a4c59c0eac1d GIT binary patch literal 497 zcmZo*nfi>80Ss!VX!M8#6y+!7q~;pNm*mGA$A>2t<(3vq>ES9)EeS1f&PgmTp3*j@ zhovMlH+4$e6nA^22C&u)#vaL%)Z&u(g2bW{!}!Fq)S|@n)cB&*^2DMPkPf!Q;^Nez zk|}LdYNu#;Gq~HIoCyN6ycrQpCU>w|3=9n3%y7}t48{z$wka7bAlou{!74Hsd-&kC z8O4_w6;5fJlEDEp`+ywC=$Rn156BpUfQdJg`vD=SD6{(k0g#}vu{VqR0dA-$D?$OA zJKO|zcen{02qq^&0T;r}-0lY?&w#*LZyxspqF|RYc=Ng+5KjYvbZ<VGf^**d2-^e@ zZV*JcObD(36ac)i07xhR8;ceIg+^uY0PtpTKcE6u#88~Um>~?)8I=MSEY$-52Pv+p literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem2BobsPolicy.pkl b/irlc/tests/unitgrade_data/Problem2BobsPolicy.pkl new file mode 100644 index 0000000000000000000000000000000000000000..6a3aeda8f5e65ae42b2ef46f1e849800365db6cd GIT binary patch literal 368 zcmZo*nVQPT00y;FG<t*rit>|kQge-*@{@`K@^dniE2s2u6{nVj7C7f578g%xo6^Hl zl9`)2rEQA4z2*Y2#tg<D-jdYflK8~<)V#9zQbUj`w#4G%)S{9pZBuHeWH4s1wN1%j z0qGHSfawtj>q&}F%qdT-ERIi1F3HT#i!U{p(l#Z71FDS|rfosd29UlC#vUBnK$gO_ z3B$A<TiOQIrh?rz!}#Ko#G;bSy!3b@0~D(zVP>2%U4q{X1Ds~a!_3%plLcf(sU83# C4}@s| literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem2DeterministicDP.pkl b/irlc/tests/unitgrade_data/Problem2DeterministicDP.pkl new file mode 100644 index 0000000000000000000000000000000000000000..b2c9f862612e2ec027398436366b5a8529c55b9e GIT binary patch literal 203 zcmZo*nR<W$0&1sd^oR!(<tOE&<{G)AmZTQtX69uUmt-cp1Wf7SDo!m4EpX0BEH0kX zHl>H9Br`X4O4}57d;SMt?HP<cq9v)tCGjZ*@hQlfL8{pji;Gi>N~W|;shy(X&EQ`D z0j!6?n-RfeLNJ-#9U$@y-Yo78LJ+n$tGj~$gjt%wn8DUIC4&WIzef~Uuv8BK44^p7 literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem3InventoryInventoryEnvironment.pkl b/irlc/tests/unitgrade_data/Problem3InventoryInventoryEnvironment.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2884379ef4ad61d5c1f40f6b0d358ed37807e00a GIT binary patch literal 322 zcmZo*nQG3+00y;FG<sA6it>|kQge+x^U6~5O7e>;;SATjvdp6Vyxi2hk|{l0#i=Es z1<pB%#l=(Fru49sWag$$X`AA1&*=a*D}%8|pd_`pBt8{MSKE{xw#4G%)S{9pZBuHe zcr)~f=9T6aRO%(?7p3aumgbaXCKeSXR!-?*D^5<#Ni3Q&c}fo}Sjm(g)|8UUf>e+Q zQ<}w;&W`peK~prmnR^&*rug~!dHw(Y|38@UW+<7G<jis3zju0`kl=wSZBv4#6lXAI zu(eIeU;(-C;4A}>6Ehfl1i>yWO3X{i&y7z^2YIY*N(KkSZ5g~7!p<C}lO<Tf{E&>1 Oh8c5gIt$2{Qau3EU3>Qc literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem3LQR.pkl b/irlc/tests/unitgrade_data/Problem3LQR.pkl new file mode 100644 index 0000000000000000000000000000000000000000..dd9396d7727e03e60310dbeb194c6fa0e926ad71 GIT binary patch literal 2024 zcmZo*nR=I<0Ss!VX!LLg6y+!7q~;p?1O`p%;VMoo2`zBWNh~g&(l(`sr6e;qbxPY5 zcl&^OU>zBZJ!~bZ#U=4RAZfP5;^Nezk|}LdYNu#;GkCLjGkP<5Gq+9gX6g~mE6pva z)Jx7UO4Z9P%_+%DEGkN@oYKP+UzD1hpI2N`RGM5eW%86BR<Ob;J?wcY5G9kRcr&z4 zab`@K(mo|<iU!Qg4E`S0l#<GVRFEd7G>a*n9T0iu9!8rfetv#l|NsC04<@`BN~R=r zIvcdP@9ef`XE@Nf>!0Vbx4Z|;{o_nbvVZIsy}ROsm*>I#+jv7>Z+XDya3I6$fB3(D z_ESoxBzZGKy}**emmvspNro`Q9;n|kq&uAr5`yJgX9~QrKbo*xZ_c0B`@Lsb*>rz; zV_#|3_&>Jh^?s|}T1q{pkL(}c?JhhTaU5bYE7W8*d?sH{)~K6QBkd4=mjB(B0~hW2 zVlD^lW&38YEpI4mvt91M@8xR_{h0c6zx5Kv!!{q^?gzV>9cnTMK9ld?(L84K{jI(C z`;7@L2S3<*&uW^pHtCUlTxSETZNabox%Yl7mhygUZ#3tQ)BN3!z-}(hV9a1^o07o- zP6O9b(?HIYwka7LD3RYf#hVF>8(OD;LQUXRr6cP(&X4xB@tt#K%YA{ko!OhIb&5B( z(1z-|)3a%3L)D}Gg8TkNEw}jyc9%CRSQoaCgzCE6vcIA^Mf$*ezF+gb^MxH?;nX_C z8(Szrb!okRYPOeK`GDz(;%i&~Gk|r0!oVCB2F`O(!ypVL3|PGxy_q2y05cT85}<JK z2v})ZvF^}e`xTk7f)N))9JF+na)zb<f%Ee`=A~cB7CKPKXshv9iTwaf9>!mguaR~= z<_shxn4vae2|<L724Bi1Rts@E1oq8i-KhF^ziQ9i`C@ZF?}zaNe*C#Cu=tn#43XaK zOG=mQVe&A3_Uaj#UaAiuF~$nD5liSJY&0>gkX-A+ap2^wS>CxxzxF#e?zEoui`@an zkKsNt?c$;%`<WZQpMD&9$sQ&T<4e0bRBU0s2eFYIY9p4IL)iG^;le8^x6j+BzJ3zy zeC)@5#?7l$CS82HAI6Vh4!4L_{AFKs;<w+<<mdJ<c^F?|bzqm&m#q*RIiWUk;fu!u zrPk-|j?A#1^Un0Hc;mzUIUhO~vQE8Z|LI(%f!_5e`zuOft}QLNVSivsUjNH~XZA-e z+#Htl`L+EC{TWfWjh^r4=(7>|5Pk)0BPf+c!cv*L5^5?d!%St^a~d-w9ZQJr&8uZ% z|Fb{gU)hz1?C<S2{cZ?o%lQLOG1zk)Om{<WFjL*ZHTDPC-zXm0@XY?l-0+z`!Oy_% z^k(&DZk^(dE$*Rq7cF|JT{w-|!R`m&zPoHJ4pvJ_og35z4nT7tNH?~4gzB!GKfm#y zsNjLl)%X5=OyhFs@pyJ}(p-LUPW0vk+l?(wpt@Zy1^3<D^J4#+M<FVDdavy>zEAiX zto8!zZ%_y~!9$o27Q*b{`m8J&IfyfOdf1AS6LS)arc9oaA??g@=HbsJ<;j2Tr?gE8 zn&Qovu>mA_IB>_r69(K45J4u0pvXs`O-$Qapn}X0!NzSreQ%X>Km{>#swSvd;P`Mm z{LGQx&?L|5&Em}lF67uV?7TU^EY1v9Z!R#4JHyAD2h8Hl2nKm<HOyl{d0>x~>Hz?t Cf-PA9 literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem3PID.pkl b/irlc/tests/unitgrade_data/Problem3PID.pkl new file mode 100644 index 0000000000000000000000000000000000000000..0a50350d1e3873dc5a0027ddef29807f8cb73567 GIT binary patch literal 334 zcmZo*nd;2Q00y;FG<vuLit>|kQge+1JYA;ra22PPgcdmGBo-G>X`9l+Qj(dQI;Cxj zyFI4^SVsn94_`@YaY=kZW=ecAOc`5ZadB!<$&|J!wNtzq+`%dt7#NB(7&F+~rev^y z4A7VW7S3So;f5RFT`;9>N(Ki=n}#=o`vDiQ5(aNZ_X8#nW@!dv1~1GALkqBA24fFD z+=!CIqV!ad%?M*0Lcq$v#z0L386ylcMo$1NpTXF}12-lyCkMqTU=<7uU^5~gfO#M@ NBw=Rgu7HT?0RV#$Uts_M literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem3StochasticDP.pkl b/irlc/tests/unitgrade_data/Problem3StochasticDP.pkl new file mode 100644 index 0000000000000000000000000000000000000000..a9e1f718b4a5fe6496c6ce865c9debb2532f36a8 GIT binary patch literal 345 zcmZo*nd-;L00y;FG<rk=it>|kQge-iOY)O55{pYRlU)L)^l%lYmV_2K=Oh*vPidRd z!%~u&n>wX!in~1rSSLdUV-I&pYH>+?L4HnVawSL&TVio>YEj9Qwkfq!G`tzWgg2u% zqc?*$lQ%=DH)HG+4Rk?teg=1HX$E5kTicWj7LaXn3SjFp7<<^jws}oyo07o+wZWSK zX1F)Ay94h`Fz{w^cVGpxW_h!^JFs;-Pi<sV^=5N-U;!J&;LYxC|NTE0cyqYh|9a@Y zPNeFgH>bP(mos4C&E;-?*%$;&yt&=&KSB-T@n-Pm^=9zq^JV}!Q4r?Dcqg#ArFsB} C8gBOh literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem4DPAgent.pkl b/irlc/tests/unitgrade_data/Problem4DPAgent.pkl new file mode 100644 index 0000000000000000000000000000000000000000..4803c3df36a3efdeb10bbaf156bb55a8cbaf8a78 GIT binary patch literal 121 zcmZo*nVQD{0ku;!diVp1@{@8>b4^?V9Me<tN~ZL16{nVj7C7f578g%xo6^Hll9`)2 zrEQA4Jx2prTLxnfS4nDdNqiz$ecO~Cw#4G%)S{9pZBuHecr$o27H2SKu(eIeU;*ip Jh3G2P0|0*?C&K^$ literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem4InventoryTrain.pkl b/irlc/tests/unitgrade_data/Problem4InventoryTrain.pkl new file mode 100644 index 0000000000000000000000000000000000000000..1d5ec57b3873975837e96bcefd4032d25e793dff GIT binary patch literal 241 zcmZo*nfi<Y0&1sd^oRu%<tOE&=9+lsm8IsD<QG+j6eVWnP3hq(PAv&7aL!3AE}qgh zrH7>?GdFcg+Z1<ujt5}f8H_!mC8@<F@x__B1v!~%nW-u9C19;>Q+n7Ei;Gi>N~W|; zsh#4@&?A~xnp;q*mz-aes+U`uQ<9ljRFqgbrH8FJIWZ@(Xv*X%J*;3QQ+ilaN-7Id zK_X0P7E?Mq+NT6f(eP&OVYHdz=jZ43|NsC0V8WZBWJ;1VN9kk<mM}iS15?_j1WhT< VV9a1^o07o-a^_k$1&}*S^#E3!UJL*L literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem4LQRAgent.pkl b/irlc/tests/unitgrade_data/Problem4LQRAgent.pkl new file mode 100644 index 0000000000000000000000000000000000000000..fdf20eabff7843729b6fc296dc17968c489684c2 GIT binary patch literal 442 zcmZo*nYx~l0Ss!VX!HmK6y+!7q~@CV1O_>#r{<MR>ES9)EeS1f&PgmTp3*j@hovMl zH+4$e6nA@G2e7sb#vZ|v)Z&u(g8ZD!<jVM*!lL*@kV>}1;^Nezk|}LdYNu#;GxUh& zmF5;y>LuqFrRwFD=9FY678NB{PU+!^FG@|$&nqq|Dork#GI>f5D_G%_9`?Kxh?2=u zyct@jI5Q?qX`d1_MZ=rXo3V9D244?rN=aowDo6`cn#GjP4u~vs52MW#KR-XO|NsC0 z2NT{5B~y|*ojLZgzxye<^3wh(B~y~T88dh@1VH9y2to8gOqD`YSDL|?!PYh<g9YT} xDeVRzKV$Q9(v-F-85~f*;x;<_u>XAF+J^+4kb<NR<OFq?6Z%RTKu##t0|0`3sd)eZ literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem4PIDAgent.pkl b/irlc/tests/unitgrade_data/Problem4PIDAgent.pkl new file mode 100644 index 0000000000000000000000000000000000000000..0f93099ff362ede4c65df1a0b1d97713b51cd828 GIT binary patch literal 4672 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 literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem4PolicyEvaluation.pkl b/irlc/tests/unitgrade_data/Problem4PolicyEvaluation.pkl new file mode 100644 index 0000000000000000000000000000000000000000..e508cb77936ac1c0cf998ccfc2e2c6ef195f1fae GIT binary patch literal 620 zcmZo*nVQJN00y;FG<qZgit>|kQgclL@^dniD_zSHb4n9SGV}AM^l%lYmV_2K=Oh*v zPidRd!%~u&n>wX!io3m%23UIrV~<!#YH>+?0a$B%Dnf7DlpeOk;^Nezk|}LdYNvQJ z^oZt_<`z`yCFd8V>gAT^lw>9r6(v?q>EVelN=?qsD=sN2O)i--c}fo}SmBf&_Pi8` zlF3uN8Cs_}GbT-GpAs}h!<*4tpmj<HUk__aNo7GQNDEV%#gxtth%9ptqs<gQKR>Vk z|Ns976W$CZQ<6HJ8`xC)JIqSO4(#+!a_QV8cc5vZIhY3fg@J+LT0PH(!dkflTi>!S zY}1!H(8qND!P-=X12A#FGr#t%OI0`kGbb>>53C-he;ZU^)uy0Q^HQ+`FdC+AO39R@ z;ta+Nwzer5ETCZQ%{>6po59#4fjt=Glcuyy$>4y5U<Pl704N|bgdiS;1cOwkbHnEb z(ah@>Y6oC+63>f<8y0F{!$B6jtnRMAX`yxiCJs|K;m}u&nErqJcV%<_T=1L~Lms3T cgkkzXYzBr8`_avVc}x-Ju?5>WKx#|%04(73rvLx| literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem5PacmanHardcoded.pkl b/irlc/tests/unitgrade_data/Problem5PacmanHardcoded.pkl new file mode 100644 index 0000000000000000000000000000000000000000..7456df2b732f41fded93f4777ebfbb7de7ac4635 GIT binary patch literal 125 zcmZo*nOejE0ku;!dc*^Y@{@8>b4>#hlXDaEJQ9milJiqiQ>OHA6{nVj7C7f578g%x zo6^Hll9`)2rEQA4J@)~y_6)`z?vm8vlK29!PLLY5#Ny)AqLL|XQ);JVFlMl|P03&Z N>1fqh0Mb&b2LN=nD`o%y literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem5PolicyIteration.pkl b/irlc/tests/unitgrade_data/Problem5PolicyIteration.pkl new file mode 100644 index 0000000000000000000000000000000000000000..a735b4e1bfbb9327fef0896cac48c27181fd52e6 GIT binary patch literal 401 zcmZo*ncBw400y;FG<w7Xit>|kQgclM@^dniD?Lk6ixNvR^Yf<ka22PPgcdmGBo-G> zX`9l+Qj(dQI;CxjyS;b;Sa$|vk7!A1aY=juSZ91DTx;8u9=62d;?$y&DQ#0~r+72; zh~|~%7F6mb=NF~w<(B4@WF{6BC00)9;fXIwP0r6NE-5NaE}1fUN)Ibo;glZsycCF% z$y2-;TBkTOCQWId5;R4_o6%dKbxH<b4{J(EWkD)P3saiKl+F%_EOQT|%@jXBKd=A) z|NjRQ-V7yEk~*Cmz)oiPuzy!J=g$StSr5Qyh&ThoghO97V*3B>htV*3bUsA=2e>*2 mAE6(@|F9oM!}L!nnUYkT!I;6;HYI}v6pH8O>;b7M)dK+aa-!M* literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem5_6_Boeing.pkl b/irlc/tests/unitgrade_data/Problem5_6_Boeing.pkl new file mode 100644 index 0000000000000000000000000000000000000000..8962e84a52523dd962cccb029fe7420f69b17262 GIT binary patch literal 4218 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 Vv^aw?!xh%)xukmn)MF{t0|2=jioXB= literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem6ChessTournament.pkl b/irlc/tests/unitgrade_data/Problem6ChessTournament.pkl new file mode 100644 index 0000000000000000000000000000000000000000..4f72ab97d7183e2c0a92e473bbc41b1995e7700e GIT binary patch literal 197 zcmZo*nYxPs0&1sd^oR!(<tOE&=9)QYq!t&4<d+uZCFZ8)l}zd3Do!m4EpX0BEH0kX zHl>H9Br`X4O4}57dw~Y9_6)`zu9DQ^lK5nhPLLATlFX7EkeVK|kksN5g_4X^h2;FA zqSWLPg`(8r(wq{7%sjAYPG(6-PO1V}r)~+t(hSB7wzerfY>CCisYNAI+NRV_fe2-= OfNXwK;sUa|R1W}PLPzxg literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem6ValueIteration.pkl b/irlc/tests/unitgrade_data/Problem6ValueIteration.pkl new file mode 100644 index 0000000000000000000000000000000000000000..11808b575d0b326f4d0f2f81886157ec91205e30 GIT binary patch literal 399 zcmZo*ncBk000y;FG<w7Wit>|kQghA15_3vZJxfxH5=%1k^QQE06{nVj7C7f578g%x zo6^Hll9`)2rEQA4z0?J;<_yLjk&@KnlK3)^#`sLQ&bBE%Y>CCisYNAI+NRV_@n+}| z%`43<sMJf&FG|(REzK#(Oe`u&ten!r6JL~?oS#=*QdF8;GG+3V9#*izDLw3YDG()- zr+728PH|>Tn$kWcXo`k6qqjiolnlNe)|8UUf>e+erZkHwogENa<{n0yDSm!_UjP69 z{|_d-8A_%kbvieIUCi)d|E_G#p9`L|9)QshaR!D7hrVjW^#9urqha#se2DrFaCHzq jLO+E6VLyz9>7P<EC8;=rF@vpbN(Kuk5EC@PN=o$r3r3)~ literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem7PIDCar.pkl b/irlc/tests/unitgrade_data/Problem7PIDCar.pkl new file mode 100644 index 0000000000000000000000000000000000000000..c838b752379b807ec2bc13988d3e7a5185e68f1d GIT binary patch literal 419 zcmZo*nL2}!0Ss!VX!P&}6y+!7q~@9jc)B<z7ES5lDo!m4EpX0BEH0kXHl>H9Br`X4 zO4}572RWtC2Mi1h8H_!=C8@<F@kyyU`Q`Cu1|U_eC7C5TAZ0z$A*sbBnR)37nQ00+ zi3JKE?FyO23N{L622(N^GuYau^sprs7pE4LOlg}^3l+*>X`AA1cMI$)bQ?@SHe_(L zO(AHuVB3@o9;l%pHrUWBSPeBM+E6JZLqTk?q35s~YGgE}Z3+RG8X1AStc+wRhz&OM J0>sc#Jpknjj}`y` literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem7_8_PidLQR.pkl b/irlc/tests/unitgrade_data/Problem7_8_PidLQR.pkl new file mode 100644 index 0000000000000000000000000000000000000000..d72e621ef2aca6c202e903ee802dce60b23cabdd GIT binary patch literal 414 zcmZo*nL3$~0Ss!VX!HmM6y+!7q~@B(Tf_%sruYN~P3hq(PAv&7aL!3AE}qghrH7>? zGdFcg+Z1<u(GOsK8H_#RC8@<F@yYpl#U+V(CGk0hMe&L0sd*(J^=yg7#i>OgX6+OW zZ-ySxywco)O1<R#qEx-y(wvga#G<0a$|*fO@kOa%6N*ZcOQuYo(!&Z?IHiX@F9o7x z@)U1|)+x@6NmJUV1WnQKX7pxkosz-V!<tf3S&$0S!jxt)rLzMf%iP0gGsVx(&+GsH z|Np^+H$%ykq)um!-%ZOrE`40Ee@e-eByYwH-V6bdxfwzbeGpTn(A1S?FlMl|P03&Z zd3^qv0Fci!7<)Lu9``QrPMOj+C4-}F3fPYs+&yf?$%#3MMN=kE$&iBEXg{TGO3)N< e#ta>h;IH-fwE~~rf(U}lSBIHDjT>x!sU84;?W92f literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem8ValueIterationAgent.pkl b/irlc/tests/unitgrade_data/Problem8ValueIterationAgent.pkl new file mode 100644 index 0000000000000000000000000000000000000000..945ae0a0ae941571d4533d2c71c2f01c82beb9cc GIT binary patch literal 323 zcmZo*nQFnv00y;FG<u{1it>|kQgbcB5_3vZJxfxH5=%1k^BmJt^Gc@la22PPgcdmG zBo-G>X`9l+Qj(dQI;CxjyS*IP0EP_49?_E2;*$8{(vp(=y!iB@%#`x{qMQ_vYPQ7U z;?$y&DQ#0~r+72;h~|~%7F6mb=NF~w<(B4@WF{6BC00)9VJl8f%t<VoGI>f5D_F^t z9@dnS%7Rpo2veHHl+KR!DM3>-yqS9#ZKnA7`FZ{S|NlRj@Mb8PlH|+*aSOwNDQ#1N zrW9u|X0WwQ$zTCF^Y-B|kYom9k2u(wN%{HNAUC2oG=l@;!VKOFVVGe82*addhTSzh J1Tw5t4**vVcpU%$ literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/Problem9Gambler.pkl b/irlc/tests/unitgrade_data/Problem9Gambler.pkl new file mode 100644 index 0000000000000000000000000000000000000000..edce9bc7f5b6c047adacf9bc2b090c35dead8b63 GIT binary patch literal 1082 zcmZo*nX1pi00y;FG<x_0it>|kQgbcc6LXVtQj4baa22PPgcdmGBo-G>X`9l+Qj(dQ zI;CxjyS=~yu&xZo9_f<Q;*$7uh>rNO#GKO9__Wfz<dV$%Jdhr?#Ny)AqLL|XQ);Jp zGxUh&mF5;y>LuqFrRwFD=9FY678NB{PU+!^FG@|$&nqq|Dork#GI>f5D_G%_9`?Kx zh?2=uyct@jI5Q?qX`d1_MZ=rXJGFI6244?rN=aowDo6`cn#GjP4u~vs52MW#KR-XO z|NsC02NT{5B~y|*oiv!iE(a6MTTU$e;2LBv;mG}PuVkkEkGD@n!YWJcXLFTq{G8lq zUlS$ETA<o)&%Sq=wP$^={koPA1=mYc?4?bE_v$>EZm-VuqM?#;wtc|0?C7x5^X>n< z5ZJ%Kev$pJ@9N8foR-+DbS4z%6s@*zILNU2%*-|R?cvg!bG_Huzc`!G|0rXF{q@7A z`2RU<wC_167`CEkll}i`t9@Gdx7zD;2>$E1w$;A>evI<(KiljJ4z@cA3GTFiU$JXz zgWN9r*4uvON>_H<9~M^&W?g*9{$U}v>h+t4>?f(Lp8V13u>I?M3Nc%k9JYV5B2ux~ z<%qrgjRlw6&mFO^*}2!?OWINUB_B*Zi@J{4&&-;3?2hbl`&X4Zjp>_@+i%l2v&3fR z345jdGqWC6owS!+Ds%jW^(lJ;@2r1s-=47#PH+?66m!;oT0}sZ-~Y4rhMTt7t^at= z{@9_uE0-ppw=dgr^Q5EO1^dR7V7CzSi}s)9-Q@Vzc+sAt!S7AVhl}<(UsRi3Zog!o zcCbg|tITD4wMl=r3LLy_KWiok+_Ycm*3-na^`<?O!kwM{PjA}m{S}*6D0RzTD`|5> zK-Mk$8$Ykzj9P!ozAP)1W8&{y_FQcXMFM(n+p``H3}(H4+kWk-IU7zX-mw>1l;gB@ z${l;pqd9xqS?}7rK9~~Bop#qgV6*jm-u?INAMIWFGymH?d*)qw+WXw^+h2T^(Eskh zefz%eYPt-Z5A4MiKg8&`Kd_hmsWW@){s;D<Vg)s9PaoJnXw!OUEA!A^$WhFaq2ZzZ zgyo(*ZJQq2zwc+fJelQ@{Wj6xr{A4?Y;W`V>a^AO9^0?+dYSi<>4|-cLge`gT2Jhk zr7dBvN_%3j9OVDRY1R|_kT)-XWn6w@&&BSzV!Ojr`(q}q)Bl%0wQs4ioh!WIsl8y# z%r0lPXZDq4H`5+QJ+s$Z-kamH_?dmk1{X{DWzX$j8?aC5KmXib<V@D5Zk`wR^ZNr@ z^3q?}Ukh!zW4+{sy^4r|N*&`%`<ASp1CiTa+80R0xVXK0X@6-Ad!2;iEBm+^C-V<q zdu4w!)@*f)(rf!nE3eR*b6?woGY10$!<3RKNyQnA8EkD+GFU*_eu)YPNUl^50P=(N AumAu6 literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/QAgentQuestion.pkl b/irlc/tests/unitgrade_data/QAgentQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..016ea7eaeaa3fb5d36c759909b4f43314d6ed9d9 GIT binary patch literal 6895 zcmZo*nfgSE0Ss!VX!P*=Iy<JP=9L7NrWTiE=I2f6;VMoo2`zBWNh~g&(l(`sr6e;q zbxPY5cYDzTU|kuEJ^Ur9#U=59@oA-b$zV-wQ+n7Ei;Gi>N~W|;shyI+n85}Ta!5{0 z&PbioBa)n-TToh(8edYBn3bAbl3$dWT0EtP6RbZ!Kc{#~4_CZLVsS=lN^ol7l*v;x z8>jfyPU+#yNG#4MOUx-vozlfoEwf7}?%GQK;<hPC?Ni#O#7^nq&n(JG)=RB0Fw{!~ zd16WrR|w38$|;klXv9v@=n>5;%`K?ZOU^G!)ypl-DalMMDoU)J(!	l$xBMS6ot5 znp`qv@{}G{u)--l?0G2=C6lLkGqg@|W=xvWJ|$?1hBu>ThI|ieN=aowDo8z3rp1)b z4u}+U52MW#KR-XO|NsC02NT{5B~y|*ojJf^#=yWZrDRG{hFpds$jA(3h%QFW46ROQ z4o0XNJW7}dD`6(AgoUsYR>Dfy2rFSHtOOP?cs$KX*c2|pO1KFt;UTPqm#`8(!b<oF zD-j^9M3Ar&A;L<82`dpHtVEQs5;4L`#0e{rAgn}^uo7s=hc7ou6E;PLuo79qO5_MD zkw;RJ8Vf3dycyf3cr$u4v`z750FfDIGtPQ5fJGtv^C+?xGr$n4f)T8a(VGdZ8$?3b z5OJ6(2yrH`N{AW=o5`EGZHhNDn1rwy!E6Q)*~1r-T9liamzbkaT#{IlItA=xCXn(B znI5*{<iwoBqA8Q7WN0~azzejtDM28wfK)MpR6;R>H)F;#kV0q(FiZg}WcFtC1}SCm zX7mOrX9W2Sq7YvGK@~E4Gl1;JQRafmX%NO!{D7oEcvJ~$bp;9&5FQPe(Qx4aB?J&2 zK8XRjH3lj`YNzzD<R%tpPr)cjyjfbOWT^KrWf~&418cCh16ddu85u!=R9rhHtB;X^ z0jp_QQyCc;I-N%qGlIf)G&EoZ%xGvZv`&Hdnnpuo<c0>cCtd89S~8_^N@DF4jf~T^ zQ#8C8+z$w=Up~^S{sYwh^=5KEAp9fcaYOnHZ)W!cf*)*{?#!E1nsElK6x3$)X7Fb6 zW&lYFf2)&8Xsj#EI183^KOp=z&p)T;g*T)70pZ)bi{&4G1snHKl_%^}2w2A#*~JwL z@0MnqgX$2>@n)WU%nYm}nEyh-n`2-dFHSyopQGf>?9EV`aRsatWV8DL{!dxix~H>2 zYJ?(B&VIa!4`iy)#}ivO6n-tuxQe7yXr0w#nZ6>3TS4aB21~jh;BYO!8CvKK@hrq6 zyzg0Af7-d0X50g-f!M_ocJ=(Kv-2PZxbOeeAEWX0P=9I0L%14vNbEm369i_IW<08$ z;?3Z0{{hnWF3z}*Me)CzV(r>YJf)>=(BYm87SJG3-!!nM9=<@-VWkYFwkZ%5Vh_M7 zvTB(a7(l~B862P?BLtTxgEvC}G60kzjBVH_LkcvmgHeA%#!|p$LlX%OCCC*#4khs3 z3GP7~cy|N0lF{K7?BiY3A8rA)(?C7Kwkh6B;65%BsBfHglZgS8%^_W85DD($X59e^ zgL})MJOb`dgCrrnYOqdFo^6|w@fd0@6D0e9yQZL01KKr(rxI|F6VxFc?Qy~@X-IYi zbqzom)bhoV*Fe%BJVcZrmmZ+xG1{CT?XPHf)2qJ%t=W*8KUvqA7#QI7v-^HX?aJWI zgkUnmnWb4bkX3`Kez=@BvNBM~2{sfV&4^$ko9)d|3NBE=szK!`c4ctU(yY5MC&0xJ str(DL4`A|Wrh!^HAo)jNc~Aod>eu4Zwke4A1GpJdR@VS(36$yq02{6fC;$Ke literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/RendevouzItem.pkl b/irlc/tests/unitgrade_data/RendevouzItem.pkl new file mode 100644 index 0000000000000000000000000000000000000000..c007adc309fa60055fc59ec8c3bba3ce8aab72a2 GIT binary patch literal 602 zcmZo*nd;BP00y;FG<tZ0Qu9($%koRBJWEn@r}S_Yr<Q~kIOil57f)%M(!)}cnVUML zZHl|S-~q6n48|VClGNgo_#&9T`0~t>jQrA)_?*nV)Z)~{qT~#aPS%plk{poM9%Z-{ z3LvElnLdF*3L1I&3J49FQ!*Gc*xIJ_uq753rxuk=X`50z#hal=G_N$bpi(b6zbI8N zw=}0DGqI>Bv2scePkd2oa(-TMNl|HX$&|@cdRV~<r}VJrr9hNSp5o2WI>nhWX-fN) zpeY*OjNTlrQ!<2lSW`+W3sON^n9?k!bap^wnR^&*rug~!dHw(Y|38@UW+<7G)amTN z$o_L`!Z}TcDz(Hz|4rEsO!l1dq5iC<gNe+O@Fq+40|(mk)^B>>Y`^5soYX|ohW+n< zf@yonR<QW~DJ4^qiXooMU;%~W&kuJ&A(_G0BZnm%Q3El9qisr$D%Riwha_46s<utZ z;DLl(hG2#WC;&3VARdHxU#`>HK`gc^r0krggNkf{WsDj7f$ZrP$ETmwbg*smslH~( zeqeH?5Mw_>i+xud&+h`=hW#xOt7gmTHP{QE%`bZUzZvc!kY!*GeXiaE@=&QB0B5K3 AasU7T literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/SarsaLambdaQuestion.pkl b/irlc/tests/unitgrade_data/SarsaLambdaQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..5ba0d797f173e178b1d8c28c2beabf4941532788 GIT binary patch literal 279 zcmZo*naab+00y;FG<t-C6N`!yeG+q%QW678Q;SP7^Yf<ka22PPgcdmGBo-G>X`9l+ zQj(dQI;CxjyFK3nu+9v|9+8sN;*$8H)bhlll=!sLykxM>wkbVqiN(dKMI}?(rqoW+ z@Mh3(-~a!!2EV%MboT?y^*^?EtPgWP!0%?df7>cc_XE5Rd9#wWTT7;RGxmt)mF5;y z>LuqFrRwFD=9FY678NB{PU&GQPEO28ESfTTN)Ibo$&?<}l#<GVRFDW$n#GjPj`k@* zQ#8Dpdl+q|`1$#H{r~^}KbY`lD4CMv%n_ScKVjh}rUO&jrUXqX&0x%6Ynzh6(l*82 OL6BcufPsObR1W|wqi#L` literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/SarsaQuestion.pkl b/irlc/tests/unitgrade_data/SarsaQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..157e90bfa38a07c4ecb0813c73f687ce88904ca7 GIT binary patch literal 276 zcmZo*naat?00y;FG<tZ06N`!y14~njOEUBGru1+Xr<Q~kIOil57f)%M(!)}cnVUML zZHl|SbOTsV24jzSNosLPd}4BPX>MswVo7RBd{Jt7Vo?f6JzHXNacWV?l(s3gQ#8C8 zG~5qxoH^&0S7qjYfK%Y!Nin}B_XBK)KPW7o=;VHYrD;yps`%iNDc+1dqIspc1(kZq z`9-OExurQJnTbV3iIr1&*ou=Aa}tZDOrFxi3RW_uhc%_7vLF>C!jxt)rL&`bO3)My zZ{{9Gn<;*NeqR6o|NjpryctTSBsp{Jt2F(%CWGm~l(s2BQ%W-!GuYauWU#bNad+VP K#{%+GsU85MD{Z*| literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/TD0Question.pkl b/irlc/tests/unitgrade_data/TD0Question.pkl new file mode 100644 index 0000000000000000000000000000000000000000..6a18f61d92942a8ae3c89fcaa3a6e16b94322e4f GIT binary patch literal 8326 zcmZo*nOd#D00y;FG<vv0TnqwBQ;SP7^Yf<ka22PPgcdmGBo-G>X`9l+Qj(dQI;Cxj zyS)fl149O5k8nw9aY=kxVoqsld|GK<GFW5VlpeOk;^Nezk|}LdYNuo{X0U;T9Fh~0 zGg7DYh$QFd7L=Bx#+MW&W~C;V<QHY87EkHn1nbYw&nceL!xit5Se%iX5}aB%W%3lw z#wmWaQ+hZv5{omyR!!;RsFvBK6L)Q;e{tKCr1mLoQ(~v|@Mjj~B<rPC7#Qj$rl;nW zOzGhYf!R<wW%3k_*eM!4qIspc1(kZq`9-OExurQJnTbV3iIr1&c;bsvlk@Y6ONvU9 zOQuYo(!&Z?IHiX@F9o7x@)U1|)+x@6NmJUV1WnQKX4K4(?_o_TsVqnZsb|Wxn9|t+ zkz(#)w3*`P=jZkR|NsAB!keLFN>ZmY2PEJa7^aj=Ny?DRPy`v7p$yT*sF|VF>CC|h zRf9(f6JaIHgq5%mR>DeH2^(Q0?1YuT0tSz#ISHG>MOX<pVI@3-mGBZ)!beyMKVc;T zgp~*qRw6`Li7;U$&|Hr%?TQjMMU1c#al%R@2rH2!tVD{i5^2IpWC$yfC9Fh_uo8K~ zN}y#qzBp1OY>E<LCCY@As1R17N?3^+VI}H>m1q!FqDfeZ7GWjYgq7$JR-#K-i5_7k z`h=Aj5LRMHScwr~CB}r6m=IQCilihp7E}p)Gqz3fX7pwNlOQ$&ScCy2l4Z-tzyOtm z2-q_+Fl2!UWKk40Ogj_UKnMvkmI-VuGnj<1nLt)}W3nM?n7u)InZP768>Sv43l`4` z133~|6SFsS+mx(GkW=vz-b^5c-i%-p!iH##g_y|HHYF<#!UXw%8RXs`zL3<S+|0bh z9EIYN#FEr0pis<^>0v8QPRvOxnlgDxhL$r2ynWF&C1^@k3L^spNE90O3{y}<;SCKG zQS2sQR|{|OpqPMNEv?KY#SPfQ0lO%6bFupZyISm`q=XK3mtl7UcD2~ufL$$imti*n zyIRU!hTS$&%*F0E?4sCh!>$&)C@CgjSBpI)v5R6i0lO%6_hJu8>?UAWi(M4OHgL&= zy^93uR)H{{-U3J(gh!R2_AWtT0>Y!=G8!%%po9RzqlsZOF^nb#9OH4I3<APKB$L2v z;gTsypenR>N)JnJVsZ8q4DWffv`)!T?_tU`L>{=T!8&ls!pO+T2nvDX+9_EA%nS@z zP0JEzW?<-a9#zZ;3fs}pfR(DFp~28P1wPC_8XBXaF<Od_RudZDqtyh;{O6D_7#ScF zyTyK~B~u!wB=!h`XQWF@GINUclJj$OL6hn{DXD3Rr8y-jnaL$apowFSq|(fslFYo~ zDLt%dIr)j8+2>Z!40DzxBLjo`{zHzP=HACvWLbfEr}=evo!{k<Wdr8z_<E>6M&lcJ zpxb@_m5nPB)tOgixq{_Z&IEy3S#Dt7>KVr$H973a@&NPBF;-7#)3}x83Fe)6nZv(j zlVO%On72Dcntg`<p{xKf@5&iP#hS#LtUxgD@aw?To=+9v!D;vXciq}1e0ZIn6$O^t wb8KJ0%1r@T(O}-H`TNRFY_ZBp0P*ahZYgbpE(XY80WBkF@<{-V_>}4a0Jqskd;kCd literal 0 HcmV?d00001 diff --git a/irlc/tests/unitgrade_data/UCBAgentQuestion.pkl b/irlc/tests/unitgrade_data/UCBAgentQuestion.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2c5a18391d06f2648ea043f218bd0c21e42e5bf7 GIT binary patch literal 96266 zcmZo*naa$-$N&PhQ#5+`oD%a=GD`wWQ;SP7^Yf<ka22PPgcdmGBo-G>X`9l+Qj(dQ zI;CxjyFLE_kRFB%#vZPc)Z&u(#Prm>5|9$M#Ny)AA`r87iZ?@#XkKY<L8V@Deo?Ak zZfQ<QW@1rMV&#+`p7^5F<ovwilA_Y&k|~p?^ss^zPU&IKOMxhvJjI)#b&4}%(v<co zK~prm8NIn$r)2Q;u%?t$7Nml-Fr`^c>Fj{WGWRgrO!4#c^ZNh)|9>#y%}_EWsna=t zn^)A-GWYuahB@EVU$&mwza#33ZhXPp{r}S%pTsA9w0BT%j-7n<^8Wu%I3=cs{oW7u z7Xt%>kKnGJy4Nr5Ct8XHwsqgOj|ekTy>#h-{gjd^NyQnA8EkD+de|J26O%Jir}PM< zr<TN*6eVV*CYR(FWu_KS>ETQ(%}XxH&(A5I(!&++kyxCOni8B^IA!t_&BiHywNrXH zGZKq4$`W%*Q>S!sRLktriMzJazqoBmQu~y)DX~*}_%n-glJ!z63=H)kq1(e10<)oV z%H$~;u~RfMcrye*!IU8c2?j>Z4DlYOOr&thkj54&957#ke1pXh(@tj&NU~sHz@vl- zY78DF%!HM&5LUuUSP2_pCG3Qizyb!3k2ndN!bMmKH(@0_gq83TR>DVE2|r;a0)&+a z5>_HaScx!UB_f2Ch!R#JMp%hBVI>lTl}Hj+B1Kq<G+`w&gq6q=Rw74Oi9BH?3WSv? z5>}!_Scx)WB`SoKs1jD9Mp%hDVI>-bm1q)HqD5GVHen??gq7$LR-#8(i9TT^285Lu z5>{eFScx%VB_@QGm=acEMp%hCVI>xXl~@v1VntYqHDM(-gq7G5R$@n3i9KN@4uq9B z5?10wScx-XB`$=OxDr<4Mp%hEVI>}fm3R_X;zd}AH(@0{gq8RbR^mrki9cZ_0fdzV z5>^sKSV=HpB_V{Bgc4Q~Mp#KWVI>iSl|&L&5=B@^G+`w%gq6e+RuV^8NjzaC351m- z5>}E#SV=NrB`HWsQe&rRcr*CX0f21E;O=27PEO28ESfTTN`|R3tarpPrEN;klq>@# z1_qEQyr+mF3hx}Eh{F4WqoUwwMGZ-m(D7!0hcJpbc2RF89O4|<#fO@xH#>b@?9B<c z58mS++-cUE5$<AQ(hCDAswr3N&FW2O8!315s0omg-kTX75<?^}z}-tsPC(>zB2<%N z@?cO4uE#NliKRN7Iaqz$-p=LxvLDA_CrC-QrHDn}CB_4Ilt^XWmN8}diO&=tf%W>e zDsRDK=U7IYK^Cdn|1)`}`3;|v)zfZn@ZR?opOSgXXQw_m&ftK@x$mXt9w;n&kI$46 zBaY>hHr>bPBfksTUly?b!)MBgyHl-vwNKzv!p<DJX;lRyKIbMZ(x3Ct<On`f?q5Ih zAzke^J|$ZGYfX2SKES7>|CVc0<H|SqlpK>5m-}(@4?ZQZ*%Ukx@c+TOZH#|^;4>xY zyY8Q7AOGT0Qg-OE^NI}@@x@V&|NHdF`CsuVflcn<aqjVD?q$6je&Tb>qQpH~2NUsz zi+tImv$nZ-m6$19SU7z%-e}CX{4sTY`Y(KL;j_@~J2>GJJ|#^Vud=o8u;5E|P0v>x z$ei>UpD6+<6J-AG|A<csYzhre==LQ3Gt4-G*V7+tw%@Kad5X`XO#d|11@d^)?)L{X zwSHb>#pmfeJWPtebKl{!Nb+@Z^j{{t<%{eqrxed^m+_f0&Hd0i>+?78DGA$XzT_+u z-f(#!(6jHB(iVKlyFze-(5LEs_$>OE<9<D@7;h0|5k9FR(;ROOP)kW@Sa<+$(Y*b% zmf9j_ym{K>czffi+aK^b_xyy0{TF=kn)1)*S=!g=v-nIg%Ht3G=7~2Sbw670=GIHR zCFaW~wwva)f5B(bzL^O@qCYtCrMe^g7?`pTyuufau&HT0`N$wGrD&JUW_+gfFS~om zN)m5|y~e55F8ma4wtv+u`+iLm-k3f!k7;M;@^kpYh4pV_>ij&sZmC?Za<={@-Z&~K zR6hIL46j87jy0t(7?|-zfK%t*7b^Gg=4qFr=>0b~KgZ{zZKtBE`ZZtSQ=(vVY4#3X zyv>SxyQdnTeTO%zJ<n!(yK>HVd=@R5ch$Sj2XES)p1et3WC0Vta9Q|$-^_*2@W#=P zsXc$4K3%|<>g3idRNv*q>y|fZTR+XKyNS<~nA|%mF4lMp)k0ym$kqJ6@tHCqX~Dij z?w9Z>$&owy>TKRad`d)TwG?@D<E>${)E!Pg3&Wds!@~txY6|d1qr}S_*QM4zz~`1v z&*~r8`dq`87(VUz)Du>F7oU<HDs|J%KHSA;(LTkg&Rxs5<5RL~>fEZi|MB|hgPg&a z?MLx8iCMlc4*Yx;Z|m@omeaMVqHOrmuH{OR84P@Q8w5-jtyKHB;w|e8_-8d7J%l&g zcXiHr|Hlh&^{H1@dN^wj-t@98ZR#@DP)HF3>aW#Ksh!fpmsplsl$f3xUzD0&lv)BE zZk2N8xN<t|qWiwr_TZtz;@T-$Caet5p%p1-jyV-F3C!!?<B)aiQ>!z5$>4xpFL*?f zfdSI#$1r(R7CD>;Dm1+H>(4HY#TEOMxQddr(e#MREa~DC9I1{HR}DYCC*S|c;Z1ux zq{52rkiTTf`%gIBj9+&6#UTDNmJ<KsFWV_GnRa?}r_T1ATl*D9+8ByHqFq>xnmicl z(2-VNQIhIL!;0J#n_4oZaY`a&t3U<|XxBvYss>P0WH9!KLv~FhgSJ`3r(_nF6lErr zmSpBlX`7P4(KZFNcLHOg1iS%4s?#~3Ke$9?`u{if3)45hD&E>^pSPHC535j%z50UA z4G&+o+8^JwqnGVNoBfn;Z1FRETJ3jv@-S()x7okQ(*8F6ZnOREpLJP#N}BCW1kG&r z2DO2^hQ%3-Str;S7}};}C}b#Rs6aL;WT<1?nvkJ~WA6cI+W^ReAdF+M3Zw+SUZiA7 z5{54|GeAn<i$`!PfzQ?9Rx-M?0CVCG6uP533$TaF=*|M{;WE0j0DHKM?kvC_E~7gO zu!qa&&I0V=GP<(>d$^45EWjQvqdN<*hs)^B0_@>3y0ZX#xTJtOYM}X^k|{}`c_;eq zEP$_!gt`DS<pdXn_YhH5T#t(4+i!sqI!L<#P{c_IVQ*GaRMS^2(u!pA{fAi9Otu;H z^)=<T;R-jTy#pv=;mt<5o!CtvxW5AXN^=y~VK;g3ih3jV;-L5gDJ)RL2d_^?T{c={ zL91@?QW8+>0n1P>Xl4J4j5}*5${fSDbZArGgGCu1@h<#ixD*hX!-{v&@;OHy4WoB> z*JGwv<o}em#k)#x={nu5*ER8)^5|Y!Zes`D<y~&7e<}~y<6R83CS2P)O%Csp@Wqd` zuFq4%yL8BCZcN4dQoI(4YMtN2F(2<rrw7&#_*Y8f-Og}YUBNZH1@FSF8)wUknNA-9 z&nMtW3^s?ZmQ8z%cm1w#Tf|`{FT88F6r?>{f7dO;XOYh2tJBw+;axy2)l+k8KO^47 zmis2mSXQdG7hl>fVOwJMbomQ>ZdtzbdWOkvycRJWOzq-7@)(~fI}SQ)bTHw~0SV!j z4^F1xT`@R!^Y{DGI(Qd;YR$R1`;4FfzV&qt^Y-|d#y8^&7m4GsJC8)*jp-HQUltq= z#_J;qzNl7RKfKHKFNKx;eN=>ZS*_uj>kK<~;a#P-ty0g5hZ%3UwCff;m7dRzFI*mG zxVE_0<IRm?ar5_joaVu2O1vry`}PLBK_~BSd1m)YyoJZV=Azlf_{*0AWoK4Rnlv9@ zG+zIF|8T%k$kId{dHTTKik+Wguj5O*AC}E87goo+(@eeaSDN|<yg5L3X|v7dbiC2{ zp#Rd<JvZ>iQH1p~HpvZm>wq3Mt7RU_|MB_AAo75F_s#A2l)SJOlv`zjw+Nccz4O$A zSiCh!+vSFR&(-j*VE<ZsyLfXY-YV;dwad-?#XImh_xBH5$(oONE%IWTd3LE3UW<A} zir#Cp2;)oMFO9M%@bco#Bw1lOSGIk?tK{8-mOO^g&-l`=%-U!B{q6A9Y8nC_3#A#4 z;|rI~CEpfqJdQV9^wkwppIl(Vw@XrBb-0;mKHf@rLWbFH*Znu~x#g?dV@bg?cuT2` z&g=%6bMQJh@6Ed}7S?$8T6#SD{o}MgUW?MhjU{&V;`PxpHBrSqNqCdDp4T(B3-|Gs zFFL!*McTLG-90)X@nu6n%vO9s7sM-f*Y4sod`hfl*GEVB;%$bytvjN*-VAS*buTL9 z(~_-t8*OJY55KXC#~Zq5{x~0st;f49=+2RqGxC#e<MUCIq^`>hcf93pvaa3cXI6N( zc~lyTd)6<(Tc~Qa-#nC9i8rP*t_Fy7Xye@p67u+7@y`al8#Dsaf98FEiMQfgCgE~z z=QO-Ei38(<Qy1g$)&V~6b8LG(?%@mF89l39ZTO$yQxY?CY4Ahki};kxJr%F}#T9Q^ zcYO9<m2)L{Ym)uO*`{q9@w!Dz?7D;0R>)>FP=5`y%K&ZfK>bF37KJ-FR&ql7dytNA zG5WrPQCV`=iP0}4J3TBdk6wL1_xKIx6yZ(3^_}ka4pf?y=y)W*JfHr%YzE5SfePn= zvUi}uxx_0zEJWnvAj?N##*z#Fe}9R?Rg}mMRQwK3dpD`95YF7jM%Lav{IM`N{X6Qa z!QY}7jiZ5xBiPOY*ouAd=7Jfw!H44Zh`ARfrevn(m7rbbkipb81+oo+3#^bKE033f z0d$W6;T;G2t~|O>VEf4a^0#K=&v!rU=WCgema*^Y{uO+60$0~P*}tWTl|`rK#{Sd0 z?!0d1{%#-RU~~4upAGg-(c!JX4qe=DY5t=)Y11wHh@UNL#nlhN-JxQH{i8b$5cfBL z*5{AjWq^IX(&$|V*u!P?E(7f0GJ2N*_HY@!%K&@0jNWB{JzPfbGQb`#qjwo#50}xq z46ujG=v@Zb!)5d?1MJ~4dY1upE;<0sc6qaUvwL%Rvv_lOGkY_7vwL%Tvx3ef_h#^B z0<#&xvJ7BVoZgJy4Bo8X9NwH@n#G&Ro5`C4YzCV*gExmaJD6nfX7pzBX7pzCW&)cG zGL;i-J~P-%R&PdcPH!e}R&Qo+R&P#k7O-g`b3iN>Z;+i3^B`{F@MiF41KZ2y%?8#9 zk_Fkt>CNfQ4stQbFE|$B*z%|KEWe2NV6>QtFU5^Fyu`O^BIxuw`Iv=x7kMm@pHcq4 zcQrm!Vp6B)HlN13#^CWc^?rvrtoT+<?0F^p<BSypJ|*rp^CMLSnDHsG;!S_Dx(Dx^ zG1rytOI9hp#pk2?XJzJH9e7vqZL*eo{BPDv@bCtXIQr#fVtJ<??{qr{i+WeF8eUJ| zIvtX2-ivqs+V*qU)*?T=3oHCr2gt6U{|BF^E#*!qd+Fd^dttqcdrhDJ4}7LX2+v>3 z?1gt>MXCPQIX!ug@CDtj6>)-%O?X#un3pu%GBC%x_Tp5|!M<O~ctiJ!QpK*xmUx5i zda&xtzf<uhhKv<VHf{6q9?6;!6mC(r9Iq*V*UH)6m%fiLT-Lvv%r@&H-W5OZ=WFVA zG5*3AM_-pLoR<C(Z$5gsZ(g#)lJEFTF@0#>mbB#&J|!<$T)i};@UG%(xUp~gl%j3; zJgqTD^`g@fylW)Q?5i%!UvUYaDH#%Fx@F}X@F}^lbl0v6m)GM{lHzqv_0w;>D>#-^ zo&4PO9`EYu1F}oDZ7g8Lw{k9NH=pMWzW?|_ceUW(c*~D?)2{2Wo^6-?@vc^zF!@YI z$Z-~Yh3ZGgyD#>*;=LJQ-Fe%&E6nja_tsKRqgA)?dU{vSrsfH{cn>g5-gtT0Isv>D z-)D`TTmQ+v#us!RuB(eGlX&oXy7ut|9W^$*LAPt#)e=#8HhiX(f1mY`(;IIowejGp znZ|B-mo9!g7;}Ez(%1MB=DQe<njB`l(b%&#uOVk8-qY3pt+jrcQHj@-!pD(4ZkzBf zP_hVcN{v<I#uqL#l2rSiIN&u!!Qy7d`--*rJbgtsuEu&Y-b0ByK2PLyP{q4+@q>Dc zi2O6WrIf-i^UF1p@n(C@|7LpX9e5Y|MJ-<VrBE5Kb9c=>7WHv5-by&`U9#P?SiFni zt-rl?(piT0o(^`!=!0|r<87Rz-G1-eB!agNQ0OXrcc}R|zO2?1Kkxh&BfJd)t-S8U z#d3HviNZ;fTPI8Kw(I<2)L%=^!@K_O#<fth_Bgy}OABQ#f3w~NZ*%MO*59>@X5n4B zxZtOn{L9&p^>;X0hr)N>&%1FC@A1=qCLN83SL0nqxz$fv@9+n_4W-Wq1dQsB;!T(x zn(^9Ptl#iOqwM!D?+$n3U1@pg)2zafZ+Pn?KZc+GcK^V;NHyb%PgS(!CVX!3v-e9B zh`^hq`s;sntqZ^#E+;0GHXo?KYmrmU#pyO`cw4G7RE@usJ>mdY<)Ho==1NQa^X6=G zxvjVtu;5tfVX!5{!BHRADj<tJ9;pF(9AxPY_9|Izw^;y(UY1=Ql4+HEIArm=dAj`8 z!-sFu;>=s`=Z4Mu_;7^=e%Z&H6;`kE;=<u0O5BV;tSE^={64}T3;6BD?_c~r!tW~l zshtv6QDQItoPs}X;FrbkBmAL(KL$6%G31y2{flF*9sbb3?<)NEQerZGz4+4=e*fav zi(eLh4B}54l!PSyT!vqklJXh9Ui|jrPqFxA@y7ywd-2B+etYrz7r$QouEL)-@TYeC z_To=h`1MlaD*Sr!#~^+;<IlhN!wSF2_(KD~EG72h*Nfl3_+5qHzxYkYFN;4t<IiRI zO~xM@l+-Es-HcxrzrFZl0aX^V(h{*!5xml}D-e8)GguV11e4&Q&2HO1|GiSN)Bfwu zTU~!sx7#1rw3>9feuus3dka_hqMi1_iH9$1r|z`>_4f4vOXXemN1WDX-YeW?zr&&F z(eW9(?H9R%4A@~mFHZBc!0}z+5fI1{N|+NyS5c0xqU7L(re8eAZ;!5`#6H_Tx{4Be zxQwo%#2zlAt0=LD%jhaf?BO!HiV}OcjIN@@9xkJ+D6xmj=qgI=;WE045_`CeuA-#k zDoW5=N6-pK&>Bk6nnxCI&{|2*x<}B;O3+$Lc5gQDT1e1(M|N)(Z;%RR@ES`F@LEZb zJP31ovw>Geg7kq_V6u3FR!g#i)q_@Fg7mR_GlI?H0I$CUt-=JYie&L-2Ct(8sQ{S* zT4M=X9|>B~$>0qU0j;eB@j>e<L2D=>?%)Kk=;ZWf0nN(cn1dC1=G>ecg7=czs?<V< zmIZhxHMKkwg7&xKU6eIN=G4kvPw=j|dNbGd<oAVmmtL^UWO%Y<%X{#601h8D2ul2` zv44VZ_B8p8So-`_ygs@x_1(HvN_dw$Y&Tjh>U;sOr_bD)J6AIG2tK!@z574=tr^}) z@U#h5)0^Jmb&HYzx%sQUbAjhzafFLT!IU*h&QI~V<wBm)Goc3`@hK^s$M&AH0Plo+ ztlG9fFOkdmOnLMqeTLglylWZ0+}J8{V+!6SDTOA2_vYNkn;6bBpAoTqg*WJ!6=gsC zwZuEE&wsnaH268*Rg^`Yx|SbJ@%l);{1|KHUA*hItYViIYp=(9;Ff^<&EOAAV)#}T zC2I0MO>Dxu`b)dmy#LL5ylXLq+@Bb^^4-Fh)sFSNlUl{`0bfiz{5UX)@yZN*ro2ul ze7+L@3caYR%kC1Qco!6wO?fFB&4@Q2IsB`A-DB_!pL1uWO<nkn6K|dlYG96<t$7fi zk9uCESzVFDyQo}R?MP+3Cf+4)CfhkRely}-6J)s2^vSEKcymDeROSuwEqGTs{kg~S zti%BCN;JP)7G2EC@g~f^z)KU}EQRcL$590F+**=1zYG7>>yL#kC-A+%7e^6cn<@)( zc=45WzowMAraR-!_8qrRU6y6Vo4h~V7hyBGycb_gPjF2;@+lJU!v7NzvlpJ$#k+FR z<L52wVsE?&^TV%=r@VjTbxUp1kq3gIc;kqpyzi@9@fCcb>tUZ++MI`X4OvCoruRK{ zc<TW1{(xI)8}Y7BI`C=lLo0i{C8oQXQgE+4-ty(Bh1sKed%R1#1ZK4gN4Me)7lUb^ z{yl$%_i(`nx+^|=E8$%$WiXi|uwxTm=VsoTlK+(H3ce(@X=z8nw|DRGDS77NCI0i> zSA0tNPW?=*F?x<qNuq(*x=P_s_!7gZ>}j`Z1n{<{iqf;Uyjq4gF^H^Eyczu(Z&~-{ zl+!$&pM3c8G~+X+%G00lmQuet48C~&zK738YUl6BwBX+o^vP?T>7fL?Ef0BtS@-`I zU&m+B!4Gaf{;tJ)s&0(TuS4Msg7`fB??~|6*j;$zh$Z@`asE%d5s)R@lxcL~1U~0( z**M1`^D5prs^Pa5EwzKp#o;L6%Pe~WSI@?~cK5=gS)1Q9U&QB@XOBbICtmoAFYOBa zy<fPq81G7Yv#QVE&RF4XZZ&qe9I?{;jn6HD$8{!uS&lb1=6>0}@_`H9_0@Avt@W~A zgttDr6>eUAumayI%FB^P&w@66!?79)zwE7bKQ@2ff$P+=jJaCNZB`56SQ&_47Qek| z-4lJHp3~xNK>R+!@2V%!j!t(&aGfoN-(={FBaU-Hbv2Lpv`H}G2+1YsE#6$9^K?NM zJz<<Fia)IIyE&mo)`XXV5r@5$xcP!kj>JiuUpP`7{;<ODX8f+gFN@z^{3#ZHIO8`N zfBfQ)1xnH+ev|QsGk(4J{fl2O{*c6<a`4A5{&2=`FMc24w->*g@y8&3z4-0L?`Hh= z;xAPwu@`^3!tW~l_TrCU{Id9CAHOVqSK-%-KQG{qLHzdOFR$>&FYQttejniv4g6^X zzsa<d#UEDq!x_J;C<zVxX@ioG#P459WbykKe@No@FMe74v4CF|f2o3BFMe56HzTd0 zge_JCFQmMoBn?v7BM|EB<d~kCR}xs7T3nKupEm{Ru*w4<B@9{fC5Sz&Qb6t8ts6q$ z?3H;vPseyNA9!GWO5%L<bo)JPj%uE0da>Vsf#fxv_KW)^1Z3|o^}A{>yJ%U^anl3# zOLuj8e4qSuzZSQVV`s*d{RukUD_8&j2kr|MBkUhtW;wdda&(y`mf;T2$)%#;%*w!k zXZh*qGE3~s6h@a>Vh@+mWtP~(WptS(_HY?pW{EvqMweM)50}wpme|8(beSdga2Z`@ zi9K9KmswJ8nI-&sb!c-MGPeR3#ePXV6I3zyLT<QPW~`ztSVdW}io$Or0L{_B&1J`` zmIJFOCst9YAe!H>`vSYmu!~}MFZOW2ZUXku!R|Lwe1Y9%*lok^GVHct7sYNH<>q3K zA?$IC-8Sq##_nG1wqZAylr)K5E%sD`J$y+K#h!MshXX0*j;du~$S`$=1ut4zG8#IA zJ#?_=W9;#Uy?nr~7JI3IUG1nS(WwN_wh1P+C8YwYc-K$E2IO%J4oY=8a~$E?!LH(o zclGFuLw3DKpDx6=7K$Tgr>hY6a`4DKmVru;MRT&3PS`c+1wK=HE~%gKbi060$$SYO zp3{MNmrJR*E^_9cj(1^P=U&16xvF^2RJ^f|eZ%6vc+Yo?-7rbXY~=%do~{w}EeRCH zdjeryqU2o#2E3P$OK-pGZj_2QT(oXISn3{z_w2ws{o3-ooFC(JZqiMu%h%uFJ^MJ# zra|>a2HtD3+p6|(J<Y;<Gx91mmn&2C?%;DvYSOzOb1d<$9?jl2?P`Z6-Uv9xzKf@& z`zpR9RkLB^2d@)&7shP}y0M7)_W^vS?BsKEo6C!Lo6Y;cI~v(Kc+b_na9ek|S|Q$5 z`vI!yyc?e5-DI#v@BY!95AZI>oa5Vc@=Ffhtx!VSGM@bM!+V-DPk-9dBmeO(NM_j7 zx3R|puX7IyJoa!cz`Nd_pXqEu$~U~G9OyCh<+y=2bb0n(Talo29bYtx9F=_$%!2p0 zeonjOF4bRnPp)S=o|JZO6W+~T@4P1DXdcF!NgQ-|3}TPW#+OMBX#bHr6^%C^ZP6Cr zDf0X?K2sjnXWAZJj5i0YtdpNM|GNObb;3bMch#w8;8n73r@^YvTktN)|CayOqIDMD z#q<yI*mlg=vj<-^8f3nR`Zo7DK2ICywM%wJ;H~(6_ufgkGXw8}<iA4BclQ|LU8ud~ z!iyU>C*a-B^TK-mivtt!hRfDz0nFh{c;m={W6s*Pdc1DwYus*es}k=%gd)i`LVa;~ z^U)Qqyf{NEye*F@H?CfJDUUY?NW5}0Tx5=SL)Ao!!{vL<;jIJu6%*OsKL3g@F-TZ_ zQ0EB68;$CG9P1q8@ovELV3?ctan@0M7PV>$E}E3ijW3gII~d@TcpI;$-x@!>6_<}U z2b_pXx)NoIHv-Z=Zo9oU1aGP<+?KIxl04od)idLTrmzFv9Rxa$nGV)u;cc9xblUN6 z>$-_AH~u)!zst1z4ZhHQ>AtmMUozf;jAdP6<QaCnHAx%WmJj@2Pvf&lU=5><{sp|w zE%1=o=q0cYpN}FVj3abQ@vi+BSpDnqlFfK8tVm;He7CUj7e421*xx^Y?J2x%O!eZQ z{rq$AhHjs78=L1syfOVz_UB@6A-o%8PPmmnh<}N9->r;b-&+yGYxsOL#YVLH*h9P- zc74g&?h}4I__A8*UHwF>FL-O%JiWi{Oj&q+^sUNJ<-m8mnZ$uj=ew;fq+t!}uaSEA zv`A(Sug(-)hazw9&`c@*hif^%_Wz|f-o$*i2M<AGEayKeXrJk0_y>pV_wu5U&v~D4 z$WBe>t(t1^9fxe6`idV9<8d8&?eb_{z5V&;IP^ZfRkJ*LHY-^h1@MOkejnkN#qVGI z;f&v8{IP&PtWbtZFya?~XyEq|epli55q?+Um&NZY+S!XgtnjBv{I0?ulKB0L-&OeS zr6dpH*NZ>3<BwlTWbx+({NYTAy`y?r85kfFjZ$bs`xs@;XjqMg6$512XV9b#{N*J6 z6pO!n#;+HD>5X6SsO;d&N6>8(@SP9fJrh|X;HU!cM}TdnAb9vRSPR1kdk9TA37Wxy zY>9w5VRTo-=&p#-T@hF&8%K9VluSv&5iYXOk_c3s;7~HUD+2p!%h6pC*u!OXR|NKO z8Qm3uJzPe2MPLt?(OnVP!)0_=1om(l-4%g7Tt;_AjP8oyfGtl3Pm4hYHcg#5u&<cM zu9g&0Xrmf3C<eC;`^t9g=3-xIONx83uWZM@Zw31rVC*Y+NpUZBbFrI1iYO@|Ns76o zs3pa3q^Kpu4fIt@N_wD`%Sg!q*xi6VZw>~(VRtWfQS5tXu&br7DE4xPzHS(`4YHqL z#DoKAl?|5RE6_HBt`+;2KKI0XSn33&J2#VG9m2N)Nh7iJsQbN5_>@e^unuGK!F$eZ zh-cx_T?)tWnKD6d_CF4r{rHsZnDFRjy80u0N($G7@qB-a_tfVVe_q+zUBJ8Y)6{0U zR{bTs%f_e94p4nzhIff+OU0CHif8azw7y1rn#n4>N}MHcv^e~Dgl~aehjrK^uK6eN zh0FbB@03Y-cvqn^&dV$o|BHA1sM@5z&lnEw#pf0VJ?YarH_qa7%MFX#xbG2*QIt&m zTn?$9G7xhaphWCt|3}+-;~#uBYN#`GT6p6<iu#hO>YP8}c#oHV)0~nWcMPwREeYnU zUkBk`?#^3d6gocv@9Nob7lEZp<#?B)zLc2D5YvTs_3Q<s`4=jy@$Mm#IOXna@Ez|? zfy59SgWLUh7ubGeESc%>AMfIDlV^^CV$1OQNMMqjc$N_4JY^ikRjBQChuBkiSMqju zdsj2*;$00XaQn-o860?hRME6GoXrStOglXIC^Y*L-pswpsarZ}7T!gz6a4&Ts+{ny zsa!YzdVwo1-kkzh4$NQ9b`kH%{M#QK;5NF2HwVnP?6LNyE8aL-Sg&uKV2<~oZ}(8k z4acJJ#!*Ck{)C8wcr7~md#i$L3SK47E+4cONZ?N|a?8(ETH!4^xeF3^x~AYgmt4Vh zIa|QKc6{Z_I&s70FHhl33~BSK*dLVQT^bv*CR@LDCf>USqOM-dNfgJMVcnhoW!8)1 zO)t{#eIKW<!|Um^6En8yxZzDwWy$AGS0%IKTUGqk{o>#CHh5QC*L3aVV~oV>Ts~gU zt%*1BZunqu@)q4?j`tFbnC^DN72omRLgIGhLZHwayh-X$&xONv*YM`)_cxb*7CMeM zPw(~deln*CZ+c-!wz{!^bsoM{H{o7Mzyi@}D3v5y-FU$7#)es~cyBE5Z{zr#5r#K0 z94wu2c~v&veHe#rd^Y6H#~ZpLbCyYFZpE7z6mI6onknGTu!7I!gR2+fO?8jvmugO% zkGGZ5x1-=#FE8G<j_d)SFKT&ss|k~YRb@8&@K(Y-3H+Ti<nWf5>beclsr&F+bWOWo z%cBZ!l6oEK_N#J|FuvS4CE#d`!VkPf(6P54HXjzm8v*Ao&R|IBevL2H_5N@El6Mua zk4&z!hyBNYN8RL4FAeO!;@!2t@95phrG)n;2h-AXWs^SOEj)6BKNd2|@#70Rkpo=+ zKOezceXioJORZ?f8+1PwZ2g$%k2kBS`K0~G@`Y5NppF~n_J|jK8>DiI_;73pQ0XXY znxVmqL)Ph~T%h2W|2Vc9@ViDl%oo75d7>nBYSGpWxb&9&IDcL69j^N-OuI9i7H-6~ zwZc%S{_=w;TqZ->{J0iTiX41;=CLYy+avIsj9(UiEZ`4G{3hcMD@y!}KL+uq9Q^T% zKV4DcU;OssH<=PyN@9=_dnwUNNmx;$ml8J*PQ8?*=YjGOB_#uXH{&nshGJOZ_b+}~ zN@^?oCJ&S>{(51cTs3O%;9K%vJ0;6x)K$3JqNphrX?p~07Xo;P#P*vfKni=L{qpmQ zOA<>m^Gos)iz;zlFae#^&C*aK_JRo>-|CRFJP$E;Q;0nIa{1tiBlZD5xfT1o4%@qb z)1RUKYaNEV#C|d7|GN&u#X-xTixKvZZlyp>KY&)x!&jr=UPum~kjAZq1C%Bh@ZL-S zO$qoeFW@3<3O8XTJcO0-5>~=TSP4I2B?5$%2ohEzL|BP1VI`2QO?cyI^nwZO>kLP? zQeY1kRl=!mbSnk+pc~yvfjwMCw^Cpam(i^h*u!OXD+Ts&8Qn^OJzPe&QeY34(XAA8 z+e!g#G@)%F7!`#qY#j}U(Qud&GzGr3W{9K*Z`Psa;=$`)Z)R`k2~{LsK7oDn5O&ca zlCJ0*OWrKr9Q3tu)HX;v0JK^L$GYK+by;!z1$Y+)ySO}cIQsSszEw?<ZPx#5XX0H? z-H@=cjP*f3zD0Wtx3-9Q)HUE!@}bkymhbO9d~VrPE&qRi72YM+49D2{H|=V~XVD60 z9dFqWc-JEpW=ia2EPRE}Ef1KthAmXUyE-tXgzLqO=Xek1b*((%sc#KA7Zyh}x<`jT z4RXbMBK>v-y^!v&c$c_+=;Dz}PydL|M?ReoidG~u9stdJ;Bd=Hx81)EHsM`B_%r2t zkajuVLxOL-QOnf)a137@6}j(u^kg~S^=le7o!1oFPT}*>2DN}`4%hJRR!R7tkjVTV zvhoavr{^_2-~HqUUL`^u*DZpMUd87l(K{O#&p3!TA0^%M);Vv0_fTmD_Z^;`ztZtp zRKn|#vac9#xZE&iTI%a`6rU*?e-|H@wZwaCfLxTtAMZQ2@R?Fm!s%!&djp>mhJV3* z8yN5=%#4VK`wueW-LLi8;jWQG)>C|mq4X+~-V&=D_>>%Ydf8&~`(5~)Td`wf%JS_W z@hRD4n)9;q58nGkZr+ml6tfNQ0s0G$RxD3jIv1ZsJRSvxYnS4^eIv|(p*{X0-n%MZ zxiBo6CV@9}pM6&kDZ7C8{+VZi?;jN;;oZ6*pvGOlB^_@mwWrM2aaJ|npp$FK%ReOi z5??gN{OxEE%ENoAw?azAn)=_{@R`ycZ|PK*f_HKKs{e<ZW-;U4c9%Z$(p<kkcvnKR zSx$|-*K!Y^Tkh?f7TyqtH<LUz4tIUJ9dGFNCH@x;<-&Vkk<jfoI^Emx?y2KDl3pt1 zh}SLWy3g!>T7kF3{P4A^>hNB?yC+3nevwpIjki!WkeFlih8yqgJ{s1Cc$0eZo+Ymo z&shAj0q<>4!NL~oN(^{?bZTbv)g|ZgDp^sex265%C46~$`-L5g4y}EMPsy}T5^v`* z;*IHN6L0R9o`Sa$mKU)QVY-R8iSv*@b3xYxy!$mcwqE%d*|Hg5+D*Efx`xpJZv;Hh z*yFdY2JeLnyM82UXMe<7H->BoKK(WuZ@3)xzh6)$jJH`)Q*O(vRft!KNZ6H(_NRDj zwGxK9(2v{jZpQf0Be74}2=8_Q{YBLRr|a<+9$^9{ryKe3Hi_j9oAatN<Mq*-&1oS8 zyFTGdbrRaPrr)39ZTbbgKVj?k2=5-xvLjzNzSqOMb>U&6>6`oJc<;BGaynyDQ0M`C z&JB-x%$#ugJw7Fquh-1mCxO2zzx&H!+dsSw$kx0~vXT9Gw~YBa3AKKk2iaE%>aSt$ zZaDLNS)myFPaHcG)LQ)ca{Y11&N%7i5?zK%c1mYzhTsldvP*t^mw9&@m#l%=ww)iZ z<C1-#{de#A1e~&)x^KVb#3g$*UhqfJ{vSB}Yg2W_K$8QP-it3~bTU8S(p#i*jpyu5 zT(S{M9__0+giCgb%$k%tb8yM($rTCtUc@CER>*v9(L`Lba}y3+NSldE_Q$urG8;c! zvb&W$+K%JY8}apYbmwzidQY7Ti?LmWOLp1&3dXg^amlJYEV%V;H7?l~$1csewgQ*z zJu_DWyCPh&W_K>HWDCS4yXbXzNoOi9Ss6Bk)6b^jl3j62#>=G;m+U2r<O4-4xYCu{ zUn{31&|R6J8?`ZxEoc6%FL5OnmtK=7R-57_xMWYv%f8o?ic9v^jyeYkdt9;!jUkuY zzT)x`*M$etHSciA?p(*~yyO}#*&D|^gEGx<*?ZXT(9&mqxMW2(SiHNt3YYAOq9>a+ zyWo;#JK4RY$_AHgQwDcSnh7r1yN9b<6j*V|8kx_{NwCHxyP#W@t^GW%JyQ$H`;`)8 zap|>mnP`%D7FS5#JH(WE{Sz)(zak??+h@3BKLp)$`+&2YwAVW5ohpUPRV@1tCeK`t z%Ve#Mf}Fpn;gUUh`uT=aICFR6YK^1Y7UI%tC7s=|=shmk$?Kmh9k`B5_SnUDdReD% z%J!Ifi)7%EmCw$&VU>hSHvE^E+(L0i9D4vme5377Zo{QF$)~L1P60022A`Q1N>Xsi z*6+O1KiwIZy{;$u9NvWCl5M~BGhWC6m&q$x6Uv@H!gamUXT|fvfgHH>s<GZY_UsNW zz5cDQtnxSFlC^uUv+B4gE|VX>xiUpG2$!rt>ZJ2;>~P5j{F-&E0(74r)-rZq=Yd8k z4_tZ~7<1H(G;zr$rLU9<j=&}RreQJTlzd#WO^TwYn5}V@3@8&m81+J@AfK`j&f58j zx~F?E&U6*D!GC!v&Q?&<{n-+p%((LY_kxFi4aITE+I)7qT#vI9HNBcAVD|-AXtY_g zt*|?TOZMc;pTZvHxMUNI7eq3f;gY?-Kz{#kWn8iXYwSLM;K3#9z*l$TAkNrt-Bs({ z^b1#d4k_#39F>mC<i}^^-p!kUOLp2JpWj<I!DOMk8{oSVz*`%Vg&II<1iV)Ow&#K1 z<qx(xS7tqveQSTN<I=qc+|Bl7h0?qabQ|oiXs1d(ifFfgk){1@`rT&xYLRvB535@2 zdo|wj?lb7L-{r}}q}|?TZ++jtcY0ov{q3K1S$j&F!5whOb_JLdMt3ZX?pPST`~l0H z4ru$z=#B;K%lSrkEMO0p(H#re!$lWV^WopXHM(N~d(e&USil}GqdOL`hs)@W1?=H6 zx?=%*xQy;tz#cB6I~J(7W5Jslz77-nYFX@}&_)Af1tZ)9l#2+wnc(6m2eEszU>6?@ zqDX6CQQeGK8;c@77~DMS21qLOW*cfDF_?1#t-=y%eg9}qg6#Jh4Tm8W4zx?bNIQwh zP7|QjDOg6#K<CYGN-f{jzYXsyqTMe9<}o_qT^E(X!g)yfGBdt4=G)}g=R9G-yK?8N zi|~y#`1b+ue3-sMP7?3(e75r)Ys}m5uC5YWxXEkfZf<<e&7UA#uGWqB093ty`Pvg4 z@h%aX9s8*DLnB^O)IF~TTR7s~P4N2V<(-m=c+YD+^XawDAw|4O7O*9*QQd@h--yht z)B3)Gc$XE|wBNU0vhh85Vgg5!O21WD{re-{%?~aU#96L1J;P^8P3znp3#0DgTj{0f z!nYun8SgT#&A(>#cG}@xn5M8*OfF~Q4t#F8uxUzerrRBSN_O4e{;+HHCwxi-K78A2 zX^waCVA0+CRhPfxP2L?Y=b{$P#GAa8&g4ide|U(`Ehna*+m|{G?^c0*7k=gzf5)3% zRPszSmKfnZ1Uo_O0AKlhymzI%IVHHR;Nx9<F)fi+p87T)?~+x)=#|{@l6WKF!WNkX z)~$F~wN9vS+alhGcZKb>Q?DJ)Ey25}@>;^CEOBGJYaM4-U1ZDxO~zwCMGI6ko9ye6 z@TtPP4E@UF!`@rP@Gj5SVEX>~sRiC5sLRu9;zee>3G>8C!G{8;@h;EjbTZj+XAJ|s zLe*T(aMcSZylz<>aA2>jK3*le<}NLG(}OpreHwUJmU-gcDlqq|=c_PhyjksiLd)EZ zad_R5R3moR_180eY4^~or|!8bc%3UJ6L!Sb8}C}`37S7;>woOQXHmrscTLL*ym>ln z{uT9$O?Yo~NvnVV?zc1EB(+MRs?}W$Z+a19c)TS@8Ly|)E)=|ytH4_{-}oWFR4Mlj zzJe^oLw<LG8{TaTmwb%$_TI#6id&+I+|pxsee@{m#?kq{cyqv#sfRx{cH!Mz)zI*M zpOM~Ld_MXYX1a8`7~TcsA0~8#Ph~xh&y*h=@0F6a;f=<LR}Vbsmd3lr{F*H9hVc1# zqcI^VFQ*)|f&+I!w$o|ztqc8ln>fw9$u@Dz@orntSFf0IaV6diJAKl>8}nA+UCbW4 zob~2R{QJ^kS{s=)@Snq9uKr`P=~BFIIdr^6^VAW%4W*o4C#Huzz#F<gN=j1~#^Ehr z6f9Q0X1TNnUt;KTk#W6y1aC{#@96Q8#c%M|(-!XzEP1-|1im6j%)DDGQ4Vi!!eWK| zv4_lf_c6}9*ykS-h}SKjHnjX{zl68&ST7m%_OB7%_KTR>&1U8$c()3OWG9x*zl%3X zIYqU^bO+<zMt5lH?8{yqcuir*I>dT_8FCW^sK17}n;>_Q@^oI4zc^Oc>o{Ht{h^9W zwypB_%*R5wWTQSO=Sn2tx+_7rPx_tFvxhkBMH%$PSVz|omU#c8Zx;@|MRs?D{R3EV ztnFkt@M5-e?kpU79q#U2&i7~<4%vj7PbwKVmf(<Gu+Tc_Ti!YxvJEX&$%S7w;F4X> zT;0frOV;7`;grKN>v8C<-L@lL@dz&eKKP?!*Suym4!u_^dCKCx;?m3TNSVcS1}?n~ z^L8<-9$1OPWCnhZH9QQs^d7jpZt_8MTwyh#rYQ4W={6iD8;HBAugKhmOV&lRm!WSr z4%r5l$<w{Wci@l>_{XN=6uJ|KY(jz3!%s@MTy;T`ZOgMaxb!|)eAS?$0++o4lS1dO zZP<*%UIpv#&E?FvWD}TIS(Z-RibL;$1(NDU%QoSVEl8J~Z1rFZ4%rQ>Ug);{#pT}x zG7;a;C*rjCg2#=c4f}DJ{6J>G%-2`e;*fPnJ>Jm28dqv>u<HxF+l5P3Ax7j}x8YJ8 zCNDT9c4)0X&ireAE}@Vcr^$Vf1kU#1l->Agum59Q`M1ENtmxPwT)C{FzAZ%B6_?2k z_f~12-HR)yG|cBdSi!OehkqxC^X>njfXh`3&sVnJW5t!O9$4+Z^hjeB4wD_e27DAq zUx7om!D(i4#(rFR-@$TMe$jrMDd%&fP)8k3{~8uG1(o0`b4)k-|8Hc(RpU6ADn^;V zoQK2B3<s|{gfGKYr#Kifw;p{y5r^J}w#)~&)%$VD)-=6dJPnt<32df$Nf&X2^MmFD zk8MV{{F~6>e90*Zm)-`AojZ?xnuEht3YE6ZQ9ZbFio#RTo$=Yrap+BWR2q8b$YLC_ z5B6RbyEkbe4p{}Qt0@kwxb!Y)b^iE31ee|eT=y3gs^XGuaND!8doixMyWwW7W~BwL z&^R#pLt>RLF4>0qLnYB?mf`Tx0&9U=nQ^#E6@|vmQ=V^dh4TaTn%opUT(S!){#fkO z$CZyZ-0PUHx*AvcTu^Gr_VO048t22@Yvyz7aMh9psX>=sTH}%p$XisoTNPLRdq95L zB(saSTotf<_0u<T+i`@X!{v7#?ftk)h9?;YPgieb#L=$%pnI`w(=}Wse@Iq1)hCN9 zGy+~fcH(B<h{IJ3ows_FHF3&9o2pZ=?ov_s`fdBmZ@6;k0}lmZe@$Gn4c(LLYhz$J W1!*?{Y|%b=L%|fa2_P4g>Hz@qg(O1& literal 0 HcmV?d00001 diff --git a/irlc/update_files.py b/irlc/update_files.py new file mode 100644 index 0000000..7839014 --- /dev/null +++ b/irlc/update_files.py @@ -0,0 +1,109 @@ +import fnmatch +import requests +from io import BytesIO +import zipfile +import os +import sys + +print("Hello! This is an automatic updating script that will perform the following operations:") +print("1) Download the most current version of the course material from gitlab") +print("2) Check if you are missing any files and create them") +print("3) update this script to the most recent version") +print("4) Update certain files that you should not edit (_grade-scripts and so on) to the most recent version") + +url_install = "https://02465material.pages.compute.dtu.dk/02465public/information/installation.html" +sdir = os.path.dirname(__file__) +dry = False + +if "02465public" in sdir and "tuhe" in sdir: + dry = True + print("-"*100) + print("It has been detected that this script is running on the teachers computer.") + print("This means that your files will not be overwritten normally.") + print("In the highly unusual case this is a mistake, please change dry=False in the code.") + print("-"*100) + # raise Exception("(teachers not to himself: Don't run this on your own computer)") + + +print("The script is being run using python version:", sys.executable) + +if not os.path.basename(sdir) == "irlc": + print("The script was unable to locate an 'irlc' folder. The most likely reason this occurs is that you have moved the location of the script, or that you have deleted the irlc folder. ") + print("The current location of the script is:", sdir) + print("Make sure this folder contains an irlc folder. If you have deleted it, simply start over with the installation instructions. ") + sys.exit(1) # Exit with error code 1 + +try: + import unitgrade # type: ignore + # import irlc +except ImportError as e: + print("Your python environment was unable to locate unitgrade") + print("This means that you either did not install the software correctly, or that you installed it in the wrong python interpreter (i.e., you have multiple versions of python installed).") + + print("VS Code: Please select a different Python through the Command Palette (Ctrl+Shift+P) and choose ""Python: Select Interpreter"".") + print("Try all the Pythons you can choose and run the script from them") + print(f"See also {url_install}") + sys.exit(1) # Exit with error code 1 + +def read_and_extract_zip(url): + # Download the zip file from the URL + base_dir = url.split("/main/")[-1].split(".zip")[0] + response = requests.get(url) + local_students_folder = os.path.dirname(os.path.dirname(__file__)) + always_overwrite = ['irlc/update_files.py', 'irlc/__init__.py', 'irlc/tests/*', '**/unitgrade_data/*.pkl', 'irlc/car/*', 'irlc/gridworld/*', 'irlc/pacman/*', 'irlc/utils/*', '*_grade.py', '*/project*_tests.py'] + # Check if the request was successful (status code 200) + if response.status_code == 200: + zip_content = BytesIO(response.content) + # Open the zip file using the zipfile module + with zipfile.ZipFile(zip_content, 'r') as zip_ref: + # List the files in the zip file + # Iterate over the files in the zip file + for file_name in zip_ref.filelist: + # Read the content of each file + if not file_name.is_dir(): + rp = os.path.relpath(file_name.filename, base_dir) + new_path = os.path.join(local_students_folder, rp) + overwrite = [p for p in always_overwrite if fnmatch.fnmatch(rp, p)] + if len(overwrite) > 0 or not os.path.isfile(new_path): + commit = True + try: + if os.path.isfile(new_path): + with open(new_path, 'rb') as newf: + if newf.read() == zip_ref.read(file_name.filename): + commit = False + else: + commit = True + except Exception as e: + print("Problem reading local file", new_path) + pass + + if commit: + print("> Overwriting...", new_path) + if not dry: + if not os.path.isdir(os.path.dirname(new_path)): + os.makedirs(os.path.dirname(new_path)) + with open(new_path, 'wb') as f: + f.write(zip_ref.read(file_name.filename)) + else: + pass + else: + print(f"Failed to download the zip file. Status code: {response.status_code}. The DTU Gitlab server may be overloaded, unavailable, or you have no network.") + a = 34 + +# Replace 'your_zip_file_url' with the actual URL of the zip file +zip_file_url = 'https://gitlab.compute.dtu.dk/02465material/02465students/-/archive/main/02465students-main.zip' +read_and_extract_zip(zip_file_url) + +try: + import irlc +except ImportError as e: + print("Oh no, Python encountered a problem during importing irlc.") + import site + print("") + print("This is possibly because you moved or renamed the 02465students folder after the installation was completed, ") + print("or because you selected another python interpreter than the one you used during install. ") + print("Please move/rename the students folder back so it can be found at the this path again, and/or select another interpreter from the command pallette") + print(f"See also {url_install}") + sys.exit(1) # Exit with error code 1 + +print("> The script terminated successfully. Your files should be up to date.") \ No newline at end of file diff --git a/irlc/utils/__init__.py b/irlc/utils/__init__.py new file mode 100644 index 0000000..a56057c --- /dev/null +++ b/irlc/utils/__init__.py @@ -0,0 +1 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. diff --git a/irlc/utils/__pycache__/__init__.cpython-311.pyc b/irlc/utils/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d927f6899883d10645c4359d8b581fd82bf24276 GIT binary patch literal 170 zcmZ3^%ge>Uz`$UU-<!6Pfq~&Mhy%lnP{wCA1_p-d3@Hr344RC7D;bKI7#J8ngCu|1 z>SyHVrs|iJW~A!7<R_QrrskCt>u2WX=o=WBm>Lw9l%_yLigJ?mOG`3yiuL2;GxIV_ u;^XxSDt~d<<mRW8=A_ycu`)0)fb1*gXJBCXz|6?V_<;dN6frX}FaQ9%b11L? literal 0 HcmV?d00001 diff --git a/irlc/utils/__pycache__/common.cpython-311.pyc b/irlc/utils/__pycache__/common.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..117dbad6cb0d38b3aafcc6ba26318720288fab93 GIT binary patch literal 14184 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 RIr<+#;$J`nnhJ1g0RZEE56%Dp literal 0 HcmV?d00001 diff --git a/irlc/utils/__pycache__/graphics_util_pygame.cpython-311.pyc b/irlc/utils/__pycache__/graphics_util_pygame.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2a2de9b202c80da608b15438e243b1157f00709d GIT binary patch literal 28061 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 literal 0 HcmV?d00001 diff --git a/irlc/utils/__pycache__/irlc_plot.cpython-311.pyc b/irlc/utils/__pycache__/irlc_plot.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7aa1b05105fae565302e536103d713e6c25f1e18 GIT binary patch literal 13152 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 literal 0 HcmV?d00001 diff --git a/irlc/utils/__pycache__/lazylog.cpython-311.pyc b/irlc/utils/__pycache__/lazylog.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46db0cc630ee8ec0f509e98df741e7c06852dc91 GIT binary patch literal 7720 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 literal 0 HcmV?d00001 diff --git a/irlc/utils/__pycache__/player_wrapper.cpython-311.pyc b/irlc/utils/__pycache__/player_wrapper.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f57153c5e14540a2c97df79d5ceba88e28817fea GIT binary patch literal 14670 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≠C}VO( z#^i#G$<GJ;!dLh;KQJ)z%H0r=oxu2jU!bG*10S29<P8z~3#jO>xZ(oU6_OXljjxCs ze_&t|RlgxEv%qz^`y%&+o=ZG0Nb6pZ*1e&iHpB79kGtXuppF)3{811>+z^qN-~xd^ ze*F0HftgWI5=65xNJviLc*-Nt<29kU)4#{R!~bJCI7t?RYVMPAdS1K?r+B%%6q!%S zuzD#nYclz{LB@Nz!Q;I}po+Fg50rgCjlEmU>6N*+m|gSAz`flf(AYpxG)NYdU2gG0 zyT{3?IXR$7B1rxMHHIC)4gMm~_&k^ZmA1t*7{GZ5GMwAM@PSF1Rq6wSG^^B%QZTi` zd5t@mft#@5WmWmW04L-aS$RPNu24cH0zB$V4he2bgPrOIF1o>^1E7(ZlG36)lrATz z=>}@Re=cGG4c4}^PG?AAOko18+2~?rWI!H2tYPeAs9{=zHdR&2*umPtkj9k4(!x>8 z3}v&naMZHYFn2P<gUklkO*Jf?4Dp~?0P{K-Y8ca)f*CZ~5>K!)Fn}l3!E^L!rFq~g z1T;-wTAZ2!n&eg}%PcNU%*m`u1QnXadJ3K;3dxCikm+z;1xN4#fXe(*&;VOzUO_2% zv@Iz=u_#3WRJJGPrGO{t6Z4Sg;K5d+X)Xp0*%hT0m*$idL*>JuR;MZyrGmz)ijq@7 zlhnF7sfk5-plMd{U`???W*&I9KfNe3r98hVCk5Fm=%jj5r9xs#3RsT<XofZiG(1>R zl&FxCnU|`NkdT^JrlSBhPQg|oGp{7I2vp^irGjShb-?192?=^&cY)R?q~(MB4Kl7c zBfq>@0pz`k#N2|MRHTIhc6N3OX+`<D3g9XU?m9g<D;{YzMX^F=Zb5!giGovpeztp2 zW{N9fr3KhpP#uF}B1{8#tW8G&JUOF->~<7wsd;4zw%82UfD93W=4MiDmB0gDN;(Qv z`T4oF26`5n3d#xrpp_fQs?@=%)G?C>B!FNp#T%v&_kw~~Qxl{C2`el3CT2qxbRY!~ zvd{Ds{PIgcDiTW+GD{TlQd3jFaR81eR7ZeA2V@O2dUX`?N^|2=3o?uIQ&Nj<jnFNJ zxI<YXGQSj*&Os|$GV>G?^HLN_i$OM~LQ@Gy1le_o#R{dMjDl)=YF?QhxZR|o3CS^@ zB?^f-#rX=Ud5K9msl^J=oCC{b5F1d;EdedBK`bCj%S<mVN>#`&QUGU|%o2sfVueJ7 zf|N9cw9K4Tg;G%Jh9qb`&>ABR&>9qwW5H=$52UFeB~3#;w=y22Uaue}4V<#UiN!G| zM<FFOHy;$3DGCs);MprLza+I-A+ZQFN}d9<s06gO2Uc!C^O{vbVo_o)C=*&KI4Y!9 zf|>ADLmG*B3b1A#Y@JR*f@@w`LIPw-kS5qEP(#2mYNg<q2Mu=Yy1{85yME}Ht(8J} zMruh$Y7w}kD9+3+%>fr^3dI@V6-G&^3Z;4Af#4Jc(C95_0TXCpPbI`LMX8{|8|)60 z$jM8Ax~n`RGdTk??U0n3nx{~llbN1Tl2fTrT9A?mT_BPRP1U*Zq^tm12cnRgn4F=I z4|1FyJlR1LTP`Se!RZR36tn~@ApxAG6B2Y0;SNf*us#8+XKrG8swQKRKLY~;%H$xZ zJ^*#4KdUf8CLK~3J6RB`HIkV+SwQV%a3#S|%h1V!eO?Z=D^$x^!+@->lX(HCa{@60 zi9{c8tYt!8Z-ba!t6@U#+@Yug)tO*ZQ>dd3K3s(AE66koXq^vdQF>B*Vo_0I<t^s? zv@}ijTii%xVUabs(*P>wp=t_pN^Y@b=7Q>lTP%qcnZ>twN<e8LJ}0p<zqCY?^%iqc zZpkgyw4%h^)LTrMxkdG$RuE`3v>4<$q$w8`PzJ7&M5>MuGb|t}0Y(Of;u1(x=!U%3 z3g<Qc7dT`(n0xqV2;UG8p3XIiYa-7So(|R<QnDb?8@xjO@m=vVLND?vU*T2mV7kk} z-NQA(sFSaUuY(W7;g}%W$=}1@!H>?l!Xa^yL+T2L)CCv<H*-*yt$>0OoV+G5!;=>` zO7h}HN?wee+(acWrW(dhBz>J+IFc7ya;RmlVW?%PVZlC~ik^6icx%ARVOyDy$2(G3 zYT5EsQdn!*aGHZQ5>dpB&73^wXvA!W6!sdn*$i`;YgtR+V;l?&h>^?%pfCg{Z)5^v zB#9kmGzD#0Yzjv<xT#lUjKdBjn-R9upqWxEQi3!VngwU0t3w?PP2t30Cw!C?VIu<r zy1!6IV;C7~*iu-aqe~h!%nLxhZDj3WHo6&%3@IEbTsgeCe6<{mprunBSX3|sGn9aO z`(P6o7_#8wmMPq8crc0|WR>u-%o@zmUSxHkJ`&jU6trd0jHot)@(WlUM)AXu!k5FF zD*_s|Vq&P_tYJ;zUn77XLMXm~k4j^h#SqM(Dd<<!2wKI%qF0cY{_@ZN|Nn0>7v!bi zVlGHYt6~AQ1AZ~;f$NYe#o)v;aN9O7v7k63zXViGBUgJR`I?NkB;#}Q%Thtp@A;)A z1*IkNDVas7$tC$km6}X1K>=Dc88l<Tc#AzPGrc&oDzykS`k~2qiyhhq2?4RoQj3!E zi&Hhlikd;CAgDAgY5^6g9I1IJkY$og`Ng+b3KB~)K*LQ%pd~}Mm~&F|Zn0(-r(_o0 z;s8~vDVasZMW9uVx7ZVtiouFmK-S!10kyr0CV|Xu1sTf*Y19<8fkfItL<fkN3X)?1 zmD!p+w^%?8qoPibco&H121)W3Ljxlow0QXzQ*qiYmbBE0l3PqEc@XnKW+0X2pwtSg zmLV8Ai(Uj$R3(G8L<hOIASF!-RH*L)&Gj}g5L2i>Krhs9NXT^X-r$zF&aHTfTXBKf zMQ+V2+?pR4I5?GW2+GYUUcfY?_==!%htmyVi4K<zmj@u~2EWX8e$`9-steLC^6OsV z*Zsi2%&UAuRB3_n0;dJWS47n(Fil{3AgVNh>4AVyM_fnTgb)zf!E~3Gzb71Atpr`< zRk*^d(7|+<o3Ep&)4a!gLSUD5hxOc|Ipy<fXVtC<x+rgOMc$yp`YsP&kM|5F$gsj) z4&DoVhFgucm~Xe=WPiZuqOsc*W4DVO?pHY6FL1cu;O3uT3YxdO!Nb?@-sL{Qsnfg1 zyTkhikJ$xObc09r0*~r~q>DV7S9mlpz|d13{vNLx6&H9kF7jwx;nBFjqj47`G@+=| zug9;$55)195DIk+5C0V&nTtGfS9s(u@W|cZQMrJMZtw_qxKD6ez;b~{^&*ez6|kLP zBRai$ygI-TTs49!`T$QKNQwZDUi5$x6DR>_vLOZrz^$|*xD;4<F&hH|189AK0%Y*x z7B^CYDO$<E!0-_?kO;~#p!EPB%otduF0e=<qo+KwGg21>Z?L$)V{?(m<_eEZgX;$t z4p!+847dmpMbJ_>T!afFgMdhbbBo6fA;|{k7H`mWDr<+;1r|}TZ&BKrAm@YHnxEH! zr_y0#8nq0Jpz#f6&_0w}(4G{=6qX#8T-I8qT((+faAC~|nyOiYHUU%1f>PbFFfr6H z*RY@#)2Ibw3=;!GElVwH4a)+ol^uEkS;MjbUcrG&V<>?|9jKiKl|@kK>QWd}=;%u( z&_)238rBq!HJqqBU>F%{SQZfHVy;>?@Wej1AGi(xZEFbxcdIlRZwX@=lh9;>EQ0|x zHEywj2LzyV6ff;HnZTv_Ef&xy!b{N36-~xlJjng-m#;u|1NSY+R6uHlp`l)3Jh-n{ z1lntJOBGaXBL+$kER-RWqBWo#1zHt_a0@tl++r<CElw?gWGk@!>|k>t8o-N4LGDJ% zh2SLyp!sk}aSdIW&XSv$nOC%xfq}shR4OYng7z`oV9~gMiXO0dUO+`RSQIZ{LpQi& zFL24OP~X9Pfy?G1m(3L}n+E5*f-*CL7pN{!UBSFiYl+rHLES5Yx{Y29&K;sRSlHV= zn>-u6Tf7^*K^%`Jk4CQ+uLds=2QKr0je*sRk!Eh-Y;f&R?kHVge1S#%B8&PJ7WE4( z>ZlIjV&LRya0Eecad3+xJ{}ZyprKqhP03rF>6N*8iN%?vxkaFY;TAtQep4$94D}$f z4vvmgP;_R32+$(LBG4f3EkVTQDZPS9P_G9xWd)*(KoxosXobfuZcp&o8F(8-Q6;Fl zW+_iB$}7?YnFT71ZZYQ<r4)sLxM3gyTpm}0SfJ7r9K(=7YtSkSun)ka&c8TpAWN3* ziuOTwIux&GWMKHf%*e?2fI;R0D!Rd-cmWmNVBl^5!y61-4PbbKLHq&?-C*Es0K*R~ zoQ(V*xENSfF0d#gqZ=%O4ZaZg;|9CX2L>iaegtuYg}=eA#ruMQ--W;s5DE>u7#Myf zF#MuG_(hh8D=ZNgSR!t4@ijOjAb60Um5GrbG|11T$*A&y0h5?u`Vl1h1w=sP!x$NO z1v;E3Fn4<Ncr<X{;8tkh_`npw#3=KD0XsQ^=Ob9=3z&qeievR<WEA_r03s(OPf3Tc z7NkPx1HwndPpDpS2!L?0kO@p;j65G0;6w}~0}D?_)g@-h3(S(BT)^4j(&*OW)&Pbd h*cn))E-*`iHz3X9(qvf4>L|v%PR>z~`Jf<(2>=;0T_ykk literal 0 HcmV?d00001 diff --git a/irlc/utils/__pycache__/ptext.cpython-311.pyc b/irlc/utils/__pycache__/ptext.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb451879a9f6a5d67719c036754531e523e49a34 GIT binary patch literal 52471 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%0D)ZyVk77`} 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 literal 0 HcmV?d00001 diff --git a/irlc/utils/__pycache__/timer.cpython-311.pyc b/irlc/utils/__pycache__/timer.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92b2dccac3ab657ffcb6961d6f22f710e8c4a9ea GIT binary patch literal 3743 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 literal 0 HcmV?d00001 diff --git a/irlc/utils/common.py b/irlc/utils/common.py new file mode 100644 index 0000000..43c9d70 --- /dev/null +++ b/irlc/utils/common.py @@ -0,0 +1,206 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from gymnasium import spaces +import collections +import inspect +import types +import numpy as np +import os, glob, csv +from irlc.utils.lazylog import LazyLog + +class defaultdict2(collections.defaultdict): + def __missing__(self, key): + if self.default_factory is None: + raise KeyError((key,)) + + if isinstance(self.default_factory, types.FunctionType): + nargs = len(inspect.getfullargspec(self.default_factory).args) + self[key] = value = self.default_factory(key) if nargs == 1 else self.default_factory() + return value + else: + return super().__missing__(key) + +## Helper functions for saving/loading a time series +def load_time_series(experiment_name, exclude_empty=True): + """ + Load most recent non-empty time series (we load non-empty since lazylog creates a new dir immediately) + """ + files = list(filter(os.path.isdir, glob.glob(experiment_name+"/*"))) + if exclude_empty: + files = [f for f in files if os.path.exists(os.path.join(f, "log.txt")) and os.stat(os.path.join(f, "log.txt")).st_size > 0] + + if len(files) == 0: + return [], None + recent = sorted(files, key=lambda file: os.path.basename(file))[-1] + stats = [] + with open(recent + '/log.txt', 'r') as f: + csv_reader = csv.reader(f, delimiter='\t') + for i, row in enumerate(csv_reader): + if i == 0: + head = row + else: + def tofloat(v): + try: + return float(v) + except Exception: + return v + + stats.append( {k:tofloat(v) for k, v in zip(head, row) } ) + return stats, recent + +def average_trajectories(trajectories): + if len(trajectories) == 0: + return None + from irlc.ex01.agent import Trajectory, fields + t = trajectories[0] + # t._asdict() + # n = max( [len(t.time) for t in trajectories] ) + trajectories2 = sorted(trajectories, key=lambda t: len(t.time)) + tlong = trajectories2[-1] + dd = dict(state=[], action=[],reward=[]) + # keys = list(dd.keys()) + + for t in range(len(tlong.time)): + for k in ['state', 'action', 'reward']: + avg = [] + for traj in trajectories: + z = traj.__getattribute__(k) + if len(z) > t: + avg.append(z[t]) + if len(avg) > 0: + # avg = np.stack(avg) + avg = np.mean(avg, axis=0) + dd[k].append(avg) + + dd = {k: np.stack(v) for k, v in dd.items()} + tavg = Trajectory(**dd, time=tlong.time, env_info=[]) + return tavg + + # tlong.state *= 0 + # tlong.action *= 0 + + # for i in range(n): + + +def experiment_load(experiment_name, exclude_empty=True): + files = list(filter(os.path.isdir, glob.glob(experiment_name + "/*"))) + if exclude_empty: + files = [f for f in files if + os.path.exists(os.path.join(f, "log.txt")) and os.stat(os.path.join(f, "log.txt")).st_size > 0] + if len(files) == 0: + return [] + values = [] + files = sorted(files, key=lambda file: os.path.basename(file)) + for recent in files: + # recent = sorted(files, key=lambda file: os.path.basename(file))[-1] + stats = [] + with open(recent + '/log.txt', 'r') as f: + csv_reader = csv.reader(f, delimiter='\t') + for i, row in enumerate(csv_reader): + if i == 0: + head = row + else: + def tofloat(v): + try: + return float(v) + except Exception: + return v + + stats.append({k: tofloat(v) for k, v in zip(head, row)}) + + from irlc import cache_read, cache_write, cache_exists + tpath = recent + "/trajectories.pkl" + if cache_exists(tpath): + trajectories = cache_read(tpath) + else: + trajectories = None + values.append( (stats, trajectories, recent) ) + return values + +def log_time_series(experiment, list_obs, max_xticks_to_log=None, run_name=None): + logdir = f"{experiment}/" + + if max_xticks_to_log is not None and len(list_obs) > max_xticks_to_log: + I = np.round(np.linspace(0, len(list_obs) - 1, max_xticks_to_log)) + list_obs = [o for i, o in enumerate(list_obs) if i in I.astype(np.int).tolist()] + + akeys = list(list_obs[0].keys()) + akeys += [k for k in list_obs[-1].keys() if k not in akeys] + with LazyLog(logdir) as logz: + for n,l in enumerate(list_obs): + for k in akeys: + v = None + if k not in l: + for ll in list_obs[n:]: + if k in ll: + v = ll[k] + break + if v is None: + v = np.nan + else: + v = l.get(k) + logz.log_tabular(k,v) + if "Steps" not in l: + logz.log_tabular("Steps", n) + if "Episode" not in l: + logz.log_tabular("Episode",n) + logz.dump_tabular(verbose=False) + experiment_name = logz.experiment_name + return experiment_name + + +class DiscreteTextActionSpace(spaces.Space): + def __init__(self, actions, seed=None): + # self.env = env + # self._actions = actions + self.actions = actions + self.ds = spaces.Discrete(seed=seed, n=len(actions)) + # self.start = 0 + # self.actions = actions + # super().__init__(shape=(len(actions),)) + + # @property + # def actions(self): + # return self._actions + # return self.env.A(self.env.state) + + def sample(self, mask=None): + return self.actions[self.ds.sample(mask)] + + @property + def n(self): + return self.ds.n + + def _make_mask(self, actions): + mask = np.zeros((self.n,), dtype=np.int8) + for a in actions: + mask[self.actions.index(a)] = 1 + return mask + + def __str__(self): + return f"<ExplicitAction space with actions: {', '.join(self.actions)}>" + + # def __contains__(self, action): + # return + + +class ExplicitActionSpace(spaces.Discrete): + # Hacky stuff I don't think I need anymore. + + def __init__(self, env): + self.env = env + self.start = 0 + raise Exception() + # pass + # self.actions = actions + # super().__init__(len(actions)) + + @property + def actions(self): + return self.env.A(self.env.state) + + @property + def n(self): + return len(self.actions) + + def sample(self): + return np.random.choice(self.actions) diff --git a/irlc/utils/graphics/car.png b/irlc/utils/graphics/car.png new file mode 100644 index 0000000000000000000000000000000000000000..386a86e58b77fe213f662d638df86609c5294be2 GIT binary patch literal 21921 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Π0|bKq>7VYI@1Uf7hNy{mb4UiC_<PV~ELJYAZH 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 CdpH~b literal 0 HcmV?d00001 diff --git a/irlc/utils/graphics/dtu_icon.png b/irlc/utils/graphics/dtu_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9bcea902ea9d3e647d7b73e3a90dbc194dfdfd8b GIT binary patch literal 18108 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 HoD!M<XAKNl literal 0 HcmV?d00001 diff --git a/irlc/utils/graphics/locomotive.png b/irlc/utils/graphics/locomotive.png new file mode 100644 index 0000000000000000000000000000000000000000..95e5dc6682930e7ecff714937e2f021e5c26b98d GIT binary patch literal 73324 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�omAm? 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 a{xcjqJI$e0Z4v_m1B0ilpUXO@geCxWll~Y0 literal 0 HcmV?d00001 diff --git a/irlc/utils/graphics_util_pygame.py b/irlc/utils/graphics_util_pygame.py new file mode 100644 index 0000000..3792440 --- /dev/null +++ b/irlc/utils/graphics_util_pygame.py @@ -0,0 +1,415 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# graphicsUtils.py +# ---------------- +# Licensing Information: You are free to use or extend these projects for +# educational purposes provided that (1) you do not distribute or publish +# solutions, (2) you retain this notice, and (3) you provide clear +# attribution to UC Berkeley, including a link to http://ai.berkeley.edu. +# +# Attribution Information: The Pacman AI projects were developed at UC Berkeley. +# The core projects and autograders were primarily created by John DeNero +# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). +# Student side autograding was added by Brad Miller, Nick Hay, and +# Pieter Abbeel (pabbeel@cs.berkeley.edu). +import numpy as np +import os +import pygame +from pygame import gfxdraw +import threading +import time +import pygame +import platform +import sys + +ghost_shape = [ + (0, - 0.5), + (0.25, - 0.75), + (0.5, - 0.5), + (0.75, - 0.75), + (0.75, 0.5), + (0.5, 0.75), + (- 0.5, 0.75), + (- 0.75, 0.5), + (- 0.75, - 0.75), + (- 0.5, - 0.5), + (- 0.25, - 0.75) +] + +def _adjust_coords(coord_list, x, y): + for i in range(0, len(coord_list), 2): + coord_list[i] = coord_list[i] + x + coord_list[i + 1] = coord_list[i + 1] + y + return coord_list + +def formatColor(r, g, b): + return '#%02x%02x%02x' % (int(r * 255), int(g * 255), int(b * 255)) + +def colorToVector(color): + return list(map(lambda x: int(x, 16) / 256.0, [color[1:3], color[3:5], color[5:7]])) + +def h2rgb(color): + if color is None or isinstance(color, tuple): + return color + if color.startswith("#"): + color = color[1:] + return tuple(int(color[i:i + 2], 16) / 255 for i in (0, 2, 4)) + +def h2rgb255(color): + if isinstance(color, tuple): + return color + # c = + return tuple(int(cc*255) for cc in h2rgb(color)) + if color is None: + return None + if color.startswith("#"): + color = color[1:] + return tuple(int(color[i:i + 2], 16) / 255 for i in (0, 2, 4)) + +class GraphicsCache: + break_cache = False + def __init__(self, viewer, verbose=False): + self.viewer = viewer + # self._items_in_viewer = {} + # self._seen_things = set() + self.clear() + self.verbose = verbose + + def copy_all(self): + self._seen_things.update( set( self._items_in_viewer.keys() ) ) + + def clear(self): + self._seen_things = set() + self.viewer.geoms.clear() + self._items_in_viewer = {} + + def prune_frame(self): + s0 = len(self._items_in_viewer) + self._items_in_viewer = {k: v for k, v in self._items_in_viewer.items() if k in self._seen_things } + if self.verbose: + print("removed", len(self._items_in_viewer) - s0, "geom size", len(self._items_in_viewer)) + self.viewer.geoms = list( self._items_in_viewer.values() ) + self._seen_things = set() + + + def add_geometry(self, name, geom): + if self.break_cache: + if self._items_in_viewer == None: + self.viewer.geoms = [] + self._items_in_viewer = {} + + self._items_in_viewer[name] = geom + self._seen_things.add(name) + + + +class GraphicsUtilGym: + viewer = None + _canvas_xs = None # Size of canvas object + _canvas_ys = None + _canvas_x = None # Current position on canvas + _canvas_y = None + + def begin_graphics(self, width=640, height=480, color=formatColor(0, 0, 0), title="02465 environment", local_xmin_xmax_ymin_ymax=None, verbose=False, + frames_per_second=None): + """ Main interface for managing graphics. + The local_xmin_xmax_ymin_ymax controls the (local) coordinate system which is mapped onto screen coordinates. I.e. specify this + to work in a native x/y coordinate system. If not, it will default to screen coordinates familiar from Gridworld. + """ + width = int(width) + height = int(height) # For width/height to be integers to avoid crashes on some systems. + + icon = os.path.dirname(__file__) + "/../utils/graphics/dtu_icon.png" + pygame_icon = pygame.image.load(icon) + pygame.display.set_icon(pygame_icon) + screen_width = width + screen_height = height + pygame.init() + pygame.display.init() + self.frames_per_second = frames_per_second + + + self.screen = pygame.display.set_mode( + (screen_width, screen_height) + ) + self.screen_width = width + self.screen_height = height + + pygame.display.set_caption(title) + + if height % 2 == 1: + height += 1 # Must be divisible by 2. + self._bg_color = color + # viewer = Viewer(width=int(width), height=int(height)) + # viewer.window.set_caption(title) + # self.viewer = viewer + # self.gc = GraphicsCache(viewer, verbose=verbose) + self._canvas_xs, self._canvas_ys = width - 1, height - 1 + self._canvas_x, self._canvas_y = 0, self._canvas_ys + if local_xmin_xmax_ymin_ymax is None: + # local_coordinates = [] + # This will align the coordinate system so it begins in the top-left corner. + # This is the default behavior of pygame. + local_xmin_xmax_ymin_ymax = (0, width, 0, height) + self._local_xmin_xmax_ymin_ymax = local_xmin_xmax_ymin_ymax + + self.demand_termination = threading.Event() + self.pause_refresh = False + self.ask_for_pause = False + self.is_paused = False + self.time_last_blit = -1 + + + def refresh_window(gutils): + refresh_interval_seconds = 0.1 # Miliseconds + t0 = time.time() + while not gutils.demand_termination.is_set(): + t1 = time.time() + if t1 - t0 > refresh_interval_seconds: + if not self.ask_for_pause: + self.is_paused = False + if not (sys.platform == 'darwin' and platform.processor() == 'i386'): + pass # Disable the thread startup. This causes problems on linux (segfaults). Must find better fix, perhaps win-only. + # pygame.display.update() + else: + self.is_paused = True + t0 = t1 + time.sleep(refresh_interval_seconds/100) + + self.refresh_thread = threading.Thread(target=refresh_window, args=(self, )) + self.refresh_thread.start() + + def close(self): + self.demand_termination.set() + self.refresh_thread.join(timeout=1000) + pygame.display.quit() + pygame.quit() + # TH 2023: These two lines are super important. + # pdraw cache the fonts. So when pygame is loaded/quites, + # the font cache is not flushed. This is not a problem + # when determining the width of strings the font has seen, + # but causes a segfault with NEW strings. + from irlc.utils import ptext + ptext._font_cache = {} + self.isopen = False + + def render(self): + pass + + def blit(self, render_mode=None): + self.render() + self.screen.blit(self.surf, (0, 0)) + if render_mode == "human": + tc = time.time() + + if self.frames_per_second is not None: + + if tc - self.time_last_blit < 1/self.frames_per_second: + tw = 1/self.frames_per_second - (tc - self.time_last_blit ) + time.sleep(tw) + else: + tw = 0 + + self.time_last_blit = tc + + pygame.event.pump() + pygame.display.flip() + elif render_mode == "rgb_array": + return np.transpose(np.array(pygame.surfarray.pixels3d(self.screen)), axes=(1, 0, 2)) + + def rectangle(self, color, x, y, width, height, border=0, fill_color=None): + x2,y2 = self.fixxy((x+width, y+height)) + x, y = self.fixxy((x,y)) + + c1 = min([x, x2]) + c2 = min([y, y2]) + + w = abs(x-x2) + h = abs(y - y2) + + pygame.draw.rect(self.surf, color, pygame.Rect( int(c1), int(c2), int(w), int(h)), border) + + + def draw_background(self, background_color=None): + if background_color is None: + background_color = (0, 0, 0) + self._bg_color = background_color + x1, x2, y1, y2 = self._local_xmin_xmax_ymin_ymax + corners = [ (x1, y1), (x2, y1), (x2, y2), (x1, y2) ] + self.surf = pygame.Surface((self.screen_width, self.screen_height)) + self.polygon(name="background", coords=corners, outlineColor=self._bg_color, fillColor=self._bg_color, filled=True, smoothed=False) + + def fixxy(self, xy): + x,y = xy + x = (x - self._local_xmin_xmax_ymin_ymax[0]) / (self._local_xmin_xmax_ymin_ymax[1] - self._local_xmin_xmax_ymin_ymax[0]) * self.screen.get_width() + y = (y - self._local_xmin_xmax_ymin_ymax[2]) / (self._local_xmin_xmax_ymin_ymax[3] - self._local_xmin_xmax_ymin_ymax[2]) * self.screen.get_height() + return int(x), int(y) + + + def plot(self, name, x, y, color=None, width=1.0): + coords = [(x_,y_) for (x_, y_) in zip(x,y)] + if color is None: + color = "#000000" + return self.polygon(name, coords, outlineColor=color, filled=False, width=width) + + def polygon(self, name, coords, outlineColor=None, fillColor=None, filled=True, smoothed=1, behind=0, width=1.0, closed=False): + c = [] + for coord in coords: + c.append(coord[0]) + c.append(coord[1]) + + coords = [self.fixxy(c) for c in coords] + if fillColor == None: fillColor = outlineColor + poly = None + if not filled: fillColor = "" + + c = [self.fixxy(tuple(c[i:i+2])) for i in range(0, len(c), 2)] + if not filled: + gfxdraw.polygon(self.surf, coords, h2rgb255(outlineColor)) + pygame.draw.polygon(self.surf, h2rgb255(outlineColor), coords, width=int(width)) + + else: + gfxdraw.filled_polygon(self.surf, coords, h2rgb255(fillColor)) + + if outlineColor is not None and len(outlineColor) > 0 and filled: # Not sure why this cannot be merged with the filled case... + # gfxdraw.polygon(self.surf, coords, h2rgb255(outlineColor), width=int(width)) + pygame.draw.polygon(self.surf, h2rgb255(outlineColor), coords, width=int(width)) + + return poly + + def square(self, name, pos, r, color, filled=1, behind=0): + x, y = pos + coords = [(x - r, y - r), (x + r, y - r), (x + r, y + r), (x - r, y + r)] + return self.polygon(name, coords, color, color, filled, 0, behind=behind) + + def centered_arc(self, color, pos, r, start_angle, stop_angle, width=1): + # Draw a centered arc (pygame defaults to boxed arcs) + x, y = pos + tt = np.linspace(start_angle / 360 * 2 * np.pi,stop_angle / 360 * 2 * np.pi, int(r * 10)) + px = np.cos(tt) * r + py = -np.sin(tt) * r + pp = list(zip(px.tolist(), py.tolist())) + + pp = [((x + a, y + b)) for (a, b) in pp] + # if style == 'arc': # For pacman. I guess this one makes the rounded wall segments. + pp = [self.fixxy(p_) for p_ in pp] + + pygame.draw.lines(self.surf, h2rgb255(color), False, pp, width) + + def circle(self, name, pos, r, outlineColor=None, fillColor=None, endpoints=None, style='pieslice', width=2): + pos = self.fixxy(pos) + x, y = pos + if endpoints == None: + e = [0, 359] + else: + e = list(endpoints) + while e[0] > e[1]: e[1] = e[1] + 360 + if endpoints is not None and len(endpoints) > 0: + tt = np.linspace(e[0]/360 * 2*np.pi, e[-1]/360 * 2*np.pi, int(r*20) ) + px = np.cos(tt) * r + py = -np.sin(tt) * r + pp = list(zip(px.tolist(), py.tolist())) + if style == 'pieslice': + pp = [(0,0),] + pp + [(0,0),] + pp = [( (x+a, y+b)) for (a,b) in pp ] + if style == 'arc': # For pacman. I guess this one makes the rounded wall segments. + pp = [self.fixxy(p_) for p_ in pp] + pygame.draw.lines(self.surf, outlineColor, False, pp, width) + elif style == 'pieslice': + self.polygon(name, pp, fillColor=fillColor, outlineColor=outlineColor, width=width) + else: + raise Exception("bad style", style) + else: + gfxdraw.filled_circle(self.surf, x, y, int(r), h2rgb255(fillColor)) + + def text(self, name, pos, color, contents, font='Helvetica', size=12, style='normal', anchor="w", fontsize=24, + bold=False): + pos = self.fixxy(pos) + ax = "center" + ax = "left" if anchor == "w" else ax + ay = "center" + ay = "baseline" if anchor == "s" else ay + + from irlc.utils.ptext import draw + if anchor == 'w': + opts = dict(midleft=pos) + elif anchor == 'e': + opts = dict(midright=pos) + elif anchor == 's': + opts = dict(midbottom=pos) + elif anchor == 'n': + opts = dict(midtop=pos) + elif anchor == 'c': + opts = dict(center=pos) + else: + raise Exception("Unknown anchor", anchor) + opts['fontsize'] = fontsize + opts['bold'] = bold + draw(contents, surf=self.surf, color=h2rgb255(color), pos=pos, **opts) + return + + + def line(self, name, here, there, color=formatColor(0, 0, 0), width=2): + + here, there = self.fixxy(here), self.fixxy(there) + pygame.draw.line(self.surf, h2rgb255(color), here, there, width) + + def polyline(self, name, xs, ys, color=formatColor(0, 0, 0), width=2): + for i in range(len(xs) - 1): + self.line("asfasf", here=(xs[i] , ys[i]), + there=(xs[i + 1], ys[i + 1]), + color=color, width=width) + + +def rotate_around(pos, xy0, angle): + if isinstance(pos, list) and isinstance(pos[0], tuple): + return [rotate_around(p, xy0, angle) for p in pos] + return ((pos[0] - xy0[0]) * np.cos(angle / 180 * np.pi) - (pos[1] - xy0[1]) * np.sin(angle / 180 * np.pi) + xy0[0], + (pos[0] - xy0[0]) * np.sin(angle / 180 * np.pi) + (pos[1] - xy0[1]) * np.cos(angle / 180 * np.pi) + xy0[1]) + +class Object(pygame.sprite.Sprite): + def __init__(self, file, image_width=None, graphics=None): + super(Object, self).__init__() + fpath = os.path.dirname(__file__) +"/graphics/"+file + image = pygame.image.load(fpath).convert_alpha() + if image_width is not None: + image_height = int( image_width / image.get_width() * image.get_height() ) + self.og_surf = pygame.transform.smoothscale(image, (image_width, image_height)) + # raise Exception("Implement this") + else: + self.og_surf = image + # self.og_surf = pygame.transform.smoothscale(image, (100, 100)) + self.surf = self.og_surf + self.rect = self.surf.get_rect(center=(400, 400)) + self.ga = graphics + + def move_center_to_xy(self, x, y): + # Note: These are in the local coordinate system coordinates. + x,y = self.ga.fixxy((x,y)) + self.rect.center = (x,y) + + def rotate(self, angle): + """ Rotate sprite around it's center. """ + self.angle = angle + self.surf = pygame.transform.rotate(self.og_surf, self.angle) + self.rect = self.surf.get_rect(center=self.rect.center) + + def blit(self, surf): + surf.blit(self.surf, self.rect) + + +class UpgradedGraphicsUtil(GraphicsUtilGym): + def __init__(self, screen_width=800, screen_height=None, xmin=0., xmax=800., ymin=0., ymax=600., title="Gym window"): + if screen_height is None: + screen_height = np.abs( int(screen_width / (xmax - xmin) * (ymax-ymin)) ) + elif xmin is None: + xmin = 0 + xmax = screen_width + ymin = 0 + ymax = screen_height + else: + raise Exception() + self.begin_graphics(width=screen_width, height=screen_height, local_xmin_xmax_ymin_ymax=(xmin, xmax, ymin, ymax), title=title) + + def get_sprite(self, name): + """ Load a sprite from the graphics directory. """ + pass diff --git a/irlc/utils/irlc_plot.py b/irlc/utils/irlc_plot.py new file mode 100644 index 0000000..fcbb498 --- /dev/null +++ b/irlc/utils/irlc_plot.py @@ -0,0 +1,266 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import os +import numpy as np + +""" +Using the plotter: + +Call it from the command line, and supply it with logdirs to experiments. +Suppose you ran an experiment with name 'test', and you ran 'test' for 10 +random seeds. The runner code stored it in the directory structure + + data + L test_EnvName_DateTime + L 0 + L log.txt + L params.json + L 1 + L log.txt + L params.json + . + . + . + L 9 + L log.txt + L params.json + +To plot learning curves from the experiment, averaged over all random +seeds, call + + python lmpc_plot.py data/test_EnvName_DateTime --value AverageReturn + +and voila. To see a different statistics, change what you put in for +the keyword --value. You can also enter /multiple/ values, and it will +make all of them in order. + + +Suppose you ran two experiments: 'test1' and 'test2'. In 'test2' you tried +a different set of hyperparameters from 'test1', and now you would like +to compare them -- see their learning curves side-by-side. Just call + + python lmpc_plot.py data/test1 data/test2 + +and it will plot them both! They will be given titles in the legend according +to their exp_name parameters. If you want to use custom legend titles, use +the --legend flag and then provide a title for each logdir. + +""" + +def plot_data(data, y="accumulated_reward", x="Episode", ci=95, estimator='mean', **kwargs): + import seaborn as sns + import matplotlib.pyplot as plt + import pandas as pd + if isinstance(data, list): # is this correct even? + data = pd.concat(data, ignore_index=True,axis=0) + plt.figure(figsize=(12, 6)) + sns.set(style="darkgrid", font_scale=1.5) + lp = sns.lineplot(data=data, x=x, y=y, hue="Condition", errorbar=('ci', 95), estimator=estimator, **kwargs) + plt.legend(loc='best') #.set_draggable(True) + +def existing_runs(experiment): + nex = 0 + for root, dir, files in os.walk(experiment): + if 'log.txt' in files: + nex += 1 + return nex + +def _get_most_recent_log_dir(fpath): + files = [os.path.basename(root) for root, dir, files in os.walk(fpath) if 'log.txt' in files] + return sorted(files, key=lambda file: os.path.basename(file))[-1] if len(files) > 0 else None + +def get_datasets(fpath, x, condition=None, smoothing_window=None, resample_key=None, resample_ticks=None, only_most_recent=False): + import pandas as pd + unit = 0 + if condition is None: + condition = fpath + datasets = [] + + if only_most_recent: + most_recent = _get_most_recent_log_dir(fpath) + + for root, dir, files in os.walk(fpath): + # print(files) + if 'log.txt' in files: + if only_most_recent and most_recent is not None and os.path.basename(root) != most_recent: # Skip this log. + continue + json = os.path.join(root, 'params.json') + if os.path.exists(json): + with open(json) as f: + param_path = open(json) + params = json.load(param_path) + # exp_name = params['exp_name'] + + log_path = os.path.join(root, 'log.txt') + if os.stat(log_path).st_size == 0: + print("Bad plot file", log_path, "size is zero. Skipping") + continue + experiment_data = pd.read_table(log_path) + + if smoothing_window: + ed_x = experiment_data[x] + experiment_data = experiment_data.rolling(smoothing_window,min_periods=1).mean() + experiment_data[x] = ed_x + + experiment_data.insert( + len(experiment_data.columns), + 'Unit', + unit + ) + experiment_data.insert( + len(experiment_data.columns), + 'Condition', + condition) + + datasets.append(experiment_data) + unit += 1 + + nc = f"({unit}x)"+condition[condition.rfind("/")+1:] + for i, d in enumerate(datasets): + datasets[i] = d.assign(Condition=lambda x: nc) + + if resample_key is not None: + nmax = 0 + vmax = -np.inf + vmin = np.inf + for d in datasets: + nmax = max( d.shape[0], nmax) + vmax = max(d[resample_key].max(), vmax) + vmin = min(d[resample_key].min(), vmin) + if resample_ticks is not None: + nmax = min(resample_ticks, nmax) + + new_datasets = [] + tnew = np.linspace(vmin + 1e-6, vmax - 1e-6, nmax) + for d in datasets: + nd = {} + cols = d.columns.tolist() + for c in cols: + if c == resample_key: + y = tnew + elif d[c].dtype == 'O': + y = [ d[c][0] ] * len(tnew) + else: + y = np.interp(tnew, d[resample_key].tolist(), d[c], left=np.nan, right=np.nan) + y = y.astype(d[c].dtype) + nd[c] = y + + ndata = pd.DataFrame(nd) + ndata = ndata.dropna() + new_datasets.append(ndata) + datasets = new_datasets + return datasets + + +def _load_data(experiments, legends=None, smoothing_window=None, resample_ticks=None, + x_key="Episode", + only_most_recent=False): + ensure_list = lambda x: x if isinstance(x, list) else [x] + experiments = ensure_list(experiments) + if legends is None: + legends = experiments + legends = ensure_list(legends) + + data = [] + for logdir, legend_title in zip(experiments, legends): + resample_key = x_key if resample_ticks is not None else None + data += get_datasets(logdir, x=x_key, condition=legend_title, smoothing_window=smoothing_window, resample_key=resample_key, resample_ticks=resample_ticks, + only_most_recent=only_most_recent) + return data + +def main_plot(experiments, legends=None, smoothing_window=None, resample_ticks=None, + x_key="Episode", + y_key='Accumulated Reward', + no_shading=False, + **kwargs): + if no_shading: + kwargs['units'] = 'Unit' + kwargs['estimator'] = None + + ensure_list = lambda x: x if isinstance(x, list) else [x] + experiments = ensure_list(experiments) + + if legends is None: + legends = experiments + legends = ensure_list(legends) + + data = [] + for logdir, legend_title in zip(experiments, legends): + resample_key = x_key if resample_ticks is not None else None + data += get_datasets(logdir, x=x_key, condition=legend_title, smoothing_window=smoothing_window, resample_key=resample_key, resample_ticks=resample_ticks) + + plot_data(data, y=y_key, x=x_key, **kwargs) + + +def main(): + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('logdir', nargs='*') + parser.add_argument('--legend', nargs='*') + parser.add_argument('--value', default='AverageReturn', nargs='*') + parser.add_argument('--title', default="please specify title", help="The title to show") + parser.add_argument('--pdf_name', default=None, help="Name of pdf") + + args = parser.parse_args() + main_plot(args.logdir, args.legend, args.value, title=args.title) + +if __name__ == "__main__": + main() + + +#### TRAJECTORY PLOTTING HERE #### +def plot_trajectory(trajectory, env=None, xkeys=None, ukeys=None): + """ + Used to visualize trajectories returned from the :func:`~irlc.ex01.agent.train`-function. An example: + + .. plot:: + :include-source: + + import matplotlib.pyplot as plt + import numpy as np + from irlc import Agent, plot_trajectory, train + from irlc.ex04.model_pendulum import GymSinCosPendulumEnvironment + env = GymSinCosPendulumEnvironment() + stats, trajectories = train(env, Agent(env), num_episodes=1, return_trajectory=True) + plot_trajectory(trajectories[0], env) + + Labels will be derived from the ``env`` if supplied. The parameters ``xkeys`` and ``ukeys`` can be used to limit which + coordinates are plotted. For instance, if you only want to plot the first two x-coordinates you can set ``xkeys=[0,1]``: + + + .. plot:: + + import matplotlib.pyplot as plt + import numpy as np + from irlc import Agent, plot_trajectory, train + from irlc.ex04.model_pendulum import GymSinCosPendulumEnvironment + env = GymSinCosPendulumEnvironment() + stats, trajectories = train(env, Agent(env), num_episodes=1, return_trajectory=True) + plot_trajectory(trajectories[0], env, xkeys=[0,1], ukeys=[]) + + :param trajectory: A single trajectory computed using ``train`` (see example above) + :param env: A gym control environment (optional) + :param xkeys: List of integers corresponding to the coordinates of :math:`x` we wish to plot + :param ukeys: List of integers corresponding to the coordinates of :math:`u` we wish to plot + + .. tip:: + If the plot does not show, you might want to import matplotlib as ``import matplotlib.pyplot as plt`` and call ``plt.show()`` + """ + if xkeys is None: + xkeys = [i for i in range(trajectory.state.shape[1])] + if ukeys is None: # all + ukeys = [i for i in range(trajectory.action.shape[-1])] + import seaborn as sns + import matplotlib.pyplot as plt + plt.figure(figsize=(12, 6)) + sns.set(style="darkgrid", font_scale=1.5) + def fp(time, X, keys, labels): + for i, k in enumerate(keys): + label = labels[k] if labels is not None else None + sns.lineplot(x=time, y=X[:,k], label=label) + + time = trajectory.time.squeeze() + fp(time, trajectory.state, xkeys, labels=env.state_labels if env is not None else None) + fp(time[:-1], trajectory.action, ukeys, labels=env.action_labels if env is not None else None) + plt.xlabel("Time / seconds") + if env is not None: + plt.legend() diff --git a/irlc/utils/lazylog.py b/irlc/utils/lazylog.py new file mode 100644 index 0000000..8b1fdb8 --- /dev/null +++ b/irlc/utils/lazylog.py @@ -0,0 +1,140 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +""" +Inspired by logz from berkleys deep RL course but re-written as a context manager like God intended. + +To load the learning curves, you can do, for yafcport + +A = np.genfromtxt('/tmp/expt_1468984536/log.txt',delimiter='\t',dtype=None, names=True) +A['EpRewMean'] + +""" +import json +import os +import time +from datetime import datetime + +color2num = dict( + gray=30, + red=31, + green=32, + yellow=33, + blue=34, + magenta=35, + cyan=36, + white=37, + crimson=38) + + +def colorize(string, color, bold=False, highlight=False): + attr = [] + num = color2num[color] + if highlight: num += 10 + attr.append(str(num)) + if bold: attr.append('1') + return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string) + + +class LazyLog(object): + output_dir = None + output_file = None + first_row = True + log_headers = [] + log_current_row = {} + + def __init__(self, experiment_name, run_name=None, data=None): + if run_name is None: + experiment_name += "/"+ datetime.utcnow().strftime("%Y-%m-%d_%H-%M-%S.%f")[:-3] + else: + experiment_name += "/" + run_name + self.experiment_name = experiment_name + configure_output_dir(self, experiment_name) + if data is not None: + self.save_params(data) + + def __enter__(self): + return self + + def save_params(self, data): + save_params(self, data) + + def dump_tabular(self, verbose=False): + dump_tabular(self, verbose) + + def log_tabular(self, key, value): + log_tabular(self, key, value) + + def __exit__(self, type, value, traceback): + self.output_file.close() + + +def configure_output_dir(G, d=None): + """ + Set output directory to d, or to /tmp/somerandomnumber if d is None + """ + # CDIR = os.path.dirname(os.path.realpath(__file__)).replace('\\', '/') + G.first_row = True + G.output_dir = d or "/tmp/experiments/%i" % int(time.time()) + assert not os.path.exists( + G.output_dir), "Log dir %s already exists! Delete it first or use a different dir" % G.output_dir + os.makedirs(G.output_dir) + G.output_file = open(os.path.join(G.output_dir, "log.txt"), 'w') + print(colorize("Logging data to %s" % G.output_file.name, 'green', bold=True)) + +def log_tabular(G, key, val): + """ + Log a value of some diagnostic + Call this once for each diagnostic quantity, each iteration + """ + if G.first_row: + G.log_headers.append(key) + else: + assert key in G.log_headers, "Trying to introduce a new key %s that you didn't include in the first iteration" % key + assert key not in G.log_current_row, "You already set %s this iteration. Maybe you forgot to call dump_tabular()" % key + G.log_current_row[key] = val + + +def save_params(G, params): + with open(os.path.join(G.output_dir, "params.json"), 'w') as out: + out.write(json.dumps(params, separators=(',\n', '\t:\t'), sort_keys=True)) + + +# def pickle_tf_vars(): +# import tensorflow as tf +# """ +# Saves tensorflow variables +# Requires them to be initialized first, also a default session must exist +# """ +# _dict = {v.name: v.eval() for v in tf.global_variables()} +# with open(osp.join(G.output_dir, "vars.pkl"), 'wb') as f: +# pickle.dump(_dict, f) + + +def dump_tabular(G, verbose=True): + """ + Write all of the diagnostics from the current iteration + """ + vals = [] + key_lens = [len(key) for key in G.log_headers] + max_key_len = max(15, max(key_lens)) + keystr = '%' + '%d' % max_key_len + fmt = "| " + keystr + "s | %15s |" + n_slashes = 22 + max_key_len + print("-" * n_slashes) if verbose else None + for key in G.log_headers: + val = G.log_current_row.get(key, "") + if hasattr(val, "__float__"): + valstr = "%8.3g" % val + else: + valstr = val + print(fmt % (key, valstr)) if verbose else None + vals.append(val) + print("-" * n_slashes) if verbose else None + if G.output_file is not None: + if G.first_row: + G.output_file.write("\t".join(G.log_headers)) + G.output_file.write("\n") + G.output_file.write("\t".join(map(str, vals))) + G.output_file.write("\n") + G.output_file.flush() + G.log_current_row.clear() + G.first_row = False diff --git a/irlc/utils/minigrid.py b/irlc/utils/minigrid.py new file mode 100644 index 0000000..3498ea1 --- /dev/null +++ b/irlc/utils/minigrid.py @@ -0,0 +1,102 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +import gymnasium as gym +from gymnasium.spaces.discrete import Discrete +from minigrid.core.constants import OBJECT_TO_IDX, COLOR_TO_IDX +from minigrid.wrappers import FullyObsWrapper +import numpy as np + + +class ProjectObservationSpaceWrapper(gym.core.ObservationWrapper): + """ + Use the image as the only observation output, no language/mission. + """ + def __init__(self, env, dims): + super().__init__(env) + os = self.observation_space.spaces['image'] + # if dims is not None: + os.high = os.high[:,:,dims] + os.low = os.low[:,:,dims] + + self.observation_space.spaces['image'] = os + self.dims = dims + + def observation(self, obs): + obs['image'] = obs['image'][:, :, self.dims] + return obs + + +class SaneBoundsWrapper(gym.core.ObservationWrapper): + """ + Use the image as the only observation output, no language/mission. + """ + def __init__(self, env): + super().__init__(env) + os = self.observation_space.spaces['image'] + os.high[:, :, 0] = max(OBJECT_TO_IDX.values()) + if os.high.shape[2] >= 2: + os.high[:, :, 1] = max(COLOR_TO_IDX.values()) + if os.high.shape[2] >= 3: + os.high[:, :, 2] = 3 + self.observation_space.spaces['image'] = os + + def observation(self, obs): + return obs + +class HashableImgObsWrapper(gym.core.ObservationWrapper): + """ + Use the image as the only observation output, no language/mission. + """ + + def __init__(self, env,dims=None): + super().__init__(env) + self.observation_space = env.observation_space.spaces['image'] + + def observation(self, obs): + # ls = obs['image'].flat.tolist() + return tuple( obs['image'].flat ) + # return obs['image'] + + +class LinearSpaceWrapper(gym.core.ObservationWrapper): + """ + Fully observable gridworld using a compact grid encoding + """ + def __init__(self, env): + super().__init__(env) + sz = self.observation_space.spaces['image'].shape + npo = np.zeros( sz, dtype=np.object) + for i in range(sz[0]): + for j in range(sz[1]): + for k in range(sz[2]): + if k == 0: + n = max(OBJECT_TO_IDX.values())+1 + elif k == 1: + n = max(COLOR_TO_IDX.values())+1 + elif k == 2: + n = 4 + else: + raise Exception("Bad k") + + npo[i,j,k] = Discrete(n) + ospace = tuple(npo.flat) + + sz = np.cumsum([o.n for o in ospace]) + sz = sz - sz[0] + self.sz = sz + # from gym.spaces.box import Box + self.observation_space = ospace + + def observation(self, obs): + s = obs['image'].reshape((obs['image'].size,)) + return s + + +if __name__ == "__main__": + """ Example use: """ + env = gym.make("MiniGrid-Empty-5x5-v0") + env = FullyObsWrapper(env) # use this + env = LinearSpaceWrapper(env) + s = env.reset() + print(s) + # Use with for instance: + # agent = LinearSemiGradSarsa(env, gamma=1, epsilon=0.1, alpha=0.5) diff --git a/irlc/utils/player_wrapper.py b/irlc/utils/player_wrapper.py new file mode 100644 index 0000000..2d6a0b3 --- /dev/null +++ b/irlc/utils/player_wrapper.py @@ -0,0 +1,370 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from gymnasium import logger +from irlc.ex01.agent import Agent +import time +import sys +import gymnasium as gym +import os + +try: + # Imports that may not be availble: + # Using this backend apparently clash with scientific mode. Not sure why it was there in the first place so + # disabling it for now. + # matplotlib.use('TkAgg') + import matplotlib.pyplot as plt + import pygame +except ImportError as e: + logger.warn('failed to set matplotlib backend, plotting will not work: %s' % str(e)) + plt = None + + +class AgentWrapper(Agent): + """Wraps the environment to allow a modular transformation. + + This class is the base class for all wrappers. The subclass could override + some methods to change the behavior of the original environment without touching the + original code. + + .. note:: + + Don't forget to call ``super().__init__(env)`` if the subclass overrides :meth:`__init__`. + + """ + def __init__(self, agent, env): + # print("AgentWrapper is deprecated. ") + self.agent = agent + self.env = env + + def __getattr__(self, name): + if name.startswith('_'): + raise AttributeError("attempted to get missing private attribute '{}'".format(name)) + return getattr(self.agent, name) + + @classmethod + def class_name(cls): + return cls.__name__ + + def pi(self, state, k, info=None): + return self.agent.pi(state, k, info) + # return self.env.step(action) + + def train(self, *args, **kwargs): + return self.agent.train(*args, **kwargs) + + def __str__(self): + return '<{}{}>'.format(type(self).__name__, self.agent) + + def __repr__(self): + return str(self) + + @property + def unwrapped(self): + return self.agent.unwrapped + +PAUSE_KEY = ord('p') +SPACEBAR = "_SPACE_BAR_PRESSED_" +class PlayWrapperPygame(AgentWrapper): + def __init__(self, agent : Agent, env : gym.Env, keys_to_action=None, autoplay=False): + super().__init__(agent, env) + if keys_to_action is None: + if hasattr(env, 'get_keys_to_action'): + keys_to_action = env.get_keys_to_action() + elif hasattr(env.env, 'get_keys_to_action'): + keys_to_action = env.env.get_keys_to_action() + elif hasattr(env.unwrapped, 'get_keys_to_action'): + keys_to_action = env.unwrapped.get_keys_to_action() + else: + print(env.spec.id +" does not have explicit key to action mapping, please specify one manually") + assert False, env.spec.id + " does not have explicit key to action mapping, " + \ + "please specify one manually" + # keys_to_action = dict() + self.keys_to_action = keys_to_action + self.env = env + self.human_wants_restart = False + self.human_sets_pause = False + self.human_agent_action = -1 + self.human_demand_autoplay = autoplay + # Now fix the train function + train2 = agent.train + def train_(s, a, r, sp, done, info1, info2): + train2(s, a, r, sp, done, info1, info2) + env.render() + + agent.train = train_ + env.agent = agent + + # space bar: 0x0020 + def key_press(self,key, mod): + if key == 0xff0d: self.human_wants_restart = True + if key == PAUSE_KEY: + self.human_demand_autoplay = not self.human_demand_autoplay + a = -1 + else: + a = self.keys_to_action.get((key,), -1) + + if a == -1 and hasattr(self.env, 'keypress'): + self.env.keypress(key) + + if key == 0x0020: + a = SPACEBAR + self.human_agent_action = a + + def key_release(self,key, mod): + pass + + # def _get_viewer(self): + # return None + # return self.env.viewer if hasattr(self.env, 'viewer') else self.env.unwrapped.viewer + + # def setup(self): + # # print("In play wrapper - setup") + # # print(self._get_viewer()) + # # return + # return + # viewer = self._get_viewer() + # if viewer is not None: + # viewer.window.on_key_press = self.key_press + # viewer.window.on_key_release = self.key_release + + + def pi(self,state, k, info=None): + pi_action = super().pi(state, k, info) # make sure super class pi method is called in case it has side effects. + # self.setup() + # If unpaused, don't use events given by keyboard until pause is hit again. + a = None + while True: + # Get pygame events: + # for event in pygame.event.get(): + # # get the pressed key + for event in pygame.event.get(): + if event.type == pygame.QUIT: + # print("Want to quit") + if hasattr(self, 'env'): + self.env.close() + time.sleep(0.1) + pygame.display.quit() + time.sleep(0.1) + pygame.quit() + time.sleep(0.1) + # print("Laila tov!") + sys.exit() + + + # checking if keydown event happened or not + if event.type == pygame.KEYDOWN: + # if keydown event happened + # than printing a string to output + # print("A key has been pressed", event) + # if event.key == pygame.K_LEFT: + # print("LEFT!") + # print(event.key, event.unicode) + # Determine if event is one environment should handle. + + if event.key == pygame.K_SPACE: + # Got space, autoplay. + a = pi_action + break + elif (event.key,) in self.keys_to_action: + a = self.keys_to_action[(event.key,)] + if info is not None and 'mask' in info: + # Consider refactoring the environment later. + from irlc.utils.common import DiscreteTextActionSpace + + if isinstance(self.env.action_space, DiscreteTextActionSpace): + aint = self.env.action_space.actions.index(a) + else: + aint = a + + if info['mask'][aint] == 0: + # The action was masked. This means that this action is unavailable, and we should select another. + # The default is to select one of the available actions from the mask. + a = info['mask'].argmax() + if isinstance(self.env.action_space, DiscreteTextActionSpace): + a = self.env.action_space.actions[a] + + + + else: + break + elif event.unicode == 'p': + # unpause + self.human_demand_autoplay = not self.human_demand_autoplay + break + else: + # try to pass event on to the game. + if hasattr(self.env, 'keypress'): + self.env.keypress(event) + # now broke and got event. + if self.human_demand_autoplay: + a = pi_action + + if a is not None: + # return a # We don't are if action is not in action-space. + # if hasattr(self.env, 'A') and a not in self.env.A(state): + # print(f"Got action {a} not available in action space {self.env.A(state)}") + # a = self.env.A(state)[-1] # Last because of the gym environment. + # else: + # return a + try: + from irlc.pacman.gamestate import GameState + if isinstance(state, GameState): + if a not in state.A(): + a = "Stop" + except Exception as e: + pass + + return a + # viewer = self._get_viewer() + time.sleep(0.1) + # if viewer is not None: + # viewer.window.dispatch_events() + # a = self.human_agent_action + # if a == SPACEBAR or self.human_demand_autoplay: + # # Just do what the agent wanted us to do + # action_okay = True + # a = pi_action + # elif hasattr(self.env, 'P'): + # if len(self.env.P[state]) == 1 and a != -1: + # a = next(iter(self.env.P[state])) + # action_okay = a in self.env.P[state] + # elif self.env.action_space is not None: + # action_okay = self.env.action_space.contains(a) + # else: + # action_okay = a != -1 + # if action_okay: + # self.human_agent_action = -1 + # break + # print("In keyboard wrapper, returning action", a) + # return a + + +def interactive(env : gym.Env, agent: Agent, autoplay=False) -> (gym.Env, Agent): + """ + This function is used for visualizations. It can + + - Allow you to input keyboard commands to an environment + - Allow you to save results + - Visualize reinforcement-learning agents in the gridworld environment. + + by adding a single extra line ``env, agent = interactive(env,agent)``. + The following shows an example: + + >>> from irlc.gridworld.gridworld_environments import BookGridEnvironment + >>> from irlc import train, Agent, interactive + >>> env = BookGridEnvironment(render_mode="human", zoom=0.8) # Pass render_mode='human' for visualization. + >>> env, agent = interactive(env, Agent(env)) # Make the environment interactive. Note that it needs an agent. + >>> train(env, agent, num_episodes=2) # You can train and use the agent and environment as usual. + >>> env.close() + + It also enables you to visualize the environment at a matplotlib figure or save it as a pdf file using ``env.plot()`` and ``env.savepdf('my_file.pdf)``. + + All demos and figures in the notes are made using this function. + + :param env: A gym environment (an instance of the ``Env`` class) + :param agent: An agent (an instance of the ``Agent`` class) + :param autoplay: Whether the simulation should be unpaused automatically + :return: An environment and agent which have been slightly updated to make them interact with each other. You can use them as usual with the ``train``-function. + """ + from PIL import Image # Let's put this one here in case we run the code in headless mode. + + agent = PlayWrapperPygame(agent, env, autoplay=autoplay) + + def plot(): + env.render_mode, rmt = 'rgb_array', env.render_mode + frame = env.render() + env.render_mode = rmt + im = Image.fromarray(frame) + plt.imshow(im) + plt.axis('off') + plt.axis('off') + plt.tight_layout() + + def savepdf(file): + env.render_mode, rmt = 'rgb_array', env.render_mode + frame = env.render() + env.render_mode = rmt + + im = Image.fromarray(frame) + snapshot_base = file + if snapshot_base.endswith(".png"): + sf = snapshot_base[:-4] + fext = 'png' + else: + fext = 'pdf' + if snapshot_base.endswith(".pdf"): + sf = snapshot_base[:-4] + else: + sf = snapshot_base + + sf = f"{sf}.{fext}" + dn = os.path.dirname(sf) + if len(dn) > 0 and not os.path.isdir(dn): + os.makedirs(dn) + print("Saving snapshot of environment to", os.path.abspath(sf)) + if fext == 'png': + im.save(sf) + from irlc import _move_to_output_directory + _move_to_output_directory(sf) + else: + plt.figure(figsize=(16, 16)) + plt.imshow(im) + plt.axis('off') + plt.tight_layout() + from irlc import savepdf + savepdf(sf, verbose=True) + plt.show() + env.plot = plot + env.savepdf = savepdf + return env, agent + + +def main(): + from irlc.ex11.q_agent import QAgent + + from irlc.gridworld.gridworld_environments import BookGridEnvironment + from irlc import train, Agent + env = BookGridEnvironment(render_mode="human", zoom=0.8) # Pass render_mode='human' for visualization. + env, agent = interactive(env, Agent(env)) # Make th + env.reset() # We always need to call reset + env.plot() # Plot the environment. + env.close() + + # Interaction with a random agent. + from irlc.gridworld.gridworld_environments import BookGridEnvironment + from irlc import train, Agent + env = BookGridEnvironment(render_mode="human", zoom=0.8) # Pass render_mode='human' for visualization. + env, agent = interactive(env, Agent(env)) # Make the environment interactive. Note that it needs an agent. + train(env, agent, num_episodes=100) # You can train and use the agent and environment as usual. + env.close() + + # Second example: plotting. + + + a = 234 + # from irlc.utils.berkley import BerkleyBookGridEnvironment + # from irlc.ex11.sarsa_agent import SarsaAgent + # from irlc.ex01.agent import train + # from irlc.utils.berkley import VideoMonitor + # env = BerkleyBookGridEnvironment(adaptor='gym') + # agent = SarsaAgent(env, gamma=0.95, alpha=0.5) + # """ + # agent = PlayWrapper(agent, env) + + # env = VideoMonitor(env, agent=agent, video_file="videos/SarsaGridworld.mp4", fps=30, continious_recording=True, + # label="SADSF", + # monitor_keys=("Q",)) + # """ + # env.reset() + # env.render() + # train(env, agent, num_episodes=3) + # env.close() + # parser = argparse.ArgumentParser() + # parser.add_argument('--env', type=str, default='MontezumaRevengeNoFrameskip-v4', help='Define Environment') + # args = parser.parse_args() + # env = gym.make(args.env) + # play(env, zoom=4, fps=60) + +if __name__ == "__main__": + + + main() diff --git a/irlc/utils/ptext.py b/irlc/utils/ptext.py new file mode 100644 index 0000000..c552f09 --- /dev/null +++ b/irlc/utils/ptext.py @@ -0,0 +1,991 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +# ptext module: place this in your import directory. + +# ptext.draw(text, pos=None, **options) + +# Please see README.md for explanation of options. +# https://github.com/cosmologicon/pygame-text + +from __future__ import division, print_function + +from math import ceil, sin, cos, radians, exp +from collections import namedtuple +import pygame + +# Global default values +DEFAULT_FONT_SIZE = 24 +REFERENCE_FONT_SIZE = 100 +DEFAULT_LINE_HEIGHT = 1.0 +DEFAULT_PARAGRAPH_SPACE = 0.0 +DEFAULT_FONT_NAME = None +DEFAULT_SYSFONT_NAME = None +FONT_NAME_TEMPLATE = "%s" +DEFAULT_COLOR = "white" +DEFAULT_BACKGROUND = None +DEFAULT_SHADE = 0 +DEFAULT_OUTLINE_WIDTH = None +DEFAULT_OUTLINE_COLOR = "black" +OUTLINE_UNIT = 1 / 24 +DEFAULT_SHADOW_OFFSET = None +DEFAULT_SHADOW_COLOR = "black" +SHADOW_UNIT = 1 / 18 +DEFAULT_ALIGN = "left" # left, center, or right +DEFAULT_ANCHOR = 0, 0 # 0, 0 = top left ; 1, 1 = bottom right +DEFAULT_STRIP = True +ALPHA_RESOLUTION = 16 +ANGLE_RESOLUTION_DEGREES = 3 +DEFAULT_UNDERLINE_TAG = None +DEFAULT_BOLD_TAG = None +DEFAULT_ITALIC_TAG = None +DEFAULT_COLOR_TAG = {} + +AUTO_CLEAN = True +MEMORY_LIMIT_MB = 64 +MEMORY_REDUCTION_FACTOR = 0.5 + +pygame.font.init() + + +# Options objects encapsulate the keyword arguments to functions that take a lot of optional keyword +# arguments. + +# Options object base class. Subclass for Options objects specific to different functions. +# Specify valid fields in the _fields list. All keyword fields are optional. Unspecified fields +# default to None, unless otherwise specified in the _defaults list. +class _Options(object): + _fields = () + _defaults = {} + + def __init__(self, **kwargs): + fields = self._allfields() + badfields = set(kwargs) - fields + if badfields: + raise ValueError("Unrecognized args: " + ", ".join(badfields)) + for field in fields: + value = kwargs[field] if field in kwargs else self._defaults.get(field) + setattr(self, field, value) + + @classmethod + def _allfields(cls): + return set(cls._fields) | set(cls._defaults) + + def asdict(self): + return {field: getattr(self, field) for field in self._allfields()} + + def copy(self): + return self.__class__(**self.asdict()) + + def keys(self): + return self._allfields() + + def __getitem__(self, field): + return getattr(self, field) + + def update(self, **newkwargs): + kwargs = self.asdict() + kwargs.update(**newkwargs) + return self.__class__(**kwargs) + + # For cached function calls, this is a hashable representation of the options object. Assumes + # that all field values are either hashable, or dicts whose keys are comparable and values are + # hashable. + def key(self): + values = [] + for field in sorted(self._allfields()): + value = getattr(self, field) + if isinstance(value, dict): + value = tuple(sorted(value.items())) + values.append(value) + return tuple(values) + + def getsuboptions(self, optclass): + return {field: getattr(self, field) for field in optclass._allfields() if hasattr(self, field)} + + # The following methods are just put here for code deduplication. A couple different functions + # use a lot of the same code. + def resolvetags(self): + if self.underlinetag is _default_sentinel: + self.underlinetag = DEFAULT_UNDERLINE_TAG + if self.boldtag is _default_sentinel: + self.boldtag = DEFAULT_BOLD_TAG + if self.italictag is _default_sentinel: + self.italictag = DEFAULT_ITALIC_TAG + if self.colortag is _default_sentinel: + self.colortag = DEFAULT_COLOR_TAG + + +# Used as the default value for any argument for which (1) None is a valid value, and (2) there's a +# global default value. +_default_sentinel = () + + +# Options argument for the draw function. Specifies both text styling and positioning. +class _DrawOptions(_Options): + _fields = ("pos", + "fontname", "fontsize", "sysfontname", "antialias", "bold", "italic", "underline", + "color", "background", + "top", "left", "bottom", "right", "topleft", "bottomleft", "topright", "bottomright", + "midtop", "midleft", "midbottom", "midright", "center", "centerx", "centery", + "width", "widthem", "lineheight", "pspace", "strip", "align", + "owidth", "ocolor", "shadow", "scolor", "gcolor", "shade", + "alpha", "anchor", "angle", + "underlinetag", "boldtag", "italictag", "colortag", + "surf", "cache") + _defaults = { + "fontname": _default_sentinel, + "sysfontname": _default_sentinel, + "antialias": True, "alpha": 1.0, "angle": 0, + "owidth": _default_sentinel, + "shadow": _default_sentinel, + "underlinetag": _default_sentinel, + "boldtag": _default_sentinel, + "italictag": _default_sentinel, + "colortag": _default_sentinel, + "surf": _default_sentinel, "cache": True} + + def __init__(self, **kwargs): + _Options.__init__(self, **kwargs) + self.expandposition() + self.expandanchor() + self.resolvesurf() + + # Expand each 2-element position specifier and overwrite the corresponding 1-element + # position specifiers. + def expandposition(self): + if self.topleft: self.left, self.top = self.topleft + if self.bottomleft: self.left, self.bottom = self.bottomleft + if self.topright: self.right, self.top = self.topright + if self.bottomright: self.right, self.bottom = self.bottomright + if self.midtop: self.centerx, self.top = self.midtop + if self.midleft: self.left, self.centery = self.midleft + if self.midbottom: self.centerx, self.bottom = self.midbottom + if self.midright: self.right, self.centery = self.midright + if self.center: self.centerx, self.centery = self.center + + # Update the pos and anchor fields, if unspecified, to be specified by the positional + # keyword arguments. + def expandanchor(self): + x, y = self.pos or (None, None) + hanchor, vanchor = self.anchor or (None, None) + if self.left is not None: x, hanchor = self.left, 0 + if self.centerx is not None: x, hanchor = self.centerx, 0.5 + if self.right is not None: x, hanchor = self.right, 1 + if self.top is not None: y, vanchor = self.top, 0 + if self.centery is not None: y, vanchor = self.centery, 0.5 + if self.bottom is not None: y, vanchor = self.bottom, 1 + if x is None: + raise ValueError("Unable to determine horizontal position") + if y is None: + raise ValueError("Unable to determine vertical position") + self.pos = x, y + + if self.align is None: self.align = hanchor + if hanchor is None: hanchor = DEFAULT_ANCHOR[0] + if vanchor is None: vanchor = DEFAULT_ANCHOR[1] + self.anchor = hanchor, vanchor + + # Unspecified surf values default to the display surface. + def resolvesurf(self): + if self.surf is _default_sentinel: + self.surf = pygame.display.get_surface() + + def togetsurfoptions(self): + return self.getsuboptions(_GetsurfOptions) + + +# Options for the layout function. By design, this has the same options as draw, although some of +# them are silently ignored. +class _LayoutOptions(_DrawOptions): + def __init__(self, **kwargs): + _Options.__init__(self, **kwargs) + self.expandposition() + self.expandanchor() + if self.lineheight is None: self.lineheight = DEFAULT_LINE_HEIGHT + if self.pspace is None: self.pspace = DEFAULT_PARAGRAPH_SPACE + self.resolvetags() + + def towrapoptions(self): + return self.getsuboptions(_WrapOptions) + + def togetfontoptions(self): + return self.getsuboptions(_GetfontOptions) + + +class _DrawboxOptions(_Options): + _fields = ( + "fontname", "sysfontname", "antialias", "bold", "italic", "underline", + "color", "background", + "lineheight", "pspace", "strip", "align", + "owidth", "ocolor", "shadow", "scolor", "gcolor", "shade", + "underlinetag", "boldtag", "italictag", "colortag", + "alpha", "anchor", "angle", "surf", "cache") + _defaults = { + "fontname": _default_sentinel, + "sysfontname": _default_sentinel, + "antialias": True, "alpha": 1.0, "angle": 0, "anchor": (0.5, 0.5), + "owidth": _default_sentinel, + "shadow": _default_sentinel, + "underlinetag": _default_sentinel, + "boldtag": _default_sentinel, + "italictag": _default_sentinel, + "colortag": _default_sentinel, + "surf": _default_sentinel, "cache": True} + + def __init__(self, **kwargs): + _Options.__init__(self, **kwargs) + if self.fontname is _default_sentinel: self.fontname = DEFAULT_FONT_NAME + if self.sysfontname is _default_sentinel: self.sysfontname = DEFAULT_SYSFONT_NAME + if self.lineheight is None: self.lineheight = DEFAULT_LINE_HEIGHT + if self.pspace is None: self.pspace = DEFAULT_PARAGRAPH_SPACE + + def todrawoptions(self): + return self.getsuboptions(_DrawOptions) + + def tofitsizeoptions(self): + return self.getsuboptions(_FitsizeOptions) + + +class _GetsurfOptions(_Options): + _fields = ("fontname", "fontsize", "sysfontname", "bold", "italic", "underline", "width", + "widthem", "strip", "color", "background", "antialias", "ocolor", "owidth", "scolor", + "shadow", "gcolor", "shade", "alpha", "align", "lineheight", "pspace", "angle", + "underlinetag", "boldtag", "italictag", "colortag", "cache") + _defaults = { + "fontname": _default_sentinel, + "sysfontname": _default_sentinel, + "antialias": True, "alpha": 1.0, "angle": 0, + "owidth": _default_sentinel, + "shadow": _default_sentinel, + "underlinetag": _default_sentinel, + "boldtag": _default_sentinel, + "italictag": _default_sentinel, + "colortag": _default_sentinel, + "cache": True} + + def __init__(self, **kwargs): + _Options.__init__(self, **kwargs) + if self.fontname is _default_sentinel: self.fontname = DEFAULT_FONT_NAME + if self.sysfontname is _default_sentinel: self.sysfontname = DEFAULT_SYSFONT_NAME + if self.fontsize is None: self.fontsize = DEFAULT_FONT_SIZE + self.fontsize = int(round(self.fontsize)) + if self.align is None: self.align = DEFAULT_ALIGN + if self.align in ["left", "center", "right"]: + self.align = [0, 0.5, 1][["left", "center", "right"].index(self.align)] + if self.lineheight is None: self.lineheight = DEFAULT_LINE_HEIGHT + if self.pspace is None: self.pspace = DEFAULT_PARAGRAPH_SPACE + self.color = _resolvecolor(self.color, DEFAULT_COLOR) + self.background = _resolvecolor(self.background, DEFAULT_BACKGROUND) + self.gcolor = _resolvecolor(self.gcolor, None) + if self.shade is None: self.shade = DEFAULT_SHADE + if self.shade: + self.gcolor = _applyshade(self.gcolor or self.color, self.shade) + self.shade = 0 + self.resolveoutlineshadow() + self.alpha = _resolvealpha(self.alpha) + self.angle = _resolveangle(self.angle) + self.strip = DEFAULT_STRIP if self.strip is None else self.strip + self.resolvetags() + + def resolveoutlineshadow(self): + if self.owidth is _default_sentinel: + self.owidth = DEFAULT_OUTLINE_WIDTH + if self.shadow is _default_sentinel: + self.shadow = DEFAULT_SHADOW_OFFSET + self.ocolor = None if self.owidth is None else _resolvecolor(self.ocolor, DEFAULT_OUTLINE_COLOR) + self.scolor = None if self.shadow is None else _resolvecolor(self.scolor, DEFAULT_SHADOW_COLOR) + self._opx = None if self.owidth is None else ceil(self.owidth * self.fontsize * OUTLINE_UNIT) + self._spx = None if self.shadow is None else tuple(ceil(s * self.fontsize * SHADOW_UNIT) for s in self.shadow) + + def checkinline(self): + if self.angle is None or self._opx is not None or self._spx is not None or self.align != 0 or self.gcolor or self.shade: + raise ValueError( + "Inline style not compatible with rotation, outline, drop shadow, gradient, or non-left-aligned text.") + + def towrapoptions(self): + return self.getsuboptions(_WrapOptions) + + def togetfontoptions(self): + return self.getsuboptions(_GetfontOptions) + + +class _WrapOptions(_Options): + _fields = ("fontname", "fontsize", "sysfontname", + "bold", "italic", "underline", "width", "widthem", "strip", + "color", + "underlinetag", "boldtag", "italictag", "colortag") + _defaults = { + "underlinetag": _default_sentinel, + "boldtag": _default_sentinel, + "italictag": _default_sentinel, + "colortag": _default_sentinel, + } + + def __init__(self, **kwargs): + _Options.__init__(self, **kwargs) + self.resolvetags() + if self.widthem is not None and self.width is not None: + raise ValueError("Can't set both width and widthem") + + if self.widthem is not None: + self.fontsize = REFERENCE_FONT_SIZE + self.width = self.widthem * self.fontsize + + if self.strip is None: + self.strip = DEFAULT_STRIP + + def togetfontoptions(self): + return self.getsuboptions(_GetfontOptions) + + +class _GetfontOptions(_Options): + _fields = ("fontname", "fontsize", "sysfontname", "bold", "italic", "underline") + _defaults = { + "fontname": _default_sentinel, + "sysfontname": _default_sentinel, + } + + def __init__(self, **kwargs): + _Options.__init__(self, **kwargs) + if self.fontname is _default_sentinel: self.fontname = DEFAULT_FONT_NAME + if self.sysfontname is _default_sentinel: self.sysfontname = DEFAULT_SYSFONT_NAME + if self.fontname is not None and self.sysfontname is not None: + raise ValueError("Can't set both fontname and sysfontname") + if self.fontsize is None: + self.fontsize = DEFAULT_FONT_SIZE + + def getfontpath(self): + return self.fontname if self.fontname is None else FONT_NAME_TEMPLATE % self.fontname + + +class _FitsizeOptions(_Options): + _fields = ("fontname", "sysfontname", "bold", "italic", "underline", + "lineheight", "pspace", "strip", + "underlinetag", "boldtag", "italictag", "colortag") + _defaults = { + "underlinetag": _default_sentinel, + "boldtag": _default_sentinel, + "italictag": _default_sentinel, + "colortag": _default_sentinel, + } + + def togetfontoptions(self): + return self.getsuboptions(_GetfontOptions) + + def towrapoptions(self): + return self.getsuboptions(_WrapOptions) + + +_font_cache = {} + + +def getfont(**kwargs): + options = _GetfontOptions(**kwargs) + key = options.key() + if key in _font_cache: return _font_cache[key] + if options.sysfontname is not None: + font = pygame.font.SysFont(options.sysfontname, options.fontsize, options.bold or False, + options.italic or False) + else: + try: + font = pygame.font.Font(options.getfontpath(), options.fontsize) + except IOError: + raise IOError("unable to read font filename: %s" % options.getfontpath()) + if options.bold is not None: + font.set_bold(options.bold) + if options.italic is not None: + font.set_italic(options.italic) + if options.underline is not None: + font.set_underline(options.underline) + _font_cache[key] = font + return font + + +# Return the largest integer in the range [xmin, xmax] such that f(x) is True. +def _binarysearch(f, xmin=1, xmax=256): + if not f(xmin): return xmin + if f(xmax): return xmax + # xmin is the largest known value for which f(x) is True + # xmax is the smallest known value for which f(x) is False + while xmax - xmin > 1: + x = (xmax + xmin) // 2 + if f(x): + xmin = x + else: + xmax = x + return xmin + + +_fit_cache = {} + + +def _fitsize(text, size, **kwargs): + options = _FitsizeOptions(**kwargs) + key = text, size, options.key() + if key in _fit_cache: return _fit_cache[key] + width, height = size + + def fits(fontsize): + opts = options.copy() + wmax, hmax = 0, 0 + for span in _wrap(text, fontsize=fontsize, width=width, **opts.towrapoptions()): + y = span.font.get_linesize() * (opts.pspace * span.jpara + opts.lineheight * span.jline) + w, h = span.font.size(span.text) + wmax = max(wmax, span.right) + hmax = max(hmax, y + h) + return wmax <= width and hmax <= height + + fontsize = _binarysearch(fits) + _fit_cache[key] = fontsize + return fontsize + + +# Returns the color as a color RGB or RGBA tuple (i.e. 3 or 4 integers in the range 0-255) +# If color is None, fall back to the default. If default is also None, return None. +# Both color and default can be a list, tuple, a color name, an HTML color format string, a hex +# number string, or an integer pixel value. See pygame.Color constructor for specification. +def _resolvecolor(color, default): + if color is None: color = default + if color is None: return None + try: + return tuple(pygame.Color(color)) + except ValueError: + return tuple(color) + + +def _applyshade(color, shade): + f = exp(-0.4 * shade) + r, g, b = [ + min(max(int(round((c + 50) * f - 50)), 0), 255) + for c in color[:3] + ] + return (r, g, b) + tuple(color[3:]) + + +def _resolvealpha(alpha): + if alpha >= 1: + return 1 + return max(int(round(alpha * ALPHA_RESOLUTION)) / ALPHA_RESOLUTION, 0) + + +def _resolveangle(angle): + if not angle: + return 0 + angle %= 360 + return int(round(angle / ANGLE_RESOLUTION_DEGREES)) * ANGLE_RESOLUTION_DEGREES + + +# Return the set of points in the circle radius r, using Bresenham's circle algorithm +_circle_cache = {} + + +def _circlepoints(r): + r = int(round(r)) + if r in _circle_cache: + return _circle_cache[r] + x, y, e = r, 0, 1 - r + _circle_cache[r] = points = [] + while x >= y: + points.append((x, y)) + y += 1 + if e < 0: + e += 2 * y - 1 + else: + x -= 1 + e += 2 * (y - x) - 1 + points += [(y, x) for x, y in points if x > y] + points += [(-x, y) for x, y in points if x] + points += [(x, -y) for x, y in points if y] + points.sort() + return points + + +# Rotate the given surface by the given angle, in degrees. +# If angle is an exact multiple of 90, use pygame.transform.rotate, otherwise fall back to +# pygame.transform.rotozoom. +def _rotatesurf(surf, angle): + if angle in (90, 180, 270): + return pygame.transform.rotate(surf, angle) + else: + return pygame.transform.rotozoom(surf, angle, 1.0) + + +# Apply the given alpha value to a copy of the Surface. +def _fadesurf(surf, alpha): + surf = surf.copy() + asurf = surf.copy() + asurf.fill((255, 255, 255, int(round(255 * alpha)))) + surf.blit(asurf, (0, 0), None, pygame.BLEND_RGBA_MULT) + return surf + + +def _istransparent(color): + return len(color) > 3 and color[3] == 0 + + +# Produce a 1xh Surface with the given color gradient. +_grad_cache = {} + + +def _gradsurf(h, y0, y1, color0, color1): + key = h, y0, y1, color0, color1 + if key in _grad_cache: + return _grad_cache[key] + surf = pygame.Surface((1, h)).convert_alpha() + r0, g0, b0 = color0[:3] + r1, g1, b1 = color1[:3] + for y in range(h): + f = min(max((y - y0) / (y1 - y0), 0), 1) + g = 1 - f + surf.set_at((0, y), ( + int(round(g * r0 + f * r1)), + int(round(g * g0 + f * g1)), + int(round(g * b0 + f * b1)), + 0 + )) + _grad_cache[key] = surf + return surf + + +# Tracks everything that can be updated by tags. +class TagSpec(namedtuple("TagSpec", ["underline", "bold", "italic", "color"])): + @staticmethod + def fromoptions(options): + return TagSpec( + underline=options.underline, + bold=options.bold, + italic=options.italic, + color=options.color + ) + + def updateoptions(self, options): + options.underline = self.underline + options.bold = self.bold + options.italic = self.italic + options.color = self.color + + def toggleunderline(self): + return self._replace(underline=not self.underline) + + def togglebold(self): + return self._replace(bold=not self.bold) + + def toggleitalic(self): + return self._replace(italic=not self.italic) + + def setcolor(self, color): + return self._replace(color=color) + + +# Splits a string into substrings with corresponding tag specs. +# Empty strings are skipped. Consecutive identical tag specs are not merged. +# e.g. if tagspec0.underline = False and underlinetag = "_" then: +# _splitbytags("_abc__def_ ghi_") yields three items: +# ("abc", TagSpec(underline=True)) +# ("def", TagSpec(underline=True)) +# (" ghi", TagSpec(underline=False)) +def _splitbytags(text, tagspec0, color0, underlinetag, boldtag, italictag, colortag): + colortag = {k: _resolvecolor(v, color0) for k, v in colortag.items()} + tags = sorted((set([underlinetag, boldtag, italictag]) | set(colortag.keys())) - set([None])) + if not tags: + yield text, tagspec0 + return + tagspec = tagspec0 + while text: + tagsin = [tag for tag in tags if tag in text] + if not tagsin: + break + a, tag = min((text.index(tag), tag) for tag in tagsin) + if a > 0: + yield text[:a], tagspec + text = text[a + len(tag):] + if tag == underlinetag: + tagspec = tagspec.toggleunderline() + if tag == boldtag: + tagspec = tagspec.togglebold() + if tag == italictag: + tagspec = tagspec.toggleitalic() + if tag in colortag: + tagspec = tagspec.setcolor(colortag[tag]) + if text: + yield text, tagspec + + +# The _Span class tracks many attributes of a single span of text, i.e. a string of text within a +# single line that has a single font and TagSpec. That is, a single span corresponds to a single +# call to font.render. +# This is not a clean abstraction, and some of the state of this object only makes sense in the +# context of the overall draw call. At various stages of the call, some of the fields will not yet +# be populated. +class _Span: + # Phase 1: set by _wrapline + def __init__(self, text, tagspec, x, font): + self.tagspec = tagspec + self.x = x # Offset from the beginning of the line + self.font = font + self.settext(text) + + # Phase 2: set by _wrap + def setlayout(self, jpara, jline, linewidth): + self.jpara = jpara + self.jline = jline + self.linewidth = linewidth + + # Phase 3: set by getsurf + # These are not required to determine layout or position, only for rendering. + def setdetails(self, antialias, gcolor, background): + self.antialias = antialias + self.gcolor = gcolor + self.background = background + + def settext(self, text): + self.text = text + self.width = self.getwidth(self.text) + self.right = self.x + self.width + + def getwidth(self, text): + if text == '0': + pass + return self.font.size(text)[0] + + def render(self): + if self.gcolor is None: + # Workaround: pygame.Font.render does not allow passing None as an argument value for + # background. We have to call the 3-argument form to specify no background. + args = self.text, self.antialias, self.tagspec.color + if self.background is not None and not _istransparent(self.background): + args += (self.background,) + self.surf = self.font.render(*args).convert_alpha() + else: + self.surf = self.font.render(self.text, self.antialias, (0, 0, 0)).convert_alpha() + w, h = self.surf.get_size() + asc = self.font.get_ascent() + gsurf0 = _gradsurf(h, 0.5 * asc, asc, self.tagspec.color, self.gcolor) + gsurf = pygame.transform.scale(gsurf0, (w, h)) + self.surf.blit(gsurf, (0, 0), None, pygame.BLEND_RGBA_ADD) + + +# Finds the last valid breakpoint in the line of text. A breakpoint is a position at which the line +# can be split without improperly breaking words. +# Returns (breaktext, breakpoint) +def _breaktext(text, width, font, canbreakatstart=False): + # TODO: binary search + # The text to be printed that actually comes from text. Does not include stripped characters, + # e.g. soft hyphens, trailing or otherwise. Does include trailing spaces. + btext = "" + # Index of the first character in text that does not appear in btext. + b = 0 if canbreakatstart else None + # Any additional characters to be appended on return, i.e. hyphen generated by soft hyphens. + bapp = "" + # Partial buildup of btext. + ptext = "" + + def isvalid(t): + return width is None or font.size(t)[0] <= width + + for j, c in enumerate(text): + atbreak, napp = False, "" + # Space and hyphen character allow for a breakpoint. + if c in [" ", "-"]: + atbreak = True + # Non-breaking space. No breakpoint here. Instead just add a space. + elif c == "\u00A0": + c = " " + # Non-breaking hyphen. No breakpoint here. Instead just add a hyphen. + elif c == "\u2011": + c = "-" + # Zero-width space. Allow a breakpoint but don't add anything (i.e. remove this character) + elif c == "\u200B": + atbreak = True + c = "" + # Soft hyphen. Allow a breakpoint with an appending string of hyphen ("-"). + elif c == "\u00AD": + atbreak = True + c = "" + napp = "-" + ptext += c + if atbreak: + if b is None or isvalid((ptext + napp).rstrip(" ")): + btext = ptext + b = j + 1 + bapp = napp + else: + break + else: + # One past the end of the line is always considered a breakpoint. + if b is None or isvalid(ptext): + return ptext, len(text) + # Invalid breakpoint found. Take trailing spaces starting from the last valid breakpoint. + while b < len(text) and text[b] == " ": + b += 1 + bapp += " " + return btext + bapp, b + + +# Split a single line of text. +# textandtags is the output of _splitbytags, i.e. a sequence of (string, tag spec) tuples. +def _wrapline(textandtags, width, getfontbytagspec): + x = 0 + canbreakatstart = False + lines = [] + line = [] + for text, tagspec in textandtags: + font = getfontbytagspec(tagspec) + while text: + rwidth = None if width is None else width - x + btext, b = _breaktext(text, rwidth, font, canbreakatstart) + if b == 0: + lines.append((line, x)) + line = [] + x = 0 + canbreakatstart = False + else: + span = _Span(btext, tagspec, x, font) + line.append(span) + x += span.width + text = text[b:] + canbreakatstart = True + lines.append((line, x)) + return lines + + +def _wrap(text, **kwargs): + options = _WrapOptions(**kwargs) + # Returns a function mapping strings to int widths in the specified font + opts = options.copy() + + def getfontbytagspec(tagspec): + tagspec.updateoptions(opts) + return getfont(**opts.togetfontoptions()) + + # Apparently Font.render accepts None for the text argument, in which case it's treated as the + # empty string. We match that behavior here. + if text is None: text = "" + spans = [] + tagspec0 = TagSpec.fromoptions(options) + jline = 0 + for jpara, para in enumerate(text.replace("\t", " ").split("\n")): + if options.strip: + para = para.rstrip(" ") + tagargs = options.underlinetag, options.boldtag, options.italictag, options.colortag + textandtags = list(_splitbytags(para, tagspec0, options.color, *tagargs)) + _, tagspec0 = textandtags[-1] + for line, linewidth in _wrapline(textandtags, options.width, getfontbytagspec): + if not line: + jline += 1 + continue + # Strip trailing spaces from the end of each line. + span = line[-1] + if options.strip: + span.settext(span.text.rstrip(" ")) + elif options.width is not None: + while span.text[-1] == " " and span.right > options.width: + span.settext(span.text[:-1]) + linewidth = span.right + for span in line: + span.setlayout(jpara, jline, linewidth) + spans.append(span) + jline += 1 + return spans + + +_surf_cache = {} +_surf_tick_usage = {} +_surf_size_total = 0 +_unrotated_size = {} +_tick = 0 + + +def getsurf(text, **kwargs): + global _tick, _surf_size_total + options = _GetsurfOptions(**kwargs) + key = text, options.key() + if key in _surf_cache: + _surf_tick_usage[key] = _tick + _tick += 1 + return _surf_cache[key] + + if options.angle: + surf0 = getsurf(text, **options.update(angle=0)) + surf = _rotatesurf(surf0, options.angle) + # draw() requires the unrotated size for proper positioning, but the unrotated surface will + # not necessarily be cached, so we add it to a global store here. In principle you could + # compute it from surf.get_size() and options.angle, were it not for rounding issues. + _unrotated_size[(surf.get_size(), options.angle, text)] = surf0.get_size() + elif options.alpha < 1.0: + surf = _fadesurf(getsurf(text, **options.update(alpha=1.0)), options.alpha) + elif options._spx is not None: + color = (0, 0, 0) if _istransparent(options.color) else options.color + surf0 = getsurf(text, **options.update(background=(0, 0, 0, 0), color=color, shadow=None, scolor=None)) + sopts = { + "color": options.scolor, + "shadow": None, + "scolor": None, + "background": (0, 0, 0, 0), + "gcolor": None, + "colortag": {k: None for k in options.colortag}, + } + ssurf = getsurf(text, **options.update(**sopts)) + w0, h0 = surf0.get_size() + sx, sy = options._spx + surf = pygame.Surface((w0 + abs(sx), h0 + abs(sy))).convert_alpha() + surf.fill(options.background or (0, 0, 0, 0)) + dx, dy = max(sx, 0), max(sy, 0) + surf.blit(ssurf, (dx, dy)) + x0, y0 = abs(sx) - dx, abs(sy) - dy + if _istransparent(options.color): + surf.blit(surf0, (x0, y0), None, pygame.BLEND_RGBA_SUB) + else: + surf.blit(surf0, (x0, y0)) + elif options._opx is not None: + color = (0, 0, 0) if _istransparent(options.color) else options.color + surf0 = getsurf(text, **options.update(color=color, ocolor=None, owidth=None)) + oopts = { + "color": options.ocolor, + "ocolor": None, + "owidth": None, + "background": (0, 0, 0, 0), + "gcolor": None, + "colortag": {k: None for k in options.colortag}, + } + osurf = getsurf(text, **options.update(**oopts)) + w0, h0 = surf0.get_size() + opx = options._opx + surf = pygame.Surface((w0 + 2 * opx, h0 + 2 * opx)).convert_alpha() + surf.fill(options.background or (0, 0, 0, 0)) + for dx, dy in _circlepoints(opx): + surf.blit(osurf, (dx + opx, dy + opx)) + if _istransparent(options.color): + surf.blit(surf0, (opx, opx), None, pygame.BLEND_RGBA_SUB) + else: + surf.blit(surf0, (opx, opx)) + else: + # Each span is rendered separately into a Surface, and then the different spans' Surfaces + # are blitted onto the final Surface. + spans = _wrap(text, **options.towrapoptions()) + for span in spans: + span.setdetails(options.antialias, options.gcolor, options.background) + span.render() + # Now to blit the span Surfaces together onto a single Surface. As an optimization, when + # there is only one span Surface, just use that. (We can't use this optimization if there's + # a gradient color, because the background color still needs to be applied.) + if not spans: + surf = pygame.Surface((0, 0)).convert_alpha() + elif len(spans) == 1 and options.gcolor is None: + surf = spans[0].surf + else: + font = spans[0].font + w = max(span.linewidth for span in spans) + linesize = font.get_linesize() * options.lineheight + parasize = font.get_linesize() * options.pspace + for span in spans: + span.y = int(round(span.jline * linesize + span.jpara * parasize)) + h = max(span.y for span in spans) + font.get_height() + surf = pygame.Surface((w, h)).convert_alpha() + surf.fill(options.background or (0, 0, 0, 0)) + for span in spans: + x = int(round(span.x + options.align * (w - span.linewidth))) + surf.blit(span.surf, (x, span.y)) + if options.cache: + w, h = surf.get_size() + _surf_size_total += 4 * w * h + _surf_cache[key] = surf + _surf_tick_usage[key] = _tick + _tick += 1 + return surf + + +# The actual position on the screen where the surf is to be blitted, rather than the specified +# anchor position. +def _blitpos(angle, pos, anchor, size, text): + angle = _resolveangle(angle) + x, y = pos + sw, sh = size + hanchor, vanchor = anchor + if angle: + w0, h0 = _unrotated_size[(size, angle, text)] + S, C = sin(radians(angle)), cos(radians(angle)) + dx, dy = (0.5 - hanchor) * w0, (0.5 - vanchor) * h0 + x += dx * C + dy * S - 0.5 * sw + y += -dx * S + dy * C - 0.5 * sh + else: + x -= hanchor * sw + y -= vanchor * sh + x = int(round(x)) + y = int(round(y)) + return x, y + + +def layout(text, **kwargs): + options = _LayoutOptions(**kwargs) + if options.angle != 0: + raise ValueError("Nonzero angle not yet supported for ptext.layout") + font = getfont(**options.togetfontoptions()) + fl = font.get_linesize() + linesize = fl * options.lineheight + parasize = fl * options.pspace + + spans = _wrap(text, **options.towrapoptions()) + + rects = [] + sw = max(span.linewidth for span in spans) + for span in spans: + y = int(round(span.jpara * parasize + span.jline * linesize)) + rect = pygame.Rect(span.x, y, *font.size(span.text)) + rect.x += int(round(options.align * (sw - span.linewidth))) + rects.append(rect) + sh = max(rect.bottom for rect in rects) + + x0, y0 = _blitpos(options.angle, options.pos, options.anchor, (sw, sh), None) + + # Adjust the rects as necessary to account for outline and shadow. + # TODO: the following is duplicated from _GetsurfOptions.__init__ + dx, dy = 0, 0 + if options.owidth is not None: + opx = ceil(options.owidth * options.fontsize * OUTLINE_UNIT) + dx, dy = max(dx, abs(opx)), max(dy, abs(opx)) + if options.shadow is not None: + spx, spy = (ceil(s * options.fontsize * SHADOW_UNIT) for s in options.shadow) + dx, dy = max(dx, -spx), max(dy, -spy) + rects = [rect.move(x0 + dx, y0 + dy) for rect in rects] + + return [(span.text, rect, span.font) for span, rect in zip(spans, rects)] + + +def draw(text, pos=None, **kwargs): + # if text == '0': + # print("herpaderp") + pass + options = _DrawOptions(pos=pos, **kwargs) + tsurf = getsurf(text, **options.togetsurfoptions()) + pos = _blitpos(options.angle, options.pos, options.anchor, tsurf.get_size(), text) + if options.surf is not None: + options.surf.blit(tsurf, pos) + if AUTO_CLEAN: + clean() + return tsurf, pos + + +def drawbox(text, rect, **kwargs): + options = _DrawboxOptions(**kwargs) + rect = pygame.Rect(rect) + hanchor, vanchor = options.anchor + x = rect.x + hanchor * rect.width + y = rect.y + vanchor * rect.height + fontsize = _fitsize(text, rect.size, **options.tofitsizeoptions()) + return draw(text, pos=(x, y), width=rect.width, fontsize=fontsize, **options.todrawoptions()) + + +def clean(): + global _surf_size_total + memory_limit = MEMORY_LIMIT_MB * (1 << 20) + if _surf_size_total < memory_limit: + return + memory_limit *= MEMORY_REDUCTION_FACTOR + keys = sorted(_surf_cache, key=_surf_tick_usage.get) + for key in keys: + w, h = _surf_cache[key].get_size() + del _surf_cache[key] + del _surf_tick_usage[key] + _surf_size_total -= 4 * w * h + if _surf_size_total < memory_limit: + break diff --git a/irlc/utils/timer.py b/irlc/utils/timer.py new file mode 100644 index 0000000..14614f1 --- /dev/null +++ b/irlc/utils/timer.py @@ -0,0 +1,45 @@ +# This file may not be shared/redistributed without permission. Please read copyright notice in the git repo. If this file contains other copyright notices disregard this text. +from collections import defaultdict +import datetime + +class Timer: + def __init__(self, show_time_per_tic=True, start=False): + self.tspend = defaultdict(lambda: 0) + self.t_start = {} + self.n_tics = defaultdict(lambda: 0) + self.s_ = None + self.show_time_per_tic = show_time_per_tic + if start: + self.start() + + + def start(self): + self.s_ = datetime.datetime.now() + + def tic(self, name): + self.lst = name + self.t_start[name] = datetime.datetime.now() + + def toc(self, name=None): + name = name if name is not None else self.lst + self.tspend[name] += (datetime.datetime.now() - self.t_start[name]).total_seconds() + self.n_tics[name] += 1 + + def display(self): + Tknown = sum(self.tspend.values()) + if self.s_ is not None: + Ttot = (datetime.datetime.now() - self.s_).total_seconds() + + if self.show_time_per_tic: + spend = {k: v/self.n_tics[k] for k, v in self.tspend.items()} + # Tknown = + else: + spend = self.tspend + + s = ", ".join( [f"{k}: {v:.2f} ({int(self.tspend[k]/Tknown*100)} %)" for k, v in spend.items()] ) + + + if self.s_ is not None: + return f"{Ttot:.2f} ({(Tknown/Ttot*100):.1f} %). " + s + else: + return s diff --git a/requirements_conda.txt b/requirements_conda.txt new file mode 100644 index 0000000..2b402cf --- /dev/null +++ b/requirements_conda.txt @@ -0,0 +1,16 @@ +# On linux, you also need these packages: +# apt install build-essential python3.11-dev swig +# (replace 3.11 with your python version; this works on Ubuntu 23.10 mantic) +gymnasium[box2d]<=0.29.1 +torch +sympy +tqdm +seaborn +pillow +scikit-learn +matplotlib +requests # Required when updating the local files (read stuff from gitlab). +pyqt5 +pygame +numpy<=1.26.4 # Version 2 has a problem with gymnasium + diff --git a/requirements_pip.txt b/requirements_pip.txt new file mode 100644 index 0000000..a375525 --- /dev/null +++ b/requirements_pip.txt @@ -0,0 +1,3 @@ +# PyQt5>=5.15.9 # 5.15.8 has a problem with matplotlib; but newest version is 5.15.9 +unitgrade +-e . diff --git a/solutions/ex00/fruit_homework_TODO_1.py b/solutions/ex00/fruit_homework_TODO_1.py new file mode 100644 index 0000000..b498ceb --- /dev/null +++ b/solutions/ex00/fruit_homework_TODO_1.py @@ -0,0 +1 @@ + return a+b \ No newline at end of file diff --git a/solutions/ex00/fruit_homework_TODO_2.py b/solutions/ex00/fruit_homework_TODO_2.py new file mode 100644 index 0000000..f546843 --- /dev/null +++ b/solutions/ex00/fruit_homework_TODO_2.py @@ -0,0 +1 @@ + return ["mr " + a for a in animals] \ No newline at end of file diff --git a/solutions/ex00/fruit_homework_TODO_3.py b/solutions/ex00/fruit_homework_TODO_3.py new file mode 100644 index 0000000..5be72c6 --- /dev/null +++ b/solutions/ex00/fruit_homework_TODO_3.py @@ -0,0 +1 @@ + return sum([x * p for x, p in p_dict.items()]) \ No newline at end of file diff --git a/solutions/ex00/fruit_homework_TODO_4.py b/solutions/ex00/fruit_homework_TODO_4.py new file mode 100644 index 0000000..c836aa8 --- /dev/null +++ b/solutions/ex00/fruit_homework_TODO_4.py @@ -0,0 +1 @@ + return list(order_dict.keys()) \ No newline at end of file diff --git a/solutions/ex00/fruit_homework_TODO_5.py b/solutions/ex00/fruit_homework_TODO_5.py new file mode 100644 index 0000000..84c3b39 --- /dev/null +++ b/solutions/ex00/fruit_homework_TODO_5.py @@ -0,0 +1 @@ + return self.prices[fruit] \ No newline at end of file diff --git a/solutions/ex00/fruit_homework_TODO_6.py b/solutions/ex00/fruit_homework_TODO_6.py new file mode 100644 index 0000000..dc8b7ab --- /dev/null +++ b/solutions/ex00/fruit_homework_TODO_6.py @@ -0,0 +1 @@ + return sum([quantity * self.cost(fruit) for fruit, quantity in order.items()]) \ No newline at end of file diff --git a/solutions/ex00/fruit_homework_TODO_7.py b/solutions/ex00/fruit_homework_TODO_7.py new file mode 100644 index 0000000..f02ea8d --- /dev/null +++ b/solutions/ex00/fruit_homework_TODO_7.py @@ -0,0 +1,2 @@ + cs = [s.price_of_order(order) for s in fruit_shops] + best_shop = fruit_shops[cs.index(min(cs))] \ No newline at end of file diff --git a/solutions/ex01/bobs_friend_TODO_1.py b/solutions/ex01/bobs_friend_TODO_1.py new file mode 100644 index 0000000..2d03d7c --- /dev/null +++ b/solutions/ex01/bobs_friend_TODO_1.py @@ -0,0 +1,3 @@ + + self.s = self.x0 + \ No newline at end of file diff --git a/solutions/ex01/bobs_friend_TODO_2.py b/solutions/ex01/bobs_friend_TODO_2.py new file mode 100644 index 0000000..9caf28a --- /dev/null +++ b/solutions/ex01/bobs_friend_TODO_2.py @@ -0,0 +1,9 @@ + terminated = True + if a == 0: + s_next = self.s * 1.1 + else: + if np.random.rand() < 1/4: + s_next = 0 + else: + s_next = self.s + 12 + reward = s_next - self.s \ No newline at end of file diff --git a/solutions/ex01/bobs_friend_TODO_3.py b/solutions/ex01/bobs_friend_TODO_3.py new file mode 100644 index 0000000..8399f7f --- /dev/null +++ b/solutions/ex01/bobs_friend_TODO_3.py @@ -0,0 +1 @@ + return 0 \ No newline at end of file diff --git a/solutions/ex01/bobs_friend_TODO_4.py b/solutions/ex01/bobs_friend_TODO_4.py new file mode 100644 index 0000000..36a268f --- /dev/null +++ b/solutions/ex01/bobs_friend_TODO_4.py @@ -0,0 +1 @@ + return 1 \ No newline at end of file diff --git a/solutions/ex01/chess_TODO_1.py b/solutions/ex01/chess_TODO_1.py new file mode 100644 index 0000000..f8752f9 --- /dev/null +++ b/solutions/ex01/chess_TODO_1.py @@ -0,0 +1 @@ + self.s = [] \ No newline at end of file diff --git a/solutions/ex01/chess_TODO_2.py b/solutions/ex01/chess_TODO_2.py new file mode 100644 index 0000000..9b82990 --- /dev/null +++ b/solutions/ex01/chess_TODO_2.py @@ -0,0 +1,7 @@ + if np.random.rand() < self.p_draw: + game_outcome = 0 + else: + if np.random.rand() < self.p_win: + game_outcome = 1 + else: + game_outcome = -1 \ No newline at end of file diff --git a/solutions/ex01/chess_TODO_3.py b/solutions/ex01/chess_TODO_3.py new file mode 100644 index 0000000..29e1443 --- /dev/null +++ b/solutions/ex01/chess_TODO_3.py @@ -0,0 +1 @@ + done = len(self.s) >= 2 and self.s[-1] == self.s[-2] and self.s[-1] != 0 \ No newline at end of file diff --git a/solutions/ex01/chess_TODO_4.py b/solutions/ex01/chess_TODO_4.py new file mode 100644 index 0000000..d45e38a --- /dev/null +++ b/solutions/ex01/chess_TODO_4.py @@ -0,0 +1 @@ + r = self.s[-1] == 1 if done else 0 \ No newline at end of file diff --git a/solutions/ex01/chess_TODO_5.py b/solutions/ex01/chess_TODO_5.py new file mode 100644 index 0000000..c270359 --- /dev/null +++ b/solutions/ex01/chess_TODO_5.py @@ -0,0 +1 @@ + stats, _ = train(env, Agent(env), num_episodes=T) \ No newline at end of file diff --git a/solutions/ex01/inventory_environment_TODO_1.py b/solutions/ex01/inventory_environment_TODO_1.py new file mode 100644 index 0000000..5f5a775 --- /dev/null +++ b/solutions/ex01/inventory_environment_TODO_1.py @@ -0,0 +1,5 @@ + s_next = max(0, min(2, self.s-w+a)) # next state; x_{k+1} = f_k(x_k, u_k, w_k) + reward = -(a + (self.s + a - w)**2) # reward = -cost = -g_k(x_k, u_k, w_k) + terminated = self.k == self.N-1 # Have we terminated? (i.e. is k==N-1) + self.s = s_next # update environment state + self.k += 1 # update current time step \ No newline at end of file diff --git a/solutions/ex01/inventory_environment_TODO_2.py b/solutions/ex01/inventory_environment_TODO_2.py new file mode 100644 index 0000000..bebe04b --- /dev/null +++ b/solutions/ex01/inventory_environment_TODO_2.py @@ -0,0 +1 @@ + return np.random.choice(3) # Return a random action \ No newline at end of file diff --git a/solutions/ex01/inventory_environment_TODO_3.py b/solutions/ex01/inventory_environment_TODO_3.py new file mode 100644 index 0000000..0855951 --- /dev/null +++ b/solutions/ex01/inventory_environment_TODO_3.py @@ -0,0 +1,7 @@ + a = agent.pi(s, k) + sp, r, terminated, truncated, metadata = env.step(a) + agent.train(s, a, sp, r, terminated) + s = sp + J += r + if terminated or truncated: + break \ No newline at end of file diff --git a/solutions/ex01/pacman_hardcoded_TODO_1.py b/solutions/ex01/pacman_hardcoded_TODO_1.py new file mode 100644 index 0000000..5c532d7 --- /dev/null +++ b/solutions/ex01/pacman_hardcoded_TODO_1.py @@ -0,0 +1,7 @@ + if k < 7: + return 'South' + elif k < 14: + return 'East' + elif k < 21: + return 'North' + elif k < 28: \ No newline at end of file diff --git a/solutions/ex02/dp_TODO_1.py b/solutions/ex02/dp_TODO_1.py new file mode 100644 index 0000000..a266a96 --- /dev/null +++ b/solutions/ex02/dp_TODO_1.py @@ -0,0 +1,4 @@ + Qu = {u: sum(pw * (model.g(x, u, w, k) + J[k + 1][model.f(x, u, w, k)]) for w, pw in model.Pw(x, u, k).items()) for u in model.A(x, k)} + umin = min(Qu, key=Qu.get) + J[k][x] = Qu[umin] # Compute the expected cost function + pi[k][x] = umin # Compute the optimal policy \ No newline at end of file diff --git a/solutions/ex02/dp_agent_TODO_1.py b/solutions/ex02/dp_agent_TODO_1.py new file mode 100644 index 0000000..18f9f78 --- /dev/null +++ b/solutions/ex02/dp_agent_TODO_1.py @@ -0,0 +1 @@ + action = self.pi_[k][s] \ No newline at end of file diff --git a/solutions/ex02/flower_store_TODO_1.py b/solutions/ex02/flower_store_TODO_1.py new file mode 100644 index 0000000..4fec1d3 --- /dev/null +++ b/solutions/ex02/flower_store_TODO_1.py @@ -0,0 +1,23 @@ +class FlowerStoreModel(InventoryDPModel): + def __init__(self, N=3, c=0., prob_empty=False): + self.c = c + self.prob_empty = prob_empty + super().__init__(N=N) + + def g(self, x, u, w, k): # Cost function g_k(x,u,w) + if self.prob_empty: + return 0 + return u * self.c + np.abs(x + u - w) + + def f(self, x, u, w, k): # Dynamics f_k(x,u,w) + return max(0, min(max(self.S(k)), x + u - w)) + + def Pw(self, x, u, k): # Distribution over random disturbances + pw = {0: .1, 1: .3, 2: .6} + return pw + + def gN(self, x): + if self.prob_empty: + return -1 if x == 1 else 0 + else: + return 0 \ No newline at end of file diff --git a/solutions/ex02/flower_store_TODO_2.py b/solutions/ex02/flower_store_TODO_2.py new file mode 100644 index 0000000..29eed84 --- /dev/null +++ b/solutions/ex02/flower_store_TODO_2.py @@ -0,0 +1,3 @@ + model = FlowerStoreModel(N=N, c=c, prob_empty=False) + J, pi = DP_stochastic(model) + u = pi[0][x0] \ No newline at end of file diff --git a/solutions/ex02/flower_store_TODO_3.py b/solutions/ex02/flower_store_TODO_3.py new file mode 100644 index 0000000..62bdb1d --- /dev/null +++ b/solutions/ex02/flower_store_TODO_3.py @@ -0,0 +1,3 @@ + model = FlowerStoreModel(N=N, prob_empty=True) + J, pi = DP_stochastic(model) + pr_empty = -J[0][x0] \ No newline at end of file diff --git a/solutions/ex02/graph_traversal_TODO_1.py b/solutions/ex02/graph_traversal_TODO_1.py new file mode 100644 index 0000000..2eb7542 --- /dev/null +++ b/solutions/ex02/graph_traversal_TODO_1.py @@ -0,0 +1 @@ + return u \ No newline at end of file diff --git a/solutions/ex02/graph_traversal_TODO_2.py b/solutions/ex02/graph_traversal_TODO_2.py new file mode 100644 index 0000000..cd59ca2 --- /dev/null +++ b/solutions/ex02/graph_traversal_TODO_2.py @@ -0,0 +1 @@ + return self.G[(x,u)] \ No newline at end of file diff --git a/solutions/ex02/graph_traversal_TODO_3.py b/solutions/ex02/graph_traversal_TODO_3.py new file mode 100644 index 0000000..3bdbfbc --- /dev/null +++ b/solutions/ex02/graph_traversal_TODO_3.py @@ -0,0 +1 @@ + return 0 if x == self.t else np.inf \ No newline at end of file diff --git a/solutions/ex02/inventory_TODO_1.py b/solutions/ex02/inventory_TODO_1.py new file mode 100644 index 0000000..38ded4d --- /dev/null +++ b/solutions/ex02/inventory_TODO_1.py @@ -0,0 +1 @@ + return {0:.1, 1:.7, 2:0.2} \ No newline at end of file diff --git a/solutions/ex03/inventory_evaluation_TODO_1.py b/solutions/ex03/inventory_evaluation_TODO_1.py new file mode 100644 index 0000000..ec037ab --- /dev/null +++ b/solutions/ex03/inventory_evaluation_TODO_1.py @@ -0,0 +1,2 @@ + k = 0 + expected_number_of_items = sum([p * model.f(x, u, w, k=0) for w, p in model.Pw(x, u, k).items()]) \ No newline at end of file diff --git a/solutions/ex03/inventory_evaluation_TODO_2.py b/solutions/ex03/inventory_evaluation_TODO_2.py new file mode 100644 index 0000000..e2897b1 --- /dev/null +++ b/solutions/ex03/inventory_evaluation_TODO_2.py @@ -0,0 +1,12 @@ + model = InventoryDPModel() + N = model.N + J = [{} for _ in range(N + 1)] + J[N] = {x: model.gN(x) for x in model.S(model.N)} + for k in range(N - 1, -1, -1): + for x in model.S(k): + Qu = {u: sum(pw * (model.g(x, u, w, k) + J[k + 1][model.f(x, u, w, k)]) for w, pw in model.Pw(x, u, k).items()) for u + in model.A(x, k)} + + umin = pi[k][x] # min(Qu, key=Qu.get) + J[k][x] = Qu[umin] # Compute the expected cost function + J_pi_x0 = J[0][x0] \ No newline at end of file diff --git a/solutions/ex03/kuramoto_TODO_1.py b/solutions/ex03/kuramoto_TODO_1.py new file mode 100644 index 0000000..27e0fcd --- /dev/null +++ b/solutions/ex03/kuramoto_TODO_1.py @@ -0,0 +1 @@ + symbolic_f_list = [u[0] + sym.cos(x[0])] \ No newline at end of file diff --git a/solutions/ex03/kuramoto_TODO_2.py b/solutions/ex03/kuramoto_TODO_2.py new file mode 100644 index 0000000..0f1d611 --- /dev/null +++ b/solutions/ex03/kuramoto_TODO_2.py @@ -0,0 +1 @@ + f_value = cmodel.f(x, u, t=0) \ No newline at end of file diff --git a/solutions/ex03/kuramoto_TODO_3.py b/solutions/ex03/kuramoto_TODO_3.py new file mode 100644 index 0000000..f28ac99 --- /dev/null +++ b/solutions/ex03/kuramoto_TODO_3.py @@ -0,0 +1,7 @@ + Delta = tt[k + 1] - tt[k] + xn = xs[k] + k1 = np.asarray(f(xn, u)) + k2 = np.asarray(f(xn + Delta * k1/2, u)) + k3 = np.asarray(f(xn + Delta * k2/2, u)) + k4 = np.asarray(f(xn + Delta * k3, u)) + x_next = xn + 1/6 * Delta * (k1 + 2*k2 + 2*k3 + k4) \ No newline at end of file diff --git a/solutions/ex03/toy_2d_control_TODO_1.py b/solutions/ex03/toy_2d_control_TODO_1.py new file mode 100644 index 0000000..137a63b --- /dev/null +++ b/solutions/ex03/toy_2d_control_TODO_1.py @@ -0,0 +1,2 @@ + def sym_f(self, x, u, t=None): + return [x[1], sym.cos(x[0] + u[0])] \ No newline at end of file diff --git a/solutions/ex03/toy_2d_control_TODO_2.py b/solutions/ex03/toy_2d_control_TODO_2.py new file mode 100644 index 0000000..0b32ca6 --- /dev/null +++ b/solutions/ex03/toy_2d_control_TODO_2.py @@ -0,0 +1,4 @@ + toy = Toy2DControl() + x0 = np.asarray([np.pi/2, 0]) + xs, us, ts = toy.simulate( x0=x0, u_fun = u0, t0=0, tF=T) + wT = xs[-1][0] \ No newline at end of file diff --git a/solutions/ex04/discrete_kuramoto_TODO_1.py b/solutions/ex04/discrete_kuramoto_TODO_1.py new file mode 100644 index 0000000..e0e9d22 --- /dev/null +++ b/solutions/ex04/discrete_kuramoto_TODO_1.py @@ -0,0 +1 @@ + f_euler = dmodel.f(x, u, k=0) \ No newline at end of file diff --git a/solutions/ex04/discrete_kuramoto_TODO_2.py b/solutions/ex04/discrete_kuramoto_TODO_2.py new file mode 100644 index 0000000..001427a --- /dev/null +++ b/solutions/ex04/discrete_kuramoto_TODO_2.py @@ -0,0 +1 @@ + f_euler_derivative, _ = dmodel.f_jacobian(x, u) \ No newline at end of file diff --git a/solutions/ex04/discrete_kuramoto_TODO_3.py b/solutions/ex04/discrete_kuramoto_TODO_3.py new file mode 100644 index 0000000..5b50fea --- /dev/null +++ b/solutions/ex04/discrete_kuramoto_TODO_3.py @@ -0,0 +1 @@ + next_x, cost, terminated, _, metadata = env.step([u]) \ No newline at end of file diff --git a/solutions/ex04/model_pendulum_TODO_1.py b/solutions/ex04/model_pendulum_TODO_1.py new file mode 100644 index 0000000..bbdc073 --- /dev/null +++ b/solutions/ex04/model_pendulum_TODO_1.py @@ -0,0 +1 @@ + x_dot = model.f([1, 2], [0], t=0) \ No newline at end of file diff --git a/solutions/ex04/model_pendulum_TODO_2.py b/solutions/ex04/model_pendulum_TODO_2.py new file mode 100644 index 0000000..59b6a6b --- /dev/null +++ b/solutions/ex04/model_pendulum_TODO_2.py @@ -0,0 +1 @@ + x_dot_numpy = model.f([1, 2], [0], t=0) \ No newline at end of file diff --git a/solutions/ex04/pid_TODO_1.py b/solutions/ex04/pid_TODO_1.py new file mode 100644 index 0000000..be1769b --- /dev/null +++ b/solutions/ex04/pid_TODO_1.py @@ -0,0 +1,6 @@ + e = self.target - x + # if self.e_prior == 0 and self.I == 0: + # self.e_prior = e + self.I = self.I + e * self.dt + u = self.Kp * e + self.Ki * self.I + self.Kd * (e - self.e_prior)/self.dt + self.e_prior = e \ No newline at end of file diff --git a/solutions/ex04/pid_TODO_2.py b/solutions/ex04/pid_TODO_2.py new file mode 100644 index 0000000..7468df3 --- /dev/null +++ b/solutions/ex04/pid_TODO_2.py @@ -0,0 +1 @@ + u = pid.pi(x_cur[0]) \ No newline at end of file diff --git a/solutions/ex04/pid_car_TODO_1.py b/solutions/ex04/pid_car_TODO_1.py new file mode 100644 index 0000000..4201c47 --- /dev/null +++ b/solutions/ex04/pid_car_TODO_1.py @@ -0,0 +1,2 @@ + self.pid_angle = PID(dt=env.discrete_model.dt, Kp=1.0, Ki=0, Kd=0, target=0) + self.pid_velocity = PID(dt=env.discrete_model.dt, Kp=1.5, Ki=0, Kd=0, target=v_target) \ No newline at end of file diff --git a/solutions/ex04/pid_car_TODO_2.py b/solutions/ex04/pid_car_TODO_2.py new file mode 100644 index 0000000..d7b67d3 --- /dev/null +++ b/solutions/ex04/pid_car_TODO_2.py @@ -0,0 +1,2 @@ + xx = x[5] + x[3] if self.use_both_x5_x3 else x[5] + u = np.asarray([self.pid_angle.pi(xx), self.pid_velocity.pi(x[0])]) \ No newline at end of file diff --git a/solutions/ex04/pid_locomotive_agent_TODO_1.py b/solutions/ex04/pid_locomotive_agent_TODO_1.py new file mode 100644 index 0000000..e8912a0 --- /dev/null +++ b/solutions/ex04/pid_locomotive_agent_TODO_1.py @@ -0,0 +1 @@ + self.pid = PID(dt=dt, Kp=Kp, Ki=Ki, Kd=Kd, target=target) \ No newline at end of file diff --git a/solutions/ex04/pid_locomotive_agent_TODO_2.py b/solutions/ex04/pid_locomotive_agent_TODO_2.py new file mode 100644 index 0000000..a512e14 --- /dev/null +++ b/solutions/ex04/pid_locomotive_agent_TODO_2.py @@ -0,0 +1 @@ + u = self.pid.pi(x[0]) \ No newline at end of file diff --git a/solutions/ex04/pid_lunar_TODO_1.py b/solutions/ex04/pid_lunar_TODO_1.py new file mode 100644 index 0000000..7a4671f --- /dev/null +++ b/solutions/ex04/pid_lunar_TODO_1.py @@ -0,0 +1,2 @@ + alt_adj = self.pid_alt.pi( -(np.abs(x[0])- x[1]) ) + ang_adj = self.pid_ang.pi( -((.25 * np.pi) * (x[0] + x[2]) - x[4]) ) \ No newline at end of file diff --git a/solutions/ex04/pid_pendulum_TODO_1.py b/solutions/ex04/pid_pendulum_TODO_1.py new file mode 100644 index 0000000..d21532b --- /dev/null +++ b/solutions/ex04/pid_pendulum_TODO_1.py @@ -0,0 +1,2 @@ + u = self.pid.pi(x[0]) + u = np.clip(u, self.env.action_space.low, self.env.action_space.high) \ No newline at end of file diff --git a/solutions/ex04/pid_pendulum_TODO_2.py b/solutions/ex04/pid_pendulum_TODO_2.py new file mode 100644 index 0000000..6ae3232 --- /dev/null +++ b/solutions/ex04/pid_pendulum_TODO_2.py @@ -0,0 +1 @@ + agent = PIDPendulumAgent(env, dt=env.dt, Kp=12, Ki=0, Kd=2, target_angle=0) \ No newline at end of file diff --git a/solutions/ex04/pid_pendulum_TODO_3.py b/solutions/ex04/pid_pendulum_TODO_3.py new file mode 100644 index 0000000..388da47 --- /dev/null +++ b/solutions/ex04/pid_pendulum_TODO_3.py @@ -0,0 +1 @@ + agent = PIDPendulumAgent(env, dt=env.dt, Kp=12, Ki=2, Kd=2, target_angle=np.pi/6) \ No newline at end of file diff --git a/solutions/ex05/direct_TODO_1.py b/solutions/ex05/direct_TODO_1.py new file mode 100644 index 0000000..943a62d --- /dev/null +++ b/solutions/ex05/direct_TODO_1.py @@ -0,0 +1 @@ + guess = {k: solutions[i - 1]['fun'][k] for k in ['t0', 'tF', 'x', 'u'] } \ No newline at end of file diff --git a/solutions/ex05/direct_TODO_10.py b/solutions/ex05/direct_TODO_10.py new file mode 100644 index 0000000..30c2fff --- /dev/null +++ b/solutions/ex05/direct_TODO_10.py @@ -0,0 +1 @@ + x_interp = xs[:, k] + tau * fs[:, k] + (tau ** 2 / (2 * hk)) * (fs[:, k + 1] - fs[:, k]) \ No newline at end of file diff --git a/solutions/ex05/direct_TODO_2.py b/solutions/ex05/direct_TODO_2.py new file mode 100644 index 0000000..93276c3 --- /dev/null +++ b/solutions/ex05/direct_TODO_2.py @@ -0,0 +1,2 @@ + z, z0, z_lb, z_ub = z + xs[k], z0 + list(guess['x'](tk).flat), z_lb + x_low, z_ub + x_high + z, z0, z_lb, z_ub = z + us[k], z0 + list(guess['u'](tk).flat), z_lb + u_low, z_ub + u_high \ No newline at end of file diff --git a/solutions/ex05/direct_TODO_3.py b/solutions/ex05/direct_TODO_3.py new file mode 100644 index 0000000..2a48c18 --- /dev/null +++ b/solutions/ex05/direct_TODO_3.py @@ -0,0 +1,2 @@ + z, z0, z_lb, z_ub = z+[t0], z0+[guess['t0']], z_lb+[model.t0_bound().low[0]], z_ub+[model.t0_bound().high[0]] + z, z0, z_lb, z_ub = z+[tF], z0+[guess['tF']], z_lb+[model.tF_bound().low[0]], z_ub+[model.tF_bound().high[0]] \ No newline at end of file diff --git a/solutions/ex05/direct_TODO_4.py b/solutions/ex05/direct_TODO_4.py new file mode 100644 index 0000000..a17d399 --- /dev/null +++ b/solutions/ex05/direct_TODO_4.py @@ -0,0 +1,2 @@ + fs.append(model.sym_f(x=xs[k], u=us[k], t=ts[k])) + cs.append(cost.sym_c(x=xs[k], u=us[k], t=ts[k])) \ No newline at end of file diff --git a/solutions/ex05/direct_TODO_5.py b/solutions/ex05/direct_TODO_5.py new file mode 100644 index 0000000..4503612 --- /dev/null +++ b/solutions/ex05/direct_TODO_5.py @@ -0,0 +1,2 @@ + hk = (ts[k + 1] - ts[k]) + J += .5 * hk * (cs[k] + cs[k + 1]) \ No newline at end of file diff --git a/solutions/ex05/direct_TODO_6.py b/solutions/ex05/direct_TODO_6.py new file mode 100644 index 0000000..d44ee27 --- /dev/null +++ b/solutions/ex05/direct_TODO_6.py @@ -0,0 +1 @@ + Ieq.append((xs[k+1][j] - xs[k][j]) - 0.5*hk*(fs[k+1][j] + fs[k][j])) \ No newline at end of file diff --git a/solutions/ex05/direct_TODO_7.py b/solutions/ex05/direct_TODO_7.py new file mode 100644 index 0000000..40f3af4 --- /dev/null +++ b/solutions/ex05/direct_TODO_7.py @@ -0,0 +1 @@ + Iineq += model.sym_h(x=xs[k], u=us[k], t=ts[k]) \ No newline at end of file diff --git a/solutions/ex05/direct_TODO_8.py b/solutions/ex05/direct_TODO_8.py new file mode 100644 index 0000000..10dcc17 --- /dev/null +++ b/solutions/ex05/direct_TODO_8.py @@ -0,0 +1 @@ + J_jac = sym.lambdify([z], sym.derive_by_array(J, z), modules='numpy') \ No newline at end of file diff --git a/solutions/ex05/direct_TODO_9.py b/solutions/ex05/direct_TODO_9.py new file mode 100644 index 0000000..5ed2dd8 --- /dev/null +++ b/solutions/ex05/direct_TODO_9.py @@ -0,0 +1,3 @@ + for k in range(len(ts) - 1): + if ts[k] <= t_new and t_new <= ts[k + 1]: + break \ No newline at end of file diff --git a/solutions/ex05/direct_agent_TODO_1.py b/solutions/ex05/direct_agent_TODO_1.py new file mode 100644 index 0000000..dca993f --- /dev/null +++ b/solutions/ex05/direct_agent_TODO_1.py @@ -0,0 +1 @@ + self.ufun = solutions[-1]['fun']['u'] \ No newline at end of file diff --git a/solutions/ex05/direct_agent_TODO_2.py b/solutions/ex05/direct_agent_TODO_2.py new file mode 100644 index 0000000..311c0af --- /dev/null +++ b/solutions/ex05/direct_agent_TODO_2.py @@ -0,0 +1,7 @@ + t = info['time_seconds'] + if t > self.ts_grid[-1]: + print("Simulation time is", t, "which exceeds the maximal planning horizon t_F =", self.ts_grid[-1]) + raise Exception("Time exceed agents planning horizon") + + u = self.ufun(t) + u = np.asarray(self.env.discrete_model.phi_u(u)) \ No newline at end of file diff --git a/solutions/ex05/direct_cartpole_kelly_TODO_1.py b/solutions/ex05/direct_cartpole_kelly_TODO_1.py new file mode 100644 index 0000000..c3da19e --- /dev/null +++ b/solutions/ex05/direct_cartpole_kelly_TODO_1.py @@ -0,0 +1,2 @@ + Q = np.zeros((4, 4)) + return SymbolicQRCost(Q=Q, R=np.asarray([[1.0]]) ) \ No newline at end of file diff --git a/solutions/ex05/direct_cartpole_kelly_TODO_2.py b/solutions/ex05/direct_cartpole_kelly_TODO_2.py new file mode 100644 index 0000000..11a9b85 --- /dev/null +++ b/solutions/ex05/direct_cartpole_kelly_TODO_2.py @@ -0,0 +1,2 @@ + duration = 2 + return Box(duration, duration, shape=(1,)) \ No newline at end of file diff --git a/solutions/ex05/model_brachistochrone_TODO_1.py b/solutions/ex05/model_brachistochrone_TODO_1.py new file mode 100644 index 0000000..056e073 --- /dev/null +++ b/solutions/ex05/model_brachistochrone_TODO_1.py @@ -0,0 +1 @@ + cost = SymbolicQRCost(Q=np.zeros((3,3)), R = np.zeros((1,1)), qc=1.0) \ No newline at end of file diff --git a/solutions/ex05/model_brachistochrone_TODO_2.py b/solutions/ex05/model_brachistochrone_TODO_2.py new file mode 100644 index 0000000..bce8341 --- /dev/null +++ b/solutions/ex05/model_brachistochrone_TODO_2.py @@ -0,0 +1,3 @@ + v = x[2] + uu = u[0] + xp = [v * sym.sin(uu), -v * sym.cos(uu), self.g * sym.cos(uu)] \ No newline at end of file diff --git a/solutions/ex05/model_brachistochrone_TODO_3.py b/solutions/ex05/model_brachistochrone_TODO_3.py new file mode 100644 index 0000000..1e993c3 --- /dev/null +++ b/solutions/ex05/model_brachistochrone_TODO_3.py @@ -0,0 +1 @@ + return [ -x[1] - x[0]/2 - self.h ] \ No newline at end of file diff --git a/solutions/ex06/boeing_lqr_TODO_1.py b/solutions/ex06/boeing_lqr_TODO_1.py new file mode 100644 index 0000000..649101b --- /dev/null +++ b/solutions/ex06/boeing_lqr_TODO_1.py @@ -0,0 +1 @@ + Q, R, q = compute_Q_R_q(model, dt) \ No newline at end of file diff --git a/solutions/ex06/boeing_lqr_TODO_2.py b/solutions/ex06/boeing_lqr_TODO_2.py new file mode 100644 index 0000000..ba3dbc6 --- /dev/null +++ b/solutions/ex06/boeing_lqr_TODO_2.py @@ -0,0 +1 @@ + agent = LQRAgent(env, A=A, B=B, d=d, Q=Q, R=R, q=q) \ No newline at end of file diff --git a/solutions/ex06/boeing_lqr_TODO_3.py b/solutions/ex06/boeing_lqr_TODO_3.py new file mode 100644 index 0000000..e5328ff --- /dev/null +++ b/solutions/ex06/boeing_lqr_TODO_3.py @@ -0,0 +1,3 @@ + Q = cost.Q * dt + R = cost.R * dt + q = cost.q * dt \ No newline at end of file diff --git a/solutions/ex06/boeing_lqr_TODO_4.py b/solutions/ex06/boeing_lqr_TODO_4.py new file mode 100644 index 0000000..5100172 --- /dev/null +++ b/solutions/ex06/boeing_lqr_TODO_4.py @@ -0,0 +1,2 @@ + B_discrete = scipy.linalg.inv(model.A) @ (A_discrete - np.eye(model.A.shape[0])) @ model.B + d_discrete = scipy.linalg.inv(model.A) @ (A_discrete - np.eye(model.A.shape[0])) @ d \ No newline at end of file diff --git a/solutions/ex06/dlqr_TODO_1.py b/solutions/ex06/dlqr_TODO_1.py new file mode 100644 index 0000000..7615471 --- /dev/null +++ b/solutions/ex06/dlqr_TODO_1.py @@ -0,0 +1,2 @@ +import matplotlib +matplotlib.use('agg') \ No newline at end of file diff --git a/solutions/ex06/dlqr_TODO_2.py b/solutions/ex06/dlqr_TODO_2.py new file mode 100644 index 0000000..f34eec8 --- /dev/null +++ b/solutions/ex06/dlqr_TODO_2.py @@ -0,0 +1 @@ + V[N], v[N], vc[N] = QN, qN, qcN \ No newline at end of file diff --git a/solutions/ex06/dlqr_TODO_3.py b/solutions/ex06/dlqr_TODO_3.py new file mode 100644 index 0000000..14bb8ad --- /dev/null +++ b/solutions/ex06/dlqr_TODO_3.py @@ -0,0 +1,4 @@ + Suu = R[k] + B[k].T @ (V[k+1] + mu * In) @ B[k] + Sux = H[k] + B[k].T @ (V[k+1] + mu * In) @ A[k] + Su = r[k] + B[k].T @ v[k + 1] + B[k].T @ V[k + 1] @ d[k] + L[k] = -np.linalg.solve(Suu, Sux) \ No newline at end of file diff --git a/solutions/ex06/lqr_agent_TODO_1.py b/solutions/ex06/lqr_agent_TODO_1.py new file mode 100644 index 0000000..f82d69e --- /dev/null +++ b/solutions/ex06/lqr_agent_TODO_1.py @@ -0,0 +1 @@ + (self.L, self.l), _ = LQR(A=[A]*N, B=[B]*N, d=[d]*N if d is not None else None, Q=[Q]*N, q=[q]*N if q is not None else None, R=[R]*N) \ No newline at end of file diff --git a/solutions/ex06/lqr_agent_TODO_2.py b/solutions/ex06/lqr_agent_TODO_2.py new file mode 100644 index 0000000..e8994b0 --- /dev/null +++ b/solutions/ex06/lqr_agent_TODO_2.py @@ -0,0 +1 @@ + u = self.L[k] @ x + self.l[k] \ No newline at end of file diff --git a/solutions/ex06/lqr_pid_TODO_1.py b/solutions/ex06/lqr_pid_TODO_1.py new file mode 100644 index 0000000..920d0e7 --- /dev/null +++ b/solutions/ex06/lqr_pid_TODO_1.py @@ -0,0 +1,3 @@ + def pi(self,x, k, info=None): + action = self.L[0] @ x + self.l[0] + return action \ No newline at end of file diff --git a/solutions/ex06/lqr_pid_TODO_2.py b/solutions/ex06/lqr_pid_TODO_2.py new file mode 100644 index 0000000..2f1ad2a --- /dev/null +++ b/solutions/ex06/lqr_pid_TODO_2.py @@ -0,0 +1 @@ + Kp, Kd = (-L0).flat \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_1.py b/solutions/ex07/ilqr_TODO_1.py new file mode 100644 index 0000000..c9ada2c --- /dev/null +++ b/solutions/ex07/ilqr_TODO_1.py @@ -0,0 +1,2 @@ + l, L = [np.zeros((m,))]*N, [np.zeros((m,n))]*N + x_bar, u_bar = forward_pass(model, x_bar, u_bar, L=L, l=l) \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_10.py b/solutions/ex07/ilqr_TODO_10.py new file mode 100644 index 0000000..9742318 --- /dev/null +++ b/solutions/ex07/ilqr_TODO_10.py @@ -0,0 +1 @@ + Delta, mu = max(1.0, Delta) * Delta_0, max(mu_min, mu * Delta) # Increase \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_11.py b/solutions/ex07/ilqr_TODO_11.py new file mode 100644 index 0000000..dafc65d --- /dev/null +++ b/solutions/ex07/ilqr_TODO_11.py @@ -0,0 +1,4 @@ + R = c_uu + H = c_ux + q, qN = c_x[:-1], c_x[-1] + r = c_u \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_12.py b/solutions/ex07/ilqr_TODO_12.py new file mode 100644 index 0000000..b5823c6 --- /dev/null +++ b/solutions/ex07/ilqr_TODO_12.py @@ -0,0 +1,4 @@ + # fs = [(v[1],v[2]) for v in [model.f(x, u, k, compute_jacobian=True) for k, (x, u) in enumerate(zip(x_bar[:-1], u_bar))]] + fs = [model.f_jacobian(x, u, k) for k, (x, u) in enumerate(zip(x_bar[:-1], u_bar))] + + A, B = zip(*fs) \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_13.py b/solutions/ex07/ilqr_TODO_13.py new file mode 100644 index 0000000..41ceba5 --- /dev/null +++ b/solutions/ex07/ilqr_TODO_13.py @@ -0,0 +1,2 @@ + gs = [model.cost.c(x, u, i, compute_gradients=True) for i, (x, u) in enumerate(zip(x_bar[:-1], u_bar))] + c, c_x, c_u, c_xx, c_ux, c_uu = zip(*gs) \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_14.py b/solutions/ex07/ilqr_TODO_14.py new file mode 100644 index 0000000..8c92508 --- /dev/null +++ b/solutions/ex07/ilqr_TODO_14.py @@ -0,0 +1,3 @@ + c = c + (cN,) + c_x = c_x + (c_xN,) + c_xx = c_xx + (c_xxN,) \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_15.py b/solutions/ex07/ilqr_TODO_15.py new file mode 100644 index 0000000..73a0fa4 --- /dev/null +++ b/solutions/ex07/ilqr_TODO_15.py @@ -0,0 +1 @@ + u_star[i] = u_bar[i] + alpha * l[i] + L[i] @ (x[i] - x_bar[i]) \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_16.py b/solutions/ex07/ilqr_TODO_16.py new file mode 100644 index 0000000..20904f4 --- /dev/null +++ b/solutions/ex07/ilqr_TODO_16.py @@ -0,0 +1 @@ + x[i + 1] = model.f(x[i], u_star[i], i) \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_2.py b/solutions/ex07/ilqr_TODO_2.py new file mode 100644 index 0000000..a5ff3ca --- /dev/null +++ b/solutions/ex07/ilqr_TODO_2.py @@ -0,0 +1,2 @@ + A, B, c, c_x, c_u, c_xx, c_ux, c_uu = get_derivatives(model, x_bar, u_bar) + J = sum(c) \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_3.py b/solutions/ex07/ilqr_TODO_3.py new file mode 100644 index 0000000..417755d --- /dev/null +++ b/solutions/ex07/ilqr_TODO_3.py @@ -0,0 +1 @@ + L, l = backward_pass(A, B, c_x, c_u, c_xx, c_ux, c_uu, mu) \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_4.py b/solutions/ex07/ilqr_TODO_4.py new file mode 100644 index 0000000..6db866f --- /dev/null +++ b/solutions/ex07/ilqr_TODO_4.py @@ -0,0 +1 @@ + x_bar, u_bar = forward_pass(model, x_bar, u_bar, L=L, l=l, alpha=alpha) \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_5.py b/solutions/ex07/ilqr_TODO_5.py new file mode 100644 index 0000000..4ead664 --- /dev/null +++ b/solutions/ex07/ilqr_TODO_5.py @@ -0,0 +1,2 @@ + l, L = [np.zeros((m,))] * N, [np.zeros((m, n))] * N + x_bar, u_bar = forward_pass(model, x_bar, u_bar, L=L, l=l) \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_6.py b/solutions/ex07/ilqr_TODO_6.py new file mode 100644 index 0000000..2e7b84c --- /dev/null +++ b/solutions/ex07/ilqr_TODO_6.py @@ -0,0 +1,2 @@ + A, B, c, c_x, c_u, c_xx, c_ux, c_uu = get_derivatives(model, x_bar, u_bar) + J_prime = sum(c) \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_7.py b/solutions/ex07/ilqr_TODO_7.py new file mode 100644 index 0000000..f23d1c9 --- /dev/null +++ b/solutions/ex07/ilqr_TODO_7.py @@ -0,0 +1 @@ + L, l = backward_pass(A, B, c_x, c_u, c_xx, c_ux, c_uu, mu) \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_8.py b/solutions/ex07/ilqr_TODO_8.py new file mode 100644 index 0000000..123b9bb --- /dev/null +++ b/solutions/ex07/ilqr_TODO_8.py @@ -0,0 +1 @@ + J_new = cost_of_trajectory(model, x_hat, u_hat) \ No newline at end of file diff --git a/solutions/ex07/ilqr_TODO_9.py b/solutions/ex07/ilqr_TODO_9.py new file mode 100644 index 0000000..1fe4de6 --- /dev/null +++ b/solutions/ex07/ilqr_TODO_9.py @@ -0,0 +1 @@ + Delta, mu = min(1.0, Delta) / Delta_0, max(0, mu*Delta) \ No newline at end of file diff --git a/solutions/ex07/ilqr_agent_TODO_1.py b/solutions/ex07/ilqr_agent_TODO_1.py new file mode 100644 index 0000000..5632d14 --- /dev/null +++ b/solutions/ex07/ilqr_agent_TODO_1.py @@ -0,0 +1 @@ + u = self.ubar[k] + self.L[k]@ (x-self.xbar[k]) + self.l[k] \ No newline at end of file diff --git a/solutions/ex07/ilqr_pendulum_TODO_1.py b/solutions/ex07/ilqr_pendulum_TODO_1.py new file mode 100644 index 0000000..dee07f7 --- /dev/null +++ b/solutions/ex07/ilqr_pendulum_TODO_1.py @@ -0,0 +1 @@ + xs, us, J_hist, L, l = ilqr(model, N, x0, n_iter=n_iter, use_linesearch=use_linesearch) \ No newline at end of file diff --git a/solutions/ex07/linearization_agent_TODO_1.py b/solutions/ex07/linearization_agent_TODO_1.py new file mode 100644 index 0000000..9a9c162 --- /dev/null +++ b/solutions/ex07/linearization_agent_TODO_1.py @@ -0,0 +1,4 @@ + xp = model.f(xbar, ubar, k=0) + A, B = model.f_jacobian(xbar, ubar, k=0) + + d = xp - A @ xbar - B @ ubar \ No newline at end of file diff --git a/solutions/ex07/linearization_agent_TODO_2.py b/solutions/ex07/linearization_agent_TODO_2.py new file mode 100644 index 0000000..f84fac4 --- /dev/null +++ b/solutions/ex07/linearization_agent_TODO_2.py @@ -0,0 +1 @@ + (self.L, self.l), (V, v, vc) = LQR(A=[A]*N, B=[B]*N, d=[d]*N, Q=[Q]*N, q=[q]*N, R=[self.model.cost.R]*N) \ No newline at end of file diff --git a/solutions/ex07/linearization_agent_TODO_3.py b/solutions/ex07/linearization_agent_TODO_3.py new file mode 100644 index 0000000..797bd93 --- /dev/null +++ b/solutions/ex07/linearization_agent_TODO_3.py @@ -0,0 +1 @@ + u = self.L[0] @ x + self.l[0] \ No newline at end of file diff --git a/solutions/ex08/bandits_TODO_1.py b/solutions/ex08/bandits_TODO_1.py new file mode 100644 index 0000000..f971a9c --- /dev/null +++ b/solutions/ex08/bandits_TODO_1.py @@ -0,0 +1,2 @@ + reward = self.q_star[a] + np.random.randn() + regret = self.q_star[self.optimal_action] - self.q_star[a] \ No newline at end of file diff --git a/solutions/ex08/gradient_agent_TODO_1.py b/solutions/ex08/gradient_agent_TODO_1.py new file mode 100644 index 0000000..2c166f9 --- /dev/null +++ b/solutions/ex08/gradient_agent_TODO_1.py @@ -0,0 +1,9 @@ + pi_a = self.Pa() + for b in range(self.k): + if b == a: + self.H[b] += self.alpha * (r - self.R_bar) * (1 - pi_a[b]) + else: + self.H[b] -= self.alpha * (r - self.R_bar) * pi_a[b] + + if self.baseline: + self.R_bar = self.R_bar + (self.alpha if self.alpha is not None else 1/(self.t+1)) * (r - self.R_bar) \ No newline at end of file diff --git a/solutions/ex08/grand_bandit_race_TODO_1.py b/solutions/ex08/grand_bandit_race_TODO_1.py new file mode 100644 index 0000000..06e8845 --- /dev/null +++ b/solutions/ex08/grand_bandit_race_TODO_1.py @@ -0,0 +1 @@ + bandit1 = StationaryBandit(k=10) \ No newline at end of file diff --git a/solutions/ex08/grand_bandit_race_TODO_2.py b/solutions/ex08/grand_bandit_race_TODO_2.py new file mode 100644 index 0000000..c9ffb8d --- /dev/null +++ b/solutions/ex08/grand_bandit_race_TODO_2.py @@ -0,0 +1,5 @@ + agents = [BasicAgent(bandit1, epsilon=epsilon)] + agents += [MovingAverageAgent(bandit1, epsilon=epsilon, alpha=alpha)] + agents += [GradientAgent(bandit1, alpha=alpha,use_baseline=False) ] + agents += [GradientAgent(bandit1, alpha=alpha,use_baseline=True) ] + agents += [UCBAgent(bandit1, c=2)] \ No newline at end of file diff --git a/solutions/ex08/grand_bandit_race_TODO_3.py b/solutions/ex08/grand_bandit_race_TODO_3.py new file mode 100644 index 0000000..807579c --- /dev/null +++ b/solutions/ex08/grand_bandit_race_TODO_3.py @@ -0,0 +1 @@ + eval_and_plot(bandit1, agents, max_episodes=2000, labels=labels) \ No newline at end of file diff --git a/solutions/ex08/grand_bandit_race_TODO_4.py b/solutions/ex08/grand_bandit_race_TODO_4.py new file mode 100644 index 0000000..3a9cb82 --- /dev/null +++ b/solutions/ex08/grand_bandit_race_TODO_4.py @@ -0,0 +1 @@ + bandit2 = StationaryBandit(k=10, q_star_mean=4) \ No newline at end of file diff --git a/solutions/ex08/grand_bandit_race_TODO_5.py b/solutions/ex08/grand_bandit_race_TODO_5.py new file mode 100644 index 0000000..1a6cfc7 --- /dev/null +++ b/solutions/ex08/grand_bandit_race_TODO_5.py @@ -0,0 +1 @@ + eval_and_plot(bandit2, agents, max_episodes=2000, labels=labels) \ No newline at end of file diff --git a/solutions/ex08/grand_bandit_race_TODO_6.py b/solutions/ex08/grand_bandit_race_TODO_6.py new file mode 100644 index 0000000..20c9ba0 --- /dev/null +++ b/solutions/ex08/grand_bandit_race_TODO_6.py @@ -0,0 +1 @@ + bandit3 = NonstationaryBandit(k=10) \ No newline at end of file diff --git a/solutions/ex08/grand_bandit_race_TODO_7.py b/solutions/ex08/grand_bandit_race_TODO_7.py new file mode 100644 index 0000000..a2a5676 --- /dev/null +++ b/solutions/ex08/grand_bandit_race_TODO_7.py @@ -0,0 +1 @@ + eval_and_plot(bandit3, agents, max_episodes=2000, steps=10000, labels=labels) \ No newline at end of file diff --git a/solutions/ex08/grand_bandit_race_TODO_8.py b/solutions/ex08/grand_bandit_race_TODO_8.py new file mode 100644 index 0000000..b34bc62 --- /dev/null +++ b/solutions/ex08/grand_bandit_race_TODO_8.py @@ -0,0 +1 @@ + eval_and_plot(bandit1, agents2, steps=10000, labels=labels) \ No newline at end of file diff --git a/solutions/ex08/nonstationary_TODO_1.py b/solutions/ex08/nonstationary_TODO_1.py new file mode 100644 index 0000000..e53da8b --- /dev/null +++ b/solutions/ex08/nonstationary_TODO_1.py @@ -0,0 +1,2 @@ + self.q_star += self.reward_change_std * np.random.randn(self.k) + self.optimal_action = np.argmax(self.q_star) \ No newline at end of file diff --git a/solutions/ex08/nonstationary_TODO_2.py b/solutions/ex08/nonstationary_TODO_2.py new file mode 100644 index 0000000..26dc95b --- /dev/null +++ b/solutions/ex08/nonstationary_TODO_2.py @@ -0,0 +1,2 @@ + self.alpha=alpha + super().__init__(env, epsilon=epsilon) \ No newline at end of file diff --git a/solutions/ex08/nonstationary_TODO_3.py b/solutions/ex08/nonstationary_TODO_3.py new file mode 100644 index 0000000..d45b3a0 --- /dev/null +++ b/solutions/ex08/nonstationary_TODO_3.py @@ -0,0 +1 @@ + self.Q[a] = self.Q[a] + self.alpha * (r-self.Q[a]) \ No newline at end of file diff --git a/solutions/ex08/nonstationary_TODO_4.py b/solutions/ex08/nonstationary_TODO_4.py new file mode 100644 index 0000000..e4ffd80 --- /dev/null +++ b/solutions/ex08/nonstationary_TODO_4.py @@ -0,0 +1,4 @@ + bandit = NonstationaryBandit(k=10) + + agents = [BasicAgent(bandit, epsilon=epsilon)] + agents += [MovingAverageAgent(bandit, epsilon=epsilon, alpha=alpha) for alpha in alphas] \ No newline at end of file diff --git a/solutions/ex08/nonstationary_TODO_5.py b/solutions/ex08/nonstationary_TODO_5.py new file mode 100644 index 0000000..9742313 --- /dev/null +++ b/solutions/ex08/nonstationary_TODO_5.py @@ -0,0 +1 @@ + labels += [f"Mov.avg. agent, epsilon={epsilon}, alpha={alpha}" for alpha in alphas] \ No newline at end of file diff --git a/solutions/ex08/simple_agents_TODO_1.py b/solutions/ex08/simple_agents_TODO_1.py new file mode 100644 index 0000000..5416e07 --- /dev/null +++ b/solutions/ex08/simple_agents_TODO_1.py @@ -0,0 +1,2 @@ + self.Q = np.zeros((self.k,)) + self.N = np.zeros((self.k,)) \ No newline at end of file diff --git a/solutions/ex08/simple_agents_TODO_2.py b/solutions/ex08/simple_agents_TODO_2.py new file mode 100644 index 0000000..d91b393 --- /dev/null +++ b/solutions/ex08/simple_agents_TODO_2.py @@ -0,0 +1 @@ + return np.random.randint(self.k) if np.random.rand() < self.epsilon else np.argmax(self.Q) \ No newline at end of file diff --git a/solutions/ex08/simple_agents_TODO_3.py b/solutions/ex08/simple_agents_TODO_3.py new file mode 100644 index 0000000..df218f0 --- /dev/null +++ b/solutions/ex08/simple_agents_TODO_3.py @@ -0,0 +1,2 @@ + self.N[a] = self.N[a] + 1 + self.Q[a] = self.Q[a] + 1/self.N[a] * (r-self.Q[a]) \ No newline at end of file diff --git a/solutions/ex08/ucb_agent_TODO_1.py b/solutions/ex08/ucb_agent_TODO_1.py new file mode 100644 index 0000000..4812f63 --- /dev/null +++ b/solutions/ex08/ucb_agent_TODO_1.py @@ -0,0 +1,2 @@ + self.N[a] += 1 + self.Q[a] += 1/self.N[a] * (r - self.Q[a]) \ No newline at end of file diff --git a/solutions/ex08/ucb_agent_TODO_2.py b/solutions/ex08/ucb_agent_TODO_2.py new file mode 100644 index 0000000..437563c --- /dev/null +++ b/solutions/ex08/ucb_agent_TODO_2.py @@ -0,0 +1,3 @@ + k = self.env.action_space.n + self.Q = np.zeros((k,)) + self.N = np.zeros((k,)) \ No newline at end of file diff --git a/solutions/ex08/ucb_agent_TODO_3.py b/solutions/ex08/ucb_agent_TODO_3.py new file mode 100644 index 0000000..5925504 --- /dev/null +++ b/solutions/ex08/ucb_agent_TODO_3.py @@ -0,0 +1 @@ + return np.argmax( self.Q + self.c * np.sqrt( np.log(k+1)/(self.N+1e-8) ) ) \ No newline at end of file diff --git a/solutions/ex09/gambler_TODO_1.py b/solutions/ex09/gambler_TODO_1.py new file mode 100644 index 0000000..5edd917 --- /dev/null +++ b/solutions/ex09/gambler_TODO_1.py @@ -0,0 +1 @@ + return state in [0, self.goal] \ No newline at end of file diff --git a/solutions/ex09/gambler_TODO_2.py b/solutions/ex09/gambler_TODO_2.py new file mode 100644 index 0000000..63c4cf7 --- /dev/null +++ b/solutions/ex09/gambler_TODO_2.py @@ -0,0 +1 @@ + return list( range(1, min(s, self.goal - s) + 1)) \ No newline at end of file diff --git a/solutions/ex09/gambler_TODO_3.py b/solutions/ex09/gambler_TODO_3.py new file mode 100644 index 0000000..b4e0a66 --- /dev/null +++ b/solutions/ex09/gambler_TODO_3.py @@ -0,0 +1,4 @@ + r = 1 if s + a == 100 else 0 + WIN = (s+a, r) + LOSS = (s-a, 0) + outcome_dict = {WIN: self.p_heads, LOSS: 1-self.p_heads } if WIN != LOSS else {WIN: 1.} \ No newline at end of file diff --git a/solutions/ex09/jacks_car_rental_TODO_1.py b/solutions/ex09/jacks_car_rental_TODO_1.py new file mode 100644 index 0000000..14da723 --- /dev/null +++ b/solutions/ex09/jacks_car_rental_TODO_1.py @@ -0,0 +1,3 @@ + max_from_1 = min([self.max_move,c1]) + max_to_1 = min([self.max_move,c2]) + a = [s for s in range(-max_to_1, max_from_1 + 1 )] \ No newline at end of file diff --git a/solutions/ex09/jacks_car_rental_TODO_2.py b/solutions/ex09/jacks_car_rental_TODO_2.py new file mode 100644 index 0000000..cf19c18 --- /dev/null +++ b/solutions/ex09/jacks_car_rental_TODO_2.py @@ -0,0 +1 @@ + s = (s[0]-a, s[1]+a) \ No newline at end of file diff --git a/solutions/ex09/jacks_car_rental_TODO_3.py b/solutions/ex09/jacks_car_rental_TODO_3.py new file mode 100644 index 0000000..097e196 --- /dev/null +++ b/solutions/ex09/jacks_car_rental_TODO_3.py @@ -0,0 +1 @@ + d[((c1, c2), reward_1 + reward_2 + abs(a)*self.move_cost) ] += pc1 * pc2 \ No newline at end of file diff --git a/solutions/ex09/mdp_warmup_TODO_1.py b/solutions/ex09/mdp_warmup_TODO_1.py new file mode 100644 index 0000000..b8ee7db --- /dev/null +++ b/solutions/ex09/mdp_warmup_TODO_1.py @@ -0,0 +1 @@ + q_dict = {a: sum([p*(r+ (gamma*v[sp] if not mdp.is_terminal(sp) else 0)) for (sp,r), p in mdp.Psr(s,a).items()]) for a in mdp.A(s)} \ No newline at end of file diff --git a/solutions/ex09/mdp_warmup_TODO_2.py b/solutions/ex09/mdp_warmup_TODO_2.py new file mode 100644 index 0000000..f605ec3 --- /dev/null +++ b/solutions/ex09/mdp_warmup_TODO_2.py @@ -0,0 +1 @@ + raise NotImplementedError("Insert your solution and remove this error.") \ No newline at end of file diff --git a/solutions/ex09/mdp_warmup_TODO_3.py b/solutions/ex09/mdp_warmup_TODO_3.py new file mode 100644 index 0000000..c8f9a46 --- /dev/null +++ b/solutions/ex09/mdp_warmup_TODO_3.py @@ -0,0 +1 @@ + expected_reward = sum( [r * p for (sp, r), p in mdp.Psr(s, a).items() ] ) \ No newline at end of file diff --git a/solutions/ex09/mdp_warmup_TODO_4.py b/solutions/ex09/mdp_warmup_TODO_4.py new file mode 100644 index 0000000..bb8d281 --- /dev/null +++ b/solutions/ex09/mdp_warmup_TODO_4.py @@ -0,0 +1 @@ + V_s = sum( [Q[s,a] * p for a, p in policy.items()] ) \ No newline at end of file diff --git a/solutions/ex09/policy_evaluation_TODO_1.py b/solutions/ex09/policy_evaluation_TODO_1.py new file mode 100644 index 0000000..290d5ab --- /dev/null +++ b/solutions/ex09/policy_evaluation_TODO_1.py @@ -0,0 +1,2 @@ + q = value_function2q_function(mdp, s, gamma, v) + v_, v[s] = v[s], sum( [q[a] * pi_a for a,pi_a in pi[s].items()] ) \ No newline at end of file diff --git a/solutions/ex09/policy_iteration_TODO_1.py b/solutions/ex09/policy_iteration_TODO_1.py new file mode 100644 index 0000000..00c8a95 --- /dev/null +++ b/solutions/ex09/policy_iteration_TODO_1.py @@ -0,0 +1,6 @@ + for s in [mdp.nonterminal_states[i] for i in np.random.permutation(len(mdp.nonterminal_states))]: + old_a = pi[s] # The best action we would take under the current policy + Qs = value_function2q_function(mdp, s, gamma, V) + pi[s] = max(Qs, key=Qs.get) + if old_a != pi[s]: + policy_stable = False \ No newline at end of file diff --git a/solutions/ex09/value_iteration_TODO_1.py b/solutions/ex09/value_iteration_TODO_1.py new file mode 100644 index 0000000..d07abe4 --- /dev/null +++ b/solutions/ex09/value_iteration_TODO_1.py @@ -0,0 +1,2 @@ + v, V[s] = V[s], max(value_function2q_function(mdp, s, gamma, V).values()) if len(mdp.A(s)) > 0 else 0 + Delta = max(Delta, np.abs(v - V[s])) \ No newline at end of file diff --git a/solutions/ex09/value_iteration_TODO_2.py b/solutions/ex09/value_iteration_TODO_2.py new file mode 100644 index 0000000..89339fe --- /dev/null +++ b/solutions/ex09/value_iteration_TODO_2.py @@ -0,0 +1,2 @@ + Q = {a: v-(1e-8*a if isinstance(a, int) else 0) for a,v in value_function2q_function(mdp, s, gamma, V).items()} + pi[s] = max(Q, key=Q.get) \ No newline at end of file diff --git a/solutions/ex09/value_iteration_agent_TODO_1.py b/solutions/ex09/value_iteration_agent_TODO_1.py new file mode 100644 index 0000000..4909072 --- /dev/null +++ b/solutions/ex09/value_iteration_agent_TODO_1.py @@ -0,0 +1 @@ + self.policy, self.v = value_iteration(mdp, gamma=gamma, **kwargs) \ No newline at end of file diff --git a/solutions/ex09/value_iteration_agent_TODO_2.py b/solutions/ex09/value_iteration_agent_TODO_2.py new file mode 100644 index 0000000..5a41f14 --- /dev/null +++ b/solutions/ex09/value_iteration_agent_TODO_2.py @@ -0,0 +1 @@ + action = self.policy[s] \ No newline at end of file diff --git a/solutions/ex10/mc_agent_TODO_1.py b/solutions/ex10/mc_agent_TODO_1.py new file mode 100644 index 0000000..ae75aad --- /dev/null +++ b/solutions/ex10/mc_agent_TODO_1.py @@ -0,0 +1,2 @@ + G = gamma * G + episode[t][2] + sa_t = episode[t][:2] \ No newline at end of file diff --git a/solutions/ex10/mc_agent_TODO_2.py b/solutions/ex10/mc_agent_TODO_2.py new file mode 100644 index 0000000..0c62b90 --- /dev/null +++ b/solutions/ex10/mc_agent_TODO_2.py @@ -0,0 +1 @@ + returns.append( sa_t + (G,) ) \ No newline at end of file diff --git a/solutions/ex10/mc_agent_TODO_3.py b/solutions/ex10/mc_agent_TODO_3.py new file mode 100644 index 0000000..dd67432 --- /dev/null +++ b/solutions/ex10/mc_agent_TODO_3.py @@ -0,0 +1 @@ + return self.pi_eps(s, info) \ No newline at end of file diff --git a/solutions/ex10/mc_agent_TODO_4.py b/solutions/ex10/mc_agent_TODO_4.py new file mode 100644 index 0000000..a910769 --- /dev/null +++ b/solutions/ex10/mc_agent_TODO_4.py @@ -0,0 +1,12 @@ + self.episode.append((s, a, r)) + if done: + returns = get_MC_return_SA(self.episode, self.gamma, self.first_visit) + for s, a, G in returns: + # s,a = sa + if self.alpha is None: + self.returns_sum[s, a] += G + self.returns_count[s, a] += 1 + self.Q[s, a] = self.returns_sum[s, a] / self.returns_count[s, a] + else: + self.Q[s, a] += self.alpha * (G - self.Q[s, a]) + self.episode = [] \ No newline at end of file diff --git a/solutions/ex10/mc_agent_blackjack_TODO_1.py b/solutions/ex10/mc_agent_blackjack_TODO_1.py new file mode 100644 index 0000000..7d71b63 --- /dev/null +++ b/solutions/ex10/mc_agent_blackjack_TODO_1.py @@ -0,0 +1 @@ + train(env, agent, expn, num_episodes=episodes, return_trajectory=False) \ No newline at end of file diff --git a/solutions/ex10/mc_evaluate_TODO_1.py b/solutions/ex10/mc_evaluate_TODO_1.py new file mode 100644 index 0000000..a4192ab --- /dev/null +++ b/solutions/ex10/mc_evaluate_TODO_1.py @@ -0,0 +1,2 @@ + G = gamma * G + episode[t][2] + s_t = episode[t][0] \ No newline at end of file diff --git a/solutions/ex10/mc_evaluate_TODO_2.py b/solutions/ex10/mc_evaluate_TODO_2.py new file mode 100644 index 0000000..d653590 --- /dev/null +++ b/solutions/ex10/mc_evaluate_TODO_2.py @@ -0,0 +1 @@ + returns.append((s_t, G)) \ No newline at end of file diff --git a/solutions/ex10/mc_evaluate_TODO_3.py b/solutions/ex10/mc_evaluate_TODO_3.py new file mode 100644 index 0000000..9f00d39 --- /dev/null +++ b/solutions/ex10/mc_evaluate_TODO_3.py @@ -0,0 +1 @@ + self.v[s] = self.v[s] + self.alpha * (G - self.v[s]) \ No newline at end of file diff --git a/solutions/ex10/mc_evaluate_TODO_4.py b/solutions/ex10/mc_evaluate_TODO_4.py new file mode 100644 index 0000000..587cd32 --- /dev/null +++ b/solutions/ex10/mc_evaluate_TODO_4.py @@ -0,0 +1,3 @@ + self.returns_sum_S[s] += G + self.returns_count_N[s] += 1.0 + self.v[s] = self.returns_sum_S[s] / self.returns_count_N[s] \ No newline at end of file diff --git a/solutions/ex10/mc_evaluate_TODO_5.py b/solutions/ex10/mc_evaluate_TODO_5.py new file mode 100644 index 0000000..8512763 --- /dev/null +++ b/solutions/ex10/mc_evaluate_TODO_5.py @@ -0,0 +1 @@ + agent_every = MCEvaluationAgent(env, gamma=gamma, first_visit=False) \ No newline at end of file diff --git a/solutions/ex10/mc_evaluate_TODO_6.py b/solutions/ex10/mc_evaluate_TODO_6.py new file mode 100644 index 0000000..67af451 --- /dev/null +++ b/solutions/ex10/mc_evaluate_TODO_6.py @@ -0,0 +1 @@ + train(env, agent_every, num_episodes=episodes, verbose=False) \ No newline at end of file diff --git a/solutions/ex10/mc_evaluate_blackjack_TODO_1.py b/solutions/ex10/mc_evaluate_blackjack_TODO_1.py new file mode 100644 index 0000000..ddcf6a0 --- /dev/null +++ b/solutions/ex10/mc_evaluate_blackjack_TODO_1.py @@ -0,0 +1 @@ + return 0 if s[0] >= 20 else 1 \ No newline at end of file diff --git a/solutions/ex10/mc_evaluate_blackjack_TODO_2.py b/solutions/ex10/mc_evaluate_blackjack_TODO_2.py new file mode 100644 index 0000000..6918a6d --- /dev/null +++ b/solutions/ex10/mc_evaluate_blackjack_TODO_2.py @@ -0,0 +1,2 @@ + agent = MCEvaluationAgent(env, policy=policy20, gamma=1) + train(env, agent, experiment_name=experiment, num_episodes=episodes) \ No newline at end of file diff --git a/solutions/ex10/question_td0_TODO_1.py b/solutions/ex10/question_td0_TODO_1.py new file mode 100644 index 0000000..05e6e86 --- /dev/null +++ b/solutions/ex10/question_td0_TODO_1.py @@ -0,0 +1,5 @@ + deltas = [] + for t, (s, r) in enumerate(zip(states[:-1], rewards)): + sp = states[t + 1] + delta = (r + gamma * v[sp]) - v[s] + deltas.append(delta) \ No newline at end of file diff --git a/solutions/ex10/question_td0_TODO_2.py b/solutions/ex10/question_td0_TODO_2.py new file mode 100644 index 0000000..a32f983 --- /dev/null +++ b/solutions/ex10/question_td0_TODO_2.py @@ -0,0 +1,6 @@ + for t in range(len(rewards)): + s = states[t] + sp = states[t + 1] + r = rewards[t] + delta = r + gamma * v[sp] - v[s] + v[s] = v[s] + alpha * delta \ No newline at end of file diff --git a/solutions/ex10/question_td0_TODO_3.py b/solutions/ex10/question_td0_TODO_3.py new file mode 100644 index 0000000..bceb638 --- /dev/null +++ b/solutions/ex10/question_td0_TODO_3.py @@ -0,0 +1,4 @@ + deltas = a_compute_deltas(v, states, rewards, gamma) + for t in range(len(rewards)): + s = states[t] + v[s] = v[s] + alpha * deltas[t] \ No newline at end of file diff --git a/solutions/ex10/random_walk_example_TODO_1.py b/solutions/ex10/random_walk_example_TODO_1.py new file mode 100644 index 0000000..e0f1b99 --- /dev/null +++ b/solutions/ex10/random_walk_example_TODO_1.py @@ -0,0 +1 @@ + sp = s+(2*a-1) \ No newline at end of file diff --git a/solutions/ex10/td0_evaluate_TODO_1.py b/solutions/ex10/td0_evaluate_TODO_1.py new file mode 100644 index 0000000..6953d59 --- /dev/null +++ b/solutions/ex10/td0_evaluate_TODO_1.py @@ -0,0 +1,3 @@ + if isinstance(s, np.ndarray): + print("Bad type.") + self.v[s] += self.alpha * (r + self.gamma * (self.v[sp] if not done else 0) - self.v[s]) \ No newline at end of file diff --git a/solutions/ex11/nstep_sarsa_agent_TODO_1.py b/solutions/ex11/nstep_sarsa_agent_TODO_1.py new file mode 100644 index 0000000..388556a --- /dev/null +++ b/solutions/ex11/nstep_sarsa_agent_TODO_1.py @@ -0,0 +1,4 @@ + G = sum([self.gamma**(i-tau-1)*self.R[i%(n+1)] for i in range(tau+1, min(tau+n, T)+1)]) + S_tau_n, A_tau_n = self.S[(tau+n)%(n+1)], self.A[(tau+n)%(n+1)] + if tau+n < T: + G += self.gamma**n * self._q(S_tau_n, A_tau_n) \ No newline at end of file diff --git a/solutions/ex11/q_agent_TODO_1.py b/solutions/ex11/q_agent_TODO_1.py new file mode 100644 index 0000000..15b029e --- /dev/null +++ b/solutions/ex11/q_agent_TODO_1.py @@ -0,0 +1 @@ + action = self.pi_eps(s, info=info) \ No newline at end of file diff --git a/solutions/ex11/q_agent_TODO_2.py b/solutions/ex11/q_agent_TODO_2.py new file mode 100644 index 0000000..b110916 --- /dev/null +++ b/solutions/ex11/q_agent_TODO_2.py @@ -0,0 +1,3 @@ + if not done: + a_star = self.Q.get_optimal_action(sp, info_sp) + self.Q[s,a] += self.alpha * (r + self.gamma * (0 if done else self.Q[sp,a_star]) - self.Q[s,a]) \ No newline at end of file diff --git a/solutions/ex11/sarsa_agent_TODO_1.py b/solutions/ex11/sarsa_agent_TODO_1.py new file mode 100644 index 0000000..5cabe83 --- /dev/null +++ b/solutions/ex11/sarsa_agent_TODO_1.py @@ -0,0 +1 @@ + return self.pi_eps(s, info) \ No newline at end of file diff --git a/solutions/ex11/sarsa_agent_TODO_2.py b/solutions/ex11/sarsa_agent_TODO_2.py new file mode 100644 index 0000000..3a8a80c --- /dev/null +++ b/solutions/ex11/sarsa_agent_TODO_2.py @@ -0,0 +1 @@ + return self.a \ No newline at end of file diff --git a/solutions/ex11/sarsa_agent_TODO_3.py b/solutions/ex11/sarsa_agent_TODO_3.py new file mode 100644 index 0000000..5c6eb60 --- /dev/null +++ b/solutions/ex11/sarsa_agent_TODO_3.py @@ -0,0 +1 @@ + self.a = self.pi_eps(sp, info_sp) if not done else -1 \ No newline at end of file diff --git a/solutions/ex11/sarsa_agent_TODO_4.py b/solutions/ex11/sarsa_agent_TODO_4.py new file mode 100644 index 0000000..cecfe59 --- /dev/null +++ b/solutions/ex11/sarsa_agent_TODO_4.py @@ -0,0 +1,2 @@ + delta = r + (self.gamma * self.Q[sp,self.a] if not done else 0) - self.Q[s,a] + self.Q[s,a] += self.alpha * delta \ No newline at end of file diff --git a/solutions/ex11/semi_grad_q_TODO_1.py b/solutions/ex11/semi_grad_q_TODO_1.py new file mode 100644 index 0000000..1da3194 --- /dev/null +++ b/solutions/ex11/semi_grad_q_TODO_1.py @@ -0,0 +1,4 @@ + if not done: + a_star = self.Q.get_optimal_action(sp, info_sp) + td_delta = r + (0 if done else self.gamma * self.Q(sp, a_star)) - self.Q(s, a) + self.Q.w += self.alpha * td_delta * self.Q.x(s, a) \ No newline at end of file diff --git a/solutions/ex11/semi_grad_sarsa_TODO_1.py b/solutions/ex11/semi_grad_sarsa_TODO_1.py new file mode 100644 index 0000000..4cc4b80 --- /dev/null +++ b/solutions/ex11/semi_grad_sarsa_TODO_1.py @@ -0,0 +1 @@ + action = self.a if k > 0 else super().pi(s, k, info) \ No newline at end of file diff --git a/solutions/ex11/semi_grad_sarsa_TODO_2.py b/solutions/ex11/semi_grad_sarsa_TODO_2.py new file mode 100644 index 0000000..0690b1e --- /dev/null +++ b/solutions/ex11/semi_grad_sarsa_TODO_2.py @@ -0,0 +1,4 @@ + a_prime = super().pi(sp, k=0, info=info_sp) + delta = r + (0 if done else self.gamma * self.Q(sp, a_prime)) - self.Q(s, a) + self.Q.w += self.alpha * delta * self.Q.x(s,a) + self.a = a_prime \ No newline at end of file diff --git a/solutions/ex12/minigrid_wrappers_TODO_1.py b/solutions/ex12/minigrid_wrappers_TODO_1.py new file mode 100644 index 0000000..8f71903 --- /dev/null +++ b/solutions/ex12/minigrid_wrappers_TODO_1.py @@ -0,0 +1 @@ + box.high[:, :, i] = nbounds[i] \ No newline at end of file diff --git a/solutions/ex12/minigrid_wrappers_TODO_2.py b/solutions/ex12/minigrid_wrappers_TODO_2.py new file mode 100644 index 0000000..1607b9a --- /dev/null +++ b/solutions/ex12/minigrid_wrappers_TODO_2.py @@ -0,0 +1,2 @@ + box.high = box.high[:,:,dims] + box.low = box.low[:,:,dims] \ No newline at end of file diff --git a/solutions/ex12/minigrid_wrappers_TODO_3.py b/solutions/ex12/minigrid_wrappers_TODO_3.py new file mode 100644 index 0000000..d967cd1 --- /dev/null +++ b/solutions/ex12/minigrid_wrappers_TODO_3.py @@ -0,0 +1 @@ + x = obs['image'][:, :, self.dims] \ No newline at end of file diff --git a/solutions/ex12/minigrid_wrappers_TODO_4.py b/solutions/ex12/minigrid_wrappers_TODO_4.py new file mode 100644 index 0000000..bd9020d --- /dev/null +++ b/solutions/ex12/minigrid_wrappers_TODO_4.py @@ -0,0 +1 @@ + return tuple( obs['image'].flat ) \ No newline at end of file diff --git a/solutions/ex12/mountain_car_TODO_1.py b/solutions/ex12/mountain_car_TODO_1.py new file mode 100644 index 0000000..baeb97c --- /dev/null +++ b/solutions/ex12/mountain_car_TODO_1.py @@ -0,0 +1,16 @@ + for i, alpha in enumerate(alphas): + n = n_steps[i] + agent = LinearSemiGradSarsaN(env, gamma=1, alpha=alpha / num_of_tilings, epsilon=0, n=n) + experiment = f"experiments/mountaincar_10-2_{agent}_{episodes}" + train(env, agent, experiment_name=experiment, num_episodes=episodes, max_runs=max_runs) + experiments.append(experiment) + + agent = LinearSemiGradSarsaLambda(env, gamma=1, alpha=alphas[1]/num_of_tilings, epsilon=0, lamb=0.9) + experiment = f"experiments/mountaincar_10-2_{agent}_{episodes}" + train(env, agent, experiment_name=experiment, num_episodes=episodes, max_runs=max_runs) + experiments.append(experiment) + + agent = LinearSemiGradQAgent(env, gamma=1, alpha=alphas[1] / num_of_tilings, epsilon=0) + experiment = f"experiments/mountaincar_10-2_{agent}_{episodes}" + train(env, agent, experiment_name=experiment, num_episodes=episodes, max_runs=max_runs) + experiments.append(experiment) \ No newline at end of file diff --git a/solutions/ex12/sarsa_lambda_agent_TODO_1.py b/solutions/ex12/sarsa_lambda_agent_TODO_1.py new file mode 100644 index 0000000..5723174 --- /dev/null +++ b/solutions/ex12/sarsa_lambda_agent_TODO_1.py @@ -0,0 +1 @@ + a_prime = self.pi_eps(sp, info_sp) if not done else -1 \ No newline at end of file diff --git a/solutions/ex12/sarsa_lambda_agent_TODO_2.py b/solutions/ex12/sarsa_lambda_agent_TODO_2.py new file mode 100644 index 0000000..13d29a2 --- /dev/null +++ b/solutions/ex12/sarsa_lambda_agent_TODO_2.py @@ -0,0 +1 @@ + delta = r + self.gamma * (self.Q[sp,a_prime] if not done else 0) - self.Q[s,a] \ No newline at end of file diff --git a/solutions/ex12/sarsa_lambda_agent_TODO_3.py b/solutions/ex12/sarsa_lambda_agent_TODO_3.py new file mode 100644 index 0000000..5c85d46 --- /dev/null +++ b/solutions/ex12/sarsa_lambda_agent_TODO_3.py @@ -0,0 +1 @@ + self.e[(s,a)] += 1 \ No newline at end of file diff --git a/solutions/ex12/sarsa_lambda_agent_TODO_4.py b/solutions/ex12/sarsa_lambda_agent_TODO_4.py new file mode 100644 index 0000000..e36f863 --- /dev/null +++ b/solutions/ex12/sarsa_lambda_agent_TODO_4.py @@ -0,0 +1,2 @@ + self.Q[s,a] += self.alpha * delta * ee + self.e[(s,a)] = self.gamma * self.lamb * ee \ No newline at end of file diff --git a/solutions/ex12/semi_grad_nstep_sarsa_TODO_1.py b/solutions/ex12/semi_grad_nstep_sarsa_TODO_1.py new file mode 100644 index 0000000..290a33b --- /dev/null +++ b/solutions/ex12/semi_grad_nstep_sarsa_TODO_1.py @@ -0,0 +1 @@ + return self.Q(s, a) \ No newline at end of file diff --git a/solutions/ex12/semi_grad_nstep_sarsa_TODO_2.py b/solutions/ex12/semi_grad_nstep_sarsa_TODO_2.py new file mode 100644 index 0000000..89368e6 --- /dev/null +++ b/solutions/ex12/semi_grad_nstep_sarsa_TODO_2.py @@ -0,0 +1 @@ + self.Q.w += self.alpha * delta * self.Q.x(s,a) # Update q(s,a)/weights given change in q-values: delta = [G-\hat{q}(..)] \ No newline at end of file diff --git a/solutions/ex12/semi_grad_sarsa_lambda_TODO_1.py b/solutions/ex12/semi_grad_sarsa_lambda_TODO_1.py new file mode 100644 index 0000000..1fa61eb --- /dev/null +++ b/solutions/ex12/semi_grad_sarsa_lambda_TODO_1.py @@ -0,0 +1,5 @@ + Q = self.Q.w @ self.x + Q_prime = self.Q.w @ x_prime if not done else None + delta = r + (self.gamma * Q_prime if not done else 0) - Q + self.z = self.gamma * self.lamb * self.z + (1-self.alpha * self.gamma * self.lamb *self.z @ self.x) * self.x + self.Q.w += self.alpha * (delta + Q - self.Q_old) * self.z - self.alpha * (Q-self.Q_old) * self.x \ No newline at end of file diff --git a/solutions/ex13/deepq_agent_TODO_1.py b/solutions/ex13/deepq_agent_TODO_1.py new file mode 100644 index 0000000..824ede3 --- /dev/null +++ b/solutions/ex13/deepq_agent_TODO_1.py @@ -0,0 +1,3 @@ + y = r[:,0] + self.gamma * np.max(self.Q(sp), axis=1) * (1-done) + target = self.Q(s) + target[range(len(a)), a] = y \ No newline at end of file diff --git a/solutions/ex13/double_deepq_agent_TODO_1.py b/solutions/ex13/double_deepq_agent_TODO_1.py new file mode 100644 index 0000000..be47b43 --- /dev/null +++ b/solutions/ex13/double_deepq_agent_TODO_1.py @@ -0,0 +1 @@ + self.target.update_Phi(self.Q, tau=self.tau) \ No newline at end of file diff --git a/solutions/ex13/double_deepq_agent_TODO_2.py b/solutions/ex13/double_deepq_agent_TODO_2.py new file mode 100644 index 0000000..3edd701 --- /dev/null +++ b/solutions/ex13/double_deepq_agent_TODO_2.py @@ -0,0 +1,5 @@ + sp[done, :] = 0 + astar = np.argmax(self.Q(sp), axis=1) * (1-np.asarray(done)) + y = r[:,0] + self.gamma * self.target(sp)[range(len(sp)), astar] * (1 - done) + target = self.Q(s) + target[range(len(a)), a] = y \ No newline at end of file diff --git a/solutions/ex13/dyna_q_TODO_1.py b/solutions/ex13/dyna_q_TODO_1.py new file mode 100644 index 0000000..c7bd2b6 --- /dev/null +++ b/solutions/ex13/dyna_q_TODO_1.py @@ -0,0 +1 @@ + self.Q[s,a] += self.alpha * (r + (self.gamma * self.Q[sp, self.Q.get_optimal_action(sp, info_sp)] if not done else 0) - self.Q[s,a]) \ No newline at end of file diff --git a/solutions/ex13/dyna_q_TODO_2.py b/solutions/ex13/dyna_q_TODO_2.py new file mode 100644 index 0000000..46704a9 --- /dev/null +++ b/solutions/ex13/dyna_q_TODO_2.py @@ -0,0 +1,2 @@ + s_, a_, r_, sp_,done_ = self.Model[np.random.randint(len(self.Model))] + self.q_update(s_,a_,r_,sp_,done_, info_s, info_sp) \ No newline at end of file diff --git a/solutions/ex13/dyna_q_TODO_3.py b/solutions/ex13/dyna_q_TODO_3.py new file mode 100644 index 0000000..0495ae6 --- /dev/null +++ b/solutions/ex13/dyna_q_TODO_3.py @@ -0,0 +1 @@ + experiments = dyna_experiment(env, env_name='cliff',num_episodes=200,epsilon=epsilon, alpha=alpha, gamma=gamma, runs=4) \ No newline at end of file diff --git a/solutions/ex13/keras_networks_TODO_1.py b/solutions/ex13/keras_networks_TODO_1.py new file mode 100644 index 0000000..3f6fcaa --- /dev/null +++ b/solutions/ex13/keras_networks_TODO_1.py @@ -0,0 +1,6 @@ + adv_dense = layers.Dense(hidden_size, activation='relu', kernel_initializer=init())(dense2) + adv_out = layers.Dense(num_actions, kernel_initializer=init())(adv_dense) + v_dense = layers.Dense(hidden_size, activation='relu', kernel_initializer=init())(dense2) + v_out = layers.Dense(1, kernel_initializer=init())(v_dense) + norm_adv = layers.Lambda(lambda x: x - tf.reduce_mean(x))(adv_out) + combine = layers.add([v_out, norm_adv]) \ No newline at end of file diff --git a/solutions/ex13/maximization_bias_environment_TODO_1.py b/solutions/ex13/maximization_bias_environment_TODO_1.py new file mode 100644 index 0000000..3f2bdf7 --- /dev/null +++ b/solutions/ex13/maximization_bias_environment_TODO_1.py @@ -0,0 +1 @@ + return {(t, 0): 1} \ No newline at end of file diff --git a/solutions/ex13/maximization_bias_environment_TODO_2.py b/solutions/ex13/maximization_bias_environment_TODO_2.py new file mode 100644 index 0000000..ea4a34e --- /dev/null +++ b/solutions/ex13/maximization_bias_environment_TODO_2.py @@ -0,0 +1 @@ + return {(self.state_B, 0): 1} \ No newline at end of file diff --git a/solutions/ex13/tabular_double_q_TODO_1.py b/solutions/ex13/tabular_double_q_TODO_1.py new file mode 100644 index 0000000..1320700 --- /dev/null +++ b/solutions/ex13/tabular_double_q_TODO_1.py @@ -0,0 +1 @@ + return Agent.pi(self, s, k, info) if np.random.rand() < self.epsilon else a1[np.argmax(Q + np.random.rand(len(Q)) * 1e-8)] \ No newline at end of file diff --git a/solutions/ex13/tabular_double_q_TODO_2.py b/solutions/ex13/tabular_double_q_TODO_2.py new file mode 100644 index 0000000..b9f397f --- /dev/null +++ b/solutions/ex13/tabular_double_q_TODO_2.py @@ -0,0 +1,4 @@ + def train_(Q1,Q2, s, a, r, sp, done=False): + Q1[s,a] += self.alpha * (r + (self.gamma * Q2[sp,Q1.get_optimal_action(sp, info_sp)] if not done else 0) - Q1[s,a] ) + + train_(self.Q1, self.Q2, s, a, r, sp,done) if np.random.rand() < 0.5 else train_(self.Q2, self.Q1, s, a, r, sp,done) \ No newline at end of file diff --git a/solutions/ex13/torch_networks_TODO_1.py b/solutions/ex13/torch_networks_TODO_1.py new file mode 100644 index 0000000..1ab89a8 --- /dev/null +++ b/solutions/ex13/torch_networks_TODO_1.py @@ -0,0 +1,4 @@ + s = Variable(torch.FloatTensor(s)) + x = self.feature(s) + advantage = self.advantage(x) + value = self.value(x) \ No newline at end of file -- GitLab