Spaces:
Sleeping
Sleeping
| import glob | |
| import os | |
| import sys | |
| from collections.abc import Iterable | |
| import numpy as np | |
| import torch | |
| from torch.utils.data import Dataset | |
| from tqdm import tqdm | |
| def _progress_enabled() -> bool: | |
| return bool(sys.stdout.isatty()) | |
| def _normalize_domains(domain) -> list[str]: | |
| if isinstance(domain, str): | |
| return [domain] | |
| if isinstance(domain, Iterable): | |
| return [str(d) for d in domain] | |
| raise TypeError(f"Unsupported domain spec: {domain!r}") | |
| class PlanningTrajectoryDataset(Dataset): | |
| def __init__(self, data_dir, domain, split="train"): | |
| """ | |
| data_dir: root data dir (e.g., 'data/encodings/graphs') | |
| """ | |
| self.files = [] | |
| self.domains = _normalize_domains(domain) | |
| self.traj_files = [] | |
| for domain_name in self.domains: | |
| target_dir = os.path.join(data_dir, domain_name, split) | |
| if not os.path.exists(target_dir): | |
| print(f"Warning: Directory {target_dir} does not exist.") | |
| continue | |
| all_files = glob.glob(os.path.join(target_dir, "*.npy")) | |
| filtered_files = [f for f in all_files if not f.endswith("_goal.npy")] | |
| self.traj_files.extend(sorted(filtered_files)) | |
| self.traj_files = sorted(self.traj_files) | |
| def __len__(self): | |
| return len(self.traj_files) | |
| def __getitem__(self, idx): | |
| traj_path = self.traj_files[idx] | |
| goal_path = traj_path.replace(".npy", "_goal.npy") | |
| # Load numpy arrays | |
| # Traj: [T, D] | |
| # Goal: [D] | |
| traj = np.load(traj_path).astype(np.float32) | |
| goal = np.load(goal_path).astype(np.float32) | |
| # Ensure Goal is at least 1D [D] | |
| if goal.ndim == 0: | |
| goal = goal.reshape(1) | |
| # Ensure Traj is 2D [T, D] | |
| if traj.ndim == 1: | |
| # Ambiguity: Is it [T] (D=1) or [D] (T=1)? | |
| # We use Goal dimension D to decide. | |
| D = goal.shape[0] | |
| if traj.shape[0] == D: | |
| # Likely T=1, D=D | |
| traj = traj.reshape(1, D) | |
| else: | |
| # Likely T=T, D=1 | |
| traj = traj.reshape(-1, 1) | |
| return torch.from_numpy(traj), torch.from_numpy(goal) | |
| def collate_trajectories(batch): | |
| """ | |
| Custom collate function to handle variable length trajectories. | |
| Pads sequences to the longest in the batch. | |
| Returns: | |
| padded_trajs: [B, MaxT, D] | |
| goals: [B, D] | |
| lengths: [B] | |
| """ | |
| trajs, goals = zip(*batch) | |
| # Lengths for packing | |
| lengths = torch.tensor([t.shape[0] for t in trajs]) | |
| # Pad trajectories: [B, MaxT, D] | |
| padded_trajs = torch.nn.utils.rnn.pad_sequence(trajs, batch_first=True) | |
| # Stack goals: [B, D] | |
| goals = torch.stack(goals) | |
| return padded_trajs, goals, lengths | |
| def load_flat_dataset_for_xgboost(data_dir, domain, split="train", delta=False): | |
| """ | |
| Loads trajectories and flattens them into (X, y) pairs for XGBoost. | |
| X: Concatenation of [State_t, Goal] | |
| y: State_{t+1} (if delta=False) OR (State_{t+1} - State_t) (if delta=True) | |
| """ | |
| domains = _normalize_domains(domain) | |
| traj_files = [] | |
| for domain_name in domains: | |
| target_dir = os.path.join(data_dir, domain_name, split) | |
| if not os.path.exists(target_dir): | |
| print(f"Warning: Directory {target_dir} does not exist.") | |
| continue | |
| all_files = glob.glob(os.path.join(target_dir, "*.npy")) | |
| traj_files.extend(sorted([f for f in all_files if not f.endswith("_goal.npy")])) | |
| traj_files = sorted(traj_files) | |
| if not traj_files: | |
| return None, None | |
| X_list = [] | |
| y_list = [] | |
| print( | |
| f"Loading {len(traj_files)} trajectories for {split} " | |
| f"across domains: {', '.join(domains)}" | |
| ) | |
| for traj_path in tqdm( | |
| traj_files, | |
| desc=f"Flattening {split}", | |
| disable=(not _progress_enabled()), | |
| ): | |
| goal_path = traj_path.replace(".npy", "_goal.npy") | |
| # Load raw numpy (skip torch conversion) | |
| traj = np.load(traj_path).astype(np.float32) # [T, D] | |
| goal = np.load(goal_path).astype(np.float32) # [D] | |
| # Fix dimensions | |
| if goal.ndim == 0: | |
| goal = goal.reshape(1) | |
| D = goal.shape[0] | |
| if traj.ndim == 1: | |
| if traj.shape[0] == D: | |
| traj = traj.reshape(1, D) | |
| else: | |
| traj = traj.reshape(-1, 1) | |
| # Need at least 2 steps to form a pair | |
| T = traj.shape[0] | |
| if T < 2: | |
| continue | |
| # Inputs: S_0 ... S_{T-1} | |
| states_in = traj[:-1, :] # [T-1, D] | |
| # Targets: S_1 ... S_T | |
| states_out = traj[1:, :] # [T-1, D] | |
| # Expand Goal: [T-1, D] | |
| goals_in = np.tile(goal, (T - 1, 1)) | |
| # Create X: [S_t, G] | |
| # Shape: [T-1, 2D] | |
| x_chunk = np.hstack([states_in, goals_in]) | |
| # Create y | |
| if delta: | |
| y_chunk = states_out - states_in | |
| else: | |
| y_chunk = states_out | |
| X_list.append(x_chunk) | |
| y_list.append(y_chunk) | |
| if not X_list: | |
| return None, None | |
| X = np.vstack(X_list) | |
| y = np.vstack(y_list) | |
| return X, y | |