gr-libs 0.1.7.post0__py3-none-any.whl → 0.1.8__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 (61) hide show
  1. evaluation/analyze_results_cross_alg_cross_domain.py +236 -246
  2. evaluation/create_minigrid_map_image.py +10 -6
  3. evaluation/file_system.py +16 -5
  4. evaluation/generate_experiments_results.py +123 -74
  5. evaluation/generate_experiments_results_new_ver1.py +227 -243
  6. evaluation/generate_experiments_results_new_ver2.py +317 -317
  7. evaluation/generate_task_specific_statistics_plots.py +481 -253
  8. evaluation/get_plans_images.py +41 -26
  9. evaluation/increasing_and_decreasing_.py +97 -56
  10. gr_libs/__init__.py +2 -1
  11. gr_libs/_version.py +2 -2
  12. gr_libs/environment/__init__.py +16 -8
  13. gr_libs/environment/environment.py +167 -39
  14. gr_libs/environment/utils/utils.py +22 -12
  15. gr_libs/metrics/__init__.py +5 -0
  16. gr_libs/metrics/metrics.py +76 -34
  17. gr_libs/ml/__init__.py +2 -0
  18. gr_libs/ml/agent.py +21 -6
  19. gr_libs/ml/base/__init__.py +1 -1
  20. gr_libs/ml/base/rl_agent.py +13 -10
  21. gr_libs/ml/consts.py +1 -1
  22. gr_libs/ml/neural/deep_rl_learner.py +433 -352
  23. gr_libs/ml/neural/utils/__init__.py +1 -1
  24. gr_libs/ml/neural/utils/dictlist.py +3 -3
  25. gr_libs/ml/neural/utils/penv.py +5 -2
  26. gr_libs/ml/planner/mcts/mcts_model.py +524 -302
  27. gr_libs/ml/planner/mcts/utils/__init__.py +1 -1
  28. gr_libs/ml/planner/mcts/utils/node.py +11 -7
  29. gr_libs/ml/planner/mcts/utils/tree.py +14 -10
  30. gr_libs/ml/sequential/__init__.py +1 -1
  31. gr_libs/ml/sequential/lstm_model.py +256 -175
  32. gr_libs/ml/tabular/state.py +7 -7
  33. gr_libs/ml/tabular/tabular_q_learner.py +123 -73
  34. gr_libs/ml/tabular/tabular_rl_agent.py +20 -19
  35. gr_libs/ml/utils/__init__.py +8 -2
  36. gr_libs/ml/utils/format.py +78 -70
  37. gr_libs/ml/utils/math.py +2 -1
  38. gr_libs/ml/utils/other.py +1 -1
  39. gr_libs/ml/utils/storage.py +88 -28
  40. gr_libs/problems/consts.py +1549 -1227
  41. gr_libs/recognizer/gr_as_rl/gr_as_rl_recognizer.py +145 -80
  42. gr_libs/recognizer/graml/gr_dataset.py +209 -110
  43. gr_libs/recognizer/graml/graml_recognizer.py +431 -240
  44. gr_libs/recognizer/recognizer.py +38 -27
  45. gr_libs/recognizer/utils/__init__.py +1 -1
  46. gr_libs/recognizer/utils/format.py +8 -3
  47. {gr_libs-0.1.7.post0.dist-info → gr_libs-0.1.8.dist-info}/METADATA +1 -1
  48. gr_libs-0.1.8.dist-info/RECORD +70 -0
  49. {gr_libs-0.1.7.post0.dist-info → gr_libs-0.1.8.dist-info}/WHEEL +1 -1
  50. tests/test_gcdraco.py +10 -0
  51. tests/test_graml.py +8 -4
  52. tests/test_graql.py +2 -1
  53. tutorials/gcdraco_panda_tutorial.py +66 -0
  54. tutorials/gcdraco_parking_tutorial.py +61 -0
  55. tutorials/graml_minigrid_tutorial.py +42 -12
  56. tutorials/graml_panda_tutorial.py +35 -14
  57. tutorials/graml_parking_tutorial.py +37 -20
  58. tutorials/graml_point_maze_tutorial.py +33 -13
  59. tutorials/graql_minigrid_tutorial.py +31 -15
  60. gr_libs-0.1.7.post0.dist-info/RECORD +0 -67
  61. {gr_libs-0.1.7.post0.dist-info → gr_libs-0.1.8.dist-info}/top_level.txt +0 -0
