Esempio n. 1
0
    def test_raises(self):
        seed = np.random.RandomState(12345)

        message = r"'toto' is not a valid optimization method"
        with pytest.raises(ValueError, match=message):
            qmc.LatinHypercube(1, seed=seed, optimization="toto")

        message = r"not a valid strength"
        with pytest.raises(ValueError, match=message):
            qmc.LatinHypercube(1, strength=3, seed=seed)

        message = r"n is not the square of a prime number"
        with pytest.raises(ValueError, match=message):
            engine = qmc.LatinHypercube(d=2, strength=2, seed=seed)
            engine.random(16)

        message = r"n is not the square of a prime number"
        with pytest.raises(ValueError, match=message):
            engine = qmc.LatinHypercube(d=2, strength=2, seed=seed)
            engine.random(5)  # because int(sqrt(5)) would result in 2

        message = r"n is too small for d"
        with pytest.raises(ValueError, match=message):
            engine = qmc.LatinHypercube(d=5, strength=2, seed=seed)
            engine.random(9)
Esempio n. 2
0
    def test_discrepancy_hierarchy(self):
        seed = 68756348576543
        lhs = qmc.LatinHypercube(d=2, seed=seed)
        sample_ref = lhs.random(n=20)
        disc_ref = qmc.discrepancy(sample_ref)

        optimal_ = qmc.LatinHypercube(d=2, seed=seed, optimization="random-CD")
        sample_ = optimal_.random(n=20)
        disc_ = qmc.discrepancy(sample_)

        assert disc_ < disc_ref
Esempio n. 3
0
    def test_discrepancy_hierarchy(self):
        seed = np.random.RandomState(123456)
        lhs = qmc.LatinHypercube(d=2, seed=seed)
        sample_ref = lhs.random(n=20)
        disc_ref = qmc.discrepancy(sample_ref)

        seed = np.random.RandomState(123456)
        optimal_ = qmc.LatinHypercube(d=2, seed=seed, optimization="random-CD")
        sample_ = optimal_.random(n=20)
        disc_ = qmc.discrepancy(sample_)

        assert disc_ < disc_ref
Esempio n. 4
0
    def test_sample_stratified(self, optimization, centered, strength):
        seed = np.random.default_rng(37511836202578819870665127532742111260)
        p = 5
        n = p**2
        d = 6
        expected1d = (np.arange(n) + 0.5) / n
        expected = np.broadcast_to(expected1d, (d, n)).T

        engine = qmc.LatinHypercube(d=d, centered=centered,
                                    strength=strength,
                                    optimization=optimization,
                                    seed=seed)
        sample = engine.random(n=n)
        assert sample.shape == (n, d)
        assert engine.num_generated == n

        sorted_sample = np.sort(sample, axis=0)

        assert np.any(sample != expected)
        assert_allclose(sorted_sample, expected, atol=0.5 / n)
        assert np.any(sample - expected > 0.5 / n)

        if strength == 2 and optimization is None:
            unique_elements = np.arange(p)
            desired = set(product(unique_elements, unique_elements))

            for i, j in combinations(range(engine.d), 2):
                samples_2d = sample[:, [i, j]]
                res = (samples_2d * p).astype(int)
                res_set = set((tuple(row) for row in res))
                assert_equal(res_set, desired)
Esempio n. 5
0
    def test_raises(self):
        message = r"not a valid strength"
        with pytest.raises(ValueError, match=message):
            qmc.LatinHypercube(1, strength=3)

        message = r"n is not the square of a prime number"
        with pytest.raises(ValueError, match=message):
            engine = qmc.LatinHypercube(d=2, strength=2)
            engine.random(16)

        message = r"n is not the square of a prime number"
        with pytest.raises(ValueError, match=message):
            engine = qmc.LatinHypercube(d=2, strength=2)
            engine.random(5)  # because int(sqrt(5)) would result in 2

        message = r"n is too small for d"
        with pytest.raises(ValueError, match=message):
            engine = qmc.LatinHypercube(d=5, strength=2)
            engine.random(9)
