Beispiel #1
0
def fit_quadrature(orth, nodes, weights, solves, retall=False,
        norms=None, **kws):
    """
Using spectral projection to create a polynomial approximation over
distribution space.

Parameters
----------
orth : Poly
    Orthogonal polynomial expansion. Must be orthogonal for the
    approximation to be accurate.
nodes : array_like
    Where to evaluate the polynomial expansion and model to
    approximate.
    nodes.shape==(D,K) where D is the number of dimensions and K is
    the number of nodes.
weights : array_like
    Weights when doing numerical integration.
    weights.shape==(K,)
solves : array_like, callable
    The model to approximate.
    If array_like is provided, it must have len(solves)==K.
    If callable, it must take a single argument X with len(X)==D,
    and return a consistent numpy compatible shape.
norms : array_like
    In the of TTR using coefficients to estimate the polynomial
    norm is more stable than manual calculation.
    Calculated using quadrature if no provided.
    norms.shape==(len(orth),)
    """

    orth = po.Poly(orth)
    nodes = np.asfarray(nodes)
    weights = np.asfarray(weights)

    if hasattr(solves, "__call__"):
        solves = [solves(q) for q in nodes.T]
    solves = np.asfarray(solves)

    shape = solves.shape
    solves = solves.reshape(weights.size, solves.size/weights.size)

    ovals = orth(*nodes)
    vals1 = [(val*solves.T*weights).T for val in ovals]

    if norms is None:
        vals2 = [(val**2*weights).T for val in ovals]
        norms = np.sum(vals2, 1)
    else:
        norms = np.array(norms).flatten()
        assert len(norms)==len(orth)

    coefs = (np.sum(vals1, 1).T/norms).T
    coefs = coefs.reshape(len(coefs), *shape[1:])
    Q = po.transpose(po.sum(orth*coefs.T, -1))

    if retall:
        return Q, coefs
    return Q
Beispiel #2
0
def pcm_gq(func,
           order,
           dist_out,
           dist_in=None,
           acc=None,
           orth=None,
           retall=False,
           sparse=False):
    """
Probabilistic Collocation Method using optimal Gaussian quadrature

Parameters
----------
Required arguments

func : callable
    The model to be approximated.
    Must accept arguments on the form `func(z, *args, **kws)`
    where `z` is an 1-dimensional array with `len(z)==len(dist)`.
order : int
    The order of the polynomial approximation
dist_out : Dist
    Distributions for models parameter

Optional arguments

dist_in : Dist
    If included, space will be mapped using a Rosenblatt
    transformation from dist_out to dist_in before creating an
    expansin in terms of dist_in
acc : float
    The order of the sample scheme used
    If omitted order+1 will be used
orth : int, str, callable, Poly
    Orthogonal polynomial generation.

    int, str :
        orth will be passed to orth_select
        for selection of orthogonalization.
        See orth_select doc for more details.

    callable :
        the return of orth(M, dist) will be used.

    Poly :
        it will be used directly.
        All polynomials must be orthogonal for method to work
        properly.
args : itterable
    Extra positional arguments passed to `func`.
kws : dict
    Extra keyword arguments passed to `func`.
retall : bool
    If True, return also number of evaluations
sparse : bool
    If True, Smolyak sparsegrid will be used instead of full
    tensorgrid

Returns
-------
Q[, X]

Q : Poly
    Polynomial estimate of a given a model.
X : np.ndarray
    Values used in evaluation

#  Examples
#  --------
#  Define function:
#  >>> func = lambda z: z[1]*z[0]
#
#  Define distribution:
#  >>> dist = cp.J(cp.Normal(), cp.Normal())
#
#  Perform pcm:
#  >>> p, x, w, y = cp.pcm_gq(func, 2, dist, acc=3, retall=True)
#  >>> print cp.around(p, 10)
#  q0q1
#  >>> print len(w)
#  16

    """
    if acc is None:
        acc = order + 1

    if dist_in is None:
        z, w = qu.generate_quadrature(acc,
                                      dist_out,
                                      100,
                                      sparse=sparse,
                                      rule="G")
        x = z
        dist = dist_out
    else:
        z, w = qu.generate_quadrature(acc,
                                      dist_in,
                                      100,
                                      sparse=sparse,
                                      rule="G")
        x = dist_out.ppf(dist_in.cdf(z))
        dist = dist_in

    y = np.array(map(func, x.T))
    shape = y.shape
    y = y.reshape(w.size, y.size / w.size)

    if orth is None:
        if dist.dependent:
            orth = "chol"
        else:
            orth = "ttr"
    if isinstance(orth, (str, int, long)):
        orth = orth_select(orth)
    if not isinstance(orth, po.Poly):
        orth = orth(order, dist)

    ovals = orth(*z)
    vals1 = [(val * y.T * w).T for val in ovals]
    vals2 = [(val**2 * w).T for val in ovals]
    coef = (np.sum(vals1, 1).T / np.sum(vals2, 1)).T

    coef = coef.reshape(len(coef), *shape[1:])
    Q = po.transpose(po.sum(orth * coef.T, -1))

    if retall:
        return Q, x, w, y
    return Q
