Source code for sciope.utilities.priors.uniform_prior
# Copyright 2020 Prashant Singh, Richard Jiang, Fredrik Wrede and Andreas Hellander
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
The Uniform Prior
"""
# Imports
from sciope.utilities.priors.prior_base import PriorBase
from sciope.utilities.housekeeping import sciope_logger as ml
from dask import delayed
import numpy as np
# Class definition: Uniform Prior
[docs]class UniformPrior(PriorBase):
    """
    The uniform prior draws a sample from the uniform distribution in a specified d-dimensional space described as:
    [min_i, max_i], i=1..d
    """
    def __init__(self, space_min, space_max, use_logger=False):
        """
        Set up a uniform prior corresponding to the space bounded by:
        :param space_min: the lowerbound of each variable/dimension
        :param space_max: the upperbound of each variable/dimension
        :param use_logger: whether logging is enabled or disabled
        """
        self.name = 'Uniform'
        self.lb = space_min
        self.ub = space_max
        super(UniformPrior, self).__init__(self.name, use_logger)
        if self.use_logger:
            self.logger = ml.SciopeLogger().get_logger()
            self.logger.info("Uniform prior in {} dimensions initialized".format(len(self.lb)))
[docs]    def draw(self, n=1, chunk_size=1):
        """
        Draw 'n' samples within self.lb and self.ub
        :param n: the desired number of samples
        :return: the n-sized vector of drawn samples
        """
        assert n >= chunk_size, "chunk_size can not be larger than n"
        d = len(self.lb)
        generated_samples = []
        m = n % chunk_size
        if m > 0:
            generated_samples.append(self._uniform_scale(m, d))
        for i in range(0, n - m, chunk_size):
            generated_samples.append(self._uniform_scale(chunk_size, d))
        return generated_samples
[docs]    def pdf(self, x, log=False):
        if len(np.asarray(x).shape) == 1:
            z = np.asarray(x)
            if (z > self.lb).all() and (z < self.ub).all():
                v = np.prod(1 / (self.ub - self.lb))
                if log:
                    v = np.log(v)
            else:
                v = 0
                if log:
                    v = -np.inf
            return v
        else:
            z = np.asarray(x)
            vs = []
            for i in range(z.shape[0]):
                if (z[i] > self.lb).all() and (z[i] < self.ub).all():
                    v = np.prod(1 / (self.ub - self.lb))
                    if log:
                        vs.append(np.log(v))
                    else:
                        vs.append(v)
                else:
                    if log:
                        vs.append(-np.inf)
                    else:
                        vs.append(0)
            return np.asarray(vs)
        return v
    @delayed
    def _uniform_scale(self, n, d):
        # Generate samples in [0,1)
        generated_samples = np.random.random((n, d))
        # scale from [0,1) to problem range
        scaled_values = generated_samples
        for j in range(0, d):
            scaled_values[:, j] = (generated_samples[:, j] * (self.ub[j] - self.lb[j])) + self.lb[j]
        if self.use_logger:
            self.logger.info("Uniform Prior: sampled {} points in {} dimensions".format(n, len(self.lb)))
        return scaled_values