Esempio n. 6
0
    def test_perm_discrepancy(self):
        rng = np.random.default_rng(46449423132557934943847369749645759997)
        qmc_gen = qmc.LatinHypercube(5, seed=rng)
        sample = qmc_gen.random(10)
        disc = qmc.discrepancy(sample)

        for i in range(100):
            row_1 = rng.integers(10)
            row_2 = rng.integers(10)
            col = rng.integers(5)

            disc = _perturb_discrepancy(sample, row_1, row_2, col, disc)
            sample[row_1, col], sample[row_2, col] = (
                sample[row_2, col], sample[row_1, col])
            disc_reference = qmc.discrepancy(sample)
            assert_allclose(disc, disc_reference)
Esempio n. 7
0
    def test_perm_discrepancy(self):
        seed = np.random.RandomState(123456)
        qmc_gen = qmc.LatinHypercube(5, seed=seed)
        sample = qmc_gen.random(10)
        disc = qmc.discrepancy(sample)

        for i in range(100):
            row_1 = np.random.randint(10)
            row_2 = np.random.randint(10)
            col = np.random.randint(5)

            disc = _perturb_discrepancy(sample, row_1, row_2, col, disc)
            sample[row_1, col], sample[row_2,
                                       col] = (sample[row_2,
                                                      col], sample[row_1, col])
            disc_reference = qmc.discrepancy(sample)
            assert_allclose(disc, disc_reference)
Esempio n. 8
0
def draw_exploration_sample(
    x,
    lower,
    upper,
    n_samples,
    sampling_distribution,
    sampling_method,
    seed,
):
    """Get a sample of parameter values for the first stage of the tiktak algorithm.

    The sample is created randomly or using a low discrepancy sequence. Different
    distributions are available.

    Args:
        x (np.ndarray): Internal parameter vector of shape (n_params,).
        lower (np.ndarray): Vector of internal lower bounds of shape (n_params,).
        upper (np.ndarray): Vector of internal upper bounds of shape (n_params,).
        n_samples (int): Number of sample points on which one function evaluation
            shall be performed. Default is 10 * n_params.
        sampling_distribution (str): One of "uniform", "triangular". Default is
            "uniform", as in the original tiktak algorithm.
        sampling_method (str): One of "sobol", "halton", "latin_hypercube" or
            "random". Default is sobol for problems with up to 200 parameters
            and random for problems with more than 200 parameters.
        seed (int): Random seed.

    Returns:
        np.ndarray: Numpy array of shape (n_samples, n_params).
            Each row represents a vector of parameter values.
    """
    valid_rules = ["sobol", "halton", "latin_hypercube", "random"]
    valid_distributions = ["uniform", "triangular"]

    if sampling_method not in valid_rules:
        raise ValueError(
            f"Invalid rule: {sampling_method}. Must be one of\n\n{valid_rules}\n\n"
        )

    if sampling_distribution not in valid_distributions:
        raise ValueError(f"Unsupported distribution: {sampling_distribution}")

    for name, bound in zip(["lower", "upper"], [lower, upper]):
        if not np.isfinite(bound).all():
            raise ValueError(
                f"multistart optimization requires finite {name}_bounds or "
                f"soft_{name}_bounds for all parameters.")

    if sampling_method == "sobol":
        # Draw `n` points from the open interval (lower, upper)^d.
        # Note that scipy uses the half-open interval [lower, upper)^d internally.
        # We apply a burn-in phase of 1, i.e. we skip the first point in the sequence
        # and thus exclude the lower bound.
        sampler = qmc.Sobol(d=len(lower), scramble=False, seed=seed)
        _ = sampler.fast_forward(1)
        sample_unscaled = sampler.random(n=n_samples)

    elif sampling_method == "halton":
        sampler = qmc.Halton(d=len(lower), scramble=False, seed=seed)
        sample_unscaled = sampler.random(n=n_samples)

    elif sampling_method == "latin_hypercube":
        sampler = qmc.LatinHypercube(d=len(lower), strength=1, seed=seed)
        sample_unscaled = sampler.random(n=n_samples)

    elif sampling_method == "random":
        rng = get_rng(seed)
        sample_unscaled = rng.uniform(size=(n_samples, len(lower)))

    if sampling_distribution == "uniform":
        sample_scaled = qmc.scale(sample_unscaled, lower, upper)
    elif sampling_distribution == "triangular":
        sample_scaled = triang.ppf(
            sample_unscaled,
            c=(x - lower) / (upper - lower),
            loc=lower,
            scale=upper - lower,
        )

    return sample_scaled