Mercurial > hg > octave-avbm
changeset 8712:010e15c7be9a
support pchip method in interp2
author | Jaroslav Hajek <highegg@gmail.com> |
---|---|
date | Fri, 14 Mar 2008 12:54:56 +0100 |
parents | 822cab55ca85 |
children | 02d4c764de61 |
files | scripts/ChangeLog scripts/general/interp2.m src/ChangeLog src/DLD-FUNCTIONS/__pchip_deriv__.cc |
diffstat | 4 files changed, 208 insertions(+), 62 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/ChangeLog +++ b/scripts/ChangeLog @@ -1,3 +1,9 @@ +2008-03-14 Jaroslav Hajek <highegg@gmail.com> + + * general/interp2.m: Added support for pchip bicubic interpolation. + Also simplified code and added support for natural extrapolation via + "extrap". + 2009-02-09 John W. Eaton <jwe@octave.org> * miscellaneous/Makefile.in (SOURCES): Include __xzip__.m in the list.
--- a/scripts/general/interp2.m +++ b/scripts/general/interp2.m @@ -1,4 +1,5 @@ ## Copyright (C) 2000, 2006, 2007 Kai Habel +## Copyright (C) 2009 Jaroslav Hajek <highegg@gmail.com> ## ## This file is part of Octave. ## @@ -138,7 +139,9 @@ if (!ischar (method)) error ("interp2 expected string 'method'"); endif - if (!isscalar (extrapval)) + if (ischar (extrapval) || strcmp (extrapval, "extrap")) + extrapval = []; + elseif (!isscalar (extrapval)) error ("interp2 expected n extrapval"); endif @@ -161,15 +164,18 @@ endif - if (strcmp (method, "linear") || strcmp (method, "nearest")) + if (strcmp (method, "linear") || strcmp (method, "nearest") ... + || strcmp (method, "pchip")) ## If X and Y vectors produce a grid from them if (isvector (X) && isvector (Y)) - [X, Y] = meshgrid (X, Y); - elseif (! size_equal (X, Y)) + X = X(:); Y = Y(:); + elseif (size_equal (X, Y)) + X = X(1,:)'; Y = Y(:,1); + else error ("X and Y must be matrices of same size"); endif - if (! size_equal (X, Z)) + if (columns (Z) != length (X) || rows (Z) != length (Y)) error ("X and Y size must match Z dimensions"); endif @@ -181,12 +187,25 @@ error ("XI and YI must be matrices of same size"); endif - shape = size (XI); - XI = reshape (XI, 1, prod (shape)); - YI = reshape (YI, 1, prod (shape)); + ## if XI, YI are vectors, X and Y should share their orientation. + if (rows (XI) == 1) + if (rows (X) != 1) + X = X.'; + endif + if (rows (Y) != 1) + Y = Y.'; + endif + elseif (columns (XI) == 1) + if (columns (X) != 1) + X = X.'; + endif + if (columns (Y) != 1) + Y = Y.'; + endif + endif - xidx = lookup (X(1, :), XI, "lr"); - yidx = lookup (Y(:, 1), YI, "lr"); + xidx = lookup (X, XI, "lr"); + yidx = lookup (Y, YI, "lr"); if (strcmp (method, "linear")) ## each quad satisfies the equation z(x,y)=a+b*x+c*y+d*xy @@ -202,41 +221,98 @@ idx = sub2ind (size (a), yidx, xidx); ## scale XI, YI values to a 1-spaced grid - Xsc = (XI - X(1, xidx)) ./ (X(1, xidx + 1) - X(1, xidx)); - Ysc = (YI - Y(yidx, 1)') ./ (Y(yidx + 1, 1) - Y(yidx, 1))'; + Xsc = (XI - X(xidx)) ./ (X(xidx + 1) - X(xidx)); + Ysc = (YI - Y(yidx)) ./ (Y(yidx + 1) - Y(yidx)); ## apply plane equation ZI = a(idx) + b(idx).*Xsc + c(idx).*Ysc + d(idx).*Xsc.*Ysc; elseif (strcmp (method, "nearest")) - xtable = X(1, :); - ytable = Y(:, 1)'; - ii = (XI - xtable(xidx) > xtable(xidx + 1) - XI); - jj = (YI - ytable(yidx) > ytable(yidx + 1) - YI); + ii = (XI - X(xidx) > X(xidx + 1) - XI); + jj = (YI - Y(yidx) > Y(yidx + 1) - YI); idx = sub2ind (size (Z), yidx+jj, xidx+ii); ZI = Z(idx); + + elseif (strcmp (method, "pchip")) + + if (length (X) < 2 || length (Y) < 2) + error ("interp2: pchip2 requires at least 2 points in each dimension") + endif + + ## first order derivatives + DX = __pchip_deriv__ (X, Z, 2); + DY = __pchip_deriv__ (Y, Z, 1); + ## Compute mixed derivatives row-wise and column-wise, use the average. + DXY = (__pchip_deriv__ (X, DY, 2) + __pchip_deriv__ (Y, DX, 1))/2; + + ## do the bicubic interpolation + hx = diff (X); hx = hx(xidx); + hy = diff (Y); hy = hy(yidx); + + tx = (XI - X(xidx)) ./ hx; + ty = (YI - Y(yidx)) ./ hy; + + ## construct the cubic hermite base functions in x, y + + ## formulas: + ## b{1,1} = ( 2*t.^3 - 3*t.^2 + 1); + ## b{2,1} = h.*( t.^3 - 2*t.^2 + t ); + ## b{1,2} = (-2*t.^3 + 3*t.^2 ); + ## b{2,2} = h.*( t.^3 - t.^2 ); + + ## optimized equivalents of the above: + t1 = tx.^2; + t2 = tx.*t1 - t1; + xb{2,2} = hx.*t2; + t1 = t2 - t1; + xb{2,1} = hx.*(t1 + tx); + t2 += t1; + xb{1,2} = -t2; + xb{1,1} = t2 + 1; + + t1 = ty.^2; + t2 = ty.*t1 - t1; + yb{2,2} = hy.*t2; + t1 = t2 - t1; + yb{2,1} = hy.*(t1 + ty); + t2 += t1; + yb{1,2} = -t2; + yb{1,1} = t2 + 1; + + ZI = zeros (size (XI)); + for i = 1:2 + for j = 1:2 + zidx = sub2ind (size (Z), yidx+(j-1), xidx+(i-1)); + ZI += xb{1,i} .* yb{1,j} .* Z(zidx); + ZI += xb{2,i} .* yb{1,j} .* DX(zidx); + ZI += xb{1,i} .* yb{2,j} .* DY(zidx); + ZI += xb{2,i} .* yb{2,j} .* DXY(zidx); + endfor + endfor + endif - ## set points outside the table to 'extrapval' - if (X (1, 1) < X (1, end)) - if (Y (1, 1) < Y (end, 1)) - ZI (XI < X(1,1) | XI > X(1,end) | YI < Y(1,1) | YI > Y(end,1)) = ... - extrapval; + if (! isempty (extrapval)) + ## set points outside the table to 'extrapval' + if (X (1) < X (end)) + if (Y (1) < Y (end)) + ZI (XI < X(1,1) | XI > X(end) | YI < Y(1,1) | YI > Y(end)) = ... + extrapval; + else + ZI (XI < X(1) | XI > X(end) | YI < Y(end) | YI > Y(1)) = ... + extrapval; + endif else - ZI (XI < X(1,1) | XI > X(1,end) | YI < Y(end,1) | YI > Y(1,1)) = ... - extrapval; - endif - else - if (Y (1, 1) < Y (end, 1)) - ZI (XI < X(1,end) | XI > X(1,1) | YI < Y(1,1) | YI > Y(end,1)) = ... - extrapval; - else - ZI (XI < X(1,end) | XI > X(1,1) | YI < Y(end,1) | YI > Y(1,1)) = ... - extrapval; + if (Y (1) < Y (end)) + ZI (XI < X(end) | XI > X(1) | YI < Y(1) | YI > Y(end)) = ... + extrapval; + else + ZI (XI < X(1,end) | XI > X(1) | YI < Y(end) | YI > Y(1)) = ... + extrapval; + endif endif endif - ZI = reshape (ZI, shape); else ## If X and Y vectors produce a grid from them @@ -285,6 +361,15 @@ %! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; %!demo +%! [x,y,A] = peaks(10); +%! x = x(1,:)'; y = y(:,1); +%! xi=linspace(min(x),max(x),41); +%! yi=linspace(min(y),max(y),41)'; +%! mesh(xi,yi,interp2(x,y,A,xi,yi,'linear')); +%! [x,y] = meshgrid(x,y); +%! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; + +%!demo %! A=[13,-1,12;5,4,3;1,6,2]; %! x=[0,1,4]; y=[10,11,12]; %! xi=linspace(min(x),max(x),17); @@ -294,6 +379,33 @@ %! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; %!demo +%! [x,y,A] = peaks(10); +%! x = x(1,:)'; y = y(:,1); +%! xi=linspace(min(x),max(x),41); +%! yi=linspace(min(y),max(y),41)'; +%! mesh(xi,yi,interp2(x,y,A,xi,yi,'nearest')); +%! [x,y] = meshgrid(x,y); +%! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; + +%!demo +%! A=[13,-1,12;5,4,3;1,6,2]; +%! x=[0,1,2]; y=[10,11,12]; +%! xi=linspace(min(x),max(x),17); +%! yi=linspace(min(y),max(y),26)'; +%! mesh(xi,yi,interp2(x,y,A,xi,yi,'pchip')); +%! [x,y] = meshgrid(x,y); +%! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; + +%!demo +%! [x,y,A] = peaks(10); +%! x = x(1,:)'; y = y(:,1); +%! xi=linspace(min(x),max(x),41); +%! yi=linspace(min(y),max(y),41)'; +%! mesh(xi,yi,interp2(x,y,A,xi,yi,'pchip')); +%! [x,y] = meshgrid(x,y); +%! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; + +%!demo %! A=[13,-1,12;5,4,3;1,6,2]; %! x=[0,1,2]; y=[10,11,12]; %! xi=linspace(min(x),max(x),17); @@ -303,6 +415,15 @@ %! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; %!demo +%! [x,y,A] = peaks(10); +%! x = x(1,:)'; y = y(:,1); +%! xi=linspace(min(x),max(x),41); +%! yi=linspace(min(y),max(y),41)'; +%! mesh(xi,yi,interp2(x,y,A,xi,yi,'cubic')); +%! [x,y] = meshgrid(x,y); +%! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; + +%!demo %! A=[13,-1,12;5,4,3;1,6,2]; %! x=[0,1,2]; y=[10,11,12]; %! xi=linspace(min(x),max(x),17); @@ -311,6 +432,15 @@ %! [x,y] = meshgrid(x,y); %! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; +%!demo +%! [x,y,A] = peaks(10); +%! x = x(1,:)'; y = y(:,1); +%! xi=linspace(min(x),max(x),41); +%! yi=linspace(min(y),max(y),41)'; +%! mesh(xi,yi,interp2(x,y,A,xi,yi,'spline')); +%! [x,y] = meshgrid(x,y); +%! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; + %!test % simple test %! x = [1,2,3]; %! y = [4,5,6,7];
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2009-02-10 Jaroslav Hajek <highegg@gmail.com> + + * DLD-FUNCTIONS/__pchip_deriv__.cc (F__pchip_deriv__): + Add support for computing pchip derivatives along rows of matrix. + Eliminate redundant copying by using const args where appropriate. + 2009-02-09 John W. Eaton <jwe@octave.org> * version.h (OCTAVE_VERSION): Now 3.1.52.
--- a/src/DLD-FUNCTIONS/__pchip_deriv__.cc +++ b/src/DLD-FUNCTIONS/__pchip_deriv__.cc @@ -1,6 +1,7 @@ /* Copyright (C) 2002, 2006, 2007 Kai Habel +Copyright (C) 2008, 2009 Jaroslav Hajek This file is part of Octave. @@ -20,6 +21,9 @@ */ +// Jaroslav Hajek, Feb 2008: handle row-wise derivatives, +// use const pointers to avoid unnecessary copying. + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -34,12 +38,12 @@ extern "C" { F77_RET_T - F77_FUNC (dpchim, DPCHIM) (const octave_idx_type& n, double *x, double *f, + F77_FUNC (dpchim, DPCHIM) (const octave_idx_type& n, const double *x, const double *f, double *d, const octave_idx_type &incfd, octave_idx_type *ierr); F77_RET_T - F77_FUNC (pchim, PCHIM) (const octave_idx_type& n, float *x, float *f, + F77_FUNC (pchim, PCHIM) (const octave_idx_type& n, const float *x, const float *f, float *d, const octave_idx_type &incfd, octave_idx_type *ierr); } @@ -49,14 +53,16 @@ DEFUN_DLD (__pchip_deriv__, args, , "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __pchip_deriv__ (@var{x}, @var{y})\n\ +@deftypefn {Loadable Function} {} __pchip_deriv__ (@var{x}, @var{y}, @var{dim})\n\ Undocumented internal function.\n\ @end deftypefn") { octave_value retval; const int nargin = args.length (); - if (nargin == 2) + bool rows = (nargin == 3 && args (2).uint_value() == 2); + + if (nargin >= 2) { if (args(0).is_single_type () || args(1).is_single_type ()) { @@ -67,34 +73,33 @@ octave_idx_type nyr = ymat.rows (); octave_idx_type nyc = ymat.columns (); - if (nx != nyr) + if (nx != (rows ? nyc : nyr)) { - error ("number of rows for x and y must match"); + error ("__pchip_deriv__: dimension mismatch"); return retval; } - FloatColumnVector dvec (nx), yvec (nx); + const float *yvec = ymat.data (); FloatMatrix dmat (nyr, nyc); + float *dvec = dmat.fortran_vec (); octave_idx_type ierr; - const octave_idx_type incfd = 1; - for (int c = 0; c < nyc; c++) + const octave_idx_type incfd = rows ? nyr : 1; + const octave_idx_type inc = rows ? 1 : nyc; + + for (octave_idx_type i = (rows ? nyr : nyc); i > 0; i--) { - for (int r = 0; r < nx; r++) - yvec(r) = ymat(r,c); + F77_FUNC (pchim, PCHIM) (nx, xvec.data (), + yvec, dvec, incfd, &ierr); - F77_FUNC (pchim, PCHIM) (nx, xvec.fortran_vec (), - yvec.fortran_vec (), - dvec.fortran_vec (), incfd, &ierr); + yvec += inc; + dvec += inc; if (ierr < 0) { error ("PCHIM error: %i\n", ierr); return retval; } - - for (int r=0; r<nx; r++) - dmat(r,c) = dvec(r); } retval = dmat; @@ -108,34 +113,33 @@ octave_idx_type nyr = ymat.rows (); octave_idx_type nyc = ymat.columns (); - if (nx != nyr) + if (nx != (rows ? nyc : nyr)) { - error ("number of rows for x and y must match"); + error ("__pchip_deriv__: dimension mismatch"); return retval; } - ColumnVector dvec (nx), yvec (nx); + const double *yvec = ymat.data (); Matrix dmat (nyr, nyc); + double *dvec = dmat.fortran_vec (); octave_idx_type ierr; - const octave_idx_type incfd = 1; - for (int c = 0; c < nyc; c++) + const octave_idx_type incfd = rows ? nyr : 1; + const octave_idx_type inc = rows ? 1 : nyc; + + for (octave_idx_type i = (rows ? nyr : nyc); i > 0; i--) { - for (int r = 0; r < nx; r++) - yvec(r) = ymat(r,c); + F77_FUNC (dpchim, DPCHIM) (nx, xvec.data (), + yvec, dvec, incfd, &ierr); - F77_FUNC (dpchim, DPCHIM) (nx, xvec.fortran_vec (), - yvec.fortran_vec (), - dvec.fortran_vec (), incfd, &ierr); + yvec += inc; + dvec += inc; if (ierr < 0) { error ("DPCHIM error: %i\n", ierr); return retval; } - - for (int r=0; r<nx; r++) - dmat(r,c) = dvec(r); } retval = dmat;