gr-libs 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. evaluation/analyze_results_cross_alg_cross_domain.py +277 -0
  2. evaluation/create_minigrid_map_image.py +34 -0
  3. evaluation/file_system.py +42 -0
  4. evaluation/generate_experiments_results.py +92 -0
  5. evaluation/generate_experiments_results_new_ver1.py +254 -0
  6. evaluation/generate_experiments_results_new_ver2.py +331 -0
  7. evaluation/generate_task_specific_statistics_plots.py +272 -0
  8. evaluation/get_plans_images.py +47 -0
  9. evaluation/increasing_and_decreasing_.py +63 -0
  10. gr_libs/__init__.py +2 -0
  11. gr_libs/environment/__init__.py +0 -0
  12. gr_libs/environment/environment.py +227 -0
  13. gr_libs/environment/utils/__init__.py +0 -0
  14. gr_libs/environment/utils/utils.py +17 -0
  15. gr_libs/metrics/__init__.py +0 -0
  16. gr_libs/metrics/metrics.py +224 -0
  17. gr_libs/ml/__init__.py +6 -0
  18. gr_libs/ml/agent.py +56 -0
  19. gr_libs/ml/base/__init__.py +1 -0
  20. gr_libs/ml/base/rl_agent.py +54 -0
  21. gr_libs/ml/consts.py +22 -0
  22. gr_libs/ml/neural/__init__.py +3 -0
  23. gr_libs/ml/neural/deep_rl_learner.py +395 -0
  24. gr_libs/ml/neural/utils/__init__.py +2 -0
  25. gr_libs/ml/neural/utils/dictlist.py +33 -0
  26. gr_libs/ml/neural/utils/penv.py +57 -0
  27. gr_libs/ml/planner/__init__.py +0 -0
  28. gr_libs/ml/planner/mcts/__init__.py +0 -0
  29. gr_libs/ml/planner/mcts/mcts_model.py +330 -0
  30. gr_libs/ml/planner/mcts/utils/__init__.py +2 -0
  31. gr_libs/ml/planner/mcts/utils/node.py +33 -0
  32. gr_libs/ml/planner/mcts/utils/tree.py +102 -0
  33. gr_libs/ml/sequential/__init__.py +1 -0
  34. gr_libs/ml/sequential/lstm_model.py +192 -0
  35. gr_libs/ml/tabular/__init__.py +3 -0
  36. gr_libs/ml/tabular/state.py +21 -0
  37. gr_libs/ml/tabular/tabular_q_learner.py +453 -0
  38. gr_libs/ml/tabular/tabular_rl_agent.py +126 -0
  39. gr_libs/ml/utils/__init__.py +6 -0
  40. gr_libs/ml/utils/env.py +7 -0
  41. gr_libs/ml/utils/format.py +100 -0
  42. gr_libs/ml/utils/math.py +13 -0
  43. gr_libs/ml/utils/other.py +24 -0
  44. gr_libs/ml/utils/storage.py +127 -0
  45. gr_libs/recognizer/__init__.py +0 -0
  46. gr_libs/recognizer/gr_as_rl/__init__.py +0 -0
  47. gr_libs/recognizer/gr_as_rl/gr_as_rl_recognizer.py +102 -0
  48. gr_libs/recognizer/graml/__init__.py +0 -0
  49. gr_libs/recognizer/graml/gr_dataset.py +134 -0
  50. gr_libs/recognizer/graml/graml_recognizer.py +266 -0
  51. gr_libs/recognizer/recognizer.py +46 -0
  52. gr_libs/recognizer/utils/__init__.py +1 -0
  53. gr_libs/recognizer/utils/format.py +13 -0
  54. gr_libs-0.1.3.dist-info/METADATA +197 -0
  55. gr_libs-0.1.3.dist-info/RECORD +62 -0
  56. gr_libs-0.1.3.dist-info/WHEEL +5 -0
  57. gr_libs-0.1.3.dist-info/top_level.txt +3 -0
  58. tutorials/graml_minigrid_tutorial.py +30 -0
  59. tutorials/graml_panda_tutorial.py +32 -0
  60. tutorials/graml_parking_tutorial.py +38 -0
  61. tutorials/graml_point_maze_tutorial.py +43 -0
  62. tutorials/graql_minigrid_tutorial.py +29 -0
