Module musx.ran

Expand source code
import random
import math
from .tools import rescale

# moved: between, odds, pick to here

def between(a, b):
    """
    Returns a random value between a and b (exclusive).

    An int is returned if both a and b are ints,
    otherwise a float is returned. The a value can be
    less than, equal to, or greater than b.

    Parameters
    ----------
    a : int | float
        The lower bound for the random selection.
    b : int | float
        The upper bound for the random selection.

    Returns
    -------
        A randomly chosen value between a and b.
    """
    if (a < b):
        if isinstance(a, int) and isinstance(b, int):
            return random.randrange(a, b)
        else:
            return a + (random.random() * (b - a))
    if (a > b):
        if isinstance(a, int) and isinstance(b, int):
            return a - random.randrange(b)
        else:
            return a - (random.random() * (a - b))
    return a


def odds(prob, true=True, false=False):
    """
    Returns true value if a random choice is less than prob else returns
    the false.

    Parameters
    ----------
    prob : float | int
        A value between 0 and 1 inclusive.
    true : value
        If odds is true the true value is returned.
    false : value
        If odds is false the false value is returned.

    Returns
    -------
    Either the true value or the false value based on probability.
    """
    if 0 <= prob <= 1.0:
        return true if random.random() < prob else false
    raise ValueError(f"{prob} not a number between 0 and 1.")


def pick(*args):
    """
    Randomly picks one of its arguments to return.

    Parameters
    ----------
    *args : variadic
        A series of values from which one will be randomly selected.

    Returns
    -------
    One value from the argument list.
    """
    return args[random.randrange(len(args))]


def vary(value, variance, shift=None):
    """
    Returns a random number that deviates from value or list of the same by
    up to variance (1=100%) according to shift. 
    
    Parameters
    ----------
    value : number | list
        The value or list of values to vary.
    variance : number
        The maximum amount to vary the value by, e.g. 0.5 means the variance
        could be up to 50% of the input value.
    shift : None | "+" | "-"
        Specifies where the variance is placed. If None then then value is at the
        center of what could be returned. Shift "+" places value at the minimum
        of what could be returned and "-" means that value is the maximum possible
        value returned.
    """
    if isinstance(value, list):
        return [vary(v, variance, shift) for v in value]
    if value == 0 or variance == 0:
        return val
    r = abs(value * variance)
    v = random.random() * r
    if shift == None:
        return (value - (r * .5)) + v
    if shift == '+':
        return value + v
    if shift == '-':
        return value - v
    raise ValueError("shift should be None, '+', or '-' ({shift})")


def shuffle (*args, **kwargs):
    """
    Returns a new list containing the random reordering of an input
    list, tuple or variadic sequence of values. The optional keyword
    arguments 'start' and 'end' allow just a sub-sequence of the
    input values to be shuffled.

    Parameters
    ----------
    args : list | tuple | variadic
        The values to shuffle 
    start : int
        Starting position in the list to shuffle, defaults to 0.
    end : int
        Inclusive ending position in the list to shuffle,
        defaults to the length of the input.
    """
    # print("args:", args, "numargs:", len(args), "kwargs:", kwargs)
    if isinstance(args[0], list):
        args = args[0].copy()
    else:
        args = list(args)
    arglen = len(args)
    start =  kwargs.get('start', 0)
    end = kwargs.get('end', arglen)
    width = end - start
    for i in range(start, end):
        j = start + random.randrange(width)
        args[i], args[j] = args[j], args[i]
    return args


def ransegs(num, mapto, rangen=None):
    """
    Returns a list of random number segments.

    Parameters
    ----------
    num : int
        The number of random values returned in the list.
    mapto : number | [low, high]
        If mapto is a number then the values retuned will sum to that number.
        If mapto is a list then the random values are sorted and scaled to
        lie proportionatly from low to high.
    rangen : None | function
        If function is provided it will be called to return random numbers,
        otherwise uniform random numbers between are generated.
    """
    #print(f"ransegs(num={num}, mapto={mapto})")
    segs = []
    rsum = 0
    if rangen == None:
        rangen = random.random
    for i in range(num):
        n = rangen()
        segs.append(n)
        rsum += n
    if isinstance(mapto, (list, tuple)):
        segs.sort()
        #print("raws", segs)        
        for i in range(num):
            segs[i] = rescale(segs[i], segs[0], segs[-1], mapto[0], mapto[1])
    else:
        #print("raws", segs)
        for i in range(num):
            segs[i] = rescale(segs[i], 0, rsum, 0, mapto)
    #print("segs", segs)
    return segs

