ʻOhana
Population structure, admixture history, and selection using learning methods.
cpax/jade.optimizer.hpp
1 /* -------------------------------------------------------------------------
2  Ohana
3  Copyright (c) 2015-2020 Jade Cheng (\___/)
4  Jade Cheng <info@jade-cheng.com> (='.'=)
5  ------------------------------------------------------------------------- */
6 
7 #ifndef JADE_OPTIMIZER_HPP__
8 #define JADE_OPTIMIZER_HPP__
9 
10 #include "jade.improver.hpp"
11 #include "jade.settings.hpp"
12 #include "jade.stopwatch.hpp"
13 
14 namespace jade
15 {
16  ///
17  /// A template for a class that optimizes the Q and F matrices.
18  ///
19  template <typename TValue>
21  {
22  public:
23  /// The value type.
24  typedef TValue value_type;
25 
26  /// The matrix type.
28 
29  /// The options type.
31 
32  /// The settings type.
34 
35  /// The improver type.
37 
38  ///
39  /// Executes the optimization process.
40  ///
41  static void execute(
42  const settings_type & settings, ///< The settings.
43  matrix_type & q0, ///< The initial Q matrix.
44  matrix_type & f0) ///< The initial F matrix.
45  {
46  //
47  // Release memory for the initial Q and F matrices.
48  //
49  matrix_type q, fa;
50  q0.swap(q);
51  f0.swap(fa);
52 
53  _clamp_f(settings, fa);
54 
55  const auto & opts = settings.get_options();
56  const auto fg = settings.get_fg();
57  const auto fif = settings.get_fif();
58  const auto & g = settings.get_g();
59  const auto frb = opts.is_frb();
60 
61  const stopwatch sw1;
62 
63  matrix_type fb (fa.get_height(), fa.get_width());
64  _compute_fb(fa, fb);
65 
66  matrix_type qfa = q * fa;
67  matrix_type qfb = q * fb;
68 
69  auto lle = g.compute_lle(q, fa, fb, qfa, qfb);
70  _emit_header(settings, sw1, lle);
71 
72  for (size_t iter = 1;; iter++)
73  {
74  if (opts.is_max_iterations_specified())
75  if (iter > opts.get_max_iterations())
76  break;
77 
78  if (opts.is_max_time_specified())
79  if (sw1 > opts.get_max_time())
80  break;
81 
82  const stopwatch sw2;
83 
84  if (!opts.is_fixed_q())
85  {
86  q = improver_type::improve_q(g, q, fa, fb, qfa, qfb, fg);
87  matrix_type::gemm(q, fa, qfa);
88  matrix_type::gemm(q, fb, qfb);
89  }
90 
91  if (!opts.is_fixed_f())
92  {
93  fa = improver_type::improve_f(g, q, fa, fb, qfa, qfb, fif, frb);
94  _clamp_f(settings, fa);
95  _compute_fb(fa, fb);
96  matrix_type::gemm(q, fa, qfa);
97  matrix_type::gemm(q, fb, qfb);
98  }
99 
100  const auto lle_prime = g.compute_lle(q, fa, fb, qfa, qfb);
101  const auto dlle = lle_prime - lle;
102 
103  _emit_line(settings, sw2, iter, lle_prime, dlle);
104 
105  lle = lle_prime;
106 
107  if (opts.is_epsilon_specified())
108  if (dlle >= value_type(0) && dlle <= opts.get_epsilon())
109  break;
110  }
111 
112  _emit_results(settings, q, fa);
113  }
114 
115  private:
116  // --------------------------------------------------------------------
117  static void _clamp_f(const settings_type & settings, matrix_type & f)
118  {
119  const auto epsilon = settings.get_options().get_f_epsilon();
120  const auto min = value_type(0.0) + epsilon;
121  const auto max = value_type(1.0) - epsilon;
122  f.clamp(min, max);
123  }
124 
125  // --------------------------------------------------------------------
126  static void _compute_fb(const matrix_type & fa, matrix_type & fb)
127  {
128  const auto fa_end = fa.get_data() + fa.get_length();
129  auto fa_ptr = fa.get_data();
130  auto fb_ptr = fb.get_data();
131 
132  while (fa_ptr != fa_end)
133  *fb_ptr++ = value_type(1) - *fa_ptr++;
134  }
135 
136  // --------------------------------------------------------------------
137  static void _emit_header(
138  const settings_type & in,
139  const stopwatch & sw,
140  const value_type lle)
141  {
142  const auto & opts = in.get_options();
143 
144  if (opts.is_quiet())
145  return;
146 
147  std::ostringstream line;
148  line << 0 << std::fixed << std::setprecision(6)
149  << '\t' << sw;
151  line << '\t' << lle;
152 
153  std::cout
154  << "seed: " << opts.get_seed() << std::endl
155  << std::endl
156  << "iter\tduration\tlog_likelihood\tdelta-lle" << std::endl
157  << line.str() << std::endl;
158  }
159 
160  // --------------------------------------------------------------------
161  static void _emit_line(
162  const settings_type & in,
163  const stopwatch & sw,
164  const size_t iter,
165  const value_type lle,
166  const value_type dlle)
167  {
168  if (in.get_options().is_quiet())
169  return;
170 
171  std::ostringstream line;
172 
173  line << iter
174  << std::fixed << std::setprecision(6)
175  << '\t' << sw;
177  line << '\t' << lle << '\t' << dlle;
178 
179  std::cout << line.str() << std::endl;
180  }
181 
182  // --------------------------------------------------------------------
183  static void _emit_matrix(
184  const matrix_type & matrix,
185  const std::string & path,
186  const settings_type & settings,
187  const char * const name)
188  {
189  if (path.empty())
190  {
192  std::cout << "[" << name << " Matrix]\n" << matrix;
193  return;
194  }
195 
196  if (!settings.get_options().is_quiet())
197  std::cout
198  << "Writing " << name << " matrix to "
199  << path << "\n";
200 
201  std::ofstream out (path);
202  if (!out.good())
203  throw error() << "failed to create matrix '" << path << "'";
204 
206  out << matrix;
207  }
208 
209  // --------------------------------------------------------------------
210  static void _emit_results(
211  const settings_type & in,
212  const matrix_type & q,
213  const matrix_type & f)
214  {
215  static const std::string no_path;
216 
217  const auto & opts = in.get_options();
218 
219  if (!opts.is_quiet())
220  std::cout << std::endl;
221 
222  if (!opts.is_fixed_q())
223  {
224  const auto qout = opts.is_qout_specified()
225  ? opts.get_qout() : no_path;
226  _emit_matrix(q, qout, in, "Q");
227  }
228 
229  if (!opts.is_fixed_f())
230  {
231  if (!opts.is_fixed_q() && !opts.is_qout_specified())
232  std::cout << std::endl;
233 
234  const auto fout = opts.is_fout_specified()
235  ? opts.get_fout() : no_path;
236  _emit_matrix(f, fout, in, "F");
237  }
238  }
239  };
240 }
241 
242 #endif // JADE_OPTIMIZER_HPP__
jade::basic_options< value_type >
jade::basic_optimizer::improver_type
basic_improver< value_type > improver_type
The improver type.
Definition: cpax/jade.optimizer.hpp:36
jade::basic_settings::get_options
const options_type & get_options() const
Definition: cpax/jade.settings.hpp:174
jade::basic_matrix::get_width
size_t get_width() const
Definition: jade.matrix.hpp:757
jade::basic_improver::improve_f
static matrix_type improve_f(const genotype_matrix_type &g, const matrix_type &q, const matrix_type &fa, const matrix_type &fb, const matrix_type &qfa, const matrix_type &qfb, const matrix_type *fif, const bool frb)
Definition: cpax/jade.improver.hpp:44
jade::basic_settings::get_fif
const matrix_type * get_fif() const
Definition: cpax/jade.settings.hpp:149
jade::basic_stopwatch< std::chrono::high_resolution_clock >
jade::basic_matrix< value_type >::set_high_precision
static void set_high_precision(std::ostream &out)
Sets the specified stream to scientific notation with a high precision.
Definition: jade.matrix.hpp:1154
jade::basic_matrix::swap
void swap(basic_matrix &other)
Swaps this matrix and another matrix.
Definition: jade.matrix.hpp:1209
jade::basic_settings::get_g
const genotype_matrix_type & get_g() const
Definition: cpax/jade.settings.hpp:166
jade::basic_optimizer::matrix_type
basic_matrix< value_type > matrix_type
The matrix type.
Definition: cpax/jade.optimizer.hpp:27
jade::basic_improver::improve_q
static matrix_type improve_q(const genotype_matrix_type &g, const matrix_type &q, const matrix_type &fa, const matrix_type &fb, const matrix_type &qfa, const matrix_type &qfb, const forced_grouping_type *fg)
Definition: cpax/jade.improver.hpp:143
jade::basic_matrix::get_height
size_t get_height() const
Definition: jade.matrix.hpp:603
jade::basic_settings
A template for a class encapsulating the settings provided to the optimizer.
Definition: cpax/jade.settings.hpp:22
jade::basic_optimizer::value_type
TValue value_type
The value type.
Definition: cpax/jade.optimizer.hpp:24
jade::basic_settings::get_fg
const forced_grouping_type * get_fg() const
Definition: cpax/jade.settings.hpp:158
jade::basic_optimizer::options_type
basic_options< value_type > options_type
The options type.
Definition: cpax/jade.optimizer.hpp:30
jade::basic_optimizer
A template for a class that optimizes the Q and F matrices.
Definition: cpax/jade.optimizer.hpp:21
jade::basic_optimizer::settings_type
basic_settings< value_type > settings_type
The settings type.
Definition: cpax/jade.optimizer.hpp:33
jade::basic_matrix< value_type >
jade::basic_improver
A template for a class that improves the Q and F matrices.
Definition: cpax/jade.improver.hpp:21
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
jade::basic_optimizer::execute
static void execute(const settings_type &settings, matrix_type &q0, matrix_type &f0)
Executes the optimization process.
Definition: cpax/jade.optimizer.hpp:41