5 #include <boost/math/special_functions/gamma.hpp> 6 #include <boost/math/special_functions/fpclassify.hpp> 14 unsigned int nbParams = parameters.GetSize();
19 for (
unsigned int i = 0;i < nbParams;++i)
36 unsigned int nbImages = m_Residuals.size();
38 costValue = nbImages * (1.0 + std::log(2.0 * M_PI *
m_SigmaSquare));
47 unsigned int numCompartments = m_IndexesUsefulCompartments.size();
51 for (
unsigned int i = 0;i < nbValues;++i)
54 for (
unsigned int j = 0;j < numCompartments;++j)
55 m_Residuals[i] -= m_PredictedSignalAttenuations.get(i,j) * m_OptimalUsefulWeights[j];
67 unsigned int numCompartments =
m_MCMStructure->GetNumberOfCompartments();
69 m_OptimalWeights.resize(numCompartments);
70 std::fill(m_OptimalWeights.begin(),m_OptimalWeights.end(),0.0);
72 m_IndexesUsefulCompartments.resize(numCompartments);
77 for (
int i = numCompartments - 1;i >= 0;--i)
79 bool duplicated =
false;
81 for (
int j = 0;j < i;++j)
92 m_IndexesUsefulCompartments[pos] = i;
97 numCompartments = pos;
98 m_IndexesUsefulCompartments.resize(numCompartments);
99 std::sort(m_IndexesUsefulCompartments.begin(),m_IndexesUsefulCompartments.end());
102 m_PredictedSignalAttenuations.set_size(nbValues,numCompartments);
104 for (
unsigned int i = 0;i < nbValues;++i)
106 for (
unsigned int j = 0;j < numCompartments;++j)
108 unsigned int indexComp = m_IndexesUsefulCompartments[j];
110 m_PredictedSignalAttenuations.put(i,j,predictedSignal);
114 m_CholeskyMatrix.set_size(numCompartments,numCompartments);
115 m_FSignals.SetSize(numCompartments);
118 for (
unsigned int i = 0;i < numCompartments;++i)
121 for (
unsigned int j = 0;j < nbValues;++j)
127 for (
unsigned int j = i;j < numCompartments;++j)
129 double cholValue = 0.0;
130 for (
unsigned int k = 0;k < nbValues;++k)
131 cholValue += m_PredictedSignalAttenuations.get(k,i) * m_PredictedSignalAttenuations.get(k,j);
133 m_CholeskyMatrix.put(i,j,cholValue);
135 m_CholeskyMatrix.put(j,i,cholValue);
143 bool nnlsNeeded =
false;
145 for (
unsigned int i = 0;i < numCompartments;++i)
147 if (m_OptimalUsefulWeights[i] <= 0.0)
157 bool useCholeskyMatrix =
true;
158 for (
int i = numCompartments - 1;i >= 0;--i)
161 for (
unsigned int k = 0;k < numCompartments;++k)
162 normRef += m_CholeskyMatrix.get(k,i) * m_CholeskyMatrix.get(k,i);
163 normRef = std::sqrt(normRef);
165 for (
int j = 0;j < i;++j)
168 for (
unsigned int k = 0;k < numCompartments;++k)
169 normTest += m_CholeskyMatrix.get(k,j) * m_CholeskyMatrix.get(k,j);
170 normTest = std::sqrt(normTest);
172 double normsProduct = normRef * normTest;
173 double dotProduct = 0.0;
174 for (
unsigned int k = 0;k < numCompartments;++k)
175 dotProduct += m_CholeskyMatrix.get(k,i) * m_CholeskyMatrix.get(k,j) / normsProduct;
177 if (std::abs(dotProduct - 1.0) < 1.0e-6)
179 useCholeskyMatrix =
false;
184 if (!useCholeskyMatrix)
188 if (useCholeskyMatrix)
190 m_NNLSBordersOptimizer->SetDataMatrix(m_CholeskyMatrix);
191 m_NNLSBordersOptimizer->SetPoints(m_FSignals);
192 m_NNLSBordersOptimizer->SetSquaredProblem(
true);
197 for (
unsigned int i = 0;i < nbValues;++i)
201 observedSignals[i] *= -1;
204 m_NNLSBordersOptimizer->SetDataMatrix(m_PredictedSignalAttenuations);
205 m_NNLSBordersOptimizer->SetPoints(observedSignals);
206 m_NNLSBordersOptimizer->SetSquaredProblem(
false);
209 m_NNLSBordersOptimizer->StartOptimization();
210 m_OptimalUsefulWeights = m_NNLSBordersOptimizer->GetCurrentPosition();
214 m_OptimalUsefulWeights *= -1;
216 m_OptimalUsefulWeights.set_size(numCompartments);
218 m_CompartmentSwitches.resize(numCompartments);
219 for (
unsigned int i = 0;i < numCompartments;++i)
221 m_OptimalWeights[m_IndexesUsefulCompartments[i]] = m_OptimalUsefulWeights[i];
222 if (m_OptimalUsefulWeights[i] <= 0)
223 m_CompartmentSwitches[i] =
false;
226 m_OptimalWeights[m_IndexesUsefulCompartments[i]] = m_OptimalUsefulWeights[i];
227 m_CompartmentSwitches[i] =
true;
231 m_Residuals.SetSize(nbValues);
238 unsigned int numCompartments = m_IndexesUsefulCompartments.size();
240 unsigned int numOnCompartments = 0;
241 for (
unsigned int i = 0;i < numCompartments;++i)
242 numOnCompartments += m_CompartmentSwitches[i];
246 vnl_matrix<double> zeroMatrix(nbValues,numCompartments,0.0);
247 m_SignalAttenuationsJacobian.resize(nbParams);
248 std::fill(m_SignalAttenuationsJacobian.begin(),m_SignalAttenuationsJacobian.end(),zeroMatrix);
251 m_GramMatrix.set_size(numOnCompartments,numOnCompartments);
252 m_InverseGramMatrix.set_size(numOnCompartments,numOnCompartments);
254 unsigned int posX = 0;
255 unsigned int posY = 0;
256 for (
unsigned int i = 0;i < numCompartments;++i)
258 if (!m_CompartmentSwitches[i])
261 m_GramMatrix.put(posX,posX,m_CholeskyMatrix.get(i,i));
263 for (
unsigned int j = i + 1;j < numCompartments;++j)
265 if (!m_CompartmentSwitches[j])
268 double val = m_CholeskyMatrix(i,j);
270 m_GramMatrix.put(posX,posY,val);
271 m_GramMatrix.put(posY,posX,val);
278 if (numOnCompartments > 0)
279 m_leCalculator->GetTensorPower(m_GramMatrix,m_InverseGramMatrix,-1.0);
282 m_FMatrixInverseG.set_size(nbValues,numOnCompartments);
283 for (
unsigned int i = 0;i < nbValues;++i)
285 for (
unsigned int j = 0;j < numOnCompartments;++j)
287 double fInvGValue = 0.0;
288 unsigned int posK = 0;
289 for (
unsigned int k = 0;k < numCompartments;++k)
291 if (!m_CompartmentSwitches[k])
294 fInvGValue += m_PredictedSignalAttenuations(i,k) * m_InverseGramMatrix(posK,j);
298 m_FMatrixInverseG.put(i,j,fInvGValue);
302 for (
unsigned int i = 0;i < nbValues;++i)
304 unsigned int pos = 0;
306 for (
unsigned int j = 0;j < numCompartments;++j)
308 unsigned int indexComp = m_IndexesUsefulCompartments[j];
313 unsigned int compartmentSize = compartmentJacobian.size();
314 for (
unsigned int k = 0;k < compartmentSize;++k)
315 m_SignalAttenuationsJacobian[pos+k].put(i,j,compartmentJacobian[k]);
317 pos += compartmentSize;
325 unsigned int nbParams = parameters.GetSize();
330 unsigned int numCompartments = m_IndexesUsefulCompartments.size();
333 unsigned int numOnCompartments = m_GramMatrix.rows();
336 for (
unsigned int i = 0;i < nbParams;++i)
340 std::cerr << parameters << std::endl;
341 itkExceptionMacro(
"Get derivative not called with the same parameters as GetValue, suggestive of NaN...");
345 derivative.SetSize(nbValues, nbParams);
346 derivative.Fill(0.0);
349 ListType tmpVec(numOnCompartments,0.0);
351 for (
unsigned int k = 0;k < nbParams;++k)
355 std::fill(DFw.begin(),DFw.end(),0.0);
356 for (
unsigned int i = 0;i < nbValues;++i)
359 for (
unsigned int j = 0;j < numCompartments;++j)
360 DFw[i] += m_SignalAttenuationsJacobian[k].
get(i,j) * m_OptimalUsefulWeights[j];
365 unsigned int pos = 0;
366 for (
unsigned int j = 0;j < numCompartments;++j)
368 if (!m_CompartmentSwitches[j])
373 for (
unsigned int i = 0;i < nbValues;++i)
374 tmpVec[pos] += m_PredictedSignalAttenuations.get(i,j) * DFw[i] - m_SignalAttenuationsJacobian[k].get(i,j) * m_Residuals[i];
381 for (
unsigned int i = 0;i < nbValues;++i)
383 double derivativeVal = - DFw[i];
385 for (
unsigned int j = 0;j < numOnCompartments;++j)
386 derivativeVal += m_FMatrixInverseG.get(i,j) * tmpVec[j];
388 derivative.put(i,k,derivativeVal);
392 bool problem =
false;
393 for (
unsigned int i = 0;i < nbParams;++i)
395 if (!std::isfinite(derivative.get(0,i)))
404 std::cerr <<
"Derivative: " << derivative << std::endl;
405 std::cerr <<
"Optimal weights: " << m_OptimalUsefulWeights << std::endl;
406 std::cerr <<
"Gram matrix inverse: " << m_InverseGramMatrix << std::endl;
407 std::cerr <<
"Residuals: " << m_Residuals << std::endl;
409 std::cerr <<
"Params: " << parameters << std::endl;
410 itkExceptionMacro(
"Non finite derivative");
417 unsigned int nbParams = derivativeMatrix.columns();
418 unsigned int nbValues = derivativeMatrix.rows();
422 derivative.set_size(nbParams);
423 for (
unsigned int i = 0;i < nbParams;++i)
426 for (
unsigned int j = 0;j < nbValues;++j)
427 derivative[i] += m_Residuals[j] * derivativeMatrix.get(j,i);
itk::OptimizerParameters< double > ParametersType
MCMPointer m_MCMStructure
void PrepareDataForDerivative()
ListType m_ObservedSignals
void GetDerivativeMatrix(const ParametersType ¶meters, DerivativeMatrixType &derivative) ITK_OVERRIDE
Get residual derivatives for a given set of parameters, returns a matrix of residuals derivatives...
void PerformDecomposition()
Performs LDL decomposition from input matrix.
void SetInputMatrix(const MatrixType &matrix)
Set input matrix to decompose.
MeasureType GetValues(const ParametersType ¶meters) ITK_OVERRIDE
Get residual values for a given set of parameters, returns a vector of residuals. ...
double GetCurrentCostValue() ITK_OVERRIDE
For the current set of parameters, compute the cost function value, requires GetValues to be called f...
void SolveLinearLeastSquares()
Computes maximum likelihood estimates of weights.
void GetCurrentDerivative(DerivativeMatrixType &derivativeMatrix, DerivativeType &derivative) ITK_OVERRIDE
Get cost function derivatives from a derivative matrix obtained from GetDerivativeMatrix.
VectorType & SolveLinearSystem(const VectorType &b)
Solves linear system Ax=b and outputs result in new variable.
ListType m_GradientStrengths
ListType m_TestedParameters
MCMType::ListType ListType
itk::Array2D< double > DerivativeMatrixType
itk::Array< double > MeasureType
std::vector< Vector3DType > m_Gradients
itk::Array< double > DerivativeType