def __init__(
        self,
        rollouts_dir: str,
        embedding: Embedding,
        num_segments: int = None,
        len_segments: int = None,
        rand_init_rollout: bool = True,
    ):
        """
        Constructor

        :param rollouts_dir: directory where to find the of pre-recorded rollouts
        :param num_segments: number of segments in which the rollouts are split into. For every segment, the initial
                             state of the simulation is reset, and thus for every set the features of the trajectories
                             are computed separately. Either specify `num_segments` or `len_segments`.
        :param embedding: embedding used for pre-processing the data before (later) passing it to the posterior
        :param len_segments: length of the segments in which the rollouts are split into. For every segment, the initial
                            state of the simulation is reset, and thus for every set the features of the trajectories
                            are computed separately. Either specify `num_segments` or `len_segments`.
        :param rand_init_rollout: if `True`, chose the first rollout at random, and then cycle through the list
        """
        if not os.path.isdir(rollouts_dir):
            raise pyrado.PathErr(given=rollouts_dir)

        Serializable._init(self, locals())

        super().__init__(None, None, embedding, num_segments, len_segments)

        # Crawl through the directory and load every file that starts with the word rollout
        rollouts_rec = []
        for root, dirs, files in os.walk(rollouts_dir):
            dirs.clear()  # prevents walk() from going into subdirectories
            rollouts_rec = [pyrado.load(name=f, load_dir=root) for f in files if f.startswith("rollout")]
            check_all_lengths_equal(rollouts_rec)
        if not rollouts_rec:
            raise pyrado.ValueErr(msg="No rollouts have been found!")

        self.rollouts_dir = rollouts_dir
        self.rollouts_rec = rollouts_rec
        self._ring_idx = np.random.randint(0, len(rollouts_rec)) if rand_init_rollout else 0
        self._set_action_field(self.rollouts_rec)