@@ -9,264 +9,492 @@ import torch
9
9
  import dill
10
10
 
11
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
12
+ from gr_libs.ml.utils.storage import (
13
+ get_experiment_results_path,
14
+ set_global_storage_configs,
15
+ get_graql_experiment_confidence_path,
16
+ )
13
17
  from gr_libs.metrics.metrics import measure_average_sequence_distance
14
18
 
19
+
15
20
  def get_tasks_embeddings_dir_path(env_name):
16
- return os.path.join("../gr_libs", get_embeddings_result_path(env_name))
21
+ return os.path.join("../gr_libs", get_embeddings_result_path(env_name))
22
+
17
23
 
18
24
  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
-
25
+ return os.path.join("../gr_libs", "figures", domain_name, env_name)
26
+
27
+
28
+ def similarities_vector_to_std_deviation_units_vector(
29
+ ref_dict: dict, relative_to_largest
30
+ ):
31
+ """
32
+ Calculate the number of standard deviation units every other element is
33
+ from the largest/smallest element in the vector.
34
+
35
+ Parameters:
36
+ - vector: list or numpy array of numbers.
37
+ - relative_to_largest: boolean, if True, measure in relation to the largest element,
38
+ if False, measure in relation to the smallest element.
39
+
40
+ Returns:
41
+ - List of number of standard deviation units for each element in the vector.
42
+ """
43
+ vector = np.array(list(ref_dict.values()))
44
+ mean = np.mean(vector) # for the future maybe another method for measurement
45
+ std_dev = np.std(vector)
46
+
47
+ # Determine the reference element (largest or smallest)
48
+ if relative_to_largest:
49
+ reference_value = np.max(vector)
50
+ else:
51
+ reference_value = np.min(vector)
52
+ for goal, value in ref_dict.items():
53
+ ref_dict[goal] = abs(value - reference_value) / std_dev
54
+ return ref_dict
55
+
56
+
57
+ def analyze_and_produce_plots(
58
+ recognizer_type: str,
59
+ domain_name: str,
60
+ env_name: str,
61
+ fragmented_status: str,
62
+ inf_same_length_status: str,
63
+ learn_same_length_status: str,
64
+ ):
65
+ if recognizer_type == "graml":
66
+ assert os.path.exists(
67
+ get_embeddings_result_path(domain_name)
68
+ ), "Embeddings weren't made for this environment, run graml_main.py with this environment first."
69
+ tasks_embedding_dicts = {}
70
+ tasks_plans_dict = {}
71
+ goals_similarity_dict = {}
72
+ plans_similarity_dict = {}
73
+
74
+ embeddings_dir_path = get_tasks_embeddings_dir_path(domain_name)
75
+ for embeddings_file_name in [
76
+ filename
77
+ for filename in os.listdir(embeddings_dir_path)
78
+ if "embeddings" in filename
79
+ ]:
80
+ with open(
81
+ os.path.join(embeddings_dir_path, embeddings_file_name), "rb"
82
+ ) as emb_file:
83
+ splitted_name = embeddings_file_name.split("_")
84
+ goal, percentage = splitted_name[0], splitted_name[1]
85
+ with open(
86
+ os.path.join(
87
+ embeddings_dir_path, f"{goal}_{percentage}_plans_dict.pkl"
88
+ ),
89
+ "rb",
90
+ ) as plan_file:
91
+ tasks_plans_dict[f"{goal}_{percentage}"] = dill.load(plan_file)
92
+ tasks_embedding_dicts[f"{goal}_{percentage}"] = dill.load(emb_file)
93
+
94
+ for goal_percentage, embedding_dict in tasks_embedding_dicts.items():
95
+ goal, percentage = goal_percentage.split("_")
96
+ similarities = {
97
+ dynamic_goal: []
98
+ for dynamic_goal in embedding_dict.keys()
99
+ if "true" not in dynamic_goal
100
+ }
101
+ real_goal_embedding = embedding_dict[f"{goal}_true"]
102
+ for dynamic_goal, goal_embedding in embedding_dict.items():
103
+ if "true" in dynamic_goal:
104
+ continue
105
+ curr_similarity = torch.exp(
106
+ -torch.sum(torch.abs(goal_embedding - real_goal_embedding))
107
+ )
108
+ similarities[dynamic_goal] = curr_similarity.item()
109
+ if goal not in goals_similarity_dict.keys():
110
+ goals_similarity_dict[goal] = {}
111
+ goals_similarity_dict[goal][percentage] = (
112
+ similarities_vector_to_std_deviation_units_vector(
113
+ ref_dict=similarities, relative_to_largest=True
114
+ )
115
+ )
116
+
117
+ for goal_percentage, plans_dict in tasks_plans_dict.items():
118
+ goal, percentage = goal_percentage.split("_")
119
+ real_plan = plans_dict[f"{goal}_true"]
120
+ sequence_similarities = {
121
+ d_goal: measure_average_sequence_distance(real_plan, plan)
122
+ for d_goal, plan in plans_dict.items()
123
+ if "true" not in d_goal
124
+ } # aps = agent plan sequence?
125
+ if goal not in plans_similarity_dict.keys():
126
+ plans_similarity_dict[goal] = {}
127
+ plans_similarity_dict[goal][percentage] = (
128
+ similarities_vector_to_std_deviation_units_vector(
129
+ ref_dict=sequence_similarities, relative_to_largest=False
130
+ )
131
+ )
132
+
133
+ goals = list(goals_similarity_dict.keys())
134
+ percentages = sorted(
135
+ set(
136
+ percentage
137
+ for similarities in goals_similarity_dict.values()
138
+ for percentage in similarities.keys()
139
+ )
140
+ )
141
+ num_percentages = len(percentages)
142
+ fig_string = f"{recognizer_type}_{domain_name}_{env_name}_{fragmented_status}_{inf_same_length_status}_{learn_same_length_status}"
143
+
144
+ else: # algorithm = "graql"
145
+ assert os.path.exists(
146
+ get_graql_experiment_confidence_path(domain_name)
147
+ ), "Embeddings weren't made for this environment, run graml_main.py with this environment first."
148
+ tasks_scores_dict = {}
149
+ goals_similarity_dict = {}
150
+ experiments_dir_path = get_graql_experiment_confidence_path(domain_name)
151
+ for experiments_file_name in os.listdir(experiments_dir_path):
152
+ with open(
153
+ os.path.join(experiments_dir_path, experiments_file_name), "rb"
154
+ ) as exp_file:
155
+ splitted_name = experiments_file_name.split("_")
156
+ goal, percentage = splitted_name[1], splitted_name[2]
157
+ tasks_scores_dict[f"{goal}_{percentage}"] = dill.load(exp_file)
158
+
159
+ for goal_percentage, scores_list in tasks_scores_dict.items():
160
+ goal, percentage = goal_percentage.split("_")
161
+ similarities = {
162
+ dynamic_goal: score for (dynamic_goal, score) in scores_list
163
+ }
164
+ if goal not in goals_similarity_dict.keys():
165
+ goals_similarity_dict[goal] = {}
166
+ goals_similarity_dict[goal][percentage] = (
167
+ similarities_vector_to_std_deviation_units_vector(
168
+ ref_dict=similarities, relative_to_largest=False
169
+ )
170
+ )
171
+
172
+ goals = list(goals_similarity_dict.keys())
173
+ percentages = sorted(
174
+ set(
175
+ percentage
176
+ for similarities in goals_similarity_dict.values()
177
+ for percentage in similarities.keys()
178
+ )
179
+ )
180
+ num_percentages = len(percentages)
181
+ fig_string = f"{recognizer_type}_{domain_name}_{env_name}_{fragmented_status}"
182
+
183
+ # -------------------- Start of Confusion Matrix Code --------------------
184
+ # Initialize matrices of size len(goals) x len(goals)
185
+ confusion_matrix_goals, confusion_matrix_plans = np.zeros(
186
+ (len(goals), len(goals))
187
+ ), np.zeros((len(goals), len(goals)))
188
+
189
+ # if domain_name == 'point_maze' and args.task == 'L555':
190
+ # if env_name == 'obstacles':
191
+ # goals = ['(4, 7)', '(3, 6)', '(5, 5)', '(8, 8)', '(6, 3)', '(7, 4)']
192
+ # else: # if env_name is 'four_rooms'
193
+ # goals = ['(2, 8)', '(3, 7)', '(3, 4)', '(4, 4)', '(4, 3)', '(7, 3)', '(8, 2)']
194
+
195
+ # Populate confusion matrix with similarity values for goals
196
+ for i, true_goal in enumerate(goals):
197
+ for j, dynamic_goal in enumerate(goals):
198
+ percentage = percentages[-3]
199
+ confusion_matrix_goals[i, j] = goals_similarity_dict[true_goal][
200
+ percentage
201
+ ].get(dynamic_goal, 0)
202
+
203
+ if plans_similarity_dict:
204
+ # Populate confusion matrix with similarity values for plans
205
+ for i, true_goal in enumerate(goals):
206
+ for j, dynamic_goal in enumerate(goals):
207
+ percentage = percentages[-1]
208
+ confusion_matrix_plans[i, j] = plans_similarity_dict[true_goal][
209
+ percentage
210
+ ].get(dynamic_goal, 0)
211
+
212
+ # Create the figure and subplots for the unified display
213
+ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6), sharex=True)
214
+
215
+ # Plot for goal similarities
216
+ im1 = ax1.imshow(confusion_matrix_goals, cmap="Blues", interpolation="nearest")
217
+ cbar1 = fig.colorbar(im1, ax=ax1, fraction=0.046, pad=0.04)
218
+ cbar1.set_label("St. dev from most probable goal", fontsize=18)
219
+ ax1.set_title("Embeddings", fontsize=22, pad=20)
220
+ ax1.set_xticks(np.arange(len(goals)))
221
+ ax1.set_xticklabels(goals, rotation=45, ha="right", fontsize=16)
222
+ ax1.set_yticks(np.arange(len(goals)))
223
+ ax1.set_yticklabels(goals, fontsize=16) # y-tick labels for ax1
224
+
225
+ # Plot for plan similarities
226
+ im2 = ax2.imshow(confusion_matrix_plans, cmap="Greens", interpolation="nearest")
227
+ cbar2 = fig.colorbar(im2, ax=ax2, fraction=0.046, pad=0.04)
228
+ cbar2.set_label("Distance between plans", fontsize=18)
229
+ ax2.set_title("Sequences", fontsize=22, pad=20)
230
+ ax2.set_xticks(np.arange(len(goals)))
231
+ ax2.set_xticklabels(goals, rotation=45, ha="right", fontsize=16)
232
+ ax2.set_yticks(np.arange(len(goals))) # y-ticks for ax2 explicitly
233
+ ax2.set_yticklabels(goals, fontsize=16) # y-tick labels for ax2
234
+
235
+ # Adjust the figure layout to reduce overlap
236
+ plt.subplots_adjust(left=0.15, right=0.9, bottom=0.25, top=0.85, wspace=0.1)
237
+
238
+ # Unified axis labels, placed closer to the left
239
+ fig.text(0.57, 0.07, "Goals Adaptation Phase", ha="center", fontsize=22)
240
+ fig.text(
241
+ 0.12, 0.5, "Inference Phase", va="center", rotation="vertical", fontsize=22
242
+ )
243
+
244
+ # Save the combined plot
245
+ fig_dir = get_figures_dir_path(domain_name=domain_name, env_name=env_name)
246
+ if not os.path.exists(fig_dir):
247
+ os.makedirs(fig_dir)
248
+ confusion_matrix_combined_path = os.path.join(
249
+ fig_dir, f"{fig_string}_combined_conf_mat.png"
250
+ )
251
+ plt.savefig(confusion_matrix_combined_path, dpi=300)
252
+ print(
253
+ f"Combined confusion matrix figure saved at: {confusion_matrix_combined_path}"
254
+ )
255
+
256
+ # -------------------- End of Confusion Matrix Code --------------------
257
+ fig, axes = plt.subplots(
258
+ nrows=num_percentages, ncols=1, figsize=(10, 6 * num_percentages)
259
+ )
260
+
261
+ if num_percentages == 1:
262
+ axes = [axes]
263
+
264
+ for i, percentage in enumerate(percentages):
265
+ correct_tasks, tasks_num = 0, 0
266
+ ax = axes[i]
267
+ dynamic_goals = list(
268
+ next(iter(goals_similarity_dict.values()))[percentage].keys()
269
+ )
270
+ num_goals = len(goals)
271
+ num_dynamic_goals = len(dynamic_goals)
272
+ bar_width = 0.8 / num_dynamic_goals
273
+ bar_positions = np.arange(num_goals)
274
+
275
+ if recognizer_type == "graml":
276
+ for j, dynamic_goal in enumerate(dynamic_goals):
277
+ goal_similarities = [
278
+ goals_similarity_dict[goal][percentage][dynamic_goal] + 0.04
279
+ for goal in goals
280
+ ]
281
+ plan_similarities = [
282
+ plans_similarity_dict[goal][percentage][dynamic_goal] + 0.04
283
+ for goal in goals
284
+ ]
285
+ ax.bar(
286
+ bar_positions + j * bar_width,
287
+ goal_similarities,
288
+ bar_width / 2,
289
+ label=f"embedding of {dynamic_goal}",
290
+ )
291
+ ax.bar(
292
+ bar_positions + j * bar_width + bar_width / 2,
293
+ plan_similarities,
294
+ bar_width / 2,
295
+ label=f"plan to {dynamic_goal}",
296
+ )
297
+ else:
298
+ for j, dynamic_goal in enumerate(dynamic_goals):
299
+ goal_similarities = [
300
+ goals_similarity_dict[goal][percentage][dynamic_goal] + 0.04
301
+ for goal in goals
302
+ ]
303
+ ax.bar(
304
+ bar_positions + j * bar_width,
305
+ goal_similarities,
306
+ bar_width,
307
+ label=f"policy to {dynamic_goal}",
308
+ )
309
+
310
+ x_labels = []
311
+ for true_goal in goals:
312
+ guessed_goal = min(
313
+ goals_similarity_dict[true_goal][percentage],
314
+ key=goals_similarity_dict[true_goal][percentage].get,
315
+ )
316
+ tasks_num += 1
317
+ if true_goal == guessed_goal:
318
+ correct_tasks += 1
319
+ second_lowest_value = sorted(
320
+ goals_similarity_dict[true_goal][percentage].values()
321
+ )[1]
322
+ confidence_level = abs(
323
+ goals_similarity_dict[true_goal][percentage][guessed_goal]
324
+ - second_lowest_value
325
+ )
326
+ label = f"True: {true_goal}\nGuessed: {guessed_goal}\nConfidence: {confidence_level:.2f}"
327
+ x_labels.append(label)
328
+
329
+ ax.set_ylabel("Distance (units in st. deviations)", fontsize=10)
330
+ ax.set_title(
331
+ f"Confidence level for {domain_name}, {env_name}, {fragmented_status}. Accuracy: {correct_tasks / tasks_num}",
332
+ fontsize=12,
333
+ )
334
+ ax.set_xticks(bar_positions + bar_width * (num_dynamic_goals - 1) / 2)
335
+ ax.set_xticklabels(x_labels, fontsize=8)
336
+ ax.legend()
337
+
338
+ fig_path = os.path.join(fig_dir, f"{fig_string}_stats.png")
339
+ fig.savefig(fig_path)
340
+ print(f"general figure saved at: {fig_path}")
341
+
342
+
217
343
  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
