Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
mitkGeneralizedLinearModel.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
18 
19 #include <mitkDistModels.h>
20 #include <mitkLinkModels.h>
21 
22 #include <v3p_netlib.h>
23 #include <vnl/algo/vnl_qr.h>
24 #include <mitkLogMacros.h>
25 #include <algorithm>
26 #include <limits>
27 
28 static void _UpdateXMatrix(const vnl_matrix<double> &xData, bool addConstant, v3p_netlib_doublereal *x);
29 static void _UpdatePermXMatrix(const vnl_matrix<double> &xData, bool addConstant, const vnl_vector<unsigned int> &permutation, vnl_matrix<double> &x);
30 static void _InitMuEta(mitk::DistSimpleBinominal *dist, mitk::LogItLinking *link, const vnl_vector<double> &yData, vnl_vector<double> &mu, vnl_vector<double> &eta);
31 static void _FinalizeBVector(vnl_vector<double> &b, vnl_vector<unsigned int> &perm, int cols);
32 
33 
34 double mitk::GeneralizedLinearModel::Predict( const vnl_vector<double> &c)
35 {
36  LogItLinking link;
37  double mu = 0;
38  int cols = m_B.size();
39  for (int i = 0; i < cols; ++i)
40  {
41  if (!m_AddConstantColumn)
42  mu += c(i)* m_B(i);
43  else if ( i == 0)
44  mu += 1* m_B(i);
45  else
46  mu += c(i-1)*m_B(i);
47  }
48  return link.InverseLink(mu);
49 }
50 
51 vnl_vector<double> mitk::GeneralizedLinearModel::Predict(const vnl_matrix<double> &x)
52 {
53  LogItLinking link;
54  vnl_vector<double> mu(x.rows());
55  int cols = m_B.size();
56  for (unsigned int r = 0 ; r < mu.size(); ++r)
57  {
58  mu(r) = 0;
59  for (int c = 0; c < cols; ++c)
60  {
61  if (!m_AddConstantColumn)
62  mu(r) += x(r,c)*m_B(c);
63  else if ( c == 0)
64  mu(r) += m_B(c);
65  else
66  mu(r) += x(r,c-1)*m_B(c);
67  }
68  mu(r) = link.InverseLink(mu(r));
69  }
70  return mu;
71 }
72 
73 vnl_vector<double> mitk::GeneralizedLinearModel::B()
74 {
75  return m_B;
76 }
77 
78 vnl_vector<double> mitk::GeneralizedLinearModel::ExpMu(const vnl_matrix<double> &x)
79 {
80  LogItLinking link;
81  vnl_vector<double> mu(x.rows());
82  int cols = m_B.size();
83  for (unsigned int r = 0 ; r < mu.size(); ++r)
84  {
85  mu(r) = 0;
86  for (int c = 0; c < cols; ++c)
87  {
88  if (!m_AddConstantColumn)
89  mu(r) += x(r,c)*m_B(c);
90  else if ( c == 0)
91  mu(r) += m_B(c);
92  else
93  mu(r) += x(r,c-1)*m_B(c);
94  }
95  mu(r) = exp(-mu(r));
96  }
97  return mu;
98 }
99 
100 mitk::GeneralizedLinearModel::GeneralizedLinearModel(const vnl_matrix<double> &xData, const vnl_vector<double> &yData, bool addConstantColumn) :
101  m_AddConstantColumn(addConstantColumn)
102 {
103  EstimatePermutation(xData);
104 
105  DistSimpleBinominal dist;
106  LogItLinking link;
107  vnl_matrix<double> x;
108  int rows = xData.rows();
109  int cols = m_Permutation.size();
110  vnl_vector<double> mu(rows);
111  vnl_vector<double> eta(rows);
112  vnl_vector<double> weightedY(rows);
113  vnl_matrix<double> weightedX(rows, cols);
114  vnl_vector<double> oldB(cols);
115 
116  _UpdatePermXMatrix(xData, m_AddConstantColumn, m_Permutation, x);
117  _InitMuEta(&dist, &link, yData, mu, eta);
118 
119  int iter = 0;
120  int iterLimit = 100;
121  double sqrtEps = sqrt(std::numeric_limits<double>::epsilon());
122  double convertCriterion =1e-6;
123 
124  m_B.set_size(m_Permutation.size());
125  m_B.fill(0);
126 
127  while (iter <= iterLimit)
128  {
129  ++iter;
130 
131  oldB = m_B;
132  // Do Row-wise operation. No Vector oepration at this point.
133  for (int r = 0; r<rows; ++r)
134  {
135  double deta = link.DLink(mu(r));
136  double zBuffer = eta(r) + (yData(r) - mu(r))*deta;
137  double sqrtWeight = 1 / (std::abs(deta) * dist.SqrtVariance(mu(r)));
138 
139  weightedY(r) = zBuffer * sqrtWeight;
140  for (int c=0; c<cols; ++c)
141  {
142  weightedX(r,c) = x(r,c) * sqrtWeight;
143  }
144  }
145  vnl_qr<double> qr(weightedX);
146  m_B = qr.solve(weightedY);
147  eta = x * m_B;
148  for (int r = 0; r < rows; ++r)
149  {
150  mu(r) = link.InverseLink(eta(r));
151  }
152 
153  bool stayInLoop = false;
154  for(int c= 0; c < cols; ++c)
155  {
156  stayInLoop |= std::abs( m_B(c) - oldB(c)) > convertCriterion * std::max(sqrtEps, std::abs(oldB(c)));
157  }
158  if (!stayInLoop)
159  break;
160  }
161  _FinalizeBVector(m_B, m_Permutation, xData.cols());
162 }
163 
164 void mitk::GeneralizedLinearModel::EstimatePermutation(const vnl_matrix<double> &xData)
165 {
166  v3p_netlib_integer rows = xData.rows();
167  v3p_netlib_integer cols = xData.cols();
168 
169  if (m_AddConstantColumn)
170  ++cols;
171 
172  v3p_netlib_doublereal *x = new v3p_netlib_doublereal[rows* cols];
173  _UpdateXMatrix(xData, m_AddConstantColumn, x);
174  v3p_netlib_doublereal *qraux = new v3p_netlib_doublereal[cols];
175  v3p_netlib_integer *jpvt = new v3p_netlib_integer[cols];
176  std::fill_n(jpvt,cols,0);
177  v3p_netlib_doublereal *work = new v3p_netlib_doublereal[cols];
178  std::fill_n(work,cols,0);
179  v3p_netlib_integer job = 16;
180 
181  // Make a call to Lapack-DQRDC which does QR with permutation
182  // Permutation is saved in JPVT.
183  v3p_netlib_dqrdc_(x, &rows, &rows, &cols, qraux, jpvt, work, &job);
184 
185  double limit = std::abs(x[0]) * std::max(cols, rows) * std::numeric_limits<double>::epsilon();
186  // Calculate the rank of the matrix
187  int m_Rank = 0;
188  for (int i = 0; i <cols; ++i)
189  {
190  m_Rank += (std::abs(x[i*rows + i]) > limit) ? 1 : 0;
191  }
192  // Create a permutation vector
193  m_Permutation.set_size(m_Rank);
194  for (int i = 0; i < m_Rank; ++i)
195  {
196  m_Permutation(i) = jpvt[i]-1;
197  }
198 
199  delete[] x;
200  delete[] qraux;
201  delete[] jpvt;
202  delete[] work;
203 }
204 
205 // Copy a vnl-matrix to an c-array with row-wise representation.
206 // Adds a constant column if required.
207 static void _UpdateXMatrix(const vnl_matrix<double> &xData, bool addConstant, v3p_netlib_doublereal *x)
208 {
209  v3p_netlib_integer rows = xData.rows();
210  v3p_netlib_integer cols = xData.cols();
211  if (addConstant)
212  ++cols;
213 
214  for (int r=0; r < rows; ++r)
215  {
216  for (int c=0; c <cols; ++c)
217  {
218  if (!addConstant)
219  {
220  x[c*rows + r] = xData(r,c);
221  } else if (c == 0)
222  {
223  x[c*rows + r] = 1.0;
224  } else
225  {
226  x[c*rows + r] = xData(r, c-1);
227  }
228  }
229  }
230 }
231 
232 // Fills the value of the xData-matrix into the x-matrix. Adds a constant
233 // column if required. Permutes the rows corresponding to the permutation vector.
234 static void _UpdatePermXMatrix(const vnl_matrix<double> &xData, bool addConstant, const vnl_vector<unsigned int> &permutation, vnl_matrix<double> &x)
235 {
236  int rows = xData.rows();
237  int cols = permutation.size();
238  x.set_size(rows, cols);
239  for (int r=0; r < rows; ++r)
240  {
241  for (int c=0; c<cols; ++c)
242  {
243  unsigned int newCol = permutation(c);
244  if (!addConstant)
245  {
246  x(r, c) = xData(r,newCol);
247  } else if (newCol == 0)
248  {
249  x(r, c) = 1.0;
250  } else
251  {
252  x(r, c) = xData(r, newCol-1);
253  }
254  }
255  }
256 }
257 
258 // Initialize mu and eta by calling the corresponding
259 // link and distribution functions on each row
260 static void _InitMuEta(mitk::DistSimpleBinominal *dist, mitk::LogItLinking *link, const vnl_vector<double> &yData, vnl_vector<double> &mu, vnl_vector<double> &eta)
261 {
262  int rows = yData.size();
263  mu.set_size(rows);
264  eta.set_size(rows);
265  for (int r = 0; r < rows; ++r)
266  {
267  mu(r) = dist->Init(yData(r));
268  eta(r) = link->Link(mu(r));
269  }
270 }
271 
272 // Inverts the permutation on a given b-vector.
273 // Necessary to get a b-vector that match the original data
274 static void _FinalizeBVector(vnl_vector<double> &b, vnl_vector<unsigned int> &perm, int cols)
275 {
276  vnl_vector<double> tempB(cols+1);
277  tempB.fill(0);
278  for (unsigned int c = 0; c < perm.size(); ++c)
279  {
280  tempB(perm(c)) = b(c);
281  }
282  b = tempB;
283 }
static void _UpdatePermXMatrix(const vnl_matrix< double > &xData, bool addConstant, const vnl_vector< unsigned int > &permutation, vnl_matrix< double > &x)
double Predict(const vnl_vector< double > &c)
Predicts the value corresponding to the given vector.
virtual double SqrtVariance(double mu)
double Link(double mu)
GeneralizedLinearModel(const vnl_matrix< double > &xData, const vnl_vector< double > &yData, bool addConstantColumn=true)
Initialization of the GLM. The parameters needs to be passed at the beginning.
double DLink(double mu)
static T max(T x, T y)
Definition: svm.cpp:70
static void _InitMuEta(mitk::DistSimpleBinominal *dist, mitk::LogItLinking *link, const vnl_vector< double > &yData, vnl_vector< double > &mu, vnl_vector< double > &eta)
double InverseLink(double eta)
vnl_vector< double > ExpMu(const vnl_matrix< double > &x)
Estimation of the exponential factor for a given function.
static void _UpdateXMatrix(const vnl_matrix< double > &xData, bool addConstant, v3p_netlib_doublereal *x)
static void _FinalizeBVector(vnl_vector< double > &b, vnl_vector< unsigned int > &perm, int cols)
vnl_vector< double > B()
Returns the b-Vector for the estimation.
virtual double Init(double y)