Example #2
0
def plot_rollouts_segment_wise(
        plot_type: str,
        segments_ground_truth: List[List[StepSequence]],
        segments_multiple_envs: List[List[List[StepSequence]]],
        segments_nominal: List[List[StepSequence]],
        use_rec_str: bool,
        idx_iter: int,
        idx_round: int,
        state_labels: Optional[Iterable[str]] = None,
        act_labels: Optional[Iterable[str]] = None,
        x_limits: Optional[Tuple[int]] = None,
        plot_act: bool = False,
        data_field: str = "states",
        cmap_samples: Optional[colors.Colormap] = None,
        save_dir: Optional[pyrado.PathLike] = None,
        file_format: Iterable[str] = ("pdf", "pgf", "png"),
) -> List[plt.Figure]:
    r"""
    Plot the different rollouts in separate figures and the different state dimensions along the columns.

    :param plot_type: type of plot, pass "samples" to plot the rollouts of the most likely domain parameters as
                      individual lines, or pass "confidence" to plot the most likely one, and the mean $\pm$ 1 std
    :param segments_ground_truth: list of lists containing rollout segments from the ground truth environment
    :param segments_multiple_envs: list of lists of lists containing rollout segments from different environment
                                   instances, e.g. samples from a posterior coming from `NDPR`
    :param segments_nominal: list of lists containing rollout segments from the nominal environment
    :param use_rec_str: `True` if pre-recorded actions have been used to generate the rollouts
    :param idx_iter: selected iteration
    :param idx_round: selected round
    :param state_labels: y-axes labels to for the state trajectories, no label by default
    :param act_labels: y-axes labels to for the action trajectories, no label by default
    :param x_limits: tuple containing the lower and upper limits for the x-axis
    :param plot_act: if `True`, also plot the actions
    :param data_field: data field of the rollout, e.g. "states" or "observations"
    :param cmap_samples: color map for the trajectories resulting from different domain parameter samples
    :param save_dir: if not `None` create a subfolder plots in `save_dir` and save the plots in there
    :param file_format: select the file format to store the plots
    :return: list of handles to the created figures
    """
    if plot_type not in ["samples", "confidence"]:
        raise pyrado.ValueErr(given=plot_type,
                              eq_constraint="samples or confidence")
    if data_field not in ["states", "observations"]:
        raise pyrado.ValueErr(given=data_field,
                              eq_constraint="states or observations")

    # Extract the state dimension, and the number of most likely samples from the data
    dim_state = segments_ground_truth[0][0].get_data_values(data_field)[
        0, :].size
    dim_act = segments_ground_truth[0][0].get_data_values("actions")[0, :].size
    num_samples = len(segments_multiple_envs[0][0])

    # Validate the labels
    if state_labels is None:
        state_labels = [""] * dim_state
    else:
        if len(state_labels) != dim_state:
            raise pyrado.ShapeErr(given=state_labels,
                                  expected_match=(dim_state, ))
    if act_labels is None:
        act_labels = [""] * dim_act
    else:
        if len(act_labels) != dim_act:
            raise pyrado.ShapeErr(given=act_labels, expected_match=(dim_act, ))

    if cmap_samples is None:
        cmap_samples = plt.get_cmap("Reds")(np.linspace(0.6, 0.8, num_samples))
    fig_list = []
    label_samples = "ml" if plot_type == "confidence" else "samples"

    # Plot
    for idx_r in range(len(segments_ground_truth)):
        num_rows = dim_state + dim_act if plot_act else dim_state
        fig, axs = plt.subplots(nrows=num_rows,
                                figsize=(16, 9),
                                tight_layout=True,
                                sharex="col")
        axs = np.atleast_1d(axs)

        # Plot the states
        for idx_state in range(dim_state):
            # Plot the real segments
            cnt_step = [0]
            for segment_gt in segments_ground_truth[idx_r]:
                axs[idx_state].plot(
                    np.arange(cnt_step[-1], cnt_step[-1] + segment_gt.length),
                    segment_gt.get_data_values(data_field,
                                               truncate_last=True)[:,
                                                                   idx_state],
                    zorder=0,
                    c="black",
                    lw=1.0,
                    label="target" if cnt_step[-1] == 0 else "",  # print once
                )
                cnt_step.append(cnt_step[-1] + segment_gt.length)

            # Plot the maximum likely simulated segments
            for idx_seg, sml in enumerate(segments_multiple_envs[idx_r]):
                for idx_dp, sdp in enumerate(sml):
                    axs[idx_state].plot(
                        np.arange(cnt_step[idx_seg],
                                  cnt_step[idx_seg] + sdp.length),
                        sdp.get_data_values(data_field,
                                            truncate_last=True)[:, idx_state],
                        zorder=2 if idx_dp == 0 else 0,  # most likely on top
                        c=cmap_samples[idx_dp],
                        ls="-",
                        lw=1.5
                        if plot_type == "confidence" or idx_dp == 0 else 0.5,
                        alpha=1.0
                        if plot_type == "confidence" or idx_dp == 0 else 0.1,
                        label=label_samples
                        if cnt_step[idx_seg] == idx_seg == idx_dp == 0 else
                        "",  # print once
                    )
                    if plot_type != "samples":
                        # Stop here, unless the rollouts of most likely all domain parameters should be plotted
                        break

            if plot_type == "confidence":
                assert check_all_lengths_equal(
                    segments_multiple_envs[idx_r]
                    [0])  # all segments need to be equally long

                states_all = []
                for idx_dp in range(num_samples):
                    # Reconstruct the step sequences for all domain parameters
                    ss_dp = StepSequence.concat([
                        seg_dp[idx_dp] for seg_dp in
                        [segs_ro for segs_ro in segments_multiple_envs[idx_r]]
                    ])
                    states = ss_dp.get_data_values(data_field,
                                                   truncate_last=True)
                    states_all.append(states)
                states_all = np.stack(states_all, axis=0)
                states_mean = np.mean(states_all, axis=0)
                states_std = np.std(states_all, axis=0)

                for idx_seg in range(len(segments_multiple_envs[idx_r])):
                    len_segs = min([
                        len(seg)
                        for seg in segments_multiple_envs[idx_r][idx_seg]
                    ])  # use shortest
                    m_i = states_mean[cnt_step[idx_seg]:cnt_step[idx_seg] +
                                      len_segs, idx_state]
                    s_i = states_std[cnt_step[idx_seg]:cnt_step[idx_seg] +
                                     len_segs, idx_state]
                    draw_curve(
                        "std",
                        axs[idx_state],
                        pd.DataFrame(dict(mean=m_i, std=s_i)),
                        x_grid=np.arange(cnt_step[idx_seg],
                                         cnt_step[idx_seg] + len_segs),
                        show_legend=False,
                        area_label="2 std" if idx_seg == 0 else None,
                        plot_kwargs=dict(color=cmap_samples[0]),
                    )

            # Plot the nominal simulation's segments
            for idx_seg, sn in enumerate(segments_nominal[idx_r]):
                axs[idx_state].plot(
                    np.arange(cnt_step[idx_seg],
                              cnt_step[idx_seg] + sn.length),
                    sn.get_data_values(data_field,
                                       truncate_last=True)[:, idx_state],
                    zorder=2,
                    c="green",  # former: steelblue"
                    ls="--",
                    lw=1.0,
                    label="nom sim"
                    if cnt_step[idx_seg] == 0 else "",  # print once
                )

            axs[idx_state].set_ylabel(state_labels[idx_state])

        if plot_act:
            # Plot the actions
            for idx_act in range(dim_act):
                # Plot the real segments
                cnt_step = [0]
                for segment_gt in segments_ground_truth[idx_r]:
                    axs[dim_state + idx_act].plot(
                        np.arange(cnt_step[-1],
                                  cnt_step[-1] + segment_gt.length),
                        segment_gt.get_data_values(
                            "actions", truncate_last=False)[:, idx_act],
                        zorder=0,
                        c="black",
                        label="target"
                        if cnt_step[-1] == 0 else "",  # print once
                    )
                    cnt_step.append(cnt_step[-1] + segment_gt.length)

                # Plot the maximum likely simulated segments
                for idx_seg, sml in enumerate(segments_multiple_envs[idx_r]):
                    for idx_dp, sdp in enumerate(sml):
                        axs[dim_state + idx_act].plot(
                            np.arange(cnt_step[idx_seg],
                                      cnt_step[idx_seg] + sdp.length),
                            sdp.get_data_values("actions",
                                                truncate_last=False)[:,
                                                                     idx_act],
                            zorder=2
                            if idx_dp == 0 else 0,  # most likely on top
                            c=cmap_samples[idx_dp],
                            ls="--",
                            lw=1.5 if plot_type == "confidence" or idx_dp == 0
                            else 0.5,
                            alpha=1.0 if plot_type == "confidence"
                            or idx_dp == 0 else 0.4,
                            label=label_samples
                            if cnt_step[idx_seg] == idx_seg == idx_dp == 0 else
                            "",  # print once
                        )
                        if plot_type != "samples":
                            # Stop here, unless the rollouts of most likely all domain parameters should be plotted
                            break

                if plot_type == "confidence":
                    len_segs = len(segments_multiple_envs[idx_r][0][0])
                    assert check_all_lengths_equal(
                        segments_multiple_envs[idx_r]
                        [0])  # all segments need to be equally long

                    acts_all = []
                    for idx_dp in range(num_samples):
                        # Reconstruct the step sequences for all domain parameters
                        ss_dp = StepSequence.concat([
                            seg_dp[idx_dp] for seg_dp in [
                                segs_ro
                                for segs_ro in segments_multiple_envs[idx_r]
                            ]
                        ])
                        acts = ss_dp.get_data_values("actions",
                                                     truncate_last=False)
                        acts_all.append(acts)
                    acts_all = np.stack(acts_all, axis=0)
                    acts_mean = np.mean(acts_all, axis=0)
                    acts_std = np.std(acts_all, axis=0)

                    for idx_seg in range(len(segments_multiple_envs[idx_r])):
                        m_i = acts_mean[cnt_step[idx_seg]:cnt_step[idx_seg] +
                                        len_segs, idx_act]
                        s_i = acts_std[cnt_step[idx_seg]:cnt_step[idx_seg] +
                                       len_segs, idx_act]
                        draw_curve(
                            "std",
                            axs[dim_state + idx_act],
                            pd.DataFrame(dict(mean=m_i, std=s_i)),
                            x_grid=np.arange(cnt_step[idx_seg],
                                             cnt_step[idx_seg] + len_segs),
                            show_legend=False,
                            area_label="2 std" if idx_seg == 0 else None,
                            plot_kwargs=dict(color=cmap_samples[0]),
                        )

                # Plot the nominal simulation's segments
                for idx_seg, sn in enumerate(segments_nominal[idx_r]):
                    axs[dim_state + idx_act].plot(
                        np.arange(cnt_step[idx_seg],
                                  cnt_step[idx_seg] + sn.length),
                        sn.get_data_values("actions",
                                           truncate_last=False)[:, idx_act],
                        zorder=2,
                        c="steelblue",
                        ls="-.",
                        label="nom sim"
                        if cnt_step[idx_seg] == 0 else "",  # print once
                    )

                axs[dim_state + idx_act].set_ylabel(act_labels[idx_act])

        # Settings for all subplots
        for idx_axs in range(num_rows):
            if x_limits is not None:
                axs[idx_axs].set_xlim(x_limits[0], x_limits[1])

        # Set window title and the legend, placing the latter above the plot expanding and expanding it fully
        use_rec_str = ", using rec actions" if use_rec_str else ""
        round_str = f"round {idx_round}, " if idx_round != -1 else ""
        fig.canvas.manager.set_window_title(
            f"Target Domain and Simulated Rollouts (iteration {idx_iter}, {round_str}rollout {idx_r}{use_rec_str})"
        )
        lg = axs[0].legend(
            ncol=2 + num_samples,
            bbox_to_anchor=(0.0, 1.02, 1.0, 0.102),
            loc="lower left",
            mode="expand",
            borderaxespad=0.0,
        )

        # Save if desired
        if save_dir is not None:
            for fmt in file_format:
                os.makedirs(os.path.join(save_dir, "plots"), exist_ok=True)
                len_seg_str = f"seglen_{segments_ground_truth[0][0].length}"
                use_rec_str = "_use_rec" if use_rec_str else ""
                round_str = f"_round_{idx_round}" if idx_round != -1 else ""
                fig.savefig(
                    os.path.join(
                        save_dir,
                        "plots",
                        f"posterior_iter_{idx_iter}{round_str}_rollout_{idx_r}_{len_seg_str}{use_rec_str}.{fmt}",
                    ),
                    bbox_extra_artists=(lg, ),
                    dpi=150,
                )

        # Append current figure
        fig_list.append(fig)

    return fig_list
        # Get the experiments' directories to load from
        prefixes = [
            osp.join(pyrado.EXP_DIR, 'ENV_NAME', 'ALGO_NAME'),
        ]
        ex_names = [
            '',
        ]
        ex_labels = [
            '',
        ]

    else:
        raise pyrado.ValueErr(given=args.env_name, eq_constraint=f'{QCartPoleSwingUpSim.name}, {QCartPoleStabSim.name},'
                                                                 f' or {QCartPoleSwingUpSim.name}')

    if not check_all_lengths_equal([prefixes, ex_names, ex_labels]):
        raise pyrado.ShapeErr(msg=f'The lengths of prefixes, ex_names, and ex_labels must be equal, '
                                  f'but they are {len(prefixes)}, {len(ex_names)}, and {len(ex_labels)}!')

    # Create Randomizer
    pert = create_conservative_randomizer(env)
    pert.add_domain_params(UniformDomainParam(name='act_delay', mean=20, halfspan=20, clip_lo=0, roundint=True))

    # Loading the policies
    ex_dirs = [osp.join(p, e) for p, e in zip(prefixes, ex_names)]
    env_sim_list = []
    policy_list = []
    for ex_dir in ex_dirs:
        env_sim, policy, _ = load_experiment(ex_dir, args)
        policy_list.append(policy)
Example #4
0
def test_check_all_lengths_equal(x, b):
    assert check_all_lengths_equal(x) == b