ANIMA  4.0
animaMultiTensorSmoothingCostFunction.cxx
Go to the documentation of this file.
2 #include <vnl/algo/vnl_determinant.h>
3 
4 namespace anima
5 {
6 
7 void
9 ::SetReferenceModels(const std::vector <MCMPointer> &refModels)
10 {
11  unsigned int numRefModels = refModels.size();
12  m_ReferenceModels.resize(numRefModels);
13  m_ReferenceModelWeights.resize(numRefModels);
14  m_ReferenceNumberOfIsotropicCompartments.resize(numRefModels);
15 
16  for (unsigned int i = 0;i < numRefModels;++i)
17  {
18  unsigned int numCompartments = refModels[i]->GetNumberOfCompartments();
19  std::vector <TensorType> compartmentTensors(numCompartments);
20  std::vector <double> compartmentWeights(numCompartments);
21  unsigned int pos = 0;
22  unsigned int numIsoCompartments = refModels[i]->GetNumberOfIsotropicCompartments();
23  for (unsigned int j = 0;j < numCompartments;++j)
24  {
25  double currentWeight = refModels[i]->GetCompartmentWeight(j);
26  if (currentWeight > 0)
27  {
28  compartmentTensors[pos] = refModels[i]->GetCompartment(j)->GetDiffusionTensor();
29  compartmentWeights[pos] = currentWeight;
30  ++pos;
31  }
32  else if (j < refModels[i]->GetNumberOfIsotropicCompartments())
33  --numIsoCompartments;
34  }
35 
36  compartmentTensors.resize(pos);
37  compartmentWeights.resize(pos);
38 
39  m_ReferenceModels[i] = compartmentTensors;
40  m_ReferenceModelWeights[i] = compartmentWeights;
41  m_ReferenceNumberOfIsotropicCompartments[i] = 0;
42  }
43 
44  m_UpdatedReferenceData = true;
45  m_RecomputeConstantTerm = true;
46 }
47 
48 void
50 ::SetMovingModels(const std::vector<MCMPointer> &movingModels)
51 {
52  unsigned int numMovingModels = movingModels.size();
53  m_MovingModels.resize(numMovingModels);
54  m_MovingModelWeights.resize(numMovingModels);
55 
56  for (unsigned int i = 0;i < numMovingModels;++i)
57  {
58  unsigned int numCompartments = movingModels[i]->GetNumberOfCompartments();
59  std::vector <TensorType> compartmentTensors(numCompartments);
60  std::vector <double> compartmentWeights(numCompartments);
61  unsigned int pos = 0;
62  for (unsigned int j = 0;j < numCompartments;++j)
63  {
64  double currentWeight = movingModels[i]->GetCompartmentWeight(j);
65  if (currentWeight > 0)
66  {
67  compartmentTensors[pos] = movingModels[i]->GetCompartment(j)->GetDiffusionTensor();
68  compartmentWeights[pos] = currentWeight;
69  ++pos;
70  }
71  }
72 
73  compartmentTensors.resize(pos);
74  compartmentWeights.resize(pos);
75 
76  m_MovingModels[i] = compartmentTensors;
77  m_MovingModelWeights[i] = compartmentWeights;
78  }
79 
80  m_UpdatedMovingData = true;
81  m_RecomputeConstantTerm = true;
82 }
83 
86 ::GetValue(const ParametersType &parameters) const
87 {
88  unsigned int numDataPoints = m_ReferenceModels.size();
89  if (numDataPoints == 0)
90  return 0.0;
91 
92  this->UpdateDeterminants();
93 
94  double gaussianSigma = parameters[0] / m_TensorsScale;
95  MeasureType outputValue = 0;
96 
97  double pi3half = std::pow(M_PI,1.5);
98  double pi23half = std::pow(2.0 * M_PI,1.5);
99 
100  if (m_RecomputeConstantTerm)
101  {
102  m_ConstantTerm = 0;
103  for (unsigned int l = 0;l < numDataPoints;++l)
104  {
105  unsigned int pos = 0;
106  unsigned int posRefMov = 0;
107  unsigned int refModelSize = m_ReferenceModelWeights[l].size();
108  unsigned int movingModelSize = m_MovingModelWeights[l].size();
109  unsigned int numRefIsoCompartments = m_ReferenceNumberOfIsotropicCompartments[l];
110 
111  for (unsigned int i = 0;i < numRefIsoCompartments;++i)
112  {
113  m_ConstantTerm += m_ReferenceModelWeights[l][i] * m_ReferenceModelWeights[l][i] * pi3half / std::sqrt(m_ReferenceReferenceDeterminants[l][pos]);
114  ++pos;
115 
116  for (unsigned int j = i+1;j < numRefIsoCompartments;++j)
117  {
118  m_ConstantTerm += 2.0 * m_ReferenceModelWeights[l][i] * m_ReferenceModelWeights[l][j] * pi23half / std::sqrt(m_ReferenceReferenceDeterminants[l][pos]);
119  ++pos;
120  }
121 
122  pos += refModelSize - numRefIsoCompartments;
123 
124  for (unsigned int j = 0;j < movingModelSize;++j)
125  {
126  m_ConstantTerm -= 2.0 * m_ReferenceModelWeights[l][i] * m_MovingModelWeights[l][j] * pi23half / std::sqrt(m_ReferenceMovingDeterminants[l][posRefMov]);
127  ++posRefMov;
128  }
129  }
130 
131  pos = 0;
132  for (unsigned int i = 0;i < movingModelSize;++i)
133  {
134  m_ConstantTerm += m_MovingModelWeights[l][i] * m_MovingModelWeights[l][i] * pi3half / std::sqrt(m_MovingMovingDeterminants[l][pos]);
135  ++pos;
136 
137  for (unsigned int j = i+1;j < movingModelSize;++j)
138  {
139  m_ConstantTerm += 2.0 * m_MovingModelWeights[l][i] * m_MovingModelWeights[l][j] * pi23half / std::sqrt(m_MovingMovingDeterminants[l][pos]);
140  ++pos;
141  }
142  }
143  }
144 
145  m_RecomputeConstantTerm = false;
146  }
147 
148  outputValue = m_ConstantTerm;
149 
150  for (unsigned int l = 0;l < numDataPoints;++l)
151  {
152  unsigned int refModelSize = m_ReferenceModelWeights[l].size();
153  unsigned int movingModelSize = m_MovingModelWeights[l].size();
154  unsigned int numRefIsoCompartments = m_ReferenceNumberOfIsotropicCompartments[l];
155 
156  unsigned int posRefRef = 0;
157  unsigned int posRefMov = 0;
158 
159  for (unsigned int i = 0;i < refModelSize;++i)
160  {
161  if (i >= numRefIsoCompartments)
162  {
163  double refSigmaDeterminant = m_ReferenceReferenceDeterminants[l][posRefRef] + gaussianSigma * (m_ReferenceReferenceTraceDifferences[l][posRefRef] + gaussianSigma * (m_ReferenceReferenceTraces[l][posRefRef] + gaussianSigma));
164  outputValue += m_ReferenceModelWeights[l][i] * m_ReferenceModelWeights[l][i] * pi3half / std::sqrt(refSigmaDeterminant);
165 
166  for (unsigned int j = 0;j < movingModelSize;++j)
167  {
168  double refMovSigmaDeterminant = m_ReferenceMovingDeterminants[l][posRefMov] + gaussianSigma * (m_ReferenceMovingTraceDifferences[l][posRefMov] + gaussianSigma * (m_ReferenceMovingTraces[l][posRefMov] + gaussianSigma));
169 
170  outputValue -= 2.0 * m_ReferenceModelWeights[l][i] * m_MovingModelWeights[l][j] * pi23half / std::sqrt(refMovSigmaDeterminant);
171  ++posRefMov;
172  }
173  }
174  else
175  posRefMov += movingModelSize;
176 
177  ++posRefRef;
178 
179  for (unsigned int j = i+1;j < refModelSize;++j)
180  {
181  double factor = (i >= numRefIsoCompartments) + (j >= numRefIsoCompartments);
182  if (factor == 0)
183  {
184  ++posRefRef;
185  continue;
186  }
187 
188  double alphaValue = factor * gaussianSigma;
189  double refSigmaDeterminant = m_ReferenceReferenceDeterminants[l][posRefRef] + alphaValue * (m_ReferenceReferenceTraceDifferences[l][posRefRef] + alphaValue * (m_ReferenceReferenceTraces[l][posRefRef] + alphaValue));
190 
191  outputValue += 2.0 * m_ReferenceModelWeights[l][i] * m_ReferenceModelWeights[l][j] * pi23half / std::sqrt(refSigmaDeterminant);
192  ++posRefRef;
193  }
194  }
195  }
196 
197  if (outputValue <= 0)
198  outputValue = 0;
199 
200  return outputValue / numDataPoints;
201 }
202 
203 void
206 {
207  TensorType workMatrix;
208  unsigned int numDataPoints = m_ReferenceModels.size();
209  double squaredMatrixTrace;
210 
211  if (m_UpdatedReferenceData)
212  {
213  m_ReferenceReferenceDeterminants.resize(numDataPoints);
214  m_ReferenceReferenceTraces.resize(numDataPoints);
215  m_ReferenceReferenceTraceDifferences.resize(numDataPoints);
216 
217  for (unsigned int l = 0;l < numDataPoints;++l)
218  {
219  unsigned int refModelSize = m_ReferenceModelWeights[l].size();
220  unsigned int numElements = refModelSize * (refModelSize + 1) / 2;
221  m_ReferenceReferenceDeterminants[l].resize(numElements);
222  m_ReferenceReferenceTraces[l].resize(numElements);
223  m_ReferenceReferenceTraceDifferences[l].resize(numElements);
224 
225  unsigned int pos = 0;
226  for (unsigned int i = 0;i < refModelSize;++i)
227  {
228  workMatrix = m_ReferenceModels[l][i];
229  for (unsigned int k = 0;k < 3;++k)
230  workMatrix(k,k) += 1.0 / (2.0 * m_LowPassGaussianSigma);
231  m_ReferenceReferenceDeterminants[l][pos] = vnl_determinant <double> (workMatrix.GetVnlMatrix().as_matrix());
232  this->ComputeMatrixTraces(m_ReferenceModels[l][i],m_ReferenceReferenceTraces[l][pos],squaredMatrixTrace);
233  m_ReferenceReferenceTraceDifferences[l][pos] = 0.5 * (m_ReferenceReferenceTraces[l][pos] * m_ReferenceReferenceTraces[l][pos] - squaredMatrixTrace);
234 
235  ++pos;
236 
237  for (unsigned int j = i+1;j < refModelSize;++j)
238  {
239  workMatrix = m_ReferenceModels[l][i] + m_ReferenceModels[l][j];
240  for (unsigned int k = 0;k < 3;++k)
241  workMatrix(k,k) += 1.0 / m_LowPassGaussianSigma;
242  m_ReferenceReferenceDeterminants[l][pos] = vnl_determinant <double> (workMatrix.GetVnlMatrix().as_matrix());
243  this->ComputeMatrixTraces(workMatrix,m_ReferenceReferenceTraces[l][pos],squaredMatrixTrace);
244  m_ReferenceReferenceTraceDifferences[l][pos] = 0.5 * (m_ReferenceReferenceTraces[l][pos] * m_ReferenceReferenceTraces[l][pos] - squaredMatrixTrace);
245 
246  ++pos;
247  }
248  }
249  }
250  }
251 
252  if (m_UpdatedMovingData)
253  {
254  m_MovingMovingDeterminants.resize(numDataPoints);
255 
256  for (unsigned int l = 0;l < numDataPoints;++l)
257  {
258  unsigned int movingModelSize = m_MovingModelWeights[l].size();
259  unsigned int numElements = movingModelSize * (movingModelSize + 1) / 2;
260  m_MovingMovingDeterminants[l].resize(numElements);
261 
262  unsigned int pos = 0;
263  for (unsigned int i = 0;i < movingModelSize;++i)
264  {
265  workMatrix = m_MovingModels[l][i];
266  for (unsigned int k = 0;k < 3;++k)
267  workMatrix(k,k) += 1.0 / (2.0 * m_LowPassGaussianSigma);
268  m_MovingMovingDeterminants[l][pos] = vnl_determinant <double> (workMatrix.GetVnlMatrix().as_matrix());
269  ++pos;
270 
271  for (unsigned int j = i+1;j < movingModelSize;++j)
272  {
273  workMatrix = m_MovingModels[l][i] + m_MovingModels[l][j];
274  for (unsigned int k = 0;k < 3;++k)
275  workMatrix(k,k) += 1.0 / m_LowPassGaussianSigma;
276  m_MovingMovingDeterminants[l][pos] = vnl_determinant <double> (workMatrix.GetVnlMatrix().as_matrix());
277  ++pos;
278  }
279  }
280  }
281  }
282 
283  if (m_UpdatedMovingData || m_UpdatedReferenceData)
284  {
285  m_ReferenceMovingDeterminants.resize(numDataPoints);
286  m_ReferenceMovingTraces.resize(numDataPoints);
287  m_ReferenceMovingTraceDifferences.resize(numDataPoints);
288 
289  for (unsigned int l = 0;l < numDataPoints;++l)
290  {
291  unsigned int refModelSize = m_ReferenceModelWeights[l].size();
292  unsigned int movingModelSize = m_MovingModelWeights[l].size();
293  unsigned int numElements = refModelSize * movingModelSize;
294  m_ReferenceMovingDeterminants[l].resize(numElements);
295  m_ReferenceMovingTraces[l].resize(numElements);
296  m_ReferenceMovingTraceDifferences[l].resize(numElements);
297 
298  unsigned int pos = 0;
299  for (unsigned int i = 0;i < refModelSize;++i)
300  {
301  for (unsigned int j = 0;j < movingModelSize;++j)
302  {
303  workMatrix = m_ReferenceModels[l][i] + m_MovingModels[l][j];
304  for (unsigned int k = 0;k < 3;++k)
305  workMatrix(k,k) += 1.0 / m_LowPassGaussianSigma;
306  m_ReferenceMovingDeterminants[l][pos] = vnl_determinant <double> (workMatrix.GetVnlMatrix().as_matrix());
307  this->ComputeMatrixTraces(workMatrix,m_ReferenceMovingTraces[l][pos],squaredMatrixTrace);
308  m_ReferenceMovingTraceDifferences[l][pos] = 0.5 * (m_ReferenceMovingTraces[l][pos] * m_ReferenceMovingTraces[l][pos] - squaredMatrixTrace);
309 
310  ++pos;
311  }
312  }
313  }
314  }
315 
316  m_UpdatedReferenceData = false;
317  m_UpdatedMovingData = false;
318 }
319 
320 void
322 ::ComputeMatrixTraces(const TensorType &matrix, double &matrixTrace, double &squaredMatrixTrace) const
323 {
324  matrixTrace = 0;
325  squaredMatrixTrace = 0;
326 
327  for (unsigned int j = 0;j < TensorType::RowDimensions;++j)
328  {
329  matrixTrace += matrix(j,j);
330  for (unsigned int k = j;k < TensorType::ColumnDimensions;++k)
331  {
332  double factor = 2.0;
333  if (k == j)
334  factor = 1.0;
335 
336  squaredMatrixTrace += factor * matrix(j,k) * matrix(j,k);
337  }
338  }
339 }
340 
341 void
343 ::GetDerivative(const ParametersType &parameters, DerivativeType &derivative) const
344 {
345  unsigned int numDataPoints = m_ReferenceModels.size();
346  derivative.set_size(this->GetNumberOfParameters());
347  derivative.fill(0);
348 
349  if (numDataPoints == 0)
350  return;
351 
352  this->UpdateDeterminants();
353 
354  double gaussianSigma = parameters[0] / m_TensorsScale;
355  double sq2pi3half = std::sqrt(2.0) * std::pow(M_PI,1.5);
356  double spi3half = std::pow(M_PI,1.5) / 16;
357 
358  for (unsigned int l = 0;l < numDataPoints;++l)
359  {
360  unsigned int refModelSize = m_ReferenceModelWeights[l].size();
361  unsigned int movingModelSize = m_MovingModelWeights[l].size();
362  unsigned int numRefIsoCompartments = m_ReferenceNumberOfIsotropicCompartments[l];
363 
364  unsigned int posRefRef = 0;
365  unsigned int posRefMov = 0;
366 
367  for (unsigned int i = 0;i < refModelSize;++i)
368  {
369  if (i >= numRefIsoCompartments)
370  {
371  double refSigmaDeterminant = m_ReferenceReferenceDeterminants[l][posRefRef] + gaussianSigma * (m_ReferenceReferenceTraceDifferences[l][posRefRef] + gaussianSigma * (m_ReferenceReferenceTraces[l][posRefRef] + gaussianSigma));
372 
373  double traceDiff = 2.0 * m_ReferenceReferenceTraceDifferences[l][posRefRef] + 4.0 * gaussianSigma * m_ReferenceReferenceTraces[l][posRefRef] + 6.0 * gaussianSigma * gaussianSigma;
374  traceDiff *= 4.0;
375  double matrixDetCube = refSigmaDeterminant * refSigmaDeterminant * refSigmaDeterminant;
376 
377  derivative[0] -= m_ReferenceModelWeights[l][i] * m_ReferenceModelWeights[l][i] * spi3half * traceDiff / std::sqrt(matrixDetCube);
378 
379  for (unsigned int j = 0;j < movingModelSize;++j)
380  {
381  double refMovSigmaDeterminant = m_ReferenceMovingDeterminants[l][posRefMov] + gaussianSigma * (m_ReferenceMovingTraceDifferences[l][posRefMov] + gaussianSigma * (m_ReferenceMovingTraces[l][posRefMov] + gaussianSigma));
382 
383  traceDiff = 2.0 * m_ReferenceMovingTraceDifferences[l][posRefMov] + 4.0 * gaussianSigma * m_ReferenceMovingTraces[l][posRefMov] + 6.0 * gaussianSigma * gaussianSigma;
384  matrixDetCube = refMovSigmaDeterminant * refMovSigmaDeterminant * refMovSigmaDeterminant;
385 
386  derivative[0] += m_ReferenceModelWeights[l][i] * m_MovingModelWeights[l][j] * sq2pi3half * traceDiff / std::sqrt(matrixDetCube);
387  ++posRefMov;
388  }
389  }
390  else
391  posRefMov += movingModelSize;
392 
393  ++posRefRef;
394 
395  for (unsigned int j = i+1;j < refModelSize;++j)
396  {
397  double factor = (i >= numRefIsoCompartments) + (j >= numRefIsoCompartments);
398  if (factor == 0)
399  {
400  ++posRefRef;
401  continue;
402  }
403 
404  double alphaValue = factor * gaussianSigma;
405  double refSigmaDeterminant = m_ReferenceReferenceDeterminants[l][posRefRef] + alphaValue * (m_ReferenceReferenceTraceDifferences[l][posRefRef] + alphaValue * (m_ReferenceReferenceTraces[l][posRefRef] + alphaValue));
406 
407  double traceDiff = 2.0 * m_ReferenceReferenceTraceDifferences[l][posRefRef] + 4.0 * alphaValue * m_ReferenceReferenceTraces[l][posRefRef] + 6.0 * alphaValue * alphaValue;
408  double matrixDetCube = refSigmaDeterminant * refSigmaDeterminant * refSigmaDeterminant;
409 
410  derivative[0] -= factor * m_ReferenceModelWeights[l][i] * m_ReferenceModelWeights[l][j] * sq2pi3half * traceDiff / std::sqrt(matrixDetCube);
411  ++posRefRef;
412  }
413  }
414  }
415 
416  derivative[0] /= numDataPoints;
417 }
418 
419 } // end namespace anima
void SetMovingModels(const std::vector< MCMPointer > &movingModels)
void SetReferenceModels(const std::vector< MCMPointer > &refModels)
virtual void GetDerivative(const ParametersType &parameters, DerivativeType &derivative) const ITK_OVERRIDE
virtual MeasureType GetValue(const ParametersType &parameters) const ITK_OVERRIDE
void ComputeMatrixTraces(const TensorType &matrix, double &matrixTrace, double &squaredMatrixTrace) const