rbmatlab  1.16.09
 All Classes Namespaces Files Functions Variables Modules Pages
RbfInterpolant.m
1 classdef RbfInterpolant < handle
2  % implements rbf interpolation by thin plate splines or gaussian
3 
4  properties (SetAccess=private,Hidden=true)
5  data_points = [];
6  data_values = [];
7  weights;
8  end
9 
10  properties (Access=private)
11  dilation_ = 0.1;
12  end
13 
14  properties (SetAccess=private)
15  num_points = 0;
16  dimension;
17  kernel_type = 'tps';
18  end
19 
20  properties (Dependent)
21  dilation;
22  end
23 
24  methods
25 
26  % constructor: points is a (d x n)-matrix, values is a (n x 1)-matrix
27  function this = RbfInterpolant(points, values, kernel_type, dilation)
28  this.dimension = size(points, 1);
29  if nargin >= 3
30  if any(strcmp(kernel_type, {'tps', 'gaussian', 'gaussian_loc'}))
31  this.kernel_type = kernel_type;
32  else
33  warning('RbfInterpolant:RbfInterpolant', 'kernel type not supported');
34  end
35  end
36  if nargin == 4
37  this.dilation_ = dilation;
38  end
39  if ~isempty(points)
40  add_data(this, points, values, []);
41  end
42  end
43 
44  function set.dilation(this, dilation)
45  this.dilation_ = dilation;
46  update(this);
47  end
48 
49  function dilation = get.dilation(this)
50  dilation = this.dilation_;
51  end
52 
53  % points is a (d x n)-matrix, res is a (1 x n)-matrix
54  function res = evaluate(this, points)
55  if this.num_points > 0
56  res = this.weights * this.evaluate_basis(points);
57  else
58  res = zeros(0, size(points, 2));
59  end
60  end
61 
62  % points is a (d x n)-matrix, values is a (n x 1)-matrix
63  function this = add_data(this, varargin)
64  this.data_points = [this.data_points, varargin{1}];
65  this.data_values = [this.data_values; varargin{2}];
66  this.num_points = size(this.data_points, 2);
67  if strcmp(this.kernel_type, 'gaussian_loc')
68  this.dilation_ = [this.dilation_; varargin{3}(:)];
69  end
70  update(this);
71  end
72 
73  % if indices is not specified, the last added data is removed
74  function this = remove_data(this, indices)
75  if nargin < 2
76  indices = this.num_points;
77  elseif any(indices > this.num_points)
78  error('rbmatlab:RbfInterpolant:remove_data', ...
79  'Index exceeds number of data points.');
80  end
81  remain = setdiff(1:this.num_points, indices);
82  this.data_points = this.data_points(:, remain);
83  this.data_values = this.data_values(remain);
84  this.num_points = length(remain);
85  if strcmp(this.kernel_type, 'gaussian_loc')
86  this.dilation = this.dilation_(remain);
87  end
88  update(this);
89  end
90 
91  % points is a (d x n)-matrix, res is a (d x n)-matrix
92  % can be vectorized
93  function res = evaluate_gradient(this, points)
94  r = this.compute_radii(points);
95  res = zeros(this.dimension, size(points, 2));
96  for i = 1:this.dimension
97  inner = repmat(points(i, :), this.num_points, 1) ...
98  - repmat(this.data_points(i, :), size(points, 2), 1)';
99  outer = (r>eps) .* (2*log(r + (r<=eps)) + 1);
100  res(i, :) = this.weights * (outer .* inner);
101  end
102  end
103 
104  % points is a (d x n)-matrix, res is a (1 x n)-matrix
105  % returns -inf if r=0
106  % can be vectorized
107  function res = evaluate_laplacian(this, points)
108  r = this.compute_radii(points);
109  res = zeros(1, size(points, 2));
110  for i = 1:this.dimension
111  inner = repmat(points(i, :), this.num_points, 1) ...
112  - repmat(this.data_points(i, :), size(points, 2), 1)';
113  res = res + this.weights * (2*inner.^2./r + 2*log(r) + 1);
114  end
115  end
116 
117  end
118 
119  methods (Hidden=true)
120 
121  % vectorized thin plate spline basis
122  function res = evaluate_basis(this, x)
123  r = this.compute_radii(x);
124  switch this.kernel_type
125  case 'tps'
126  res = (r>eps) .* r.^2 .* log(r + (r<=eps));
127  case 'gaussian'
128  res = exp( -(r/this.dilation_).^2 );
129  case 'gaussian_loc'
130  res = exp( -(r./repmat(this.dilation_, 1, size(r, 2))).^2 );
131  end
132  end
133 
134  % overload subsref for evaluation
135  function res = subsref(this, S)
136  if strcmp(S(1).type, '()')
137  res = evaluate(this, S(1).subs{1});
138  else
139  res = builtin('subsref', this, S);
140  end
141  end
142 
143  % compute weights from data
144  function this = update(this)
145  if this.num_points > 0
146  this.weights = ((1e-9*eye(this.num_points) ...
147  + this.evaluate_basis(this.data_points)') ...
148  \ this.data_values)';
149  end
150  end
151 
152  % compute radii for a point-matrix
153  function r = compute_radii(this, x)
154  x_shift = permute(repmat(x, 1, 1, this.num_points), [1 3 2]) ...
155  - repmat(this.data_points, 1, 1, size(x, 2));
156  r = sqrt(sum(x_shift.^2, 1));
157  r = shiftdim(r);
158  end
159 
160  end
161 
162 end
implements rbf interpolation by thin plate splines or gaussian