You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

152 lines
5.7 KiB

#ifndef MEDUSA_BITS_APPROXIMATIONS_WLS_HPP_
#define MEDUSA_BITS_APPROXIMATIONS_WLS_HPP_
/**
* @file
* Implementation of weighted least squares approximation.
*/
#include "WLS_fwd.hpp"
#include <medusa/bits/utils/assert.hpp>
#include <medusa/bits/types/Range.hpp>
#include <medusa/bits/utils/numutils.hpp>
#include "JacobiSVDWrapper.hpp"
#include "WLSApproximant.hpp"
namespace mm {
template <class basis_t, class weight_t, class scale_t, class solver_t>
void WLS<basis_t, weight_t, scale_t, solver_t>::compute(const vector_t& point,
const std::vector<vector_t>& support) {
int n = support.size();
assert_msg(basis_.size() <= n,
"WLS cannot have more basis functions than points in support domain, but %d "
"support points and %d basis functions were given.", n, basis_.size());
assert_msg(basis_.size() > 0, "Cannot construct an approximation with an empty basis.");
scale_ = scale_t::scale(point, support);
local_coordinates_.resize(n);
for (int i = 0; i < n; ++i) {
local_coordinates_[i] = (support[i] - point) / scale_;
}
point_ = point;
solver_.compute(getMatrix(local_coordinates_));
}
template <class basis_t, class weight_t, class scale_t, class solver_t>
typename WLS<basis_t, weight_t, scale_t, solver_t>::ei_matrix_t
WLS<basis_t, weight_t, scale_t, solver_t>::getMatrix(
const std::vector<vector_t>& local_coordinates) const {
// Evaluate basis functions in given points
int n = local_coordinates.size();
int m = basis_.size();
ei_matrix_t WB(m, n);
for (int j = 0; j < n; j++) {
scalar_t w = weight_(local_coordinates[j]);
for (int i = 0; i < m; i++) {
WB(i, j) = w * basis_.eval(i, local_coordinates[j], local_coordinates);
}
}
return WB;
}
template <class basis_t, class weight_t, class scale_t, class solver_t>
Eigen::Matrix<typename basis_t::scalar_t, Eigen::Dynamic, 1>
WLS<basis_t, weight_t, scale_t, solver_t>::getShape() const {
int m = basis_.size();
Eigen::Matrix<scalar_t, Eigen::Dynamic, 1> b(m);
for (int i = 0; i < m; i++) {
b(i) = basis_.evalAt0(i, local_coordinates_);
}
return getShapeFromRhs(b);
}
/// @cond
template <class basis_t, class weight_t, class scale_t, class solver_t>
template <class operator_t>
Eigen::Matrix<typename basis_t::scalar_t, Eigen::Dynamic, 1>
WLS<basis_t, weight_t, scale_t, solver_t>::getShape(const operator_t& op) const {
int m = basis_.size();
Eigen::Matrix<scalar_t, Eigen::Dynamic, 1> Lb(m);
for (int i = 0; i < m; i++) {
Lb(i) = basis_.evalOpAt0(i, op, local_coordinates_, scale_);
}
return getShapeFromRhs(Lb);
}
template <class basis_t, class weight_t, class scale_t, class solver_t>
template <class Derived>
Eigen::Matrix<typename basis_t::scalar_t, Eigen::Dynamic, 1>
WLS<basis_t, weight_t, scale_t, solver_t>::getShapeFromRhs(
const Eigen::MatrixBase<Derived>& Lb) const {
int n = local_coordinates_.size();
// Solve (WB)^T x = Lb
Eigen::Matrix<scalar_t, Eigen::Dynamic, 1> result = solver_.solve(Lb);
// Multiply with weight
for (int j = 0; j < n; j++) {
result(j) *= weight_(local_coordinates_[j]);
}
return result;
}
template <class basis_t, class weight_t, class scale_t, class solver_t>
Eigen::Matrix<typename basis_t::scalar_t, Eigen::Dynamic, 1>
WLS<basis_t, weight_t, scale_t, solver_t>::getWeights() const {
int n = local_coordinates_.size();
Eigen::Matrix<scalar_t, Eigen::Dynamic, 1> w(n);
for (int j = 0; j < n; j++) {
w(j) = weight_(local_coordinates_[j]);
}
return w;
}
/// @endcond
/// Output basic info about given WLS class.
template <class basis_t, class weight_t, class scale_t, class solver_t>
std::ostream& operator<<(std::ostream& os, const WLS<basis_t, weight_t, scale_t, solver_t>& wls) {
os << "WLS:\n"
<< " dimension: " << wls.dim << '\n'
<< " basis size: " << wls.basis_.size() << '\n'
<< " basis: " << wls.basis_ << '\n'
<< " weight: " << wls.weight_ << '\n'
<< " scale: " << scale_t() << '\n';
if (wls.point_[0] != wls.point_[0]) {
os << " last point: not used yet";
} else {
os << " last point: " << wls.point_;
}
return os;
}
template <class basis_t, class weight_t, class scale_t, class solver_t>
template <typename Derived>
WLSApproximant<basis_t>
WLS<basis_t, weight_t, scale_t, solver_t>::getApproximant(
const vector_t& point, const std::vector<vector_t>& support,
const Eigen::MatrixBase<Derived>& values) const {
int n = support.size();
assert_msg(values.size() == n, "Number of given values %d must be equal to support size %d.",
values.size(), n);
assert_msg(basis_.size() <= n,
"WLS cannot have more basis functions than points in support domain, but %d "
"support points and %d basis functions were given.", n, basis_.size());
double scale = scale_t::scale(point, support);
std::vector<vector_t> local_coordinates(n);
for (int i = 0; i < n; ++i) {
local_coordinates[i] = (support[i] - point) / scale;
}
solver_t solver;
ei_matrix_t matrix = getMatrix(local_coordinates).transpose();
solver.compute(matrix);
Eigen::Matrix<scalar_t, Eigen::Dynamic, 1> w(n);
for (int j = 0; j < n; j++) {
w(j) = weight_(local_coordinates[j]);
}
Eigen::Matrix<scalar_t, Eigen::Dynamic, 1> coefficients = solver.solve(values.cwiseProduct(w));
scalar_t residual = (matrix*coefficients - values).squaredNorm();
return WLSApproximant<basis_t>(basis_, point, support, scale, coefficients, residual);
}
} // namespace mm
#endif // MEDUSA_BITS_APPROXIMATIONS_WLS_HPP_