Ejemplo n.º 1
0
def test_fast_random_choice_output():
    """Test that the fast random choice outputs are accurate."""
    n_sample = 10000

    # few samples
    weights = np.array([0.1, 0.9])
    ret = np.array([fast_random_choice(weights) for _ in range(n_sample)])
    assert 0.08 < sum(ret == 0) / n_sample < 0.12
    assert 0.88 < sum(ret == 1) / n_sample < 0.92

    # many samples
    weights = np.array([*[0.02] * 20, *[0.3] * 2])
    ret = np.array([fast_random_choice(weights) for _ in range(n_sample)])
    assert 0.005 < sum(ret == 0) / n_sample < 0.04
    assert 0.28 < sum(ret == 20) / n_sample < 0.32
Ejemplo n.º 2
0
def generate_valid_proposal(
        t: int, m: np.ndarray, p: np.ndarray,
        model_prior: RV, parameter_priors: List[Distribution],
        model_perturbation_kernel: ModelPerturbationKernel,
        transitions: List[Transition]):
    """Sample a parameter for a model.

    Parameters
    ----------
    t: Population index to generate for.
    m: Indices of alive models.
    p: Probabilities of alive models.
    model_prior: The model prior.
    parameter_priors: The parameter priors.
    model_perturbation_kernel: The model perturbation kernel.
    transitions: The transitions, one per model.

    Returns
    -------
    (m_ss, theta_ss): Model, parameter.
    """
    # first generation
    if t == 0:
        # sample from prior
        m_ss = int(model_prior.rvs())
        theta_ss = parameter_priors[m_ss].rvs()
        return m_ss, theta_ss

    # later generation
    # counter
    n_sample, n_sample_soft_limit = 0, 1000
    # sample until the prior density is positive
    while True:
        if len(m) > 1:
            index = fast_random_choice(p)
            m_s = m[index]
            m_ss = model_perturbation_kernel.rvs(m_s)
            # theta_s is None if the population m_ss has died out.
            # This can happen since the model_perturbation_kernel
            # can return a model nr which has died out.
            if m_ss not in m:
                continue
        else:
            # only one model
            m_ss = m[0]
        theta_ss = Parameter(**transitions[m_ss].rvs().to_dict())

        # check if positive under prior
        if (model_prior.pmf(m_ss)
                * parameter_priors[m_ss].pdf(theta_ss) > 0):
            return m_ss, theta_ss

        # unhealthy sampling detection
        n_sample += 1
        if n_sample == n_sample_soft_limit:
            logger.warning(
                "Unusually many (model, parameter) samples have prior "
                "density zero. The transition might be inappropriate.")
Ejemplo n.º 3
0
def test_fast_random_choice():
    """Check that `fast_random_choice` delivers the promised benefit."""
    nrep = 100000

    ws = np.random.uniform(size=(nrep, 10))
    ws /= ws.sum(axis=1, keepdims=True)

    np.random.seed(0)
    start = time()
    for w in ws:
        np.random.choice(len(w), p=w)
    time_numpy = time() - start
    print(f"Time numpy: {time_numpy}")

    np.random.seed(0)
    start = time()
    for w in ws:
        fast_random_choice(w)
    time_fast = time() - start
    print(f"Time fast_random_choice: {time_fast}")

    assert time_fast < time_numpy
Ejemplo n.º 4
0
def test_fast_random_choice_basic():
    """Test the fast random choice function for various inputs."""
    # run with many values (method 1)
    weights = np.random.uniform(0, 1, size=10000)
    weights /= weights.sum()
    fast_random_choice(weights)

    # run with few values (method 2)
    weights = np.random.uniform(0, 1, size=5)
    weights /= weights.sum()
    fast_random_choice(weights)

    # run with a single value
    fast_random_choice(np.array([1]))
Ejemplo n.º 5
0
def test_fast_random_choice_errors():
    """Test the fast random choice function for invalid inputs."""
    with pytest.raises(ValueError):
        fast_random_choice(np.array([]))

    # non-normalized weights for many values
    weights = np.random.uniform(0, 1, size=1000)
    weights /= weights.sum() / 2
    with pytest.raises(ValueError):
        fast_random_choice(weights)

    # non-normalized weights for few values
    with pytest.raises(ValueError):
        # does not always raise, but will sometimes
        for _ in range(100):
            weights = np.random.uniform(0, 1, size=5)
            weights /= 5
            fast_random_choice(weights)