Beispiel #3
0
def fit_quadrature(orth,
                   nodes,
                   weights,
                   solves,
                   retall=False,
                   norms=None,
                   **kws):
    """
Using spectral projection to create a polynomial approximation over
distribution space.

Parameters
----------
orth : Poly
    Orthogonal polynomial expansion. Must be orthogonal for the
    approximation to be accurate.
nodes : array_like
    Where to evaluate the polynomial expansion and model to
    approximate.
    nodes.shape==(D,K) where D is the number of dimensions and K is
    the number of nodes.
weights : array_like
    Weights when doing numerical integration.
    weights.shape==(K,)
solves : array_like, callable
    The model to approximate.
    If array_like is provided, it must have len(solves)==K.
    If callable, it must take a single argument X with len(X)==D,
    and return a consistent numpy compatible shape.
norms : array_like
    In the of TTR using coefficients to estimate the polynomial
    norm is more stable than manual calculation.
    Calculated using quadrature if no provided.
    norms.shape==(len(orth),)
    """

    orth = po.Poly(orth)
    nodes = np.asfarray(nodes)
    weights = np.asfarray(weights)

    if hasattr(solves, "__call__"):
        solves = [solves(q) for q in nodes.T]
    solves = np.asfarray(solves)

    shape = solves.shape
    solves = solves.reshape(weights.size, solves.size / weights.size)

    ovals = orth(*nodes)
    vals1 = [(val * solves.T * weights).T for val in ovals]

    if norms is None:
        vals2 = [(val**2 * weights).T for val in ovals]
        norms = np.sum(vals2, 1)
    else:
        norms = np.array(norms).flatten()
        assert len(norms) == len(orth)

    coefs = (np.sum(vals1, 1).T / norms).T
    coefs = coefs.reshape(len(coefs), *shape[1:])
    Q = po.transpose(po.sum(orth * coefs.T, -1))

    if retall:
        return Q, coefs
    return Q