#-----------------------------------------------------------------------------
# Random number functions with different distributions

def uniran():
    """
    Returns a uniformly chosen floating point value between 0.0 and 1.0.
    See also: lowran(), midran(), highran().
    """
    return random.random()


def lowran():
    """
    Returns a floating point value between 0.0 and 1.0 with lower 
    values more likely. See also: uniran(), midran(), highran().
    """
    return min(random.random(), random.random())


def midran():
    """
    Returns a floating point value between 0.0 and 1.0 with midrange
    values more likely. See also: uniran(), lowran(), highran().
    """
    return (random.random() + random.random()) / 2.0


def highran():
    """
    Returns a floating point value between 0.0 and 1.0 with higher 
    values more likely. See also: uniran(), lowran(), midran().
    """
    return max(random.random(), random.random())


def beta(alpha=.5, beta=.5):
    """
    Returns value between 0 and 1 from the beta distribution (https://en.wikipedia.org/wiki/Beta_distribution).
    When a=b=1 the distribution is uniform. When alpha=beta, the distribution is 
    symmetric around .5. When alpha<1 and beta<1 then the density of larger and
    smaller numbers increases. When alpha>1 and beta>1, density is similar to the
    gaussian distribution.
    """
    ra = 1.0 / alpha
    rb = 1.0 / beta
    while True:
        r1 = random.random()
        r2 = random.random()
        y1 = r1 ** ra
        y2 = r2 ** rb
        y3 = y1 + y2
        if y3 <= 1.0:
            return (y1 / y3)


def gamma(alpha=1):
    """
    Returns value greater than 0 from the gamma distribution 
    (https://en.wikipedia.org/wiki/Gamma_distribution).
    Parameter alpha controls the distribution's shape and should be a positive integer
    (if a non-integer is provided, the value is rounded.) When alpha=1, the 
    distribution is the same as exponential. As its value increases, the 
    probability density function becomes a curve with mean=alpha and standard 
    deviation = sqrt(alpha).
    """
    r = 1.0
    n = round(alpha)
    for i in range(n):
        r = r * (1 - random.random())
    return - math.log(r)


def poisson(alpha=1):
    """
    Returns value greater than 0 from the poisson distribution
    (https://en.wikipedia.org/wiki/Poisson_distribution).
    Returns positive integer values, theoretically unbounded but practically
    limited by the alpha parameter. Parameter alpha controls the distribution's 
    shape and must be positive: the mean is a and the standard deviation is sqrt(a).
    """
    b = math.exp( - alpha)
    n = 0
    p = 1.0
    while True:
        p = p * random.random()
        n += 1
        if p < b:
            return n


def expran(alpha=1):
    """
    Returns a value greater than 0 from the exponential distribution
    (https://en.wikipedia.org/wiki/Exponential_distribution) with stretching factor alpha.
    Increasing alpha "prefers" smaller numbers. The distribution is unbounded but when 
    alpha=1 then %99.9 of the time the value returned will be than 6.9077554, i.e. -log(.001).
    The distribution density is f(x)=(exp -x) with a mean of 1.0.
    """
    return (- math.log(1.0 - random.random())) / alpha


def gauss(sigma=1, mu=0):
    """
    Returns unbounded value from the normal distribution
    (https://en.wikipedia.org/wiki/Normal_distribution) with standard deviation
    sigma and mean mu.  The spread (standard deviation) is 1.0 centered at 0, 
    so 68.26% of the results are between -1 and 1 inclusive and 99.74% of the
    results are between -3 and 3 inclusive.
    """
    while True:
        x = -1 + 2 * random.random()
        y = -1 + 2 * random.random()
        r2 = (x * x) + (y * y)
        if not ((r2 > 1.0) or (r2 == 0)):
            break
    return (sigma * y * math.sqrt(-2.0 * math.log(r2) / r2)) + mu


