fastglmm
Massively scalable generalized linear mixed models
Loading...
Searching...
No Matches
satterthwaite.h
Go to the documentation of this file.
1/***************************************************************
2 * @file satterthwaite.h
3 * @author Gabriel Hoffman
4 * @email gabriel.hoffman@mssm.edu
5 * @brief Precompute values for Satterthwaite approx to ddf
6 * Copyright (C) 2024 Gabriel Hoffman
7 **************************************************************/
8
9#ifndef _SATTERTHWAITE_H_
10#define _SATTERTHWAITE_H_
11
12// if -D USE_R, use RcppArmadillo library
13#ifdef USE_R
14// [[Rcpp::depends(RcppParallel)]]
15#include <RcppArmadillo.h>
16#else
17#include <armadillo>
18#endif
19
20using namespace arma;
21
22namespace fastglmmLib {
23
24// denominator degrees of freedom using Satterthwaite method
25// For math, see https://chatgpt.com/share/698f66b1-88b0-800b-9001-e28f444f6015
26template <typename T>
28 public:
29 // constructor
31 const int &n,
32 const double &sigSq_g,
33 const double &sigSq_e,
34 const vec &s,
35 const T &Xu,
36 const mat &Gamma_XX,
37 const vec &inv_s_delta,
38 const mat &inv_s_delta_Xu);
39
42 vec get_ddf(
43 const mat &V,
44 const mat &L) const;
45
48 const mat get_hessian() const {return H;}
49 const mat get_A() const {return A;}
50 const mat get_B() const {return B;}
51
52 private:
53 /* Hessian of sigma^2_g, sigma^2_e
54 */
55 void set_hessian(
56 const vec &s);
57
58 /* Precompute value for gradient
59 */
60 void prep_gradient(
61 const vec &s,
62 const T &Xu,
63 const vec &inv_s_delta,
64 const mat &inv_s_delta_Xu,
65 const mat &Gamma_XX);
66
69 vec get_gradient(
70 const mat &L) const;
71
72 int n;
73 double sigSq_g, sigSq_e, delta;
74 mat A, B, H;
75};
76
77
78// constructor
79template <typename T>
81 const int &n,
82 const double &sigSq_g,
83 const double &sigSq_e,
84 const vec &s,
85 const T &Xu,
86 const mat &Gamma_XX,
87 const vec &inv_s_delta,
88 const mat &inv_s_delta_Xu):
89 n(n),
90 sigSq_g(sigSq_g),
91 sigSq_e(sigSq_e),
92 delta(sigSq_e/sigSq_g) {
93
94 set_hessian(s);
95 prep_gradient(s, Xu, inv_s_delta, inv_s_delta_Xu, Gamma_XX);
96}
97
98
99// denominator degrees of freedom using Satterthwaite method
100template <typename T>
101vec Satterthwaite<T>::get_ddf( const mat &V, const mat &L) const{
102
103 mat H_inv = inv(H);
104 mat g = get_gradient(L);
105
106 vec df(L.n_rows);
107 double var_Lbeta, v_numerator, v_denom;
108
109 // for each contrast (i.e. row)
110 for(int i=0; i<L.n_rows; i++){
111 // var_Lbeta <- crossprod(L[i,], vcov(fit)) %*% L[i,]
112 var_Lbeta = as_scalar(L.row(i).t() * V * L.row(i));
113 v_numerator = 2 * pow(var_Lbeta, 2);
114
115 // v_denom <- crossprod(g[[i]], A) %*% g[[i]]
116 v_denom = as_scalar(g.row(i).t() * H_inv * g.row(i));
117
118 df(i) = v_numerator / v_denom;
119 }
120
121 return df;
122}
123
124template <typename T>
125vec Satterthwaite<T>::get_gradient(const mat &L) const {
126
127 vec g(L.n_rows, 2, fill::zeros);
128 mat invAL;
129 double c;
130
131 // for each contrast (i.e. row)
132 for(int i=0; i<L.n_rows; i++){
133 // invAL <- solve(A, L[i,])
134 invAL = solve(A, L.row(i));
135
136 // C <- invAL %*% B %*% invAL
137 c = as_scalar(invAL * B * invAL);
138
139 // crossprod(L[i,], invAL) - fit$delta*C
140 g(i,0) = as_scalar(L.row(i).t() * invAL - delta*c);
141 g(i,1) = c;
142 }
143
144 return g;
145}
146
147template <typename T>
148void Satterthwaite<T>::set_hessian(const vec &s){
149
150 // n <- length(fit$y)
151 // r <- length(s)
152 double r = s.n_elem;
153
154 // A <- sum(1/(s + delta)) + (n-r)/delta
155 double a = accu(1/(s + delta)) + (n-r)/delta;
156
157 // B <- sum(1/(s + delta)^2) + (n-r)/delta^2
158 double b = accu(1/pow(s + delta,2)) + (n-r)/pow(delta, 2);
159
160 H = mat(2,2, fill::zeros);
161
162 // H[1,1] <- (n - 2*delta*a + delta^2*b) / (2*sigSq_g^2)
163 H(0,0) = (n - 2*delta*a + pow(delta,2)*b) / (2*pow(sigSq_g,2));
164
165 // H[1,2] <- H[2,1] <- (a - delta*b) / (2*sigSq_g^2)
166 H(0,1) = (a - delta*b) / (2*pow(sigSq_g,2));
167 H(1,0) = H(0,1);
168
169 // H[2,2] <- b / (2*sigSq_g^2)
170 H(1,1) = b / (2*pow(sigSq_g,2));
171}
172
173
174
175// gradient of variance for Satterthwaite method
176
177template <typename T>
178void Satterthwaite<T>::prep_gradient(
179 const vec &s,
180 const T &Xu,
181 const vec &inv_s_delta,
182 const mat &inv_s_delta_Xu,
183 const mat &Gamma_XX) {
184
185 // Xu <- crossprod(fit$U, fit$design)
186 // Gamma_XX <- crossprod(X) - crossprod(Xu)
187 // inv_s_delta <- 1 / (fit$s + fit$delta)
188 // inv_s_delta_Xu <- inv_s_delta * Xu
189
190 // A <- crossprod(Xu, inv_s_delta_Xu) + Gamma_XX / fit$delta
191 // inv_s_delta_Xu = scaleEachCol(Xu, inv_s_delta);
192 A = Xu.t() * inv_s_delta_Xu + Gamma_XX / delta;
193
194 // inv_s_delta_Xu <- inv_s_delta^2 * Xu
195 // B <- crossprod(Xu, inv_s_delta_Xu) + Gamma_XX / fit$delta^2
196 B = Xu.t() * scaleEachCol(Xu, pow(inv_s_delta,2)) + Gamma_XX / pow(delta, 2);
197}
198
199
200
201
202
203} // end namespace
204
205
206#endif
Satterthwaite(const int &n, const double &sigSq_g, const double &sigSq_e, const vec &s, const T &Xu, const mat &Gamma_XX, const vec &inv_s_delta, const mat &inv_s_delta_Xu)
Definition satterthwaite.h:80
const mat get_hessian() const
Definition satterthwaite.h:48
const mat get_A() const
Definition satterthwaite.h:49
const mat get_B() const
Definition satterthwaite.h:50
vec get_ddf(const mat &V, const mat &L) const
Definition satterthwaite.h:101
mat scaleEachCol(const mat &X, const vec &w)
Definition misc.h:16
Definition CleanData.h:17