ʻOhana
Population structure, admixture history, and selection using learning methods.
jade.likelihood.hpp
1 /* -------------------------------------------------------------------------
2  Ohana
3  Copyright (c) 2015-2020 Jade Cheng (\___/)
4  Jade Cheng <info@jade-cheng.com> (='.'=)
5  ------------------------------------------------------------------------- */
6 
7 #ifndef JADE_LIKELIHOOD_HPP__
8 #define JADE_LIKELIHOOD_HPP__
9 
10 #include "jade.matrix.hpp"
11 
12 namespace jade
13 {
14  ///
15  /// A template for a class that efficiently computes a log-likelihood based
16  /// on 1) the log of the determinant for a covariance matrix and 2) the
17  /// inverse of the covariance matrix. The class caches values based on a
18  /// [K-1 x J] rooted F matrix for major allele frequencies and a [J x 1] mu
19  /// vector.
20  ///
21  template <typename TValue>
23  {
24  public:
25  /// The value type.
26  typedef TValue value_type;
27 
28  /// The matrix type.
30 
31  ///
32  /// Initializes the class based on a rooted F matrix for major allele
33  /// frequencies and a mu vector; the constructor caches values based on
34  /// the supplied arguments.
35  ///
37  const matrix_type & rf, ///< The rooted F matrix.
38  const matrix_type & mu) ///< The mu vector.
39  : _rf (rf)
40  , _mux (_init_mux(mu))
41  , _rkltmux (_init_rkltmux(rf.get_height(), _mux))
42  , _mul (rf.get_height(), rf.get_width())
43  {
44  assert(mu.get_height() == rf.get_width());
45  }
46 
47  ///
48  /// \return The log-likelihood using values cached during the
49  /// initializaiton of this instance and the supplied arguments.
50  ///
52  const matrix_type & c_inv, ///< The inverted C matrix.
53  const value_type log_c_det) ///< The log of det(C).
54  {
55  const auto RK = _rf.get_height();
56  const auto J = _rf.get_width();
57 
58  assert(c_inv.is_size(RK, RK));
59 
60  //
61  // Use LAPACK to multiply c_inv and _rf; store the result in the
62  // pre-allocated _mul matrix, which is of size [RK x J].
63  //
64  matrix_type::gemm(c_inv, _rf, _mul);
65 
66  auto sum = value_type(0);
67 
68  //
69  // Loop over the J columns of _mul.
70  //
71  auto rkltmux_ptr = _rkltmux.get_data();
72  auto mux_ptr = _mux.get_data();
73  const auto mux_end = _mux.get_data() + J;
74  auto rf_ptr = _rf.get_data();
75  auto mul_ptr = _mul.get_data();
76  while (mux_ptr != mux_end)
77  {
78  //
79  // Do not process columns with non-positive mux[j].
80  //
81  const auto rkltmux = *rkltmux_ptr++;
82  const auto mux = *mux_ptr++;
83  if (mux <= value_type(0))
84  continue;
85 
86  auto zip = value_type(0);
87 
88  //
89  // Loop over the RK rows of _mul and _rf and sum the products of
90  // rf[rk, j] * mul[rk, j].
91  //
92  const auto rf_anchor = rf_ptr;
93  const auto mul_anchor = mul_ptr;
94  const auto mul_end = mul_ptr + (RK * J);
95  while (mul_ptr != mul_end)
96  {
97  zip += *rf_ptr * *mul_ptr;
98  rf_ptr += J;
99  mul_ptr += J;
100  }
101 
102  //
103  // For this column of J, add
104  // RK*log(2*pi * mux[j]) + (zip / mux[j]).
105  //
106  sum += rkltmux + (zip / mux);
107 
108  //
109  // Advance to the next columns.
110  //
111  rf_ptr = rf_anchor + 1;
112  mul_ptr = mul_anchor + 1;
113  }
114 
115  //
116  // The log-likelihood: -0.5 * (J * log(det(C)) + sum).
117  //
118  return value_type(-0.5) * ((value_type(J) * log_c_det) + sum);
119  }
120 
121  private:
122  // --------------------------------------------------------------------
123  static matrix_type _init_mux(const matrix_type & mu)
124  {
125  assert(mu.is_column_vector());
126 
127  //
128  // Declare a vector of the same size.
129  //
130  const auto J = mu.get_height();
131  matrix_type mux (J, 1);
132 
133  //
134  // Loop over all values in the mu vector.
135  //
136  const auto mu_end = mu.get_data() + J;
137  auto mu_ptr = mu.get_data();
138  auto mux_ptr = mux.get_data();
139  while (mu_ptr != mu_end)
140  {
141  //
142  // Cache the value for mu[j] * (1.0 - mu[j]).
143  //
144  const auto mu_j = *mu_ptr++;
145  *mux_ptr++ = mu_j * (value_type(1) - mu_j);
146  }
147 
148  return mux;
149  }
150 
151  // --------------------------------------------------------------------
152  static matrix_type _init_rkltmux(
153  const size_t RK,
154  const matrix_type & mux)
155  {
156  static const auto tau = value_type(2.0 * std::acos(-1.0));
157 
158  assert(mux.is_column_vector());
159 
160  //
161  // Declare a vector of the same size.
162  //
163  const auto J = mux.get_height();
164  matrix_type rkltmux (J, 1);
165 
166  //
167  // Loop over all values in the mux vector.
168  //
169  const auto mux_end = mux.get_data() + J;
170  auto mux_ptr = mux.get_data();
171  auto rkltmux_ptr = rkltmux.get_data();
172 
173  //
174  // Cache the values for RK * log(2*pi * mux[j]).
175  //
176  while (mux_ptr != mux_end)
177  *rkltmux_ptr++ = value_type(RK) * std::log(tau * *mux_ptr++);
178 
179  return rkltmux;
180  }
181 
182  const matrix_type & _rf; // rooted F matrix
183  const matrix_type _mux; // cache of mu[j] * (1-mu[j])
184  const matrix_type _rkltmux; // cached of (K-1) * log(2*pi * mu[j]).
185  matrix_type _mul; // placeholder for matrix multiplication.
186  };
187 }
188 
189 #endif // JADE_LIKELIHOOD_HPP__
jade::basic_matrix::get_data
const value_type * get_data() const
Definition: jade.matrix.hpp:542
jade::basic_matrix::get_width
size_t get_width() const
Definition: jade.matrix.hpp:757
jade::basic_likelihood::operator()
value_type operator()(const matrix_type &c_inv, const value_type log_c_det)
Definition: jade.likelihood.hpp:51
jade::basic_likelihood::matrix_type
basic_matrix< value_type > matrix_type
The matrix type.
Definition: jade.likelihood.hpp:29
jade::basic_likelihood
A template for a class that efficiently computes a log-likelihood based on 1) the log of the determin...
Definition: jade.likelihood.hpp:23
jade::basic_matrix::is_size
bool is_size(const basic_matrix &other) const
Definition: jade.matrix.hpp:896
jade::basic_matrix::get_height
size_t get_height() const
Definition: jade.matrix.hpp:603
jade::basic_likelihood::value_type
TValue value_type
The value type.
Definition: jade.likelihood.hpp:26
jade::basic_matrix< value_type >
jade::basic_likelihood::basic_likelihood
basic_likelihood(const matrix_type &rf, const matrix_type &mu)
Initializes the class based on a rooted F matrix for major allele frequencies and a mu vector; the co...
Definition: jade.likelihood.hpp:36
jade::basic_matrix< value_type >::gemm
static void gemm(const basic_matrix &lhs, const basic_matrix &rhs, basic_matrix &dst, const value_type alpha=value_type(1), const value_type beta=value_type(0))
Multiplies a left matrix by a right matrix and stores the result into a destination matrix....
Definition: jade.matrix.hpp:459