v2.0.0
Loading...
Searching...
No Matches
numerics.cpp
Go to the documentation of this file.
1//=============================================================================================================
26
27//=============================================================================================================
28// INCLUDES
29//=============================================================================================================
30
31// MSVC builds already define _USE_MATH_DEFINES globally (see src/CMakeLists.txt),
32// so define it here only for the toolchains that do not.
33#ifndef _USE_MATH_DEFINES
34#define _USE_MATH_DEFINES
35#endif
36#include <cmath>
37#include "numerics.h"
38
39//=============================================================================================================
40// QT INCLUDES
41//=============================================================================================================
42
43#include <QDebug>
44#include <QStringList>
45
46//=============================================================================================================
47// USED NAMESPACES
48//=============================================================================================================
49
50using namespace UTILSLIB;
51using namespace Eigen;
52
53//=============================================================================================================
54// DEFINE MEMBER METHODS
55//=============================================================================================================
56
57int Numerics::gcd(int iA, int iB)
58{
59 if (iB == 0) {
60 return iA;
61 }
62
63 return gcd(iB, iA % iB);
64}
65
66//=============================================================================================================
67
68bool Numerics::issparse(VectorXd& v)
69{
70 qint32 c = 0;
71 qint32 n = v.rows();
72 qint32 t = n / 2;
73
74 for (qint32 i = 0; i < n; ++i) {
75 if (v(i) == 0)
76 ++c;
77 if (c > t)
78 return true;
79 }
80
81 return false;
82}
83
84//=============================================================================================================
85
87{
88 int t_iNumOfCombination = static_cast<int>(n * (n - 1) * 0.5);
89
90 return t_iNumOfCombination;
91}
92
93//=============================================================================================================
94
95double Numerics::chi2Isf(double p, int dof)
96{
97 // P(a, x) summed from its power series (A&S 6.5.29), the quantile bisected; Q = 1 - P keeps
98 // ~1e-13 relative accuracy for the p = 1e-3 the inverse SNR estimates use.
99 const double a = 0.5 * dof;
100 auto upperTail = [a](double chi2) {
101 const double x = 0.5 * chi2;
102 double term = 1.0;
103 double sum = 1.0;
104 for (int n = 1; n < 100000 && term > 1e-17 * sum; ++n) {
105 term *= x / (a + n);
106 sum += term;
107 }
108 return 1.0 - sum * std::exp(a * std::log(x) - x - std::lgamma(a + 1.0));
109 };
110 double lo = 0.0;
111 double hi = dof + 10.0 * std::sqrt(2.0 * dof) + 50.0;
112 while (upperTail(hi) > p)
113 hi *= 2.0;
114 for (int i = 0; i < 200 && hi - lo > 1e-14 * hi; ++i) {
115 const double mid = 0.5 * (lo + hi);
116 (upperTail(mid) > p ? lo : hi) = mid;
117 }
118 return 0.5 * (lo + hi);
119}
120
121//=============================================================================================================
122
123MatrixXd Numerics::rescale(const MatrixXd& data,
124 const RowVectorXf& times,
125 const QPair<float, float>& baseline,
126 QString mode)
127{
128 return rescale(data, times, std::pair<float, float>(baseline.first, baseline.second), mode.toStdString());
129}
130
131//=============================================================================================================
132
133MatrixXd Numerics::rescale(const MatrixXd& data,
134 const RowVectorXf& times,
135 const std::pair<float, float>& baseline,
136 const std::string& mode)
137{
138 MatrixXd data_out = data;
139 const QStringList valid_modes{"logratio", "ratio", "zscore", "mean", "percent"};
140 if (!valid_modes.contains(QString::fromStdString(mode))) {
141 qWarning().noquote() << "[Numerics::rescale] Mode" << mode.c_str() << "is not supported. Supported modes are:" << valid_modes << "Returning input data.";
142 return data_out;
143 }
144
145 qInfo().noquote() << QString("[Numerics::rescale] Applying baseline correction ... (mode: %1)").arg(mode.c_str());
146
147 qint32 imin = 0;
148 qint32 imax = times.size();
149
150 if (baseline.second == baseline.first) {
151 imin = 0;
152 } else {
153 float bmin = baseline.first;
154 for (qint32 i = 0; i < times.size(); ++i) {
155 if (times[i] >= bmin) {
156 imin = i;
157 break;
158 }
159 }
160 }
161
162 float bmax = baseline.second;
163
164 if (baseline.second == baseline.first) {
165 bmax = 0;
166 }
167
168 for (qint32 i = times.size() - 1; i >= 0; --i) {
169 if (times[i] <= bmax) {
170 imax = i + 1;
171 break;
172 }
173 }
174
175 if (imax < imin) {
176 qWarning() << "[Numerics::rescale] imax < imin. Returning input data.";
177 return data_out;
178 }
179
180 VectorXd mean = data_out.block(0, imin, data_out.rows(), imax - imin).rowwise().mean();
181 if (mode.compare("mean") == 0) {
182 data_out -= mean.rowwise().replicate(data.cols());
183 } else if (mode.compare("logratio") == 0) {
184 for (qint32 i = 0; i < data_out.rows(); ++i)
185 for (qint32 j = 0; j < data_out.cols(); ++j)
186 data_out(i, j) = log10(data_out(i, j) / mean[i]);
187 } else if (mode.compare("ratio") == 0) {
188 data_out = data_out.cwiseQuotient(mean.rowwise().replicate(data_out.cols()));
189 } else if (mode.compare("zscore") == 0) {
190 MatrixXd std_mat = data.block(0, imin, data.rows(), imax - imin) - mean.rowwise().replicate(imax - imin);
191 std_mat = std_mat.cwiseProduct(std_mat);
192 VectorXd std_v = std_mat.rowwise().mean();
193 for (qint32 i = 0; i < std_v.size(); ++i)
194 std_v[i] = sqrt(std_v[i]);
195
196 data_out -= mean.rowwise().replicate(data_out.cols());
197 data_out = data_out.cwiseQuotient(std_v.rowwise().replicate(data_out.cols()));
198 } else if (mode.compare("percent") == 0) {
199 data_out -= mean.rowwise().replicate(data_out.cols());
200 data_out = data_out.cwiseQuotient(mean.rowwise().replicate(data_out.cols()));
201 }
202
203 return data_out;
204}
General numerical helpers: GCD, log2, histogram binning, baseline rescaling, sparsity tests.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
static int gcd(int iA, int iB)
Definition numerics.cpp:57
static double chi2Isf(double p, int dof)
Definition numerics.cpp:95
static bool issparse(Eigen::VectorXd &v)
Definition numerics.cpp:68
static Eigen::MatrixXd rescale(const Eigen::MatrixXd &data, const Eigen::RowVectorXf &times, const QPair< float, float > &baseline, QString mode)
static int nchoose2(int n)
Definition numerics.cpp:86