Module pacai.util.probability

Various utilities for working with probabilities and distributions.

Expand source code
"""
Various utilities for working with probabilities and distributions.
"""

import math
import random

def normalize(listOrDict):
    """
    Normalize a list or dictionary by dividing each value by the
    sum of all values, resulting in values to be in range [0, 1].
    Requirements for listOrDict argument:
    1. Must be non-empty.
    2. For a dict, each value must be >= 0 and the sum must be > 0.
    """

    if isinstance(listOrDict, dict):
        total = float(sum(listOrDict.values()))
        if math.isclose(total, 0):
            return listOrDict

        normalizedDict = {}
        for key, value in listOrDict.items():
            normalizedDict[key] = value / total

        return normalizedDict
    else:
        total = float(sum(listOrDict))
        if math.isclose(total, 0):
            return listOrDict

        return [val / total for val in listOrDict]

def nSample(distribution, values, n):
    if not math.isclose(sum(distribution), 1):
        distribution = normalize(distribution)

    rand = [random.random() for i in range(n)]
    rand.sort()
    samples = []
    samplePos, distPos, cdf = 0, 0, distribution[0]
    while samplePos < n:
        if rand[samplePos] < cdf:
            samplePos += 1
            samples.append(values[distPos])
        else:
            distPos += 1
            cdf += distribution[distPos]

    return samples

def sample(distribution, values = None):
    if isinstance(distribution, dict):
        items = sorted(distribution.items())
        distribution = [i[1] for i in items]
        values = [i[0] for i in items]

    if len(distribution) == 0:
        raise ValueError("Distribution to sample must be non-empty.")

    if math.isclose(sum(distribution), 1):
        distribution = normalize(distribution)

    if values is None:
        raise ValueError("When sampling list, both distribution and values must be initialized.")

    if len(distribution) != len(values):
        raise ValueError("When sampling list, distribution and values must be the same size.")

    choice = random.random()
    i = 0
    total = distribution[0]

    while choice >= total:
        i += 1
        total += distribution[i]

    return values[i]

def getProbability(value, distribution, values):
    """
    Gives the probability of a value under a discrete distribution
    defined by (distributions, values).
    """

    total = 0.0
    for prob, val in zip(distribution, values):
        if val == value:
            total += prob

    return total

def flipCoin(p):
    r = random.random()
    return r < p

Functions

def flipCoin(p)
Expand source code
def flipCoin(p):
    r = random.random()
    return r < p
def getProbability(value, distribution, values)

Gives the probability of a value under a discrete distribution defined by (distributions, values).

Expand source code
def getProbability(value, distribution, values):
    """
    Gives the probability of a value under a discrete distribution
    defined by (distributions, values).
    """

    total = 0.0
    for prob, val in zip(distribution, values):
        if val == value:
            total += prob

    return total
def nSample(distribution, values, n)
Expand source code
def nSample(distribution, values, n):
    if not math.isclose(sum(distribution), 1):
        distribution = normalize(distribution)

    rand = [random.random() for i in range(n)]
    rand.sort()
    samples = []
    samplePos, distPos, cdf = 0, 0, distribution[0]
    while samplePos < n:
        if rand[samplePos] < cdf:
            samplePos += 1
            samples.append(values[distPos])
        else:
            distPos += 1
            cdf += distribution[distPos]

    return samples
def normalize(listOrDict)

Normalize a list or dictionary by dividing each value by the sum of all values, resulting in values to be in range [0, 1]. Requirements for listOrDict argument: 1. Must be non-empty. 2. For a dict, each value must be >= 0 and the sum must be > 0.

Expand source code
def normalize(listOrDict):
    """
    Normalize a list or dictionary by dividing each value by the
    sum of all values, resulting in values to be in range [0, 1].
    Requirements for listOrDict argument:
    1. Must be non-empty.
    2. For a dict, each value must be >= 0 and the sum must be > 0.
    """

    if isinstance(listOrDict, dict):
        total = float(sum(listOrDict.values()))
        if math.isclose(total, 0):
            return listOrDict

        normalizedDict = {}
        for key, value in listOrDict.items():
            normalizedDict[key] = value / total

        return normalizedDict
    else:
        total = float(sum(listOrDict))
        if math.isclose(total, 0):
            return listOrDict

        return [val / total for val in listOrDict]
def sample(distribution, values=None)
Expand source code
def sample(distribution, values = None):
    if isinstance(distribution, dict):
        items = sorted(distribution.items())
        distribution = [i[1] for i in items]
        values = [i[0] for i in items]

    if len(distribution) == 0:
        raise ValueError("Distribution to sample must be non-empty.")

    if math.isclose(sum(distribution), 1):
        distribution = normalize(distribution)

    if values is None:
        raise ValueError("When sampling list, both distribution and values must be initialized.")

    if len(distribution) != len(values):
        raise ValueError("When sampling list, distribution and values must be the same size.")

    choice = random.random()
    i = 0
    total = distribution[0]

    while choice >= total:
        i += 1
        total += distribution[i]

    return values[i]