def cauchy(alpha=False):
    """
    Returns an unbounded value from the Cauchy distribution
    (https://en.wikipedia.org/wiki/Cauchy_distribution).
    The density function is a bell shaped curve centered at 0 similar to a
    normal distribution but with more values at the extremes. The mean and
    standard deviation of the Cauchy distribution are undefined. If parameter
    alpha is True then only positive values are returned. Density is f(x)=1/(pi(1 + x^2)).
    """
    #return math.tan( math.pi * 2 * (random.random() - 0.5))
    r = (1.5707964 if alpha else math.pi) * random.random()
    return sin(r) / cos(r)

#-----------------------------------------------------------------------------
# Noises white, brown and pink return sample values -1.0 to 1.0


def white(level=None):
    """
    Returns white (uniform) noise samples between -1.0 and 1.0.

    Parameters
    ----------
    level : None or int or float
        An optional scaler on the sample returned.
    """
    samp = random.random() * 2.0 - 1.0
    return samp * level if level else samp


# def _lowpass(current, previous, alpha):
#     """
#     The change from one filter output to the next is proportional to the
#     difference between the previous output and the next input.
#     """
#     return previous + (alpha * (current - previous))
#
# _brown = white()
# """ The previous brown sample, initialzed to a random number."""
#
# def brown(alpha=.02):
#     global _brown
#     samp = _lowpass(white(), _brown, alpha)
#     _brown = samp
#     return samp * 3.0  # boost the overall gain


_brown = 0.0

def brown():
    """
    Returns brownish (1/f**2) noise samples between -1 and 1.
    """
    # from http://vellocet.com/dsp/noise/VRand.h
    # but made to generate between -1 1
    global _brown
    while True:
        r = random.random() * 2 - 1
        _brown += r
        if (_brown < -16.0) or (_brown > 16.0):
            _brown -= r
        else:
            break
    # return interval -1 1.
    return _brown * 0.0625


_pow2 = 5
_pown = 32
_pinking = [0.0 for _ in range(_pown+1)]

def _one_over_f_aux(n, rarray, halfrange):
    s = 0.0
    for i in range(_pow2):
        p = 2.0 ** i
        if not ( (n / p) == ((n - 1) / p) ):
            rarray[i]=( (random.random() * 2 * halfrange) - halfrange)
        s += rarray[i]
    return s

_i = _pown

def pink():
    """
    Returns pinkish (1/f) noise samples between -1.0 and 1.0.  Based on Gardner
    (1978) and Dick Moore (1988?).
    """
    global _i
    if _i == _pown:
        r = [0.0 for _ in range(_pow2)]
        h = 1.0 / _pow2
        for n in range(_pown):
            _pinking[n]=_one_over_f_aux(n, r, h)
        _i = 0
    else:
        _i += 1
    return _pinking[_i]


def drunk(val, width=1):
    """
    Returns a gnerator to produce numbers in a "drunken walk" where the next 
    value returned is constrained to lie within the bounds of the previous 
    value plus/minus width. If val and width are both integers then integer 
    values are returned otherwise floating point values are returned.

    Parameters
    ----------
    val : int | float
        The initial value returned by the walk. Thereafter drunk internally
        updates this value according to width.
    width : int | float
        Constrains the next value returned to be within the bounds of the
        current value plus/minus width.
    """
    func = random.randint if isinstance(val, int) and isinstance(width, int) else random.uniform
    i = 0
    while True:
        yield val 
        val += func(-width, width)
        i += 1


if __name__ == '__main__':
    
    ransegs(num=5, mapto=10)
    ransegs(num=5, mapto=(0,4))
    ransegs(num=5, mapto=(-2,4))

    # x = 60
    # for i in range(20):
    #     print(x)
    #     x = drunk(x, width=2)
    # print(x)

   
    # for i in range(20):
    #     print(pink())

    # for i in range(20):
    #     print(brown())

    import numpy as np
    import matplotlib.pyplot as plt
    # beta(.3, .3)
    # x = [pink() for _ in range(10000)]
    # plt.hist(x, bins=20, facecolor="blue", alpha=0.5)
    # plt.show()

#     y = [expran(1.5) for _ in range(1000)]
#     plt.hist(y, bins=20, facecolor="blue", alpha=0.5)
#    #plt.plot(y)
#     plt.show()


    

    #ransegs(5, 2, 4)
    #ransegs(5, 0, 10)
    #ransegs(5, 0, 10)
    #ransegs(5, -10, 10)
    #ransegs(5, sumto=10)

 
        
    #x = ransegs(5, 10)
    #print("sum=", sum(x))









