def from_simulator(
        cls,
        simulator_func: Callable,
        theta_0: Union[Number, np.array],
        theta_1: Union[Number, np.array],
        n_samples_per_theta: int,
        shuffle: bool = True,
        include_log_probs: bool = False,
    ):
        theta_0, theta_1 = map(ensure_array, [theta_0, theta_1])
        assert theta_0.ndim == 1 == theta_1.ndim

        sim0 = build_simulator(simulator_func, theta_0)
        sim1 = build_simulator(simulator_func, theta_1)
        x0 = sim0.sample(n_samples_per_theta).numpy()
        x1 = sim1.sample(n_samples_per_theta).numpy()
        y0 = np.zeros(len(x0))
        y1 = np.ones_like(y0)
        x = np.concatenate([x0, x1], axis=0).astype(np.float32)
        y = np.concatenate([y0, y1], axis=0).astype(np.float32)

        if include_log_probs:
            log_prob_0 = sim0.log_prob(x).astype(np.float32)
            log_prob_1 = sim1.log_prob(x).astype(np.float32)
        else:
            log_prob_0 = None
            log_prob_1 = None

        return cls(x=x,
                   y=y,
                   theta_0=theta_0,
                   theta_1=theta_1,
                   log_prob_0=log_prob_0,
                   log_prob_1=log_prob_1,
                   shuffle=shuffle)
 def _simulate(theta_1, x0_i):
     sim1 = build_simulator(simulator_func, theta_1)
     x1_i = sim1.sample(n_samples_per_theta).numpy()
     x1_i = ensure_2d(x1_i)
     x0_i = ensure_2d(x0_i)
     x1.append(x1_i)
     if include_log_probs:
         log_prob_0_x0.append(sim0.log_prob(x0_i))
         log_prob_0_x1.append(sim0.log_prob(x1_i))
         log_prob_1_x0.append(sim1.log_prob(x0_i))
         log_prob_1_x1.append(sim1.log_prob(x1_i))
def exact_param_scan(simulator_func: Callable,
                     X_true: np.ndarray,
                     param_grid: ParamGrid,
                     theta_0: float,
                     to_meshgrid_shape: bool = True) -> Sequence[np.ndarray]:

    p_0 = build_simulator(simulator_func=simulator_func, theta=theta_0)
    log_prob_0 = p_0.log_prob(X_true)

    @tf.function
    def exact_nllr(theta):
        p_theta = build_simulator(simulator_func=simulator_func, theta=theta)
        return -tf.keras.backend.sum(p_theta.log_prob(X_true) - log_prob_0)

    nllr = np.array(
        [exact_nllr(theta.squeeze()).numpy() for theta in param_grid])
    mle = param_grid[np.argmin(nllr)]

    if to_meshgrid_shape:
        nllr = _to_meshgrid_shape(nllr, param_grid)

    return nllr, mle
    def from_simulator(cls,
                       simulator_func: Callable,
                       theta_0: Union[Number, np.ndarray],
                       theta_1_iterator: ParamIterator,
                       n_samples_per_theta: int,
                       shuffle: bool = True,
                       include_log_probs: bool = False):
        theta_0 = ensure_array(theta_0)
        assert theta_0.ndim == 1

        sim0 = build_simulator(simulator_func, theta_0)
        x0 = sim0.sample(n_samples_per_theta * len(theta_1_iterator)).numpy()
        x0 = ensure_2d(x0)
        y0 = np.zeros(len(x0))
        y1 = np.ones_like(y0)
        x1 = []
        theta_1s = np.zeros((len(x0), len(theta_0)))

        if include_log_probs:
            log_prob_0_x0 = []
            log_prob_0_x1 = []
            log_prob_1_x0 = []
            log_prob_1_x1 = []

        def _simulate(theta_1, x0_i):
            sim1 = build_simulator(simulator_func, theta_1)
            x1_i = sim1.sample(n_samples_per_theta).numpy()
            x1_i = ensure_2d(x1_i)
            x0_i = ensure_2d(x0_i)
            x1.append(x1_i)
            if include_log_probs:
                log_prob_0_x0.append(sim0.log_prob(x0_i))
                log_prob_0_x1.append(sim0.log_prob(x1_i))
                log_prob_1_x0.append(sim1.log_prob(x0_i))
                log_prob_1_x1.append(sim1.log_prob(x1_i))

        for i, theta_1 in enumerate(theta_1_iterator):
            start = i * n_samples_per_theta
            stop = (i + 1) * n_samples_per_theta
            theta_1s[start:stop, :] = theta_1
            _simulate(theta_1, x0[start:stop, :])

        if include_log_probs:
            log_prob_0 = np.concatenate(log_prob_0_x0 + log_prob_0_x1,
                                        axis=0).astype(np.float32)
            log_prob_1 = np.concatenate(log_prob_1_x0 + log_prob_1_x1,
                                        axis=0).astype(np.float32)
        else:
            log_prob_0 = None
            log_prob_1 = None

        x1 = ensure_2d(np.concatenate(x1, axis=0))
        x = np.concatenate([x0, x1], axis=0).astype(np.float32)
        y = np.concatenate([y0, y1], axis=0).astype(np.float32)
        theta_1s = concat_repeat(theta_1s, 2, axis=0).astype(np.float32)
        return cls(x=x,
                   y=y,
                   theta_0=theta_0,
                   theta_1s=theta_1s,
                   log_prob_0=log_prob_0,
                   log_prob_1=log_prob_1,
                   shuffle=shuffle)
 def exact_nllr(theta):
     p_theta = build_simulator(simulator_func=simulator_func, theta=theta)
     return -tf.keras.backend.sum(p_theta.log_prob(X_true) - log_prob_0)