o
    vi:                  
   @   s   d Z ddlZddlZddlZdedededejfddZd	ejd
edededejf
ddZ	de
de
fddZdededededef
ddZdede
fddZdede
fddZde
fddZd ed!ed"edefd#d$ZdS )%z4
Common helper functions for robot dataset classes.
    N	num_stepsterminal_rewardgammareturnc                 C   s   | }t j|t jd}||d< t |}d}tt|D ]}|| ||  }|||< q|dkr8d| | d }|S d| d }|S )a  
    Compute Monte Carlo returns with sparse reward at the end of an episode.
    Returns are rescaled from [0, terminal_reward] to [-1, 1].

    Args:
        num_steps (int): Number of steps in the episode
        terminal_reward (float): Reward at the terminal state (usually 0 or 1)
        gamma (float): Discount factor

    Returns:
        np.ndarray: Returns array of shape (num_steps,) rescaled to [-1, 1]
    )dtypeg        r         )npzerosfloat32
zeros_likereversedrange)r   r   r   TZrewardsreturnsGt r   K/data/cameron/vidgen/cosmos-policy/cosmos_policy/datasets/dataset_common.pycompute_monte_carlo_returns   s   

r   actionsrelative_step_idx
chunk_sizec           	      C   sb   || }||kr| |||  }|S | |d }|| }t | d |df}t j||gdd}|S )a*  
    Get action chunk starting from relative_step_idx with padding if needed.

    If there aren't enough remaining actions to fill the chunk, the last action
    is repeated to fill the chunk.

    Args:
        actions (np.ndarray): Full actions array of shape (num_steps, action_dim)
        relative_step_idx (int): Starting index for the action chunk
        chunk_size (int): Size of the action chunk
        num_steps (int): Total number of steps in the episode

    Returns:
        np.ndarray: Action chunk of shape (chunk_size, action_dim)
    Nr   r	   r   )axis)r
   tileconcatenate)	r   r   r   r   Zremaining_actionsaction_chunkZavailable_actionsZnum_padding_neededpaddingr   r   r   get_action_chunk_with_padding:   s   r   rollout_datarollout_episode_metadatac                 C   s   d}i }i }d}d}|   D ].\}}|d }	|d }
t|	D ]}|
r-||f||< |d7 }n
||f||< |d7 }|d7 }qq|  D ]2\}}t|d }	t|d }
t|	D ]}|
rd||f||< |d7 }n
||f||< |d7 }|d7 }qUqA|||||dS )a  
    Build mapping for rollout dataset with separate tracking for successful/failure episodes.

    This function creates three mappings:
    - _rollout_success_step_to_episode_map: Maps global success step index to (episode_idx, relative_idx)
    - _rollout_failure_step_to_episode_map: Maps global failure step index to (episode_idx, relative_idx)
    - Counters for total steps in each category

    Args:
        rollout_data (dict): In-memory rollout data (episode_idx -> episode_data)
        rollout_episode_metadata (dict): Lazy-loaded rollout metadata (episode_idx -> metadata)

    Returns:
        dict: Dictionary containing:
            - '_rollout_success_step_to_episode_map': dict mapping success step indices
            - '_rollout_failure_step_to_episode_map': dict mapping failure step indices
            - '_rollout_success_total_steps': int
            - '_rollout_failure_total_steps': int
            - '_rollout_total_steps': int
    r   r   successr	   )$_rollout_success_step_to_episode_map$_rollout_failure_step_to_episode_map_rollout_success_total_steps_rollout_failure_total_steps_rollout_total_steps)itemsr   intbool)r    r!   rollout_total_stepsZ#rollout_success_step_to_episode_mapZ#rollout_failure_step_to_episode_maprollout_success_total_stepsrollout_failure_total_stepsepisode_idxepisode_datar   
is_successiepisode_metadatar   r   r    build_rollout_step_index_mappingb   sB   




