HyParEstimator.h 10.9 KB
Newer Older
wangkx1's avatar
init  
wangkx1 committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/*! \file HyParEstimator.h
    \brief Contains declaration of class for estimating hyper parameters for a given GP model and data.

    \author Jesper Andersson
    \version 1.0b, Nov., 2013.
*/
// Contains declaration of class for estimating
// hyper parameters for a given GP model and data.
//
// HyParEstimator.h
//
// Jesper Andersson, FMRIB Image Analysis Group
//
// Copyright (C) 2013 University of Oxford
//

#ifndef HyParEstimator_h
#define HyParEstimator_h

#include <cstdlib>
#include <string>
#include <exception>
#include <vector>
#include <cmath>
#include <memory>
#include <thread>
#include "armawrap/newmat.h"
#include "miscmaths/miscmaths.h"
#include "miscmaths/nonlin.h"
#include "EddyHelperClasses.h"
#include "KMatrix.h"

namespace EDDY {

class FourthDimension {
public:
  explicit FourthDimension(unsigned int d4) : _d4(d4) {}
  unsigned int _d4; 
};

class DataSelector
{
public:
  DataSelector(const std::vector<std::shared_ptr<NEWIMAGE::volume<float> > >& idata,
	       const NEWIMAGE::volume<float>&                                 mask,
	       unsigned int                                                   nvox,
	       int                                                            rndinit=0) EddyTry { common_constructor(idata,mask,nvox,0.0,0,rndinit); } EddyCatch
  DataSelector(const std::vector<std::shared_ptr<NEWIMAGE::volume<float> > >& idata,
	       const NEWIMAGE::volume<float>&                                 mask,
	       unsigned int                                                   nvox,
	       float                                                          fwhm,
	       int                                                            rndinit=0) EddyTry { common_constructor(idata,mask,nvox,fwhm,0,rndinit); } EddyCatch
  DataSelector(const std::vector<std::shared_ptr<NEWIMAGE::volume<float> > >& idata,
	       const NEWIMAGE::volume<float>&                                 mask,
	       unsigned int                                                   nvox,
	       const FourthDimension&                                         d4,
	       int                                                            rndinit=0) EddyTry { common_constructor(idata,mask,nvox,0.0,d4._d4,rndinit); } EddyCatch
  DataSelector(const std::vector<std::shared_ptr<NEWIMAGE::volume<float> > >& idata,
	       const NEWIMAGE::volume<float>&                                 mask,
	       unsigned int                                                   nvox,
	       const FourthDimension&                                         d4,
	       float                                                          fwhm,
	       int                                                            rndinit=0) EddyTry { common_constructor(idata,mask,nvox,fwhm,d4._d4,rndinit); } EddyCatch
  ~DataSelector() {}
  const std::vector<NEWMAT::ColumnVector>& GetData() const EddyTry { return(_data); } EddyCatch
  DataSelector& ConcatToMe(const DataSelector& ds);
  NEWMAT::Matrix AsNEWMAT() const;
  NEWMAT::Matrix CoordsAsNEWMAT() const;
  void Write(const std::string& fname) const EddyTry { MISCMATHS::write_ascii_matrix(AsNEWMAT(),fname); } EddyCatch
  void WriteCoords(const std::string& fname) const EddyTry { MISCMATHS::write_ascii_matrix(CoordsAsNEWMAT(),fname); } EddyCatch
private:
  void common_constructor(const std::vector<std::shared_ptr<NEWIMAGE::volume<float> > >& idata,
			  const NEWIMAGE::volume<float>&                                 mask,
			  unsigned int                                                   nvox,
			  float                                                          fwhm,
			  unsigned int                                                   d4,
			  int                                                            rndinit);
  float get_smooth(const NEWIMAGE::volume<float>&           ima,
		   const NEWIMAGE::volume<float>&           mask,
		   const std::vector<unsigned int>&         coords,
		   const std::vector<NEWMAT::ColumnVector>& kernels);
  std::vector<NEWMAT::ColumnVector>        _data;   //
  std::vector<std::vector<unsigned int> >  _coords; //
};

class HyParCF : public MISCMATHS::NonlinCF
{
public:
  HyParCF(unsigned int nthreads) EddyTry { _nthreads=nthreads; } EddyCatch
  HyParCF() EddyTry : HyParCF(1) {} EddyCatch
  virtual ~HyParCF() {}
  virtual std::shared_ptr<HyParCF> Clone() const = 0;
  virtual void SetData(const std::vector<NEWMAT::ColumnVector>& data) EddyTry { _data = data; } EddyCatch
  virtual void SetKMatrix(std::shared_ptr<const KMatrix> K) EddyTry { _K = K->Clone(); } EddyCatch
  virtual double cf(const NEWMAT::ColumnVector& p) const = 0;
protected:
  std::vector<NEWMAT::ColumnVector>          _data;     // Data
  std::shared_ptr<KMatrix>                   _K;        // K-matrix
  unsigned int                               _nthreads; // No of threads for cf
  double sqr(double a) const { return(a*a); }
  float sqr(float a) const { return(a*a); }
  bool is_odd(int val) const { return(bool(val%2)); }
};

class MMLHyParCF : public HyParCF
{
public:
  MMLHyParCF(unsigned int nthreads) EddyTry : HyParCF(nthreads) {} EddyCatch
  MMLHyParCF() EddyTry : MMLHyParCF(1) {} EddyCatch
  virtual ~MMLHyParCF() {}
  std::shared_ptr<HyParCF> Clone() const EddyTry { return(std::shared_ptr<MMLHyParCF>(new MMLHyParCF(*this))); } EddyCatch
  double cf(const NEWMAT::ColumnVector& p) const;
private:
  /// Helper function for when running cf() multi-threaded
  void cf_helper(// Input
		 unsigned int first,
		 unsigned int last,
		 const std::vector<NEWMAT::ColumnVector>&  data,
		 const std::shared_ptr<const KMatrix>      K,
		 // Output
		 double&                                   neg_log_marg_ll) const;
};

class CVHyParCF : public HyParCF
{
public:
  CVHyParCF(unsigned int nthreads) EddyTry : HyParCF(nthreads) {} EddyCatch
  CVHyParCF() EddyTry : CVHyParCF(1) {} EddyCatch
  virtual ~CVHyParCF() {}
  std::shared_ptr<HyParCF> Clone() const EddyTry { return(std::shared_ptr<CVHyParCF>(new CVHyParCF(*this))); } EddyCatch
  double cf(const NEWMAT::ColumnVector& p) const;
private:
/// Helper function for when running cf() multi-threaded
  void cf_helper(// Input
    	         unsigned int                             first,
		 unsigned int                             last,
	 	 unsigned int                             tid,       // Thread number (N.B. not thread.id())
		 unsigned int                             numt,      // Number of threads
		 std::vector<std::thread>&                threads,
		 const std::vector<NEWMAT::ColumnVector>& data,
		 const std::shared_ptr<const KMatrix>     K,
		 // Output
		 std::vector<NEWMAT::ColumnVector >& ssd_vec_vec) const;
};

class GPPHyParCF : public HyParCF
{
public:
  GPPHyParCF(unsigned int nthreads) EddyTry : HyParCF(nthreads) {} EddyCatch
  GPPHyParCF() EddyTry : GPPHyParCF(1) {} EddyCatch
  virtual ~GPPHyParCF() {}
  std::shared_ptr<HyParCF> Clone() const EddyTry { return(std::shared_ptr<GPPHyParCF>(new GPPHyParCF(*this))); } EddyCatch
  double cf(const NEWMAT::ColumnVector& p) const;
};

class HyParEstimator
{
public:
  HyParEstimator() {}
  HyParEstimator(const NEWMAT::ColumnVector& hpar) EddyTry : _hpar(hpar) {} EddyCatch
  virtual ~HyParEstimator() {}
  virtual std::shared_ptr<HyParEstimator> Clone() const = 0;
  std::vector<double> GetHyperParameters() const EddyTry { return(newmat_2_stl(_hpar)); } EddyCatch
  virtual unsigned int GetNVox() const { return(0); }
  virtual int RndInit() const { return(0); }
  virtual void SetData(const std::vector<NEWMAT::ColumnVector>&    data) {}
  virtual void Estimate(std::shared_ptr<const KMatrix>  K, bool verbose) = 0;
protected:
  const NEWMAT::ColumnVector& get_hpar() const EddyTry { return(_hpar); } EddyCatch
  void set_hpar(const NEWMAT::ColumnVector& hpar) EddyTry { _hpar = hpar; } EddyCatch
  std::vector<double> newmat_2_stl(const NEWMAT::ColumnVector& nm) const EddyTry {
    std::vector<double> stl(nm.Nrows());
    for (unsigned int i=0; i<stl.size(); i++) stl[i] = nm(i+1);
    return(stl);
  } EddyCatch
  NEWMAT::ColumnVector stl_2_newmat(const std::vector<double>& stl) const EddyTry {
    NEWMAT::ColumnVector nm(stl.size());
    for (unsigned int i=0; i<stl.size(); i++) nm(i+1) = stl[i];
    return(nm);
  } EddyCatch
private:
  NEWMAT::ColumnVector         _hpar;  // Hyper parameters
};


class FixedValueHyParEstimator : public HyParEstimator
{
public:
  FixedValueHyParEstimator(const NEWMAT::ColumnVector& hpar) EddyTry : HyParEstimator(hpar) {} EddyCatch
  virtual ~FixedValueHyParEstimator() {}
  std::shared_ptr<HyParEstimator> Clone() const EddyTry { return(std::shared_ptr<FixedValueHyParEstimator>(new FixedValueHyParEstimator(*this))); } EddyCatch
  virtual void Estimate(std::shared_ptr<const KMatrix>  K, bool verbose) EddyTry {
    if (verbose) std::cout << "Hyperparameters set to user specified values: " << get_hpar() << std::endl;
  } EddyCatch
};

class CheapAndCheerfulHyParEstimator : public HyParEstimator
{
public:
  CheapAndCheerfulHyParEstimator(unsigned int                      nvox=1000,
				 int                               ir=0) EddyTry : _nvox(nvox), _ir(ir) {} EddyCatch
  virtual ~CheapAndCheerfulHyParEstimator() {}
  std::shared_ptr<HyParEstimator> Clone() const EddyTry { return(std::shared_ptr<CheapAndCheerfulHyParEstimator>(new CheapAndCheerfulHyParEstimator(*this))); } EddyCatch
  virtual unsigned int GetNVox() const { return(_nvox); }
  virtual int RndInit() const { return(_ir); }
  virtual void SetData(const std::vector<NEWMAT::ColumnVector>&    data) EddyTry { _data = data; } EddyCatch
  virtual void Estimate(std::shared_ptr<const KMatrix>  K, bool verbose);
private:
  unsigned int                       _nvox;
  int                                _ir;    // Initialise rand?
  std::vector<NEWMAT::ColumnVector>  _data;
};

class FullMontyHyParEstimator : public HyParEstimator
{
public:
  FullMontyHyParEstimator(std::shared_ptr<const HyParCF>   hpcf,
			  double                           evff=1.0,
			  unsigned int                     nvox=1000,
			  int                              ir=0,
			  bool                             verbose=false) EddyTry : _cf(hpcf->Clone()), _evff(evff), _nvox(nvox), _ir(ir), _v(verbose) {} EddyCatch
  virtual ~FullMontyHyParEstimator() {}
  std::shared_ptr<HyParEstimator> Clone() const EddyTry { return(std::shared_ptr<FullMontyHyParEstimator>(new FullMontyHyParEstimator(*this))); } EddyCatch
  virtual unsigned int GetNVox() const { return(_nvox); }
  virtual int RndInit() const { return(_ir); }
  virtual void SetData(const std::vector<NEWMAT::ColumnVector>&    data) EddyTry { _data = data; } EddyCatch
  virtual void Estimate(std::shared_ptr<const KMatrix>  K, bool verbose);
private:
  static const unsigned int          MITER=500;

  std::shared_ptr<HyParCF>           _cf;    // Cost-function object for use with nonlin
  double                             _evff;  // Error variance fudge factor
  unsigned int                       _nvox;
  int                                _ir;
  bool                               _v;     // Verbose flag
  std::vector<NEWMAT::ColumnVector>  _data;
};

} // End namespace EDDY

#endif // end #ifndef HyParEstimator_h