def interp_nd_coef(z, x, dx, y, dy, beta, gamma, \ order_set, boundary_set, boundary_zeta): """ Calculate interpolation coefficients in n-dimensional spacee. z is the point where the interpolation is evaluated, the size of z is the dimension of the space. x is the points where the function value is available, the columns of x must be the same as the size of z. dx is the measurement error at x, its size must be same as the rows of x. y is the points where the function gradient is available, the columns of y must be the same as the size of z. dy is the measurement error at y, must has same shape as y. beta is the `magnitude' of the target function. gamma is the `wave number' of the target function. combined with beta, it provides an estimate of the derivative growth: f^(k) = O(beta * gamma**k) larger gamma = more conservative and lower order interpolation. order_set is the expansion order set of the Taylor expansions. boundary_set is the boundary of order_set. boundary_zeta. return values: a, b, er2 = interp_nd_coef(...) a and b are the interpolation coefficients. er2 is the expected squared residual. """ # verifying arguments gamma = float(gamma) d, n, m = z.size, x.shape[0], y.shape[0] assert z.shape == (d,) assert x.shape == (n, d) and dx.shape == (n,) assert y.shape == (m, d) and dy.shape == (m, d) or m == 0 assert len(order_set) > 1 and order_set[0] == (0,) * d # calculate interpolant at z d2 = ((x - z)**2).sum(1) if d2.min() < 1.0E-18: # exactly matches a data point imatch = d2.argmin() if dx[imatch] == 0.0: # and function value on that point is exact a = numpy.array([0]*imatch+[1]+[0]*(n-imatch-1)) b = numpy.zeros([m, d]) return a, b, 0.0 # construct X = [Xa,Xb] N = len(order_set) - 1 X = zeros([N, n+m*d], dtype=float) for i, kappa in enumerate(order_set[1:]): # Xa part X[i,:n] = gamma**sum(kappa) / factorial(kappa) * ((x - z)**kappa).prod(1) # Xb part if m > 0: for k in range(d): if kappa[k] > 0: kappa_p = kappa[:k] + (kappa[k] - 1,) + kappa[k+1:] X[i,n+k*m:n+(k+1)*m] = gamma**sum(kappa) / factorial(kappa_p) * \ ((y - z)**kappa_p).prod(1) X *= beta # construct diagonal G matrix for the Lagrange residual G2 = zeros(n+m*d) for kappa, zeta in zip(boundary_set, boundary_zeta): Gi = gamma**sum(kappa) / factorial(kappa) * \ ((x - z)**kappa).prod(1) * sum(zeta) / sum(kappa) G2[:n] += Gi**2 if m > 0: for k in range(d): if kappa[k] > 0: kappa_p = kappa[:k] + (kappa[k] - 1,) + kappa[k+1:] zeta_p = zeta[:k] + (max(0, zeta[k] - 1),) + zeta[k+1:] Gi = gamma**sum(kappa) / factorial(kappa_p) * \ ((y - z)**kappa_p).prod(1) * sum(zeta_p) / sum(kappa_p) G2[n+k*m:n+(k+1)*m] += Gi**2 G = sqrt(G2) * beta # construct diagonal H matrix for measurement errors H = zeros(n+m*d) H[:n] = dx if m > 0: for k in range(d): H[n+k*m:n+(k+1)*m] = dy[:,k] # construct c c = zeros(n+m*d); c[:n] = 1.0 # first try to assemble the diagonal of matrix A, and sort by its diagonal diagA = (X**2).sum(0) + G**2 + H**2 isort = sorted(range(n+m*d), key=diagA.__getitem__) irevt = sorted(range(n+m*d), key=isort.__getitem__) # permute columns of X and diagonal of G and H X = X[:,isort] G = G[isort] H = H[isort] c = c[isort] ab = quad_prog(X, G, H, c) # reverse sorting permutation to get a and b and normalize abrevt = ab[irevt] a = abrevt[:n] b = zeros([m,d]) for k in range(d): b[:,k] = abrevt[n+k*m:n+(k+1)*m] # compute the expeted squared residual finite = (ab != 0) Xab = dot(X[:,finite], ab[finite])**2 Gab = (G*ab)[finite]**2 Hab = (H*ab)[finite]**2 er2 = Xab.sum() + Gab.sum() + Hab.sum() return a, b, er2
def interp_nd_grad_coef(ix, x, gamma, \ order_set, boundary_set, boundary_zeta): """ Calculate interpolation gradient coefficients in n-dimensional spacee. x[ix] is the point where the interpolation is evaluated. x is the points where the function value is available, the columns of x must be the same as the size of z. gamma is the `wave number' of the target function. it provides an estimate of the derivative growth: f^(k) = O(gamma**k) larger gamma = more conservative and lower order interpolation. order_set is the expansion order set of the Taylor expansions. boundary_set is the boundary of order_set. boundary_zeta. return values: da = interp_nd_coef(...) da are the interpolation gradient coefficients. """ # verifying arguments gamma = float(gamma) d, n = x.shape[1], x.shape[0] assert len(order_set) > 1 and order_set[0] == (0,) * d # construct X N = len(order_set) - 1 X = zeros([N, n], dtype=float) for i, kappa in enumerate(order_set[1:]): X[i,:] = gamma**sum(kappa) / factorial(kappa) * \ ((x - x[ix,:])**kappa).prod(1) # construct diagonal G matrix for the Lagrange residual G2 = zeros(n) for kappa, zeta in zip(boundary_set, boundary_zeta): Gi = gamma**sum(kappa) / factorial(kappa) * \ ((x - x[ix,:])**kappa).prod(1) * sum(zeta) / sum(kappa) G2[:n] += Gi**2 G = sqrt(G2) # construct c c = ones(n) # first try to assemble the diagonal of matrix A, and sort by its diagonal diagA = (X**2).sum(0) + G**2 finite = numpy.isfinite(diagA) isort = sorted(range(n), key=diagA.__getitem__) irevt = sorted(range(n), key=isort.__getitem__) # drop first one -- all 0 assert isort[0] == ix isort = isort[1:] # permute columns of X and diagonal of G and H X = X[:,isort] G = G[isort] c = c[isort] finite = finite[isort] # filter out faraway elements X = X[:,finite] G = G[finite] # QR decomposition of X, R is now cholesky factor of A n1, n2 = X.shape A = zeros([n1+n2, n2]) A[:n1,:] = X A[range(n1,n1+n2), range(n2)] = G R = numpy.linalg.qr(A, mode='r') # ------------------- gradient part ----------------- da = zeros([c.size + 1, d]) for i in range(d): # calculate rhs = dA * a kappa = (0,) * i + (1,) + (0,) * (d-i-1) ind = order_set.index(kappa) - 1 rhs = - gamma * X[ind,:] # solve for da tmp = solve_L(R.transpose(), rhs) da[1:,i][finite] = solve_R(R, tmp) da[0,i] = -dot(da[1:,i], c) # reverse sorting permutation to get a and b and normalize da = da[irevt,:] return -da