def momgen(order, domain, acc=100, sparse=False, rule="C", composite=1, part=None, trans=lambda x:x, **kws): if isinstance(domain, di.Dist): dim = len(domain) else: dim = np.array(domain[0]).size x0 = trans(np.zeros(dim)) if np.array(x0).shape==(): func = trans trans = lambda x: [func(x)] if part is None: X,W = generate_quadrature(order, domain=domain, acc=acc, sparse=sparse, rule=rule, composite=composite, part=part, **kws) Y = np.array(trans(X)) def _mom(k): out = np.sum(np.prod(Y.T**k, -1)*W, 0) return out else: isdist = not isinstance(domain, (tuple, list, np.ndarray)) if isdist: lo,up = domain.range() else: lo,up = np.array(domain) X,W,Y = [], [], [] for I in np.ndindex(*part): x,w = clenshaw_curtis(order, lo, up, part=(I, part)) y = np.array(trans(x)) if isdist: w *= domain.pdf(x).flatten() if np.any(w): X.append(x); W.append(w); Y.append(y) def _mom(k): out = 0. for i in xrange(len(X)): out += np.sum(np.prod(Y[i].T**k, -1)*W[i], 0) return out _mom = lazy_eval(_mom, tuple) def mom(K, **kws): out = np.array([_mom(k) for k in K.T]) return out return mom
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
if ax is None: ax = dim - np.argmin(1 * (np.array(I)[::-1] == 0)) - 1 if not i: return i, ax if I[ax] == 0: j = parent(parent(i, dim)[0], dim)[0] while child(j + 1, dim, ax) < i: j += 1 return j, ax out = np.array(I) - 1 * (np.eye(dim)[ax]) return single_index(out), ax parent = lazy_eval(parent, int) def child(i, dim, ax): """ Child node according to Bertran's notation. Parameters ---------- i : int Index of the parent node. dim : int Dimensionality of the problem. ax : int Dimension direction to define a child. Must have `0<=ax<dim`
def rule_generator(*funcs): """ Constructor for creating quadrature generator Parameters ---------- *funcs : callable One dimensional integration rule where for func in funcs: nodes, weights = func(order) order : int Order of integration rule nodes : array_like Where to evaluate. weights : array_like Weights corresponding to each node. Returns ------- mv_rule : callable Multidimensional integration rule nodes, weights = rule_gen(order) order : int, array_like Order of integration rule. If array_like, order along each axis. nodes : np.ndarray Where to evaluate with nodes.shape==(D,K), where D=len(funcs) and K is the number of points to evaluate. weights : np.ndarray Weights to go with the nodes with weights.shape=(K,). """ dim = len(funcs) def tensprod_rule(N, part=None): N = N * np.ones(dim, int) q = [np.array(funcs[i](N[i])) \ for i in xrange(dim)] x = [_[0] for _ in q] x = combine(x, part=part).T w = [_[1] for _ in q] w = np.prod(combine(w, part=part), -1) return x, w tensprod_rule = lazy_eval(tensprod_rule) def mv_rule(order, sparse=False, growth=None, part=None): """ Multidimensional integration rule Parameters ---------- order : int, array_like Order of integration rule. If array_like, order along each axis. Returns ------- nodes, weights nodes : np.ndarray Where to evaluate with nodes.shape==(D,K), where D=len(funcs) and K is the number of points to evaluate. weights : np.ndarray Weights to go with the nodes with weights.shape=(K,). """ if growth: def foo(N): N = N * np.ones(dim, int) return tensprod_rule([growth(n) for n in N], part=part) else: def foo(N): return tensprod_rule(N, part=part) if sparse: order = np.ones(dim, dtype=int) * order m = np.min(order) skew = [o - m for o in order] return sparse_grid(foo, m, dim, skew=skew) return foo(order) return mv_rule
def rule_generator(*funcs): """ Constructor for creating quadrature generator Parameters ---------- *funcs : callable One dimensional integration rule where for func in funcs: nodes, weights = func(order) order : int Order of integration rule nodes : array_like Where to evaluate. weights : array_like Weights corresponding to each node. Returns ------- mv_rule : callable Multidimensional integration rule nodes, weights = rule_gen(order) order : int, array_like Order of integration rule. If array_like, order along each axis. nodes : np.ndarray Where to evaluate with nodes.shape==(D,K), where D=len(funcs) and K is the number of points to evaluate. weights : np.ndarray Weights to go with the nodes with weights.shape=(K,). """ dim = len(funcs) def tensprod_rule(N, part=None): N = N*np.ones(dim, int) q = [np.array(funcs[i](N[i])) \ for i in xrange(dim)] x = [_[0] for _ in q] x = combine(x, part=part).T w = [_[1] for _ in q] w = np.prod(combine(w, part=part), -1) return x, w tensprod_rule = lazy_eval(tensprod_rule) def mv_rule(order, sparse=False, growth=None, part=None): """ Multidimensional integration rule Parameters ---------- order : int, array_like Order of integration rule. If array_like, order along each axis. Returns ------- nodes, weights nodes : np.ndarray Where to evaluate with nodes.shape==(D,K), where D=len(funcs) and K is the number of points to evaluate. weights : np.ndarray Weights to go with the nodes with weights.shape=(K,). """ if growth: def foo(N): N = N*np.ones(dim, int) return tensprod_rule([growth(n) for n in N], part=part) else: def foo(N): return tensprod_rule(N, part=part) if sparse: order = np.ones(dim, dtype=int)*order m = np.min(order) skew = [o-m for o in order] return sparse_grid(foo, m, dim, skew=skew) return foo(order) return mv_rule
I = multi_index(i, dim) if ax is None: ax = dim - np.argmin(1*(np.array(I)[::-1]==0))-1 if not i: return i, ax if I[ax]==0: j = parent(parent(i, dim)[0], dim)[0] while child(j+1, dim, ax)<i: j += 1 return j, ax out = np.array(I) - 1*(np.eye(dim)[ax]) return single_index(out), ax parent = lazy_eval(parent, int) def child(i, dim, ax): """ Child node according to Bertran's notation. Parameters ---------- i : int Index of the parent node. dim : int Dimensionality of the problem. ax : int Dimension direction to define a child. Must have `0<=ax<dim`