2 % implements rbf interpolation by thin plate splines or gaussian
4 properties (SetAccess=
private,Hidden=
true)
10 properties (Access=private)
14 properties (SetAccess=private)
20 properties (Dependent)
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);
30 if any(strcmp(kernel_type, {
'tps',
'gaussian',
'gaussian_loc'}))
31 this.kernel_type = kernel_type;
33 warning(
'RbfInterpolant:RbfInterpolant',
'kernel type not supported');
37 this.dilation_ = dilation;
40 add_data(this, points, values, []);
44 function set.dilation(this, dilation)
45 this.dilation_ = dilation;
49 function dilation = get.dilation(this)
50 dilation = this.dilation_;
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);
58 res = zeros(0, size(points, 2));
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}(:)];
73 %
if indices is not specified, the last added data is removed
74 function this = remove_data(
this, indices)
76 indices = this.num_points;
77 elseif any(indices > this.num_points)
79 'Index exceeds number of data points.');
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);
91 % points is a (d x n)-matrix, res is a (d x n)-matrix
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);
104 % points is a (d x n)-matrix, res is a (1 x n)-matrix
105 % returns -inf if r=0
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);
119 methods (Hidden=true)
121 % vectorized thin plate spline basis
122 function res = evaluate_basis(this, x)
123 r = this.compute_radii(x);
124 switch this.kernel_type
126 res = (r>eps) .* r.^2 .* log(r + (r<=eps));
128 res = exp( -(r/this.dilation_).^2 );
130 res = exp( -(r./repmat(this.dilation_, 1, size(r, 2))).^2 );
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});
139 res = builtin(
'subsref',
this, S);
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)';
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));
implements rbf interpolation by thin plate splines or gaussian