def orth_pcd(order, dist, eps=1.e-16, normed=False, **kws): """ Create orthogonal polynomial expansion from pivoted Cholesky decompostion. Parameters ---------- order : int Order of polynomial expansion dist : Dist Distribution space where polynomials are orthogonal normed : bool If True orthonormal polynomials will be used instead of monic. **kws : optional Extra keywords passed to dist.mom Examples -------- # >>> Z = cp.Normal() # >>> print cp.orth_pcd(2, Z) # [1.0, q0^2-1.0, q0] """ raise DeprecationWarning("Obsolete. Use orth_chol instead.") dim = len(dist) basis = po.basis(1, order, dim) C = Cov(basis, dist) N = len(basis) L, P = pcd(C, approx=1, pivot=1, tol=eps) Li = np.dot(P, np.linalg.inv(L.T)) if normed: for i in xrange(N): Li[:, i] /= np.sum(Li[:, i] * P[:, i]) E_ = -po.sum(E(basis, dist, **kws) * Li.T, -1) coefs = np.zeros((N + 1, N + 1)) coefs[1:, 1:] = Li coefs[0, 0] = 1 coefs[0, 1:] = E_ out = {} out[(0, ) * dim] = coefs[0] basis = list(basis) for i in xrange(N): I = basis[i].keys[0] out[I] = coefs[i + 1] P = po.Poly(out, dim, coefs.shape[1:], float) return P
def orth_chol(order, dist, normed=True, sort="GR", **kws): """ Create orthogonal polynomial expansion from Cholesky decomposition Parameters ---------- order : int Order of polynomial expansion dist : Dist Distribution space where polynomials are orthogonal normed : bool If True orthonormal polynomials will be used instead of monic. sort : str Ordering argument passed to poly.basis. If custom basis is used, argument is ignored. kws : optional Keyword argument passed to dist.mom. Examples -------- >>> Z = cp.Normal() >>> print cp.orth_chol(3, Z) [1.0, q0, 0.707106781187q0^2-0.707106781187, 0.408248290464q0^3-1.22474487139q0] """ dim = len(dist) basis = po.basis(1,order,dim, sort) C = Cov(basis, dist) N = len(basis) L, e = chol_gko(C) Li = np.linalg.inv(L.T).T if not normed: Li /= np.repeat(np.diag(Li), len(Li)).reshape(Li.shape) E_ = -np.sum(Li*E(basis, dist, **kws), -1) coefs = np.empty((N+1, N+1)) coefs[1:,1:] = Li coefs[0,0] = 1 coefs[0,1:] = 0 coefs[1:,0] = E_ coefs = coefs.T out = {} out[(0,)*dim] = coefs[0] for i in xrange(N): I = basis[i].keys[0] out[I] = coefs[i+1] P = po.Poly(out, dim, coefs.shape[1:], float) return P
def orth_chol(order, dist, normed=True, sort="GR", **kws): """ Create orthogonal polynomial expansion from Cholesky decomposition Parameters ---------- order : int Order of polynomial expansion dist : Dist Distribution space where polynomials are orthogonal normed : bool If True orthonormal polynomials will be used instead of monic. sort : str Ordering argument passed to poly.basis. If custom basis is used, argument is ignored. kws : optional Keyword argument passed to dist.mom. Examples -------- >>> Z = cp.Normal() >>> print cp.orth_chol(3, Z) [1.0, q0, 0.707106781187q0^2-0.707106781187, 0.408248290464q0^3-1.22474487139q0] """ dim = len(dist) basis = po.basis(1, order, dim, sort) C = Cov(basis, dist) N = len(basis) L, e = chol_gko(C) Li = np.linalg.inv(L.T).T if not normed: Li /= np.repeat(np.diag(Li), len(Li)).reshape(Li.shape) E_ = -np.sum(Li * E(basis, dist, **kws), -1) coefs = np.empty((N + 1, N + 1)) coefs[1:, 1:] = Li coefs[0, 0] = 1 coefs[0, 1:] = 0 coefs[1:, 0] = E_ coefs = coefs.T out = {} out[(0, ) * dim] = coefs[0] for i in xrange(N): I = basis[i].keys[0] out[I] = coefs[i + 1] P = po.Poly(out, dim, coefs.shape[1:], float) return P
def orth_pcd(order, dist, eps=1.e-16, normed=False, **kws): """ Create orthogonal polynomial expansion from pivoted Cholesky decompostion. Parameters ---------- order : int Order of polynomial expansion dist : Dist Distribution space where polynomials are orthogonal normed : bool If True orthonormal polynomials will be used instead of monic. **kws : optional Extra keywords passed to dist.mom Examples -------- # >>> Z = cp.Normal() # >>> print cp.orth_pcd(2, Z) # [1.0, q0^2-1.0, q0] """ raise DeprecationWarning("Obsolete. Use orth_chol instead.") dim = len(dist) basis = po.basis(1,order,dim) C = Cov(basis, dist) N = len(basis) L, P = pcd(C, approx=1, pivot=1, tol=eps) Li = np.dot(P, np.linalg.inv(L.T)) if normed: for i in xrange(N): Li[:,i] /= np.sum(Li[:,i]*P[:,i]) E_ = -po.sum(E(basis, dist, **kws)*Li.T, -1) coefs = np.zeros((N+1, N+1)) coefs[1:,1:] = Li coefs[0,0] = 1 coefs[0,1:] = E_ out = {} out[(0,)*dim] = coefs[0] basis = list(basis) for i in xrange(N): I = basis[i].keys[0] out[I] = coefs[i+1] P = po.Poly(out, dim, coefs.shape[1:], float) return P
def lagrange_polynomial(X, sort="GR"): """ Lagrange Polynomials X : array_like Sample points where the lagrange polynomials shall be """ X = np.asfarray(X) if len(X.shape) == 1: X = X.reshape(1, X.size) dim, size = X.shape order = 1 while ber.terms(order, dim) <= size: order += 1 indices = np.array(ber.bindex(1, order, dim, sort)[:size]) s, t = np.mgrid[:size, :size] M = np.prod(X.T[s]**indices[t], -1) det = np.linalg.det(M) if det == 0: raise np.linalg.LinAlgError, "invertable matrix" v = po.basis(1, order, dim, sort)[:size] coeffs = np.zeros((size, size)) if size == 2: coeffs = np.linalg.inv(M) else: for i in xrange(size): for j in xrange(size): coeffs[i, j] += np.linalg.det(M[1:, 1:]) M = np.roll(M, -1, axis=0) M = np.roll(M, -1, axis=1) coeffs /= det return po.sum(v * (coeffs.T), 1)
def fit_lagrange(X, Y): """Simple lagrange method""" X = np.array(X) Y = np.array(Y) assert X.shape[0] == Y.shape[0] if len(X.shape) == 1: X = X.reshape(1, X.size) N, dim = X.shape basis = [] n = 1 while len(basis) < N: basis = po.basis(0, n, dim) n += 1 basis = basis[:N] return fit_regression(basis, X, Y)
def lagrange_polynomial(X, sort="GR"): """ Lagrange Polynomials X : array_like Sample points where the lagrange polynomials shall be """ X = np.asfarray(X) if len(X.shape)==1: X = X.reshape(1,X.size) dim,size = X.shape order = 1 while ber.terms(order, dim)<=size: order += 1 indices = np.array(ber.bindex(1, order, dim, sort)[:size]) s,t = np.mgrid[:size, :size] M = np.prod(X.T[s]**indices[t], -1) det = np.linalg.det(M) if det==0: raise np.linalg.LinAlgError, "invertable matrix" v = po.basis(1, order, dim, sort)[:size] coeffs = np.zeros((size, size)) if size==2: coeffs = np.linalg.inv(M) else: for i in xrange(size): for j in xrange(size): coeffs[i,j] += np.linalg.det(M[1:,1:]) M = np.roll(M, -1, axis=0) M = np.roll(M, -1, axis=1) coeffs /= det return po.sum(v*(coeffs.T), 1)
def orth_hybrid(order, dist, eps=1.e-30, normed=True, **kws): """ Create orthogonal polynomial expansion from Cholesky decompostion Parameters ---------- order : int Order of polynomial expansion dist : Dist Distribution space where polynomials are orthogonal eps : float The accuracy if PCD is used normed : bool If True orthonormal polynomials will be used instead of monic. kws : optional Keyword argument passed to stieltjes. Examples -------- # >>> Z = cp.Normal() # >>> print cp.orth_chol(3, Z) # [1.0, q0, 0.707106781187q0^2-0.707106781187, 0.408248290464q0^3-1.22474487139q0] """ if order==1: return orth_svd(order, dist, eps, normed, **kws) dim = len(dist) basis = po.basis(1,order,dim) C = Cov(basis, dist) L, P = pcd(C, approx=0, pivot=1, tol=eps) eig = np.array(np.sum(np.cumsum(P, 0), 0)-1, dtype=int) for i in range(len(C)-1): try: I,J = np.meshgrid(eig[i:], eig[i:]) D = C[J,I] L = np.linalg.cholesky(D) break except np.linalg.LinAlgError: continue if i==(len(C)-2): return orth_svd(order, dist, eps, normed, **kws) if i: print "subset", i basis = basis[eig[i:]] N = len(basis) Li = np.linalg.inv(L.T).T Ln = Li/np.repeat(np.diag(Li), len(Li)).reshape(Li.shape) E_ = -np.sum(Ln*E(basis, dist, **kws), -1) coefs = np.empty((N+1, N+1)) coefs[1:,1:] = Ln coefs[0,0] = 1 coefs[0,1:] = 0 coefs[1:,0] = E_ coefs = coefs.T out = {} out[(0,)*dim] = coefs[0] for i in xrange(N): I = basis[i].keys[0] out[I] = coefs[i+1] P = po.Poly(out, dim, coefs.shape[1:], float) if normed: norm = np.sqrt(Var(P, dist, **kws)) norm[0] = 1 P = P/norm return P
def orth_hybrid(order, dist, eps=1.e-30, normed=True, **kws): """ Create orthogonal polynomial expansion from Cholesky decompostion Parameters ---------- order : int Order of polynomial expansion dist : Dist Distribution space where polynomials are orthogonal eps : float The accuracy if PCD is used normed : bool If True orthonormal polynomials will be used instead of monic. kws : optional Keyword argument passed to stieltjes. Examples -------- # >>> Z = cp.Normal() # >>> print cp.orth_chol(3, Z) # [1.0, q0, 0.707106781187q0^2-0.707106781187, 0.408248290464q0^3-1.22474487139q0] """ raise DeprecationWarning("Obsolete. Use orth_chol instead.") if order == 1: return orth_svd(order, dist, eps, normed, **kws) dim = len(dist) basis = po.basis(1, order, dim) C = Cov(basis, dist) L, P = pcd(C, approx=0, pivot=1, tol=eps) eig = np.array(np.sum(np.cumsum(P, 0), 0) - 1, dtype=int) for i in range(len(C) - 1): try: I, J = np.meshgrid(eig[i:], eig[i:]) D = C[J, I] L = np.linalg.cholesky(D) break except np.linalg.LinAlgError: continue if i == (len(C) - 2): return orth_svd(order, dist, eps, normed, **kws) if i: print "subset", i basis = basis[eig[i:]] N = len(basis) Li = np.linalg.inv(L.T).T Ln = Li / np.repeat(np.diag(Li), len(Li)).reshape(Li.shape) E_ = -np.sum(Ln * E(basis, dist, **kws), -1) coefs = np.empty((N + 1, N + 1)) coefs[1:, 1:] = Ln coefs[0, 0] = 1 coefs[0, 1:] = 0 coefs[1:, 0] = E_ coefs = coefs.T out = {} out[(0, ) * dim] = coefs[0] for i in xrange(N): I = basis[i].keys[0] out[I] = coefs[i + 1] P = po.Poly(out, dim, coefs.shape[1:], float) if normed: norm = np.sqrt(Var(P, dist, **kws)) norm[0] = 1 P = P / norm return P
def orth_gs(order, dist, normed=False, sort="GR", **kws): """ Gram-Schmidt process for generating orthogonal polynomials in a weighted function space. Parameters ---------- order : int, Poly The upper polynomial order. Alternative a custom polynomial basis can be used. dist : Dist Weighting distribution(s) defining orthogonality. normed : bool If True orthonormal polynomials will be used instead of monic. sort : str Ordering argument passed to poly.basis. If custom basis is used, argument is ignored. kws : optional Keyword argument passed to dist.mom if the moments need to be estimated. Returns ------- P : Poly The orthogonal polynomial expansion. Examples -------- >>> Z = cp.J(cp.Normal(), cp.Normal()) >>> print cp.orth_gs(2, Z) [1.0, q1, q0, -1.0+q1^2, q0q1, q0^2-1.0] """ dim = len(dist) if isinstance(order, int): if order==0: return po.Poly(1, dim=dim) basis = po.basis(0, order, dim, sort) else: basis = order basis = list(basis) P = [basis[0]] if normed: for i in xrange(1,len(basis)): for j in xrange(i): tmp = P[j]*E(basis[i]*P[j], dist, **kws) basis[i] = basis[i] - tmp g = E(P[-1]**2, dist, **kws) if g<=0: print "Warning: Polynomial cutoff at term %d" % i break basis[i] = basis[i]/np.sqrt(g) P.append(basis[i]) else: G = [1.] for i in xrange(1,len(basis)): for j in xrange(i): tmp = P[j]*(E(basis[i]*P[j], dist, **kws) / G[j]) basis[i] = basis[i] - tmp G.append(E(P[-1]**2, dist, **kws)) if G[-1]<=0: print "Warning: Polynomial cutoff at term %d" % i break P.append(basis[i]) return po.Poly(P, dim=dim, shape=(len(P),))
def orth_svd(order, dist, eps=1.e-300, normed=False, **kws): """ Create orthogonal polynomial expansion from pivoted Cholesky decompostion. If eigenvalue of covariance matrix is bellow eps, the polynomial is subset. Parameters ---------- order : int Order of polynomial expansion dist : Dist Distribution space where polynomials are orthogonal eps : float Threshold for when to subset the expansion. normed : bool If True, polynomial will be orthonormal. **kws : optional Extra keywords passed to dist.mom Examples -------- # >>> Z = cp.Normal() # >>> print cp.orth_svd(2, Z) # [1.0, q0^2-1.0, q0] """ dim = len(dist) if isinstance(order, po.Poly): basis = order else: basis = po.basis(1,order,dim) basis = list(basis) C = Cov(basis, dist, **kws) L, P = pcd(C, approx=0, pivot=1, tol=eps) N = L.shape[-1] if len(L)!=N: I = [_.tolist().index(1) for _ in P] b_ = [0]*N for i in xrange(N): b_[i] = basis[I[i]] basis = b_ C = Cov(basis, dist, **kws) L, P = pcd(C, approx=0, pivot=1, tol=eps) N = L.shape[-1] basis = po.Poly(basis) Li = rlstsq(L, P, alpha=1.e-300).T E_ = -po.sum(E(basis, dist, **kws)*Li.T, -1) coefs = np.zeros((N+1, N+1)) coefs[1:,1:] = Li coefs[0,0] = 1 coefs[0,1:] = E_ out = {} out[(0,)*dim] = coefs[0] for i in xrange(N): I = basis[i].keys[0] out[I] = coefs[i+1] P = po.Poly(out, dim, coefs.shape[1:], float) if normed: norm = np.sqrt(Var(P, dist, **kws)) norm[0] = 1 P = P/norm return P
def orth_bert(N, dist, normed=False, sort="GR"): """ # Stabilized process for generating orthogonal polynomials in a weighted function space. Add a comment to this line Parameters ---------- N : int The upper polynomial order. dist : Dist Weighting distribution(s) defining orthogonality. normed Returns ------- P : Poly The orthogonal polynomial expansion. Examples -------- >>> Z = cp.MvNormal([0,0], [[1,.5],[.5,1]]) >>> P = orth_bert(2, Z) >>> print P [1.0, q0, q1-0.5q0, q0^2-1.0, -0.5q0^2+q0q1, 0.25q0^2-0.75+q1^2-q0q1] """ dim = len(dist) sort = sort.upper() # Start orthogonalization x = po.basis(1,1,dim) if not ("R" in sort): x = x[::-1] foo = ber.Fourier_recursive(dist) # Create order=0 pool = [po.Poly(1, dim=dim, shape=())] # start loop M = ber.terms(N,dim) for i in xrange(1, M): par, ax0 = ber.parent(i, dim) gpar, ax1 = ber.parent(par, dim) oneup = ber.child(0, dim, ax0) # calculate rank to cut some terms rank = ber.multi_index(i, dim) while rank[-1]==0: rank = rank[:-1] rank = dim - len(rank) candi = x[ax0]*pool[par] for j in xrange(gpar, i): # cut irrelevant term if rank and np.any(ber.multi_index(j, dim)[-rank:]): continue A = foo(oneup, par, j) P = pool[j] candi = candi - P*A if normed: candi = candi/np.sqrt(foo(i, i, 0)) pool.append(candi) if "I" in sort: pool = pool[::-1] P = po.Poly([_.A for _ in pool], dim, (ber.terms(N, dim),)) return P
def orth_bert(N, dist, normed=False, sort="GR"): """ # Stabilized process for generating orthogonal polynomials in a weighted function space. Add a comment to this line Parameters ---------- N : int The upper polynomial order. dist : Dist Weighting distribution(s) defining orthogonality. normed Returns ------- P : Poly The orthogonal polynomial expansion. Examples -------- >>> Z = cp.MvNormal([0,0], [[1,.5],[.5,1]]) >>> P = orth_bert(2, Z) >>> print P [1.0, q0, q1-0.5q0, q0^2-1.0, -0.5q0^2+q0q1, 0.25q0^2-0.75+q1^2-q0q1] """ dim = len(dist) sort = sort.upper() # Start orthogonalization x = po.basis(1, 1, dim) if not ("R" in sort): x = x[::-1] foo = ber.Fourier_recursive(dist) # Create order=0 pool = [po.Poly(1, dim=dim, shape=())] # start loop M = ber.terms(N, dim) for i in xrange(1, M): par, ax0 = ber.parent(i, dim) gpar, ax1 = ber.parent(par, dim) oneup = ber.child(0, dim, ax0) # calculate rank to cut some terms rank = ber.multi_index(i, dim) while rank[-1] == 0: rank = rank[:-1] rank = dim - len(rank) candi = x[ax0] * pool[par] for j in xrange(gpar, i): # cut irrelevant term if rank and np.any(ber.multi_index(j, dim)[-rank:]): continue A = foo(oneup, par, j) P = pool[j] candi = candi - P * A if normed: candi = candi / np.sqrt(foo(i, i, 0)) pool.append(candi) if "I" in sort: pool = pool[::-1] P = po.Poly([_.A for _ in pool], dim, (ber.terms(N, dim), )) return P
def orth_gs(order, dist, normed=False, sort="GR", **kws): """ Gram-Schmidt process for generating orthogonal polynomials in a weighted function space. Parameters ---------- order : int, Poly The upper polynomial order. Alternative a custom polynomial basis can be used. dist : Dist Weighting distribution(s) defining orthogonality. normed : bool If True orthonormal polynomials will be used instead of monic. sort : str Ordering argument passed to poly.basis. If custom basis is used, argument is ignored. kws : optional Keyword argument passed to dist.mom if the moments need to be estimated. Returns ------- P : Poly The orthogonal polynomial expansion. Examples -------- >>> Z = cp.J(cp.Normal(), cp.Normal()) >>> print cp.orth_gs(2, Z) [1.0, q1, q0, -1.0+q1^2, q0q1, q0^2-1.0] """ dim = len(dist) if isinstance(order, int): if order == 0: return po.Poly(1, dim=dim) basis = po.basis(0, order, dim, sort) else: basis = order basis = list(basis) P = [basis[0]] if normed: for i in xrange(1, len(basis)): for j in xrange(i): tmp = P[j] * E(basis[i] * P[j], dist, **kws) basis[i] = basis[i] - tmp g = E(P[-1]**2, dist, **kws) if g <= 0: print "Warning: Polynomial cutoff at term %d" % i break basis[i] = basis[i] / np.sqrt(g) P.append(basis[i]) else: G = [1.] for i in xrange(1, len(basis)): for j in xrange(i): tmp = P[j] * (E(basis[i] * P[j], dist, **kws) / G[j]) basis[i] = basis[i] - tmp G.append(E(P[-1]**2, dist, **kws)) if G[-1] <= 0: print "Warning: Polynomial cutoff at term %d" % i break P.append(basis[i]) return po.Poly(P, dim=dim, shape=(len(P), ))
def orth_svd(order, dist, eps=1.e-300, normed=False, **kws): """ Create orthogonal polynomial expansion from pivoted Cholesky decompostion. If eigenvalue of covariance matrix is bellow eps, the polynomial is subset. Parameters ---------- order : int Order of polynomial expansion dist : Dist Distribution space where polynomials are orthogonal eps : float Threshold for when to subset the expansion. normed : bool If True, polynomial will be orthonormal. **kws : optional Extra keywords passed to dist.mom Examples -------- # >>> Z = cp.Normal() # >>> print cp.orth_svd(2, Z) # [1.0, q0^2-1.0, q0] """ raise DeprecationWarning("Obsolete") dim = len(dist) if isinstance(order, po.Poly): basis = order else: basis = po.basis(1, order, dim) basis = list(basis) C = Cov(basis, dist, **kws) L, P = pcd(C, approx=0, pivot=1, tol=eps) N = L.shape[-1] if len(L) != N: I = [_.tolist().index(1) for _ in P] b_ = [0] * N for i in xrange(N): b_[i] = basis[I[i]] basis = b_ C = Cov(basis, dist, **kws) L, P = pcd(C, approx=0, pivot=1, tol=eps) N = L.shape[-1] basis = po.Poly(basis) Li = rlstsq(L, P, alpha=1.e-300).T E_ = -po.sum(E(basis, dist, **kws) * Li.T, -1) coefs = np.zeros((N + 1, N + 1)) coefs[1:, 1:] = Li coefs[0, 0] = 1 coefs[0, 1:] = E_ out = {} out[(0, ) * dim] = coefs[0] for i in xrange(N): I = basis[i].keys[0] out[I] = coefs[i + 1] P = po.Poly(out, dim, coefs.shape[1:], float) if normed: norm = np.sqrt(Var(P, dist, **kws)) norm[0] = 1 P = P / norm return P
def golub_welsch(order, dist, acc=100, **kws): """ Golub-Welsch algorithm for creating quadrature nodes and weights Parameters ---------- order : int Quadrature order dist : Dist Distribution nodes and weights are found for with `dim=len(dist)` acc : int Accuracy used in discretized Stieltjes procedure. Will be increased by one for each itteration. Returns ------- x : numpy.array Optimal collocation nodes with `x.shape=(dim, order+1)` w : numpy.array Optimal collocation weights with `w.shape=(order+1,)` Examples -------- >>> Z = cp.Normal() >>> x, w = cp.golub_welsch(3, Z) >>> print x [[-2.33441422 -0.74196378 0.74196378 2.33441422]] >>> print w [ 0.04587585 0.45412415 0.45412415 0.04587585] Multivariate >>> Z = cp.J(cp.Uniform(), cp.Uniform()) >>> x, w = cp. golub_welsch(1, Z) >>> print x [[ 0.21132487 0.21132487 0.78867513 0.78867513] [ 0.21132487 0.78867513 0.21132487 0.78867513]] >>> print w [ 0.25 0.25 0.25 0.25] """ o = np.array(order)*np.ones(len(dist), dtype=int)+1 P,g,a,b = stieltjes(dist, np.max(o), acc=acc, retall=True, **kws) X,W = [], [] dim = len(dist) for d in xrange(dim): if o[d]: A = np.empty((2, o[d])) A[0] = a[d, :o[d]] A[1,:-1] = np.sqrt(b[d, 1:o[d]]) vals, vecs = eig_banded(A, lower=True) x, w = vals.real, vecs[0,:]**2 indices = np.argsort(x) x, w = x[indices], w[indices] p = P[-1][d] dp = po.differential(p, po.basis(1,1,dim)[d]) x = x - p(x)/dp(x) x = x - p(x)/dp(x) x = x - p(x)/dp(x) z = np.arange(dim) b = dist.mom([k*(z == d) for k in range(2*o[d]-3)]) X_,r = np.meshgrid(x, np.arange(2*o[d]-3)) X_ = X_**r w = np.linalg.lstsq(X_, b)[0].T[0] else: x,w = np.array([a[d,0]]), np.array([1.]) X.append(x) W.append(w) if dim==1: x = np.array(X).reshape(1,o[0]) w = np.array(W).reshape(o[0]) else: x = combine(X).T w = np.prod(combine(W), -1) assert len(x)==dim assert len(w)==len(x.T) return x, w