344
+ parser = argparse.ArgumentParser(
345
+ description="Parse command-line arguments for the RL experiment.",
346
+ formatter_class=argparse.RawTextHelpFormatter,
347
+ )
348
+
349
+ # Required arguments
350
+ required_group = parser.add_argument_group("Required arguments")
351
+ required_group.add_argument(
352
+ "--domain",
353
+ choices=["point_maze", "minigrid", "parking", "franka_kitchen", "panda"],
354
+ required=True,
355
+ help="Domain type (point_maze, minigrid, parking, or franka_kitchen)",
356
+ )
357
+ required_group.add_argument(
358
+ "--recognizer",
359
+ choices=["graml", "graql", "draco"],
360
+ required=True,
361
+ help="Recognizer type (graml, graql, draco). graql only for discrete domains.",
362
+ )
363
+ required_group.add_argument(
364
+ "--task",
365
+ choices=[
366
+ "L1",
367
+ "L2",
368
+ "L3",
369
+ "L4",
370
+ "L5",
371
+ "L11",
372
+ "L22",
373
+ "L33",
374
+ "L44",
375
+ "L55",
376
+ "L111",
377
+ "L222",
378
+ "L333",
379
+ "L444",
380
+ "L555",
381
+ ],
382
+ required=True,
383
+ help="Task identifier (e.g., L1, L2,...,L5)",
384
+ )
385
+ required_group.add_argument(
386
+ "--partial_obs_type",
387
+ required=True,
388
+ choices=["fragmented", "continuing"],
389
+ help="Give fragmented or continuing partial observations for inference phase inputs.",
390
+ )
391
+
392
+ # Optional arguments
393
+ optional_group = parser.add_argument_group("Optional arguments")
394
+ optional_group.add_argument(
395
+ "--minigrid_env",
396
+ choices=["four_rooms", "obstacles"],
397
+ help="Minigrid environment (four_rooms or obstacles)",
398
+ )
399
+ optional_group.add_argument(
400
+ "--parking_env",
401
+ choices=["gd_agent", "gc_agent"],
402
+ help="Parking environment (agent or gc_agent)",
403
+ )
404
+ optional_group.add_argument(
405
+ "--point_maze_env",
406
+ choices=["obstacles", "four_rooms"],
407
+ help="Parking environment (agent or gc_agent)",
408
+ )
409
+ optional_group.add_argument(
410
+ "--franka_env",
411
+ choices=["comb1", "comb2"],
412
+ help="Franka Kitchen environment (comb1 or comb2)",
413
+ )
414
+ optional_group.add_argument(
415
+ "--panda_env",
416
+ choices=["gc_agent", "gd_agent"],
417
+ help="Panda Robotics environment (gc_agent or gd_agent)",
418
+ )
419
+ optional_group.add_argument(
420
+ "--learn_same_seq_len",
421
+ action="store_true",
422
+ help="Learn with the same sequence length",
423
+ )
424
+ optional_group.add_argument(
425
+ "--inference_same_seq_len",
426
+ action="store_true",
427
+ help="Infer with the same sequence length",
428
+ )
429
+
430
+ args = parser.parse_args()
431
+
432
+ ### VALIDATE INPUTS ###
433
+ # Assert that all required arguments are provided
434
+ assert (
435
+ args.domain is not None
436
+ and args.recognizer is not None
437
+ and args.task is not None
438
+ ), "Missing required arguments: domain, recognizer, or task"
439
+
440
+ # Validate the combination of domain and environment
441
+ if args.domain == "minigrid" and args.minigrid_env is None:
442
+ parser.error(
443
+ "Missing required argument: --minigrid_env must be provided when --domain is minigrid"
444
+ )
445
+ elif args.domain == "parking" and args.parking_env is None:
446
+ parser.error(
447
+ "Missing required argument: --parking_env must be provided when --domain is parking"
448
+ )
449
+ elif args.domain == "point_maze" and args.point_maze_env is None:
450
+ parser.error(
451
+ "Missing required argument: --point_maze_env must be provided when --domain is point_maze"
452
+ )
453
+ elif args.domain == "franka_kitchen" and args.franka_env is None:
454
+ parser.error(
455
+ "Missing required argument: --franka_env must be provided when --domain is franka_kitchen"
456
+ )
457
+
458
+ if args.recognizer != "graml":
459
+ if args.learn_same_seq_len == True:
460
+ parser.error("learn_same_seq_len is only relevant for graml.")
461
+ if args.inference_same_seq_len == True:
462
+ parser.error("inference_same_seq_len is only relevant for graml.")
463
+
464
+ return args
465
+
261
466
 