Beispiel #4
0
def fit_adaptive(func,
                 poly,
                 dist,
                 abserr=1.e-8,
                 relerr=1.e-8,
                 budget=0,
                 norm=0,
                 bufname="",
                 retall=False):
    """Adaptive estimation of Fourier coefficients.

Parameters
----------
func : callable
    Should take a single argument `q` which is 1D array
    `len(q)=len(dist)`.
    Must return something compatible with np.ndarray.
poly : Poly
    Polynomial vector for which to create Fourier coefficients for.
dist : Dist
    A distribution to optimize the Fourier coefficients to.
abserr : float
    Absolute error tolerance.
relerr : float
    Relative error tolerance.
budget : int
    Soft maximum number of function evaluations.
    0 means unlimited.
norm : int
    Specifies the norm that is used to measure the error and
    determine convergence properties (irrelevant for single-valued
    functions). The `norm` argument takes one of the values:
    0 : L0-norm
    1 : L0-norm on top of paired the L2-norm. Good for complex
        numbers where each conseqtive pair of the solution is real
        and imaginery.
    2 : L2-norm
    3 : L1-norm
    4 : L_infinity-norm
bufname : str, optional
    Buffer evaluations to file such that the fit_adaptive can be
    run again without redooing all evaluations.
retall : bool
    If true, returns extra values.

Returns
-------
estimate[, coeffs, norms, coeff_error, norm_error]

estimate : Poly
    The polynomial chaos expansion representation of func.
coeffs : np.ndarray
    The Fourier coefficients.
norms : np.ndarray
    The norm of the orthogonal polynomial squared.
coeff_error : np.ndarray
    Estimated integration error of the coeffs.
norm_error : np.ndarray
    Estimated integration error of the norms.

Examples
--------
>>> func = lambda q: q[0]*q[1]
>>> poly = cp.basis(0,2,2)
>>> dist = cp.J(cp.Uniform(0,1), cp.Uniform(0,1))
>>> res = cp.fit_adaptive(func, poly, dist, budget=100)
>>> print res
    """

    if bufname:
        func = lazy_eval(func, load=bufname)

    dim = len(dist)
    n = [0, 0]

    dummy_x = dist.inv(.5 * np.ones(dim, dtype=np.float64))
    val = np.array(func(dummy_x), np.float64)

    xmin = np.zeros(dim, np.float64)
    xmax = np.ones(dim, np.float64)

    def f1(u, ns, *args):
        qs = dist.inv(u.reshape(ns, dim))
        out = (poly(*qs.T)**2).T.flatten()
        return out

    dim1 = len(poly)
    val1 = np.empty(dim1, dtype=np.float64)
    err1 = np.empty(dim1, dtype=np.float64)
    _cubature(f1, dim1, xmin, xmax, (), "h", abserr, relerr, norm, budget,
              True, val1, err1)
    val1 = np.tile(val1, val.size)

    dim2 = np.prod(val.shape) * dim1
    val2 = np.empty(dim2, dtype=np.float64)
    err2 = np.empty(dim2, dtype=np.float64)

    def f2(u, ns, *args):
        n[0] += ns
        n[1] += 1
        qs = dist.inv(u.reshape(ns, dim))
        Y = np.array([func(q) for q in qs])
        Q = poly(*qs.T)
        out = np.array([Y.T * q1 for q1 in Q]).T.flatten()
        out = out / np.tile(val1, ns)
        return out

    try:
        _ = _cubature
    except:
        raise NotImplementedError("cubature not install properly")
    _cubature(f2, dim2, xmin, xmax, (), "h", abserr, relerr, norm, budget,
              True, val2, err2)

    shape = (dim1, ) + val.shape
    val2 = val2.reshape(shape[::-1]).T

    out = po.transpose(po.sum(poly * val2.T, -1))

    if retall:
        return out, val2, val1, err2, err1
    return val2
Beispiel #5
0
def fit_adaptive(func, poly, dist, abserr=1.e-8, relerr=1.e-8,
        budget=0, norm=0, bufname="", retall=False):
    """Adaptive estimation of Fourier coefficients.

Parameters
----------
func : callable
    Should take a single argument `q` which is 1D array
    `len(q)=len(dist)`.
    Must return something compatible with np.ndarray.
poly : Poly
    Polynomial vector for which to create Fourier coefficients for.
dist : Dist
    A distribution to optimize the Fourier coefficients to.
abserr : float
    Absolute error tolerance.
relerr : float
    Relative error tolerance.
budget : int
    Soft maximum number of function evaluations.
    0 means unlimited.
norm : int
    Specifies the norm that is used to measure the error and
    determine convergence properties (irrelevant for single-valued
    functions). The `norm` argument takes one of the values:
    0 : L0-norm
    1 : L0-norm on top of paired the L2-norm. Good for complex
        numbers where each conseqtive pair of the solution is real
        and imaginery.
    2 : L2-norm
    3 : L1-norm
    4 : L_infinity-norm
bufname : str, optional
    Buffer evaluations to file such that the fit_adaptive can be
    run again without redooing all evaluations.
retall : bool
    If true, returns extra values.

Returns
-------
estimate[, coeffs, norms, coeff_error, norm_error]

estimate : Poly
    The polynomial chaos expansion representation of func.
coeffs : np.ndarray
    The Fourier coefficients.
norms : np.ndarray
    The norm of the orthogonal polynomial squared.
coeff_error : np.ndarray
    Estimated integration error of the coeffs.
norm_error : np.ndarray
    Estimated integration error of the norms.

Examples
--------
>>> func = lambda q: q[0]*q[1]
>>> poly = cp.basis(0,2,2)
>>> dist = cp.J(cp.Uniform(0,1), cp.Uniform(0,1))
>>> res = cp.fit_adaptive(func, poly, dist, budget=100)
>>> print res
    """

    if bufname:
        func = lazy_eval(func, load=bufname)

    dim = len(dist)
    n = [0,0]

    dummy_x = dist.inv(.5*np.ones(dim, dtype=np.float64))
    val = np.array(func(dummy_x), np.float64)

    xmin = np.zeros(dim, np.float64)
    xmax = np.ones(dim, np.float64)

    def f1(u, ns, *args):
        qs = dist.inv(u.reshape(ns, dim))
        out = (poly(*qs.T)**2).T.flatten()
        return out
    dim1 = len(poly)
    val1 = np.empty(dim1, dtype=np.float64)
    err1 = np.empty(dim1, dtype=np.float64)
    _cubature(f1, dim1, xmin, xmax, (), "h", abserr, relerr, norm,
            budget, True, val1, err1)
    val1 = np.tile(val1, val.size)

    dim2 = np.prod(val.shape)*dim1
    val2 = np.empty(dim2, dtype=np.float64)
    err2 = np.empty(dim2, dtype=np.float64)
    def f2(u, ns, *args):
        n[0] += ns
        n[1] += 1
        qs = dist.inv(u.reshape(ns, dim))
        Y = np.array([func(q) for q in qs])
        Q = poly(*qs.T)
        out = np.array([Y.T*q1 for q1 in Q]).T.flatten()
        out = out/np.tile(val1, ns)
        return out
    try:
        _ = _cubature
    except:
        raise NotImplementedError(
                "cubature not install properly")
    _cubature(f2, dim2, xmin, xmax, (), "h", abserr, relerr, norm,
                budget, True, val2, err2)

    shape = (dim1,)+val.shape
    val2 = val2.reshape(shape[::-1]).T

    out = po.transpose(po.sum(poly*val2.T, -1))

    if retall:
        return out, val2, val1, err2, err1
    return val2