r3   r,   r-   demonstration_sampling_probsuccess_rollout_sampling_probc                 C   sP  || }|dk}|r|dks|dkrd}|}d}n4|dks!|dkr(|}d}d}n%|}	|}
t |
| d|  }t |	d|  | }|	|k rI|}|
}n|	}|}|dksU| dkrXd}nC|dkrc| }d}d}n8| }|| }t || d|  }t |d|  | }||k r|}n| }t || }t |d|  }n| }d}d}|| | }||||dS )ai  
    Calculate epoch layout with proper scaling: demos, success rollouts, failure rollouts.

    This function computes adjusted counts for each data type to maintain the desired
    sampling probabilities during training.

    Args:
        num_steps (int): Number of demonstration steps
        rollout_success_total_steps (int): Number of success rollout steps
        rollout_failure_total_steps (int): Number of failure rollout steps
        demonstration_sampling_prob (float): Target probability of sampling demos vs rollouts
        success_rollout_sampling_prob (float): Target probability of sampling success vs failure rollouts

    Returns:
        dict: Dictionary containing:
            - 'adjusted_demo_count': int
            - 'adjusted_success_rollout_count': int
            - 'adjusted_failure_rollout_count': int
            - 'epoch_length': int
    r   r	   )adjusted_demo_countadjusted_success_rollout_countadjusted_failure_rollout_countepoch_length)r)   )r   r,   r-   r4   r5   r+   Zhas_rollout_datar7   r8   sfZs_newf_newr6   drZd_newZr_newr9   r   r   r   calculate_epoch_structure   sX   r?   data_dirdatac           	      C      t j| d}t j|r/t|d}t|}W d   n1 s"w   Y  td|  n9||}i }| D ]
\}}|	 ||< q9t|d}tj
||dd W d   n1 s\w   Y  td|  i }| D ]\}}t|||< qn|S )	a  
    Load dataset statistics from JSON file if it exists, otherwise compute and save them.

    Args:
        data_dir (str): Directory where statistics JSON file should be stored
        data (dict): Dataset dictionary (episode_idx -> episode_data)
        calculate_dataset_statistics_func: Function to compute statistics from data

    Returns:
        dict: Dataset statistics with numpy array values
    zdataset_statistics.jsonr>   Nz Loaded dataset statistics from: w   indentzDataset statistics saved to: ospathjoinexistsopenjsonloadprintr(   tolistdumpr
   array)	r@   rA   !calculate_dataset_statistics_funcdataset_stats_pathr;   
json_statsdataset_stats	stat_name
stat_valuer   r   r   "load_or_compute_dataset_statistics   $   rY   c           	      C   rB   )	a  
    Load post-normalization dataset statistics from JSON file if it exists, otherwise compute and save them.

    Args:
        data_dir (str): Directory where statistics JSON file should be stored
        data (dict): Dataset dictionary (episode_idx -> episode_data) with normalized data
        calculate_dataset_statistics_func: Function to compute statistics from data

    Returns:
        dict: Post-normalization dataset statistics with numpy array values
    z!dataset_statistics_post_norm.jsonr>   Nz3Loaded post-normalization dataset statistics from: rC   rD   rE   z0Post-normalization dataset statistics saved to: rG   )	r@   rA   rS   Zdataset_stats_post_norm_pathr;   rU   dataset_stats_post_normrW   rX   r   r   r   -load_or_compute_post_normalization_statistics   rZ   r\   c                 C   sN   i }d}|   D ]\}}|d }t|D ]}||f||< |d7 }qq||dS )am  
    Build a mapping from global step index to (episode index, relative index within episode).

    Args:
        data (dict): Dataset dictionary (episode_idx -> episode_data)

    Returns:
        dict: Dictionary containing:
            - '_step_to_episode_map': dict mapping global step index to (episode_idx, relative_idx)
            - '_total_steps': int
    r   r   r	   )_step_to_episode_map_total_steps)r(   r   )rA   Zstep_to_episode_maptotal_stepsr.   r/   r   r1   r   r   r   build_demo_step_index_mappingF  s   
r`   idxr6   r7   c                 C   s    | |k rdS | || k rdS dS )a  
    Determine which dataset to sample from based on index ranges.

    Layout of indices: [demos] [success rollouts] [failure rollouts]

    Args:
        idx (int): Sample index
        adjusted_demo_count (int): Number of demo samples in epoch
        adjusted_success_rollout_count (int): Number of success rollout samples in epoch

    Returns:
        str: One of "demo", "success_rollout", or "failure_rollout"
    demosuccess_rolloutfailure_rolloutr   )ra   r6   r7   r   r   r   determine_sample_type`  s
   re   )__doc__rM   rH   numpyr
   r)   floatndarrayr   r   dictr3   r?   strrY   r\   r`   re   r   r   r   r   <module>   s@   !
(C
U&&