71 const std::vector<double> & y,
const unsigned int s,
const double frequency,
const double r,
72 const double lambda0,
const double lambda1,
const double lambda2,
73 const unsigned int loop,
const double eps,
const BeadsPenalty penalty
77 throw std::invalid_argument(
"BaselineBeads(): the length of y is zero.");
81 throw std::invalid_argument(
"BaselineBeads(): s must be 1, 2 or 3.");
85 throw std::invalid_argument(
"BaselineBeads(): non-positive frequency value is given.");
89 throw std::invalid_argument(
"BaselineBeads(): non-positive r value is given.");
92 if(lambda0 <= 0 || lambda1 <= 0 || lambda2 <= 0) {
93 throw std::invalid_argument(
"BaselineBeads(): non-positive lambda value is given.");
97 throw std::invalid_argument(
"BaselineBeads(): loop is zero.");
101 throw std::invalid_argument(
"BaselineBeads(): non-positive eps value is given.");
104 const double eps0 = 1e-6;
105 const double eps1 = 1e-6;
107 Eigen::VectorXd yy = Eigen::VectorXd::Map(y.data(), y.size());
109 std::function<double(
const double)> phi, wfun;
113 phi = [&](
const double xx) {
114 double abs_x = std::fabs(xx);
115 return std::sqrt(abs_x * abs_x + eps1);
117 wfun = [&](
const double xx) {
122 phi = [&](
const double xx) {
123 double abs_x = std::fabs(xx);
124 return abs_x - eps1 * std::log(abs_x + eps1);
126 wfun = [&](
const double xx) {
127 return 1 / (std::fabs(xx) + eps1);
131 throw std::invalid_argument(
"invalid penalty function type.");
134 auto theta = [&](
const double xx) {
138 else if(xx < -eps0) {
142 return (1 + r) * xx * xx / (4 * eps0) + (1 - r) * xx / 2 + eps0 * (1 + r) / 4;
146 int length = yy.size();
147 auto [ A, B ] = BAfilt(s, frequency, length);
149 Eigen::SparseMatrix<double> I, D1, D2;
151 I.resize(length, length);
156 Eigen::SparseLU< Eigen::SparseMatrix<double> > solverA, solverQ;
160 if(solverA.info() != Eigen::Success) {
161 throw std::runtime_error(
"BaselineBeads(): solverA calculation fails.");
164 Eigen::SparseMatrix<double> BTB = B.transpose() * B;
165 Eigen::VectorXd b = Eigen::VectorXd::Constant(length, (1 - r) / 2);
166 Eigen::VectorXd d = BTB * (solverA.solve(yy)) - lambda0 * A.transpose() * b;
167 Eigen::VectorXd w1 = Eigen::VectorXd::Constant(length - 1, lambda1);
168 Eigen::VectorXd w2 = Eigen::VectorXd::Constant(length - 2, lambda2);
170 Eigen::VectorXd x = yy;
173 * (B * solverA.solve(x)).unaryExpr([](
const double xx){
return xx * xx; }).sum()
174 + lambda0 * x.unaryExpr(theta).sum()
175 + lambda1 * (D1 * x).unaryExpr(phi).sum()
176 + lambda2 * (D2 * x).unaryExpr(phi).sum();
178 for(
unsigned int i = 0; i < loop; i++) {
179 Eigen::SparseMatrix<double> L1, L2, G, M;
181 L1 = (w1.array() * (D1 * x).unaryExpr(wfun).array()).matrix().asDiagonal();
182 L2 = (w2.array() * (D2 * x).unaryExpr(wfun).array()).matrix().asDiagonal();
184 G = x.unaryExpr([&](
const double xx) {
185 double z = (-eps0 <= xx && xx <= eps0) ? eps0 : std::fabs(xx);
186 return (1 + r) / 4 / z;
189 M = 2 * lambda0 * G + D1.transpose() * L1 * D1 + D2.transpose() * L2 * D2;
190 solverQ.compute(BTB + A.transpose() * M * A);
192 if(solverQ.info() != Eigen::Success) {
193 throw std::runtime_error(
"BaselineBeads(): solverQ calculation fails.");
196 x = A * solverQ.solve(d);
198 Eigen::VectorXd a = yy - x;
200 * (B * solverA.solve(a)).unaryExpr([](
const double xx){
return xx * xx; }).sum()
201 + lambda0 * x.unaryExpr(theta).sum()
202 + lambda1 * (D1 * x).unaryExpr(phi).sum()
203 + lambda2 * (D2 * x).unaryExpr(phi).sum();
205 if(std::fabs((prev_c - c) / c) < eps) {
212 Eigen::VectorXd f = yy - x;
213 f = (f - B * solverA.solve(f)).eval();
215 std::vector<double> f_result(f.size()), x_result(x.size());
217 Eigen::VectorXd::Map(f_result.data(), f.size()) = f;
218 Eigen::VectorXd::Map(x_result.data(), x.size()) = x;
220 return std::tuple< std::vector<double>, std::vector<double> >(f_result, x_result);
const std::tuple< std::vector< double >, std::vector< double > > BaselineBeads(const std::vector< double > &y, const unsigned int s, const double frequency, const double r, const double lambda0, const double lambda1, const double lambda2, const unsigned int loop, const double eps, const BeadsPenalty penalty)
Performs baseline estimation and denoising using Sparsity (BEADS).
const Derived1::PlainObject Convolve(const Eigen::MatrixBase< Derived1 > &v1, const Eigen::MatrixBase< Derived2 > &v2, const ConvolveMode mode=ConvolveMode::Full)
Returns the discrete, linear convolution of two one-dimensional sequences.
Eigen::SparseMatrix< typename Derived::PlainObject::Scalar > Spdiags(const Eigen::MatrixBase< Derived > &data, const Eigen::VectorXi &diags, const int m=-1, const int n=-1)
Returns a sparse matrix with the specified elements on its diagonals.