Beispiel #6
0
def pcm_gq(func, order, dist_out, dist_in=None, acc=None,
        orth=None, retall=False, sparse=False):
    """
Probabilistic Collocation Method using optimal Gaussian quadrature

Parameters
----------
Required arguments

func : callable
    The model to be approximated.
    Must accept arguments on the form `func(z, *args, **kws)`
    where `z` is an 1-dimensional array with `len(z)==len(dist)`.
order : int
    The order of the polynomial approximation
dist_out : Dist
    Distributions for models parameter

Optional arguments

dist_in : Dist
    If included, space will be mapped using a Rosenblatt
    transformation from dist_out to dist_in before creating an
    expansin in terms of dist_in
acc : float
    The order of the sample scheme used
    If omitted order+1 will be used
orth : int, str, callable, Poly
    Orthogonal polynomial generation.

    int, str :
        orth will be passed to orth_select
        for selection of orthogonalization.
        See orth_select doc for more details.

    callable :
        the return of orth(M, dist) will be used.

    Poly :
        it will be used directly.
        All polynomials must be orthogonal for method to work
        properly.
args : itterable
    Extra positional arguments passed to `func`.
kws : dict
    Extra keyword arguments passed to `func`.
retall : bool
    If True, return also number of evaluations
sparse : bool
    If True, Smolyak sparsegrid will be used instead of full
    tensorgrid

Returns
-------
Q[, X]

Q : Poly
    Polynomial estimate of a given a model.
X : np.ndarray
    Values used in evaluation

#  Examples
#  --------
#  Define function:
#  >>> func = lambda z: z[1]*z[0]
#  
#  Define distribution:
#  >>> dist = cp.J(cp.Normal(), cp.Normal())
#  
#  Perform pcm:
#  >>> p, x, w, y = cp.pcm_gq(func, 2, dist, acc=3, retall=True)
#  >>> print cp.around(p, 10)
#  q0q1
#  >>> print len(w)
#  16

    """
    if acc is None:
        acc = order+1

    if dist_in is None:
        z,w = qu.generate_quadrature(acc, dist_out, 100, sparse=sparse,
                rule="G")
        x = z
        dist = dist_out
    else:
        z,w = qu.generate_quadrature(acc, dist_in, 100, sparse=sparse,
                rule="G")
        x = dist_out.ppf(dist_in.cdf(z))
        dist = dist_in

    y = np.array(map(func, x.T))
    shape = y.shape
    y = y.reshape(w.size, y.size/w.size)

    if orth is None:
        if dist.dependent:
            orth = "chol"
        else:
            orth = "ttr"
    if isinstance(orth, (str, int, long)):
        orth = orth_select(orth)
    if not isinstance(orth, po.Poly):
        orth = orth(order, dist)

    ovals = orth(*z)
    vals1 = [(val*y.T*w).T for val in ovals]
    vals2 = [(val**2*w).T for val in ovals]
    coef = (np.sum(vals1, 1).T/np.sum(vals2, 1)).T

    coef = coef.reshape(len(coef), *shape[1:])
    Q = po.transpose(po.sum(orth*coef.T, -1))

    if retall:
        return Q, x, w, y
    return Q