262
467
  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)
468
+ args = parse_args()
469
+ set_global_storage_configs(
470
+ recognizer_str=args.recognizer,
471
+ is_fragmented=args.partial_obs_type,
472
+ is_inference_same_length_sequences=args.inference_same_seq_len,
473
+ is_learn_same_length_sequences=args.learn_same_seq_len,
474
+ )
475
+ (env_name,) = [
476
+ x
477
+ for x in [
478
+ args.minigrid_env,
479
+ args.parking_env,
480
+ args.point_maze_env,
481
+ args.franka_env,
482
+ ]
483
+ if isinstance(x, str)
484
+ ]
485
+ if args.inference_same_seq_len:
486
+ inference_same_seq_len = "inference_same_seq_len"
487
+ else:
488
+ inference_same_seq_len = "inference_diff_seq_len"
489
+ if args.learn_same_seq_len:
490
+ learn_same_seq_len = "learn_same_seq_len"
491
+ else:
492
+ learn_same_seq_len = "learn_diff_seq_len"
493
+ analyze_and_produce_plots(
494
+ args.recognizer,
495
+ domain_name=args.domain,
496
+ env_name=env_name,
497
+ fragmented_status=args.partial_obs_type,
498
+ inf_same_length_status=inference_same_seq_len,
499
+ learn_same_length_status=learn_same_seq_len,
500
+ )