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
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
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
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
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
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