Developer documentation
Version 3.0.3-105-gd3941f44
glm.h
Go to the documentation of this file.
1/* Copyright (c) 2008-2022 the MRtrix3 contributors.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 *
7 * Covered Software is provided under this License on an "as is"
8 * basis, without warranty of any kind, either expressed, implied, or
9 * statutory, including, without limitation, warranties that the
10 * Covered Software is free of defects, merchantable, fit for a
11 * particular purpose or non-infringing.
12 * See the Mozilla Public License v. 2.0 for more details.
13 *
14 * For more details, see http://www.mrtrix.org/.
15 */
16
17#ifndef __math_stats_glm_h__
18#define __math_stats_glm_h__
19
20#include "app.h"
21#include "types.h"
22
24#include "math/least_squares.h"
25#include "math/zstatistic.h"
26#include "math/stats/import.h"
27#include "math/stats/typedefs.h"
28
29#include "misc/bitset.h"
30
31namespace MR
32{
33 namespace Math
34 {
35 namespace Stats
36 {
37 namespace GLM
38 {
39
40
41
42 extern const char* const column_ones_description;
43
44 App::OptionGroup glm_options (const std::string& element_name);
45
46
47
48 // Define a base class to contain information regarding an individual hypothesis, and
49 // pre-compute as much as possible with regards to Freedman-Lane
50 // Note: This can be constructed for both t-tests and F-tests
51 // (This is why the constructor is a template: Could be created either from a row()
52 // call on the contrast matrix, or from a matrix explicitly constructed from a set of
53 // rows from the contrast matrix, which is how an F-test is constructed.
54 // In the case of a single-row F-test, still need to be able to differentiate between
55 // a t-test and an F-test for the sake of signedness (and taking the square root);
56 // this is managed by having two separate constructor templates
59 public:
60
61 class Partition
62 { MEMALIGN (Partition)
63 public:
64 Partition (const matrix_type& x, const matrix_type& z) :
65 X (x),
66 Z (z),
67 Hz (Z.cols() ?
68 (Z * Math::pinv (Z)) :
69 matrix_type (matrix_type::Zero (X.rows(), X.rows()))),
70 Rz (matrix_type::Identity (X.rows(), X.rows()) - Hz),
71 rank_x (Math::rank (X)),
72 rank_z (Z.cols() ? Math::rank (Z) : 0) { }
73 // X = Component of design matrix related to effect of interest
74 // Z = Component of design matrix related to nuisance regressors
75 const matrix_type X, Z;
76 // Hz: Projection matrix of nuisance regressors only
77 // Rz: Residual-forming matrix due to nuisance regressors only
78 const matrix_type Hz, Rz;
79 // rank_x: Rank of X
80 // rank_z: Rank of Z
81 const size_t rank_x, rank_z;
82 };
83
84 Hypothesis (matrix_type::ConstRowXpr& in, const size_t index) :
85 c (in),
86 r (Math::rank (c)),
87 F (false),
88 i (index) { check_nonzero(); }
89
90 Hypothesis (const matrix_type& in, const size_t index) :
91 c (check_rank (in, index)),
92 r (Math::rank (c)),
93 F (true),
94 i (index) { check_nonzero(); }
95
96 Partition partition (const matrix_type&) const;
97
98 const matrix_type& matrix() const { return c; }
99 ssize_t cols() const { return c.cols(); }
100 size_t rank() const { return r; }
101 bool is_F() const { return F; }
102 std::string name() const { return std::string(F ? "F" : "t") + str(i+1); }
103
104 private:
105 const matrix_type c;
106 const size_t r;
107 const bool F;
108 const size_t i;
109
110 void check_nonzero() const;
111 matrix_type check_rank (const matrix_type&, const size_t) const;
112 };
113
114
115
116 void check_design (const matrix_type&, const bool);
117
118 index_array_type load_variance_groups (const size_t num_inputs);
119
120 vector<Hypothesis> load_hypotheses (const std::string& file_path);
121
122
123
131 matrix_type solve_betas (const matrix_type& measurements, const matrix_type& design);
132
133
134
141 vector_type abs_effect_size (const matrix_type& measurements, const matrix_type& design, const Hypothesis& hypothesis);
142 matrix_type abs_effect_size (const matrix_type& measurements, const matrix_type& design, const vector<Hypothesis>& hypotheses);
143
144
145
151 matrix_type stdev (const matrix_type& measurements, const matrix_type& design);
152
153
154
160 matrix_type stdev (const matrix_type& measurements, const matrix_type& design, const index_array_type& variance_groups);
161
162
163
170 vector_type std_effect_size (const matrix_type& measurements, const matrix_type& design, const Hypothesis& hypothesis);
171 matrix_type std_effect_size (const matrix_type& measurements, const matrix_type& design, const vector<Hypothesis>& hypotheses);
172
173
174
186 void all_stats (const matrix_type& measurements, const matrix_type& design, const vector<Hypothesis>& hypotheses, const index_array_type& variance_groups,
188
201 void all_stats (const matrix_type& measurements, const matrix_type& design, const vector<CohortDataImport>& extra_columns, const vector<Hypothesis>& hypotheses, const index_array_type& variance_groups,
203
205
206
207
208
209
210
211 // Define a base class for GLM tests
213 { MEMALIGN(TestBase)
214 public:
215 TestBase (const matrix_type& measurements, const matrix_type& design, const vector<Hypothesis>& hypotheses) :
216 y (measurements),
217 M (design),
218 c (hypotheses),
220 {
221 assert (y.rows() == M.rows());
222 // Can no longer apply this assertion here; GLMTTestVariable later
223 // expands the number of columns in M
224 //assert (c.cols() == M.cols());
225 }
226
227 virtual ~TestBase() { }
228
236 virtual void operator() (const matrix_type& shuffling_matrix, matrix_type& output) const;
237
243 virtual void operator() (const matrix_type& shuffling_matrix, matrix_type& stat, matrix_type& zstat) const = 0;
244
245
246 size_t num_inputs () const { return M.rows(); }
247 size_t num_elements () const { return y.cols(); }
248 size_t num_hypotheses () const { return c.size(); }
249
250 virtual size_t num_factors() const { return M.cols(); }
251
252 protected:
253 const matrix_type& y, M;
255 std::shared_ptr<Math::Zstatistic> stat2z;
256
257 };
258
259
260
261
275 public:
281 TestFixedHomoscedastic (const matrix_type& measurements,
282 const matrix_type& design,
283 const vector<Hypothesis>& hypotheses);
284
290 void operator() (const matrix_type& shuffling_matrix, matrix_type& stats, matrix_type& zstats) const override;
291
292 protected:
293 // New classes to store information relevant to Freedman-Lane implementation
299
300 };
302
303
317 public:
324 TestFixedHeteroscedastic (const matrix_type& measurements,
325 const matrix_type& design,
326 const vector<Hypothesis>& hypotheses,
327 const index_array_type& variance_groups);
328
329 size_t num_variance_groups() const { return num_vgs; }
330
336 void operator() (const matrix_type& shuffling_matrix, matrix_type& stats, matrix_type& zstats) const override;
337
338 protected:
339 // Variance group assignments
341 // Total number of variance groups
342 const size_t num_vgs;
343 // Number of inputs that are part of each variance group
345 // Might as well construct this in the functor rather than here,
346 // given 1 value for each VG is computed
348 // Also store the reciprocal of these, so as to avoid repeated division
350 // Multiplication weights for calculation of gamma;
351 // varies depending on the rank of the contrast matrix of each hypothesis
353
354 };
356
357
358
375 public:
377 const matrix_type& measurements,
378 const matrix_type& design,
379 const vector<Hypothesis>& hypotheses,
380 const bool nans_in_data,
381 const bool nans_in_columns);
382
391 void operator() (const matrix_type& shuffling_matrix, matrix_type& stat, matrix_type& zstat) const override;
392
393 size_t num_factors() const override { return M.cols() + importers.size(); }
394
395 protected:
398
399 void get_mask (const size_t ie, BitSet&, const matrix_type& extra_columns) const;
400 void apply_mask (const BitSet& mask,
401 matrix_type::ConstColXpr data,
402 const matrix_type& shuffling_matrix,
403 const matrix_type& extra_column_data,
404 matrix_type& Mfull_masked,
405 matrix_type& shuffling_matrix_masked,
406 vector_type& y_masked) const;
407
408 };
409
410
411
429 public:
431 const matrix_type& measurements,
432 const matrix_type& design,
433 const vector<Hypothesis>& hypotheses,
434 const index_array_type& variance_groups,
435 const bool nans_in_data,
436 const bool nans_in_columns);
437
446 void operator() (const matrix_type& shuffling_matrix, matrix_type& stat, matrix_type& zstat) const override;
447
448 size_t num_factors() const override { return M.cols() + importers.size(); }
449 size_t num_variance_groups() const { return num_vgs; }
450
451 protected:
452 // Only a limited amount can be pre-calculated from the variance group information;
453 // other data may vary as rows of the design matrix & data are excluded
455 const size_t num_vgs;
457
458 // Need to apply the row selection mask to the variance groups in addition to other data
459 void apply_mask_VG (const BitSet& mask,
460 index_array_type& VG_masked,
461 index_array_type& VG_counts) const;
462
463 };
464
465
466
467
468
469 }
470 }
471 }
472}
473
474
475#endif
a class to hold a named list of Option's
a class for storing bitwise information
Definition: bitset.h:43
void get_mask(const size_t ie, BitSet &, const matrix_type &extra_columns) const
const matrix_type & y
Definition: glm.h:253
vector< default_type > one_over_dof
Definition: glm.h:298
void all_stats(const matrix_type &measurements, const matrix_type &design, const vector< Hypothesis > &hypotheses, const index_array_type &variance_groups, matrix_type &betas, matrix_type &abs_effect_size, matrix_type &std_effect_size, matrix_type &stdev)
const matrix_type M
Definition: glm.h:253
const vector< Hypothesis > & c
Definition: glm.h:254
matrix_type solve_betas(const matrix_type &measurements, const matrix_type &design)
std::shared_ptr< Math::Zstatistic > stat2z
Definition: glm.h:255
void apply_mask_VG(const BitSet &mask, index_array_type &VG_masked, index_array_type &VG_counts) const
vector_type abs_effect_size(const matrix_type &measurements, const matrix_type &design, const Hypothesis &hypothesis)
const vector< CohortDataImport > & importers
Definition: glm.h:396
matrix_type stdev(const matrix_type &measurements, const matrix_type &design)
void apply_mask(const BitSet &mask, matrix_type::ConstColXpr data, const matrix_type &shuffling_matrix, const matrix_type &extra_column_data, matrix_type &Mfull_masked, matrix_type &shuffling_matrix_masked, vector_type &y_masked) const
vector< Hypothesis::Partition > partitions
Definition: glm.h:294
vector_type std_effect_size(const matrix_type &measurements, const matrix_type &design, const Hypothesis &hypothesis)
Eigen::Matrix< typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic > pinv(const MatrixType &M)
return Moore-Penrose pseudo-inverse of M
Definition: least_squares.h:39
size_t rank(const MatrixType &M)
Definition: least_squares.h:48
const char *const column_ones_description
void check_design(const matrix_type &, const bool)
index_array_type load_variance_groups(const size_t num_inputs)
App::OptionGroup glm_options(const std::string &element_name)
vector< Hypothesis > load_hypotheses(const std::string &file_path)
Eigen::Array< size_t, Eigen::Dynamic, 1 > index_array_type
Definition: typedefs.h:36
Eigen::Array< value_type, Eigen::Dynamic, 1 > vector_type
Definition: typedefs.h:35
Eigen::Matrix< value_type, Eigen::Dynamic, Eigen::Dynamic > matrix_type
Definition: typedefs.h:34
Definition: base.h:24
std::string str(const T &value, int precision=0)
Definition: mrtrix.h:247
size_t index
#define MEMALIGN(...)
Definition: types.h:185