@@ -0,0 +1,272 @@
1
+ import argparse
2
+ import sys
3
+ import matplotlib.pyplot as plt
4
+ import numpy as np
5
+ import os
6
+ import ast
7
+ import inspect
8
+ import torch
9
+ import dill
10
+
11
+ from gr_libs.ml.utils import get_embeddings_result_path
12
+ from gr_libs.ml.utils.storage import get_experiment_results_path, set_global_storage_configs, get_graql_experiment_confidence_path
13
+ from gr_libs.metrics.metrics import measure_average_sequence_distance
14
+
15
+ def get_tasks_embeddings_dir_path(env_name):
16
+ return os.path.join("../gr_libs", get_embeddings_result_path(env_name))
17
+
18
+ def get_figures_dir_path(domain_name, env_name):
19
+ return os.path.join("../gr_libs", "figures", domain_name, env_name)
20
+
21
+ def similarities_vector_to_std_deviation_units_vector(ref_dict: dict, relative_to_largest):
22
+ """
23
+ Calculate the number of standard deviation units every other element is
24
+ from the largest/smallest element in the vector.
25
+
26
+ Parameters:
27
+ - vector: list or numpy array of numbers.
28
+ - relative_to_largest: boolean, if True, measure in relation to the largest element,
29
+ if False, measure in relation to the smallest element.
30
+
31
+ Returns:
32
+ - List of number of standard deviation units for each element in the vector.
33
+ """
34
+ vector = np.array(list(ref_dict.values()))
35
+ mean = np.mean(vector) # for the future maybe another method for measurement
36
+ std_dev = np.std(vector)
37
+
38
+ # Determine the reference element (largest or smallest)
39
+ if relative_to_largest:
40
+ reference_value = np.max(vector)
41
+ else:
42
+ reference_value = np.min(vector)
43
+ for goal, value in ref_dict.items():
44
+ ref_dict[goal] = abs(value - reference_value) / std_dev
45
+ return ref_dict
46
+
47
+ def analyze_and_produce_plots(recognizer_type: str, domain_name: str, env_name: str, fragmented_status: str, inf_same_length_status: str, learn_same_length_status: str):
48
+ if recognizer_type == "graml":
49
+ assert os.path.exists(get_embeddings_result_path(domain_name)), "Embeddings weren't made for this environment, run graml_main.py with this environment first."
50
+ tasks_embedding_dicts = {}
51
+ tasks_plans_dict = {}
52
+ goals_similarity_dict = {}
53
+ plans_similarity_dict = {}
54
+
55
+ embeddings_dir_path = get_tasks_embeddings_dir_path(domain_name)
56
+ for embeddings_file_name in [filename for filename in os.listdir(embeddings_dir_path) if 'embeddings' in filename]:
57
+ with open(os.path.join(embeddings_dir_path, embeddings_file_name), 'rb') as emb_file:
58
+ splitted_name = embeddings_file_name.split('_')
59
+ goal, percentage = splitted_name[0], splitted_name[1]
60
+ with open(os.path.join(embeddings_dir_path, f'{goal}_{percentage}_plans_dict.pkl'), 'rb') as plan_file:
61
+ tasks_plans_dict[f"{goal}_{percentage}"] = dill.load(plan_file)
62
+ tasks_embedding_dicts[f"{goal}_{percentage}"] = dill.load(emb_file)
63
+
64
+ for goal_percentage, embedding_dict in tasks_embedding_dicts.items():
65
+ goal, percentage = goal_percentage.split('_')
66
+ similarities = {dynamic_goal: [] for dynamic_goal in embedding_dict.keys() if 'true' not in dynamic_goal}
67
+ real_goal_embedding = embedding_dict[f"{goal}_true"]
68
+ for dynamic_goal, goal_embedding in embedding_dict.items():
69
+ if 'true' in dynamic_goal: continue
70
+ curr_similarity = torch.exp(-torch.sum(torch.abs(goal_embedding-real_goal_embedding)))
71
+ similarities[dynamic_goal] = curr_similarity.item()
72
+ if goal not in goals_similarity_dict.keys(): goals_similarity_dict[goal] = {}
73
+ goals_similarity_dict[goal][percentage] = similarities_vector_to_std_deviation_units_vector(ref_dict=similarities, relative_to_largest=True)
74
+
75
+ for goal_percentage, plans_dict in tasks_plans_dict.items():
76
+ goal, percentage = goal_percentage.split('_')
77
+ real_plan = plans_dict[f"{goal}_true"]
78
+ sequence_similarities = {d_goal:measure_average_sequence_distance(real_plan, plan) for d_goal,plan in plans_dict.items() if 'true' not in d_goal} # aps = agent plan sequence?
79
+ if goal not in plans_similarity_dict.keys(): plans_similarity_dict[goal] = {}
80
+ plans_similarity_dict[goal][percentage] = similarities_vector_to_std_deviation_units_vector(ref_dict=sequence_similarities, relative_to_largest=False)
81
+
82
+ goals = list(goals_similarity_dict.keys())
83
+ percentages = sorted(set(percentage for similarities in goals_similarity_dict.values() for percentage in similarities.keys()))
84
+ num_percentages = len(percentages)
85
+ fig_string = f"{recognizer_type}_{domain_name}_{env_name}_{fragmented_status}_{inf_same_length_status}_{learn_same_length_status}"
86
+
87
+ else: # algorithm = "graql"
88
+ assert os.path.exists(get_graql_experiment_confidence_path(domain_name)), "Embeddings weren't made for this environment, run graml_main.py with this environment first."
89
+ tasks_scores_dict = {}
90
+ goals_similarity_dict = {}
91
+ experiments_dir_path = get_graql_experiment_confidence_path(domain_name)
92
+ for experiments_file_name in os.listdir(experiments_dir_path):
93
+ with open(os.path.join(experiments_dir_path, experiments_file_name), 'rb') as exp_file:
94
+ splitted_name = experiments_file_name.split('_')
95
+ goal, percentage = splitted_name[1], splitted_name[2]
96
+ tasks_scores_dict[f"{goal}_{percentage}"] = dill.load(exp_file)
97
+
98
+ for goal_percentage, scores_list in tasks_scores_dict.items():
99
+ goal, percentage = goal_percentage.split('_')
100
+ similarities = {dynamic_goal: score for (dynamic_goal, score) in scores_list}
101
+ if goal not in goals_similarity_dict.keys(): goals_similarity_dict[goal] = {}
102
+ goals_similarity_dict[goal][percentage] = similarities_vector_to_std_deviation_units_vector(ref_dict=similarities, relative_to_largest=False)
103
+
104
+ goals = list(goals_similarity_dict.keys())
105
+ percentages = sorted(set(percentage for similarities in goals_similarity_dict.values() for percentage in similarities.keys()))
106
+ num_percentages = len(percentages)
107
+ fig_string = f"{recognizer_type}_{domain_name}_{env_name}_{fragmented_status}"
108
+
109
+ # -------------------- Start of Confusion Matrix Code --------------------
110
+ # Initialize matrices of size len(goals) x len(goals)
111
+ confusion_matrix_goals, confusion_matrix_plans = np.zeros((len(goals), len(goals))), np.zeros((len(goals), len(goals)))
112
+
113
+ # if domain_name == 'point_maze' and args.task == 'L555':
114
+ # if env_name == 'obstacles':
115
+ # goals = ['(4, 7)', '(3, 6)', '(5, 5)', '(8, 8)', '(6, 3)', '(7, 4)']
116
+ # else: # if env_name is 'four_rooms'
117
+ # goals = ['(2, 8)', '(3, 7)', '(3, 4)', '(4, 4)', '(4, 3)', '(7, 3)', '(8, 2)']
118
+
119
+ # Populate confusion matrix with similarity values for goals
120
+ for i, true_goal in enumerate(goals):
121
+ for j, dynamic_goal in enumerate(goals):
122
+ percentage = percentages[-3]
123
+ confusion_matrix_goals[i, j] = goals_similarity_dict[true_goal][percentage].get(dynamic_goal, 0)
124
+
125
+ if plans_similarity_dict:
126
+ # Populate confusion matrix with similarity values for plans
127
+ for i, true_goal in enumerate(goals):
128
+ for j, dynamic_goal in enumerate(goals):
129
+ percentage = percentages[-1]
130
+ confusion_matrix_plans[i, j] = plans_similarity_dict[true_goal][percentage].get(dynamic_goal, 0)
131
+
132
+ # Create the figure and subplots for the unified display
133
+ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6), sharex=True)
134
+
135
+ # Plot for goal similarities
136
+ im1 = ax1.imshow(confusion_matrix_goals, cmap='Blues', interpolation='nearest')
137
+ cbar1 = fig.colorbar(im1, ax=ax1, fraction=0.046, pad=0.04)
138
+ cbar1.set_label('St. dev from most probable goal', fontsize=18)
139
+ ax1.set_title('Embeddings', fontsize=22, pad=20)
140
+ ax1.set_xticks(np.arange(len(goals)))
141
+ ax1.set_xticklabels(goals, rotation=45, ha="right", fontsize=16)
142
+ ax1.set_yticks(np.arange(len(goals)))
143
+ ax1.set_yticklabels(goals, fontsize=16) # y-tick labels for ax1
144
+
145
+ # Plot for plan similarities
146
+ im2 = ax2.imshow(confusion_matrix_plans, cmap='Greens', interpolation='nearest')
147
+ cbar2 = fig.colorbar(im2, ax=ax2, fraction=0.046, pad=0.04)
148
+ cbar2.set_label('Distance between plans', fontsize=18)
149
+ ax2.set_title('Sequences', fontsize=22, pad=20)
150
+ ax2.set_xticks(np.arange(len(goals)))
151
+ ax2.set_xticklabels(goals, rotation=45, ha="right", fontsize=16)
152
+ ax2.set_yticks(np.arange(len(goals))) # y-ticks for ax2 explicitly
153
+ ax2.set_yticklabels(goals, fontsize=16) # y-tick labels for ax2
154
+
155
+ # Adjust the figure layout to reduce overlap
156
+ plt.subplots_adjust(left=0.15, right=0.9, bottom=0.25, top=0.85, wspace=0.1)
157
+
158
+ # Unified axis labels, placed closer to the left
159
+ fig.text(0.57, 0.07, 'Goals Adaptation Phase', ha='center', fontsize=22)
160
+ fig.text(0.12, 0.5, 'Inference Phase', va='center', rotation='vertical', fontsize=22)
161
+
162
+ # Save the combined plot
163
+ fig_dir = get_figures_dir_path(domain_name=domain_name, env_name=env_name)
164
+ if not os.path.exists(fig_dir):
165
+ os.makedirs(fig_dir)
166
+ confusion_matrix_combined_path = os.path.join(fig_dir, f"{fig_string}_combined_conf_mat.png")
167
+ plt.savefig(confusion_matrix_combined_path, dpi=300)
168
+ print(f"Combined confusion matrix figure saved at: {confusion_matrix_combined_path}")
169
+
170
+ # -------------------- End of Confusion Matrix Code --------------------
171
+ fig, axes = plt.subplots(nrows=num_percentages, ncols=1, figsize=(10, 6 * num_percentages))
172
+
173
+ if num_percentages == 1:
174
+ axes = [axes]
175
+
176
+ for i, percentage in enumerate(percentages):
177
+ correct_tasks, tasks_num = 0, 0
178
+ ax = axes[i]
179
+ dynamic_goals = list(next(iter(goals_similarity_dict.values()))[percentage].keys())
180
+ num_goals = len(goals)
181
+ num_dynamic_goals = len(dynamic_goals)
182
+ bar_width = 0.8 / num_dynamic_goals
183
+ bar_positions = np.arange(num_goals)
184
+
185
+ if recognizer_type == "graml":
186
+ for j, dynamic_goal in enumerate(dynamic_goals):
187
+ goal_similarities = [goals_similarity_dict[goal][percentage][dynamic_goal] + 0.04 for goal in goals]
188
+ plan_similarities = [plans_similarity_dict[goal][percentage][dynamic_goal] + 0.04 for goal in goals]
189
+ ax.bar(bar_positions + j * bar_width, goal_similarities, bar_width/2, label=f"embedding of {dynamic_goal}")
190
+ ax.bar(bar_positions + j * bar_width + bar_width/2, plan_similarities, bar_width/2, label=f"plan to {dynamic_goal}")
191
+ else:
192
+ for j, dynamic_goal in enumerate(dynamic_goals):
193
+ goal_similarities = [goals_similarity_dict[goal][percentage][dynamic_goal] + 0.04 for goal in goals]
194
+ ax.bar(bar_positions + j * bar_width, goal_similarities, bar_width, label=f"policy to {dynamic_goal}")
195
+
196
+ x_labels = []
197
+ for true_goal in goals:
198
+ guessed_goal = min(goals_similarity_dict[true_goal][percentage], key=goals_similarity_dict[true_goal][percentage].get)
199
+ tasks_num += 1
200
+ if true_goal == guessed_goal: correct_tasks += 1
201
+ second_lowest_value = sorted(goals_similarity_dict[true_goal][percentage].values())[1]
202
+ confidence_level = abs(goals_similarity_dict[true_goal][percentage][guessed_goal] - second_lowest_value)
203
+ label = f"True: {true_goal}\nGuessed: {guessed_goal}\nConfidence: {confidence_level:.2f}"
204
+ x_labels.append(label)
205
+
206
+ ax.set_ylabel('Distance (units in st. deviations)', fontsize=10)
207
+ ax.set_title(f'Confidence level for {domain_name}, {env_name}, {fragmented_status}. Accuracy: {correct_tasks / tasks_num}', fontsize=12)
208
+ ax.set_xticks(bar_positions + bar_width * (num_dynamic_goals - 1) / 2)
209
+ ax.set_xticklabels(x_labels, fontsize=8)
210
+ ax.legend()
211
+
212
+ fig_path = os.path.join(fig_dir, f"{fig_string}_stats.png")
213
+ fig.savefig(fig_path)
214
+ print(f"general figure saved at: {fig_path}")
215
+
216
+
217
+ def parse_args():
218
+ parser = argparse.ArgumentParser(
219
+ description="Parse command-line arguments for the RL experiment.",
220
+ formatter_class=argparse.RawTextHelpFormatter
221
+ )
222
+
223
+ # Required arguments
224
+ required_group = parser.add_argument_group("Required arguments")
225
+ required_group.add_argument("--domain", choices=["point_maze", "minigrid", "parking", "franka_kitchen", "panda"], required=True, help="Domain type (point_maze, minigrid, parking, or franka_kitchen)")
226
+ required_group.add_argument("--recognizer", choices=["graml", "graql", "draco"], required=True, help="Recognizer type (graml, graql, draco). graql only for discrete domains.")
227
+ required_group.add_argument("--task", choices=["L1", "L2", "L3", "L4", "L5", "L11", "L22", "L33", "L44", "L55", "L111", "L222", "L333", "L444", "L555"], required=True, help="Task identifier (e.g., L1, L2,...,L5)")
228
+ required_group.add_argument("--partial_obs_type", required=True, choices=["fragmented", "continuing"], help="Give fragmented or continuing partial observations for inference phase inputs.")
229
+
230
+ # Optional arguments
231
+ optional_group = parser.add_argument_group("Optional arguments")
232
+ optional_group.add_argument("--minigrid_env", choices=["four_rooms", "obstacles"], help="Minigrid environment (four_rooms or obstacles)")
233
+ optional_group.add_argument("--parking_env", choices=["gd_agent", "gc_agent"], help="Parking environment (agent or gc_agent)")
234
+ optional_group.add_argument("--point_maze_env", choices=["obstacles", "four_rooms"], help="Parking environment (agent or gc_agent)")
235
+ optional_group.add_argument("--franka_env", choices=["comb1", "comb2"], help="Franka Kitchen environment (comb1 or comb2)")
236
+ optional_group.add_argument("--panda_env", choices=["gc_agent", "gd_agent"], help="Panda Robotics environment (gc_agent or gd_agent)")
237
+ optional_group.add_argument("--learn_same_seq_len", action="store_true", help="Learn with the same sequence length")
238
+ optional_group.add_argument("--inference_same_seq_len", action="store_true", help="Infer with the same sequence length")
239
+
240
+ args = parser.parse_args()
241
+
242
+ ### VALIDATE INPUTS ###
243
+ # Assert that all required arguments are provided
244
+ assert args.domain is not None and args.recognizer is not None and args.task is not None, "Missing required arguments: domain, recognizer, or task"
245
+
246
+ # Validate the combination of domain and environment
247
+ if args.domain == "minigrid" and args.minigrid_env is None:
248
+ parser.error("Missing required argument: --minigrid_env must be provided when --domain is minigrid")
249
+ elif args.domain == "parking" and args.parking_env is None:
250
+ parser.error("Missing required argument: --parking_env must be provided when --domain is parking")
251
+ elif args.domain == "point_maze" and args.point_maze_env is None:
252
+ parser.error("Missing required argument: --point_maze_env must be provided when --domain is point_maze")
253
+ elif args.domain == "franka_kitchen" and args.franka_env is None:
254
+ parser.error("Missing required argument: --franka_env must be provided when --domain is franka_kitchen")
255
+
256
+ if args.recognizer != "graml":
257
+ if args.learn_same_seq_len == True: parser.error("learn_same_seq_len is only relevant for graml.")
258
+ if args.inference_same_seq_len == True: parser.error("inference_same_seq_len is only relevant for graml.")
259
+
260
+ return args
261
+
262
+ if __name__ == "__main__":
263
+ args = parse_args()
264
+ set_global_storage_configs(recognizer_str=args.recognizer, is_fragmented=args.partial_obs_type,
265
+ is_inference_same_length_sequences=args.inference_same_seq_len, is_learn_same_length_sequences=args.learn_same_seq_len)
266
+ env_name, = [x for x in [args.minigrid_env, args.parking_env, args.point_maze_env, args.franka_env] if isinstance(x, str)]
267
+ if args.inference_same_seq_len: inference_same_seq_len = "inference_same_seq_len"
268
+ else: inference_same_seq_len = "inference_diff_seq_len"
269
+ if args.learn_same_seq_len: learn_same_seq_len = "learn_same_seq_len"
270
+ else: learn_same_seq_len = "learn_diff_seq_len"
271
+ analyze_and_produce_plots(args.recognizer, domain_name=args.domain, env_name=env_name, fragmented_status=args.partial_obs_type,
272
+ inf_same_length_status=inference_same_seq_len, learn_same_length_status=learn_same_seq_len)
@@ -0,0 +1,47 @@
1
+ import sys
2
+ import os
3
+ import pickle
4
+ import inspect
5
+
6
+
7
+ currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
8
+ GRAML_itself = os.path.dirname(currentdir)
9
+ GRAML_includer = os.path.dirname(os.path.dirname(currentdir))
10
+ sys.path.insert(0, GRAML_includer)
11
+ sys.path.insert(0, GRAML_itself)
12
+
13
+ def get_plans_result_path(env_name):
14
+ return os.path.join("dataset", (env_name), "plans")
15
+
16
+ def get_policy_sequences_result_path(env_name):
17
+ return os.path.join("dataset", (env_name), "policy_sequences")
18
+
19
+
20
+ # TODO: instead of loading the model and having it produce the sequence again, just save the sequence from the framework run, and have this script accept the whole path (including is_fragmented etc.)
21
+ def analyze_and_produce_images(env_name):
22
+ models_dir = get_models_dir(env_name=env_name)
23
+ for dirname in os.listdir(models_dir):
24
+ if dirname.startswith('MiniGrid'):
25
+ model_dir = get_model_dir(env_name=env_name, model_name=dirname, class_name="MCTS")
26
+ model_file_path = os.path.join(model_dir, "mcts_model.pth")
27
+ try:
28
+ with open(model_file_path, 'rb') as file: # Load the pre-existing model
29
+ monteCarloTreeSearch = pickle.load(file)
30
+ full_plan = monteCarloTreeSearch.generate_full_policy_sequence()
31
+ plan = [pos for ((state, pos), action) in full_plan]
32
+ plans_result_path = get_plans_result_path(env_name)
33
+ if not os.path.exists(plans_result_path): os.makedirs(plans_result_path)
34
+ img_path = os.path.join(get_plans_result_path(env_name), dirname)
35
+ print(f"plan to {dirname} is:\n\t{plan}\ngenerating image at {img_path}.")
36
+ create_sequence_image(plan, img_path, dirname)
37
+
38
+ except FileNotFoundError as e:
39
+ print(f"Warning: {e.filename} doesn't exist. It's probably a base goal, not generating policy sequence for it.")
40
+
41
+ if __name__ == "__main__":
42
+ # preventing circular imports. only needed for running this as main anyway.
43
+ from gr_libs.ml.utils.storage import get_models_dir, get_model_dir
44
+ # checks:
45
+ assert len(sys.argv) == 2, f"Assertion failed: len(sys.argv) is {len(sys.argv)} while it needs to be 2.\n Example: \n\t /usr/bin/python scripts/get_plans_images.py MiniGrid-Walls-13x13-v0"
46
+ assert os.path.exists(get_models_dir(sys.argv[1])), "plans weren't made for this environment, run graml_main.py with this environment first."
47
+ analyze_and_produce_images(sys.argv[1])
@@ -0,0 +1,63 @@
1
+ import os
2
+ import dill
3
+ import numpy as np
4
+ import matplotlib.pyplot as plt
5
+ from gr_libs.ml.utils.storage import get_experiment_results_path, set_global_storage_configs
6
+
7
+ if __name__ == "__main__":
8
+
9
+ # Define the tasks and percentages
10
+ increasing_base_goals = ['L1', 'L2', 'L3', 'L4', 'L5']
11
+ increasing_dynamic_goals = ['L111', 'L222', 'L555', 'L333', 'L444']
12
+ percentages = ['0.3', '0.5', '0.7', '0.9', '1']
13
+
14
+ # Prepare a dictionary to hold accuracy data
15
+ accuracies = {task: {perc: [] for perc in percentages} for task in increasing_base_goals + increasing_dynamic_goals}
16
+
17
+ # Collect data for both sets of goals
18
+ for task in increasing_base_goals + increasing_dynamic_goals:
19
+ set_global_storage_configs(recognizer_str='graml', is_fragmented='fragmented',
20
+ is_inference_same_length_sequences=True, is_learn_same_length_sequences=False)
21
+ res_file_path = f'{get_experiment_results_path("parking", "gd_agent", task)}.pkl'
22
+
23
+ if os.path.exists(res_file_path):
24
+ with open(res_file_path, 'rb') as results_file:
25
+ results = dill.load(results_file)
26
+ for percentage in percentages:
27
+ accuracies[task][percentage].append(results[percentage]['accuracy'])
28
+ else:
29
+ print(f"Warning: no file for {res_file_path}")
30
+
31
+ # Create the figure with two subplots
32
+ fig, axes = plt.subplots(1, 2, figsize=(12, 6))
33
+
34
+ # Bar plot function
35
+ def plot_accuracies(ax, task_set, title, type):
36
+ """Plot accuracies for a given set of tasks on the provided axis."""
37
+ x_vals = np.arange(len(task_set)) # X-axis positions for the number of goals
38
+ bar_width = 0.15 # Width of each bar
39
+ for i, perc in enumerate(['0.3', '0.5', '1']):
40
+ if perc == '1': y_vals = [max([accuracies[task]['0.5'][0], accuracies[task]['0.7'][0], accuracies[task]['0.9'][0], accuracies[task]['1'][0]]) for task in task_set] # Get mean accuracies
41
+ else: y_vals = [accuracies[task][perc][0] for task in task_set] # Get mean accuracies
42
+ if type != 'base': ax.bar(x_vals + i * bar_width, y_vals, width=bar_width, label=f'Percentage {perc}')
43
+ else: ax.bar(x_vals + i * bar_width, y_vals, width=bar_width)
44
+ ax.set_xticks(x_vals + bar_width) # Center x-ticks
45
+ ax.set_xticklabels([i+3 for i in range(len(task_set))], fontsize=16) # Set custom x-tick labels
46
+ ax.set_yticks(np.linspace(0, 1, 6))
47
+ ax.set_ylim([0, 1])
48
+ ax.set_title(title, fontsize=20)
49
+ ax.set_xlabel(f'Number of {type} Goals', fontsize=20)
50
+ if type == 'base':
51
+ ax.set_ylabel('Accuracy', fontsize=22)
52
+ ax.legend()
53
+
54
+ # Plot for increasing base goals
55
+ plot_accuracies(axes[0], increasing_base_goals, 'Increasing Base Goals', "base")
56
+
57
+ # Plot for increasing dynamic goals
58
+ plot_accuracies(axes[1], increasing_dynamic_goals, 'Increasing Active Goals', "active")
59
+ plt.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1, wspace=0.3, hspace=0.3)
60
+ # Adjust layout and save the figure
61
+ plt.tight_layout()
62
+ plt.savefig('increasing_goals_plot_bars.png', dpi=300) # Save the figure as a PNG file
63
+ print('Figure saved at: increasing_goals_plot_bars.png')
gr_libs/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ from gr_libs.recognizer.graml.graml_recognizer import ExpertBasedGraml, GCGraml
2
+ from gr_libs.recognizer.gr_as_rl.gr_as_rl_recognizer import Graql
File without changes
@@ -0,0 +1,227 @@
1
+ from abc import abstractmethod
2
+ from collections import namedtuple
3
+ import os
4
+
5
+ import gymnasium
6
+ from PIL import Image
7
+ import numpy as np
8
+ from gymnasium.envs.registration import register
9
+ from minigrid.core.world_object import Wall, Lava
10
+ from minigrid.wrappers import RGBImgPartialObsWrapper, ImgObsWrapper
11
+
12
+ MINIGRID, PANDA, PARKING, POINT_MAZE = "minigrid", "panda", "parking", "point_maze"
13
+
14
+ QLEARNING = "QLEARNING"
15
+
16
+ SUPPORTED_DOMAINS = [MINIGRID, PANDA, PARKING, POINT_MAZE]
17
+
18
+ LSTMProperties = namedtuple('LSTMProperties', ['input_size', 'hidden_size', 'batch_size', 'num_samples'])
19
+
20
+
21
+
22
+ class EnvProperty:
23
+ def __init__(self, name):
24
+ self.name = name
25
+
26
+ def __str__(self):
27
+ return f"{self.name}"
28
+
29
+ def __repr__(self):
30
+ return f"{self.name}"
31
+
32
+ def __eq__(self, other):
33
+ return self.name == other.name
34
+
35
+ def __ne__(self, other):
36
+ return not self.__eq__(other)
37
+
38
+ @abstractmethod
39
+ def str_to_goal(self):
40
+ pass
41
+
42
+ @abstractmethod
43
+ def gc_adaptable(self):
44
+ pass
45
+
46
+ @abstractmethod
47
+ def problem_list_to_str_tuple(self, problems):
48
+ pass
49
+
50
+ @abstractmethod
51
+ def goal_to_problem_str(self, goal):
52
+ pass
53
+
54
+ @abstractmethod
55
+ def is_action_discrete(self):
56
+ pass
57
+
58
+ @abstractmethod
59
+ def is_state_discrete(self):
60
+ pass
61
+
62
+ @abstractmethod
63
+ def get_lstm_props(self):
64
+ pass
65
+
66
+ class GCEnvProperty(EnvProperty):
67
+ @abstractmethod
68
+ def use_goal_directed_problem(self):
69
+ pass
70
+
71
+ def problem_list_to_str_tuple(self, problems):
72
+ return "goal_conditioned"
73
+
74
+ class MinigridProperty(EnvProperty):
75
+ def __init__(self, name):
76
+ super().__init__(name)
77
+ self.domain_name = "minigrid"
78
+
79
+ def goal_to_problem_str(self, goal):
80
+ return self.name + f"-DynamicGoal-{goal[0]}x{goal[1]}-v0"
81
+
82
+ def str_to_goal(self, problem_name):
83
+ parts = problem_name.split("-")
84
+ goal_part = [part for part in parts if "x" in part]
85
+ width, height = goal_part[0].split("x")
86
+ return (int(width), int(height))
87
+
88
+ def gc_adaptable(self):
89
+ return False
90
+
91
+ def problem_list_to_str_tuple(self, problems):
92
+ return "_".join([f"[{s.split('-')[-2]}]" for s in problems])
93
+
94
+ def is_action_discrete(self):
95
+ return True
96
+
97
+ def is_state_discrete(self):
98
+ return True
99
+
100
+ def get_lstm_props(self):
101
+ return LSTMProperties(batch_size=16, input_size=4, hidden_size=8, num_samples=40000)
102
+
103
+ def create_sequence_image(self, sequence, img_path, problem_name):
104
+ if not os.path.exists(os.path.dirname(img_path)): os.makedirs(os.path.dirname(img_path))
105
+ env_id = problem_name.split("-DynamicGoal-")[0] + "-DynamicGoal-" + problem_name.split("-DynamicGoal-")[1]
106
+ result = register(
107
+ id=env_id,
108
+ entry_point="gr_libss.minigrid_scripts.envs:CustomColorEnv",
109
+ kwargs={"size": 13 if 'Simple' in problem_name else 9,
110
+ "num_crossings": 4 if 'Simple' in problem_name else 3,
111
+ "goal_pos": self.str_to_goal(problem_name),
112
+ "obstacle_type": Wall if 'Simple' in problem_name else Lava,
113
+ "start_pos": (1, 1) if 'Simple' in problem_name else (3, 1),
114
+ "plan": sequence},
115
+ )
116
+ #print(result)
117
+ env = gymnasium.make(id=env_id)
118
+ env = RGBImgPartialObsWrapper(env) # Get pixel observations
119
+ env = ImgObsWrapper(env) # Get rid of the 'mission' field
120
+ obs, _ = env.reset() # This now produces an RGB tensor only
121
+
122
+ img = env.unwrapped.get_frame()
123
+
124
+ ####### save image to file
125
+ image_pil = Image.fromarray(np.uint8(img)).convert('RGB')
126
+ image_pil.save(r"{}.png".format(img_path))
127
+
128
+
129
+ class PandaProperty(GCEnvProperty):
130
+ def __init__(self, name):
131
+ super().__init__(name)
132
+ self.domain_name = "panda"
133
+
134
+ def str_to_goal(self, problem_name):
135
+ try:
136
+ numeric_part = problem_name.split('PandaMyReachDenseX')[1]
137
+ components = [component.replace('-v3', '').replace('y', '.').replace('M', '-') for component in numeric_part.split('X')]
138
+ floats = []
139
+ for component in components:
140
+ floats.append(float(component))
141
+ return np.array([floats], dtype=np.float32)
142
+ except Exception as e:
143
+ return "general"
144
+
145
+ def goal_to_problem_str(self, goal):
146
+ goal_str = 'X'.join([str(float(g)).replace(".", "y").replace("-","M") for g in goal[0]])
147
+ return f"PandaMyReachDenseX{goal_str}-v3"
148
+
149
+ def gc_adaptable(self):
150
+ return True
151
+
152
+ def use_goal_directed_problem(self):
153
+ return False
154
+
155
+ def is_action_discrete(self):
156
+ return False
157
+
158
+ def is_state_discrete(self):
159
+ return False
160
+
161
+ def get_lstm_props(self):
162
+ return LSTMProperties(batch_size=32, input_size=9, hidden_size=8, num_samples=20000)
163
+
164
+ def sample_goal():
165
+ goal_range_low = np.array([-0.40, -0.40, 0.10])
166
+ goal_range_high = np.array([0.2, 0.2, 0.10])
167
+ return np.random.uniform(goal_range_low, goal_range_high)
168
+
169
+
170
+ class ParkingProperty(GCEnvProperty):
171
+ # def str_to_goal(self): # TODO not use it, goal is not a part of the env property anymore.
172
+ # return self.name.split("-")[-2]
173
+
174
+ def __init__(self, name):
175
+ super().__init__(name)
176
+ self.domain_name = "parking"
177
+
178
+ def goal_to_problem_str(self, goal):
179
+ return self.name.split("-v0")[0] + f"-GI-{goal}-v0"
180
+
181
+ def gc_adaptable(self):
182
+ return True
183
+
184
+ def is_action_discrete(self):
185
+ return False
186
+
187
+ def is_state_discrete(self):
188
+ return False
189
+
190
+ def use_goal_directed_problem(self):
191
+ return True
192
+
193
+ def get_lstm_props(self):
194
+ return LSTMProperties(batch_size=32, input_size=8, hidden_size=8, num_samples=20000)
195
+
196
+
197
+ class PointMazeProperty(EnvProperty):
198
+ def __init__(self, name):
199
+ super().__init__(name)
200
+ self.domain_name = "point_maze"
201
+
202
+ def str_to_goal(self):
203
+ parts = self.name.split("-")
204
+ # Find the part containing the goal size (usually after "DynamicGoal")
205
+ sizes_parts = [part for part in parts if "x" in part]
206
+ goal_part = sizes_parts[1]
207
+ # Extract width and height from the goal part
208
+ width, height = goal_part.split("x")
209
+ return (int(width), int(height))
210
+
211
+ def gc_adaptable(self):
212
+ return False
213
+
214
+ def problem_list_to_str_tuple(self, problems):
215
+ return "_".join([f"[{s.split('-')[-1]}]" for s in problems])
216
+
217
+ def is_action_discrete(self):
218
+ return False
219
+
220
+ def is_state_discrete(self):
221
+ return False
222
+
223
+ def get_lstm_props(self):
224
+ return LSTMProperties(batch_size=32, input_size=6, hidden_size=8, num_samples=20000)
225
+
226
+ def goal_to_problem_str(self, goal):
227
+ return self.name + f"-Goal-{goal[0]}x{goal[1]}"
File without changes
@@ -0,0 +1,17 @@
1
+ import logging
2
+ import sys
3
+ from gr_libs.environment.environment import MINIGRID, PANDA, PARKING, POINT_MAZE, EnvProperty, MinigridProperty, PandaProperty, ParkingProperty, PointMazeProperty
4
+
5
+
6
+ def domain_to_env_property(domain_name: str):
7
+ if domain_name == MINIGRID:
8
+ return MinigridProperty
9
+ elif domain_name == PARKING:
10
+ return ParkingProperty
11
+ elif domain_name == PANDA:
12
+ return PandaProperty
13
+ elif domain_name == POINT_MAZE:
14
+ return PointMazeProperty
15
+ else:
16
+ logging.error(f"Domain {domain_name} is not supported.")
17
+ sys.exit(1)
File without changes