nmoo.plotting.delta_f

ΔF plots

  1"""
  2ΔF plots
  3"""
  4__docformat__ = "google"
  5
  6from itertools import product
  7from math import sqrt
  8from pathlib import Path
  9from typing import Dict
 10
 11import numpy as np
 12import pandas as pd
 13import seaborn as sns
 14from loguru import logger as logging
 15from pymoo.core.problem import Problem
 16
 17from nmoo.benchmark import Benchmark
 18
 19
 20def _load_problem_data(
 21    file_path: Path, ground_problem: Problem
 22) -> pd.DataFrame:
 23    """
 24    Loads a problem history and annotates it with true F values.
 25    """
 26    history = np.load(file_path)
 27    d1, d2 = pd.DataFrame(), pd.DataFrame()
 28    d1["_batch"] = d2["_batch"] = history["_batch"]
 29    d1["type"], d2["type"] = "approx.", "true"
 30    out: Dict[str, np.ndarray] = {}
 31    ground_problem._evaluate(history["X"], out)
 32    d1["F0"], d1["F1"] = history["F"][:, 0], history["F"][:, 1]
 33    d2["F0"], d2["F1"] = out["F"][:, 0], out["F"][:, 1]
 34    history.close()
 35    return pd.concat([d1, d2], ignore_index=True)
 36
 37
 38def generate_delta_F_plots(
 39    benchmark: Benchmark,
 40    n_generations: int = 10,
 41) -> None:
 42    """
 43    Generate all ΔF plots for a given benchmark, and save them as jpg image in
 44    the benchmark's output directory. The naming pattern is the same as in
 45    `nmoo.wrapped_problem.WrappedProblem.dump_all_histories`, except the files
 46    end with the `.jpg` extension instead of `.npz`.
 47
 48    <center>
 49        <img src="https://github.com/altaris/noisy-moo/raw/main/imgs/generate_delta_F_plots.png"
 50        alt="Example"/>
 51    </center>
 52
 53    A ΔF plot show the predicted value of a denoised noisy problem (in blue)
 54    against the true value of the base problem (in orange). In addition, the
 55    Pareto front is plotted in red. This kind of plot is only possible in a
 56    synthetic setting.
 57
 58    Args:
 59        n_generations (int): Number of generation to plot.
 60
 61    Warning:
 62        The ground pymoo problem must have a `pareto_front()` method that
 63        returns an actual array.
 64    """
 65    if not benchmark._dump_histories:
 66        raise RuntimeError(
 67            "The benchmark must have 'dump_histories=True' set when "
 68            "constructed."
 69        )
 70    everything = product(
 71        benchmark._algorithms.keys(),
 72        [(k, v["problem"]) for k, v in benchmark._problems.items()],
 73        range(1, benchmark._n_runs + 1),
 74    )
 75    for an, (pn, p), r in everything:
 76        if p.n_obj != 2:
 77            logging.warning(
 78                "Problem {} has {} objectives, but exactly 2 is needed for "
 79                "plotting",
 80                pn,
 81                p.n_obj,
 82            )
 83            continue
 84        ground_problem = p.ground_problem()
 85        # TODO: What if the ground_problem does not have a Pareto front?
 86        pareto_front = ground_problem.pareto_front()
 87        for li, l in enumerate(p.all_layers()):
 88            file_stem = f"{pn}.{an}.{r}.{li + 1}-{l._name}"
 89            df = _load_problem_data(
 90                benchmark._output_dir_path / (file_stem + ".npz"),
 91                ground_problem,
 92            )
 93            grid = sns.FacetGrid(
 94                df[
 95                    df._batch.isin(
 96                        np.linspace(
 97                            1, df._batch.max(), n_generations, dtype=int
 98                        )
 99                    )
100                ],
101                col="_batch",
102                col_wrap=int(sqrt(n_generations)),
103            )
104            grid.map_dataframe(
105                sns.scatterplot, x="F0", y="F1", style="type", hue="type"
106            )
107            grid.add_legend()
108            if pareto_front.shape[0]:
109                for ax in grid.axes:
110                    ax.plot(pareto_front[:, 0], pareto_front[:, 1], "--r")
111            grid.savefig(benchmark._output_dir_path / (file_stem + ".jpg"))
def generate_delta_F_plots(benchmark: nmoo.benchmark.Benchmark, n_generations: int = 10) -> None:
 39def generate_delta_F_plots(
 40    benchmark: Benchmark,
 41    n_generations: int = 10,
 42) -> None:
 43    """
 44    Generate all ΔF plots for a given benchmark, and save them as jpg image in
 45    the benchmark's output directory. The naming pattern is the same as in
 46    `nmoo.wrapped_problem.WrappedProblem.dump_all_histories`, except the files
 47    end with the `.jpg` extension instead of `.npz`.
 48
 49    <center>
 50        <img src="https://github.com/altaris/noisy-moo/raw/main/imgs/generate_delta_F_plots.png"
 51        alt="Example"/>
 52    </center>
 53
 54    A ΔF plot show the predicted value of a denoised noisy problem (in blue)
 55    against the true value of the base problem (in orange). In addition, the
 56    Pareto front is plotted in red. This kind of plot is only possible in a
 57    synthetic setting.
 58
 59    Args:
 60        n_generations (int): Number of generation to plot.
 61
 62    Warning:
 63        The ground pymoo problem must have a `pareto_front()` method that
 64        returns an actual array.
 65    """
 66    if not benchmark._dump_histories:
 67        raise RuntimeError(
 68            "The benchmark must have 'dump_histories=True' set when "
 69            "constructed."
 70        )
 71    everything = product(
 72        benchmark._algorithms.keys(),
 73        [(k, v["problem"]) for k, v in benchmark._problems.items()],
 74        range(1, benchmark._n_runs + 1),
 75    )
 76    for an, (pn, p), r in everything:
 77        if p.n_obj != 2:
 78            logging.warning(
 79                "Problem {} has {} objectives, but exactly 2 is needed for "
 80                "plotting",
 81                pn,
 82                p.n_obj,
 83            )
 84            continue
 85        ground_problem = p.ground_problem()
 86        # TODO: What if the ground_problem does not have a Pareto front?
 87        pareto_front = ground_problem.pareto_front()
 88        for li, l in enumerate(p.all_layers()):
 89            file_stem = f"{pn}.{an}.{r}.{li + 1}-{l._name}"
 90            df = _load_problem_data(
 91                benchmark._output_dir_path / (file_stem + ".npz"),
 92                ground_problem,
 93            )
 94            grid = sns.FacetGrid(
 95                df[
 96                    df._batch.isin(
 97                        np.linspace(
 98                            1, df._batch.max(), n_generations, dtype=int
 99                        )
100                    )
101                ],
102                col="_batch",
103                col_wrap=int(sqrt(n_generations)),
104            )
105            grid.map_dataframe(
106                sns.scatterplot, x="F0", y="F1", style="type", hue="type"
107            )
108            grid.add_legend()
109            if pareto_front.shape[0]:
110                for ax in grid.axes:
111                    ax.plot(pareto_front[:, 0], pareto_front[:, 1], "--r")
112            grid.savefig(benchmark._output_dir_path / (file_stem + ".jpg"))

Generate all ΔF plots for a given benchmark, and save them as jpg image in the benchmark's output directory. The naming pattern is the same as in nmoo.wrapped_problem.WrappedProblem.dump_all_histories, except the files end with the .jpg extension instead of .npz.

Example

A ΔF plot show the predicted value of a denoised noisy problem (in blue) against the true value of the base problem (in orange). In addition, the Pareto front is plotted in red. This kind of plot is only possible in a synthetic setting.

Arguments:
  • n_generations (int): Number of generation to plot.
Warning:

The ground pymoo problem must have a pareto_front() method that returns an actual array.