"""
(define (segs num sum)
  (let ((rgen ran)
        (args ()))
    (let* ((rsum (apply rgen args))
           (head (list rsum))
           (tail head))
      (print "rgen " rgen " rsum " rsum " args " args " head" head)
      (do ((i 1 (+ i 1))
           (n #f))
          ((not (< i num))
           (do ((tail head (cdr tail)))
               ((null? tail) head)
             (set-car! tail
                       (ffi_rescale (car tail) 0 rsum 0 sum 1))))
        (set! n (apply rgen args))
        (set-cdr! tail (list n))
        (set! tail (cdr tail))
        (set! rsum (+ rsum n))))
    ))
(let ((l (segs 7 2)))
  (print l)
  (apply + l))
"""

Functions

def beta(alpha=0.5, beta=0.5)

Returns value between 0 and 1 from the beta distribution (https://en.wikipedia.org/wiki/Beta_distribution). When a=b=1 the distribution is uniform. When alpha=beta, the distribution is symmetric around .5. When alpha<1 and beta<1 then the density of larger and smaller numbers increases. When alpha>1 and beta>1, density is similar to the gaussian distribution.

Expand source code
def beta(alpha=.5, beta=.5):
    """
    Returns value between 0 and 1 from the beta distribution (https://en.wikipedia.org/wiki/Beta_distribution).
    When a=b=1 the distribution is uniform. When alpha=beta, the distribution is 
    symmetric around .5. When alpha<1 and beta<1 then the density of larger and
    smaller numbers increases. When alpha>1 and beta>1, density is similar to the
    gaussian distribution.
    """
    ra = 1.0 / alpha
    rb = 1.0 / beta
    while True:
        r1 = random.random()
        r2 = random.random()
        y1 = r1 ** ra
        y2 = r2 ** rb
        y3 = y1 + y2
        if y3 <= 1.0:
            return (y1 / y3)
def between(a, b)

Returns a random value between a and b (exclusive).

An int is returned if both a and b are ints, otherwise a float is returned. The a value can be less than, equal to, or greater than b.

Parameters

a : int | float
The lower bound for the random selection.
b : int | float
The upper bound for the random selection.

Returns

A randomly chosen value between a and b.
Expand source code
def between(a, b):
    """
    Returns a random value between a and b (exclusive).

    An int is returned if both a and b are ints,
    otherwise a float is returned. The a value can be
    less than, equal to, or greater than b.

    Parameters
    ----------
    a : int | float
        The lower bound for the random selection.
    b : int | float
        The upper bound for the random selection.

    Returns
    -------
        A randomly chosen value between a and b.
    """
    if (a < b):
        if isinstance(a, int) and isinstance(b, int):
            return random.randrange(a, b)
        else:
            return a + (random.random() * (b - a))
    if (a > b):
        if isinstance(a, int) and isinstance(b, int):
            return a - random.randrange(b)
        else:
            return a - (random.random() * (a - b))
    return a
def brown()

Returns brownish (1/f**2) noise samples between -1 and 1.

Expand source code
def brown():
    """
    Returns brownish (1/f**2) noise samples between -1 and 1.
    """
    # from http://vellocet.com/dsp/noise/VRand.h
    # but made to generate between -1 1
    global _brown
    while True:
        r = random.random() * 2 - 1
        _brown += r
        if (_brown < -16.0) or (_brown > 16.0):
            _brown -= r
        else:
            break
    # return interval -1 1.
    return _brown * 0.0625
def cauchy(alpha=False)

Returns an unbounded value from the Cauchy distribution (https://en.wikipedia.org/wiki/Cauchy_distribution). The density function is a bell shaped curve centered at 0 similar to a normal distribution but with more values at the extremes. The mean and standard deviation of the Cauchy distribution are undefined. If parameter alpha is True then only positive values are returned. Density is f(x)=1/(pi(1 + x^2)).

Expand source code
def cauchy(alpha=False):
    """
    Returns an unbounded value from the Cauchy distribution
    (https://en.wikipedia.org/wiki/Cauchy_distribution).
    The density function is a bell shaped curve centered at 0 similar to a
    normal distribution but with more values at the extremes. The mean and
    standard deviation of the Cauchy distribution are undefined. If parameter
    alpha is True then only positive values are returned. Density is f(x)=1/(pi(1 + x^2)).
    """
    #return math.tan( math.pi * 2 * (random.random() - 0.5))
    r = (1.5707964 if alpha else math.pi) * random.random()
    return sin(r) / cos(r)
def drunk(val, width=1)

Returns a gnerator to produce numbers in a "drunken walk" where the next value returned is constrained to lie within the bounds of the previous value plus/minus width. If val and width are both integers then integer values are returned otherwise floating point values are returned.

Parameters

val : int | float
The initial value returned by the walk. Thereafter drunk internally updates this value according to width.
width : int | float
Constrains the next value returned to be within the bounds of the current value plus/minus width.
Expand source code
def drunk(val, width=1):
    """
    Returns a gnerator to produce numbers in a "drunken walk" where the next 
    value returned is constrained to lie within the bounds of the previous 
    value plus/minus width. If val and width are both integers then integer 
    values are returned otherwise floating point values are returned.

    Parameters
    ----------
    val : int | float
        The initial value returned by the walk. Thereafter drunk internally
        updates this value according to width.
    width : int | float
        Constrains the next value returned to be within the bounds of the
        current value plus/minus width.
    """
    func = random.randint if isinstance(val, int) and isinstance(width, int) else random.uniform
    i = 0
    while True:
        yield val 
        val += func(-width, width)
        i += 1
def expran(alpha=1)

Returns a value greater than 0 from the exponential distribution (https://en.wikipedia.org/wiki/Exponential_distribution) with stretching factor alpha. Increasing alpha "prefers" smaller numbers. The distribution is unbounded but when alpha=1 then %99.9 of the time the value returned will be than 6.9077554, i.e. -log(.001). The distribution density is f(x)=(exp -x) with a mean of 1.0.

Expand source code
def expran(alpha=1):
    """
    Returns a value greater than 0 from the exponential distribution
    (https://en.wikipedia.org/wiki/Exponential_distribution) with stretching factor alpha.
    Increasing alpha "prefers" smaller numbers. The distribution is unbounded but when 
    alpha=1 then %99.9 of the time the value returned will be than 6.9077554, i.e. -log(.001).
    The distribution density is f(x)=(exp -x) with a mean of 1.0.
    """
    return (- math.log(1.0 - random.random())) / alpha
def gamma(alpha=1)

Returns value greater than 0 from the gamma distribution (https://en.wikipedia.org/wiki/Gamma_distribution). Parameter alpha controls the distribution's shape and should be a positive integer (if a non-integer is provided, the value is rounded.) When alpha=1, the distribution is the same as exponential. As its value increases, the probability density function becomes a curve with mean=alpha and standard deviation = sqrt(alpha).

Expand source code
def gamma(alpha=1):
    """
    Returns value greater than 0 from the gamma distribution 
    (https://en.wikipedia.org/wiki/Gamma_distribution).
    Parameter alpha controls the distribution's shape and should be a positive integer
    (if a non-integer is provided, the value is rounded.) When alpha=1, the 
    distribution is the same as exponential. As its value increases, the 
    probability density function becomes a curve with mean=alpha and standard 
    deviation = sqrt(alpha).
    """
    r = 1.0
    n = round(alpha)
    for i in range(n):
        r = r * (1 - random.random())
    return - math.log(r)
def gauss(sigma=1, mu=0)

Returns unbounded value from the normal distribution (https://en.wikipedia.org/wiki/Normal_distribution) with standard deviation sigma and mean mu. The spread (standard deviation) is 1.0 centered at 0, so 68.26% of the results are between -1 and 1 inclusive and 99.74% of the results are between -3 and 3 inclusive.

Expand source code
def gauss(sigma=1, mu=0):
    """
    Returns unbounded value from the normal distribution
    (https://en.wikipedia.org/wiki/Normal_distribution) with standard deviation
    sigma and mean mu.  The spread (standard deviation) is 1.0 centered at 0, 
    so 68.26% of the results are between -1 and 1 inclusive and 99.74% of the
    results are between -3 and 3 inclusive.
    """
    while True:
        x = -1 + 2 * random.random()
        y = -1 + 2 * random.random()
        r2 = (x * x) + (y * y)
        if not ((r2 > 1.0) or (r2 == 0)):
            break
    return (sigma * y * math.sqrt(-2.0 * math.log(r2) / r2)) + mu
def highran()

Returns a floating point value between 0.0 and 1.0 with higher values more likely. See also: uniran(), lowran(), midran().

Expand source code
def highran():
    """
    Returns a floating point value between 0.0 and 1.0 with higher 
    values more likely. See also: uniran(), lowran(), midran().
    """
    return max(random.random(), random.random())
def lowran()

Returns a floating point value between 0.0 and 1.0 with lower values more likely. See also: uniran(), midran(), highran().

Expand source code
def lowran():
    """
    Returns a floating point value between 0.0 and 1.0 with lower 
    values more likely. See also: uniran(), midran(), highran().
    """
    return min(random.random(), random.random())
def midran()

Returns a floating point value between 0.0 and 1.0 with midrange values more likely. See also: uniran(), lowran(), highran().

Expand source code
def midran():
    """
    Returns a floating point value between 0.0 and 1.0 with midrange
    values more likely. See also: uniran(), lowran(), highran().
    """
    return (random.random() + random.random()) / 2.0
def odds(prob, true=True, false=False)

Returns true value if a random choice is less than prob else returns the false.

Parameters

prob : float | int
A value between 0 and 1 inclusive.
true : value
If odds is true the true value is returned.
false : value
If odds is false the false value is returned.

Returns

Either the true value or the false value based on probability.

Expand source code
def odds(prob, true=True, false=False):
    """
    Returns true value if a random choice is less than prob else returns
    the false.

    Parameters
    ----------
    prob : float | int
        A value between 0 and 1 inclusive.
    true : value
        If odds is true the true value is returned.
    false : value
        If odds is false the false value is returned.

    Returns
    -------
    Either the true value or the false value based on probability.
    """
    if 0 <= prob <= 1.0:
        return true if random.random() < prob else false
    raise ValueError(f"{prob} not a number between 0 and 1.")
def pick(*args)

Randomly picks one of its arguments to return.

Parameters

*args : variadic
A series of values from which one will be randomly selected.

Returns

One value from the argument list.

Expand source code
def pick(*args):
    """
    Randomly picks one of its arguments to return.

    Parameters
    ----------
    *args : variadic
        A series of values from which one will be randomly selected.

    Returns
    -------
    One value from the argument list.
    """
    return args[random.randrange(len(args))]
def pink()

Returns pinkish (1/f) noise samples between -1.0 and 1.0. Based on Gardner (1978) and Dick Moore (1988?).

Expand source code
def pink():
    """
    Returns pinkish (1/f) noise samples between -1.0 and 1.0.  Based on Gardner
    (1978) and Dick Moore (1988?).
    """
    global _i
    if _i == _pown:
        r = [0.0 for _ in range(_pow2)]
        h = 1.0 / _pow2
        for n in range(_pown):
            _pinking[n]=_one_over_f_aux(n, r, h)
        _i = 0
    else:
        _i += 1
    return _pinking[_i]
def poisson(alpha=1)

Returns value greater than 0 from the poisson distribution (https://en.wikipedia.org/wiki/Poisson_distribution). Returns positive integer values, theoretically unbounded but practically limited by the alpha parameter. Parameter alpha controls the distribution's shape and must be positive: the mean is a and the standard deviation is sqrt(a).

Expand source code
def poisson(alpha=1):
    """
    Returns value greater than 0 from the poisson distribution
    (https://en.wikipedia.org/wiki/Poisson_distribution).
    Returns positive integer values, theoretically unbounded but practically
    limited by the alpha parameter. Parameter alpha controls the distribution's 
    shape and must be positive: the mean is a and the standard deviation is sqrt(a).
    """
    b = math.exp( - alpha)
    n = 0
    p = 1.0
    while True:
        p = p * random.random()
        n += 1
        if p < b:
            return n
def ransegs(num, mapto, rangen=None)

Returns a list of random number segments.

Parameters

num : int
The number of random values returned in the list.
mapto : number | [low, high]
If mapto is a number then the values retuned will sum to that number. If mapto is a list then the random values are sorted and scaled to lie proportionatly from low to high.
rangen : None | function
If function is provided it will be called to return random numbers, otherwise uniform random numbers between are generated.
Expand source code
def ransegs(num, mapto, rangen=None):
    """
    Returns a list of random number segments.

    Parameters
    ----------
    num : int
        The number of random values returned in the list.
    mapto : number | [low, high]
        If mapto is a number then the values retuned will sum to that number.
        If mapto is a list then the random values are sorted and scaled to
        lie proportionatly from low to high.
    rangen : None | function
        If function is provided it will be called to return random numbers,
        otherwise uniform random numbers between are generated.
    """
    #print(f"ransegs(num={num}, mapto={mapto})")
    segs = []
    rsum = 0
    if rangen == None:
        rangen = random.random
    for i in range(num):
        n = rangen()
        segs.append(n)
        rsum += n
    if isinstance(mapto, (list, tuple)):
        segs.sort()
        #print("raws", segs)        
        for i in range(num):
            segs[i] = rescale(segs[i], segs[0], segs[-1], mapto[0], mapto[1])
    else:
        #print("raws", segs)
        for i in range(num):
            segs[i] = rescale(segs[i], 0, rsum, 0, mapto)
    #print("segs", segs)
    return segs
def shuffle(*args, **kwargs)

Returns a new list containing the random reordering of an input list, tuple or variadic sequence of values. The optional keyword arguments 'start' and 'end' allow just a sub-sequence of the input values to be shuffled.

Parameters

args : list | tuple | variadic
The values to shuffle
start : int
Starting position in the list to shuffle, defaults to 0.
end : int
Inclusive ending position in the list to shuffle, defaults to the length of the input.
Expand source code
def shuffle (*args, **kwargs):
    """
    Returns a new list containing the random reordering of an input
    list, tuple or variadic sequence of values. The optional keyword
    arguments 'start' and 'end' allow just a sub-sequence of the
    input values to be shuffled.

    Parameters
    ----------
    args : list | tuple | variadic
        The values to shuffle 
    start : int
        Starting position in the list to shuffle, defaults to 0.
    end : int
        Inclusive ending position in the list to shuffle,
        defaults to the length of the input.
    """
    # print("args:", args, "numargs:", len(args), "kwargs:", kwargs)
    if isinstance(args[0], list):
        args = args[0].copy()
    else:
        args = list(args)
    arglen = len(args)
    start =  kwargs.get('start', 0)
    end = kwargs.get('end', arglen)
    width = end - start
    for i in range(start, end):
        j = start + random.randrange(width)
        args[i], args[j] = args[j], args[i]
    return args
def uniran()

Returns a uniformly chosen floating point value between 0.0 and 1.0. See also: lowran(), midran(), highran().

Expand source code
def uniran():
    """
    Returns a uniformly chosen floating point value between 0.0 and 1.0.
    See also: lowran(), midran(), highran().
    """
    return random.random()
def vary(value, variance, shift=None)

Returns a random number that deviates from value or list of the same by up to variance (1=100%) according to shift.

Parameters

value : number | list
The value or list of values to vary.
variance : number
The maximum amount to vary the value by, e.g. 0.5 means the variance could be up to 50% of the input value.
shift : None | "+" | "-"
Specifies where the variance is placed. If None then then value is at the center of what could be returned. Shift "+" places value at the minimum of what could be returned and "-" means that value is the maximum possible value returned.
Expand source code
def vary(value, variance, shift=None):
    """
    Returns a random number that deviates from value or list of the same by
    up to variance (1=100%) according to shift. 
    
    Parameters
    ----------
    value : number | list
        The value or list of values to vary.
    variance : number
        The maximum amount to vary the value by, e.g. 0.5 means the variance
        could be up to 50% of the input value.
    shift : None | "+" | "-"
        Specifies where the variance is placed. If None then then value is at the
        center of what could be returned. Shift "+" places value at the minimum
        of what could be returned and "-" means that value is the maximum possible
        value returned.
    """
    if isinstance(value, list):
        return [vary(v, variance, shift) for v in value]
    if value == 0 or variance == 0:
        return val
    r = abs(value * variance)
    v = random.random() * r
    if shift == None:
        return (value - (r * .5)) + v
    if shift == '+':
        return value + v
    if shift == '-':
        return value - v
    raise ValueError("shift should be None, '+', or '-' ({shift})")
def white(level=None)

Returns white (uniform) noise samples between -1.0 and 1.0.

Parameters

level : None or int or float
An optional scaler on the sample returned.
Expand source code
def white(level=None):
    """
    Returns white (uniform) noise samples between -1.0 and 1.0.

    Parameters
    ----------
    level : None or int or float
        An optional scaler on the sample returned.
    """
    samp = random.random() * 2.0 - 1.0
    return samp * level if level else samp