SMILX  1.01
milxMath.h
1 /*=========================================================================
2  The Software is copyright (c) Commonwealth Scientific and Industrial Research Organisation (CSIRO)
3  ABN 41 687 119 230.
4  All rights reserved.
5 
6  Licensed under the CSIRO BSD 3-Clause License
7  You may not use this file except in compliance with the License.
8  You may obtain a copy of the License in the file LICENSE.md or at
9 
10  https://stash.csiro.au/projects/SMILI/repos/smili/browse/license.txt
11 
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 =========================================================================*/
18 #ifndef __MILXMATH_H
19 #define __MILXMATH_H
20 
21 #ifndef VTK_ONLY
22  //VNL
23  #include <vnl/vnl_error.h>
24  #include <vnl/vnl_matrix.h>
25  #include <vnl/vnl_vector_fixed.h>
26  #include <vnl/algo/vnl_matrix_inverse.h>
27 #endif
28 #ifndef ITK_ONLY
29  //VTK
30  #include <vtkMath.h>
31  #include <vtkPoints.h>
32 #endif
33 //SMILI
34 #include <milxGlobal.h>
35 
36 namespace milx
37 {
38 
43 template<class Type = double>
45 {
46 public:
47 #ifndef VTK_ONLY
48 
53  static Type Centroid(const vnl_vector<Type> &data);
59  static vnl_vector<Type> Centroid(const vnl_matrix<Type> &data);
63  static Type CentroidSize(const vnl_matrix<Type> &data, const vnl_vector<Type> &centroid, bool norm = false);
64 #ifndef ITK_ONLY
65  static vnl_vector<Type> Centroid(vtkPoints *points);
75  static Type CentroidSize(vtkPoints *points, const vnl_vector<Type> &centroid, bool norm = false);
76 #endif
77 #endif
78 #ifdef VTK_ONLY
79  static Type* Centroid(vtkPoints *points);
89  static Type CentroidSize(vtkPoints *points, const Type* centroid, bool norm = false);
90 #endif
91 
92 #ifndef VTK_ONLY
93  static vnl_matrix<Type> CovarianceMatrix(vnl_vector<Type> sourceVector);
102  static vnl_matrix<Type> CovarianceMatrix(vnl_vector<Type> sourceVector, vnl_vector<Type> targetVector);
109  static vnl_matrix<Type> CovarianceMatrix(const vnl_matrix<Type> &data, const vnl_vector<Type> &centroid);
116  static vnl_matrix<Type> CovarianceMatrix(const vnl_matrix<Type> &data);
117 #ifndef ITK_ONLY
118  static vnl_matrix<Type> CovarianceMatrix(vtkPoints *points, const vnl_vector<Type> &centroid);
126 #endif
127 #endif
128 
129 #ifndef VTK_ONLY
130  static Type MahalanobisDistance(const vnl_vector<Type> &source, const vnl_vector<Type> &target);
144  static Type MahalanobisDistance(const vnl_vector<Type> &target, const vnl_vector<Type> &mean, const vnl_matrix<Type> &invCovMatrix);
152  static Type MahalanobisDistance(const vnl_vector<Type> &target, const vnl_vector<Type> &mean, const vnl_matrix<Type> &covMatrix, vnl_matrix<Type> &invCovMatrix);
154 #endif
155 
161  static Type MeanSquaredError(vtkPoints *sourcePoints, vtkPoints *targetPoints);
166 
167 protected:
168 
169 private:
170  Math() {};
171  ~Math() {};
172 
173 };
174 
175 #ifndef VTK_ONLY
176 template<class Type>
177 Type Math<Type>::Centroid(const vnl_vector<Type> &data)
178 {
179  const vnl_size_t n = data.size();
180  Type centroid = 0.0;
181 
182  for (vnl_size_t j = 0; j < n; j ++)
183  centroid += data(j);
184  centroid /= n;
185 
186  return centroid;
187 }
188 
189 template<class Type>
190 vnl_vector<Type> Math<Type>::Centroid(const vnl_matrix<Type> &data)
191 {
192  const vnl_size_t n = data.rows();
193  const vnl_size_t m = data.cols();
194  vnl_vector<Type> centroid(m, 0.0);
195 
196  for (vnl_size_t j = 0; j < n; j ++)
197  {
198  centroid += data.get_row(j);
199  }
200  centroid /= n;
201 
202  return centroid;
203 }
204 
205 template<class Type>
206 Type Math<Type>::CentroidSize(const vnl_matrix<Type> &data, const vnl_vector<Type> &centroid, bool norm)
207 {
208  const vnl_size_t n = data.rows();
209  Type newScale = 0;
210 
211  for (int j = 0; j < n; j ++)
212  {
213  vnl_vector<Type> rowVector( data.get_row(j) );
214 
216  newScale += vtkMath::Distance2BetweenPoints(rowVector.data_block(), centroid.data_block());
217  }
218 
219  if(norm)
220  newScale /= n;
221 
222  return sqrt(newScale);
223 }
224 
225 #ifndef ITK_ONLY
226 template<class Type>
227 vnl_vector<Type> Math<Type>::Centroid(vtkPoints *points)
228 {
229  const vtkIdType n = points->GetNumberOfPoints();
230  vnl_vector_fixed<Type, 3> centroid(0.0);
231 
232  for (vtkIdType j = 0; j < n; j ++)
233  {
234  vnl_vector_fixed<Type, 3> location( points->GetPoint(j) );
235 
236  centroid += location;
237  }
238  centroid /= n;
239 
240  return centroid.as_vector();
241 }
242 
243 template<class Type>
244 Type Math<Type>::CentroidSize(vtkPoints *points, const vnl_vector<Type> &centroid, bool norm)
245 {
246  Type newScale = 0;
247 
248  for (vtkIdType j = 0; j < points->GetNumberOfPoints(); j ++)
249  {
250  vnl_vector_fixed<Type, 3> location( points->GetPoint(j) );
251 
253  newScale += vtkMath::Distance2BetweenPoints(location.data_block(), centroid.data_block());
254  }
255 
256  if(norm)
257  newScale /= points->GetNumberOfPoints();
258 
259  return sqrt(newScale);
260 }
261 #endif
262 #endif
263 
264 #ifdef VTK_ONLY //Code that does not depend on VNL
265 template<class Type>
266 Type* Math<Type>::Centroid(vtkPoints *points)
267 {
268  const vtkIdType n = points->GetNumberOfPoints();
269  //~ Type centroid[3] = {0.0, 0.0, 0.0};
270  Type *centroid = new Type[3];
271 
272  for (vtkIdType j = 0; j < n; j ++)
273  {
274  Type location[3];
275 
276  points->GetPoint(j, location);
277 
278  centroid[0] += location[0]/n;
279  centroid[1] += location[1]/n;
280  centroid[2] += location[2]/n;
281  }
282 
283  return centroid;
284 }
285 
286 template<class Type>
287 Type Math<Type>::CentroidSize(vtkPoints *points, const Type* centroid, bool norm)
288 {
289  Type newScale = 0;
290 
291  for (vtkIdType j = 0; j < points->GetNumberOfPoints(); j ++)
292  {
293  Type location[3];
294 
295  points->GetPoint(j, location);
296 
298  newScale += vtkMath::Distance2BetweenPoints(location, centroid);
299  }
300 
301  if(norm)
302  newScale /= points->GetNumberOfPoints();
303 
304  return sqrt(newScale);
305 }
306 #endif
307 
308 #ifndef VTK_ONLY
309 template<class Type>
310 vnl_matrix<Type> Math<Type>::CovarianceMatrix(vnl_vector<Type> sourceVector)
311 {
312  const vnl_size_t n = sourceVector.size();
313 
314  sourceVector -= sourceVector.mean();
315 
316  vnl_matrix<Type> covarianceMatrix(n, n, 0.0);
317  covarianceMatrix += outer_product(sourceVector, sourceVector);
318 
319  return covarianceMatrix;
320 }
321 
322 template<class Type>
323 vnl_matrix<Type> Math<Type>::CovarianceMatrix(vnl_vector<Type> sourceVector, vnl_vector<Type> targetVector)
324 {
325  const vnl_size_t n = sourceVector.size();
326  const vnl_size_t m = targetVector.size();
327 
328  if (m != n)
329  {
330  vnl_error_vector_dimension ("Math<Type>::CovarianceMatrix", m, n);
331  }
332 
333  sourceVector -= sourceVector.mean();
334  targetVector -= targetVector.mean();
335 
336  vnl_matrix<Type> covarianceMatrix(n, n, 0.0);
337  covarianceMatrix += outer_product(sourceVector, targetVector);
338 
339  return covarianceMatrix;
340 }
341 
342 template<class Type>
343 vnl_matrix<Type> Math<Type>::CovarianceMatrix(const vnl_matrix<Type> &data, const vnl_vector<Type> &centroid)
344 {
345  const vnl_size_t n = data.rows();
346  const vnl_size_t m = data.cols();
347  vnl_size_t norm = 1;
348 
349  if (n > 1)
350  norm = n-1;
351 
352  if (m != centroid.size())
353  {
354  vnl_error_vector_dimension ("Math<Type>::CovarianceMatrix", m, centroid.size());
355  }
356 
357  vnl_matrix<Type> covarianceMatrix(m, m, 0.0);
358  for (vnl_size_t j = 0; j < n; j ++)
359  {
360  vnl_vector<Type> rowVector(data.get_row(j));
361 
362  rowVector -= centroid;
363 
364  covarianceMatrix += outer_product(rowVector, rowVector) / norm;
365  }
366 
367  return covarianceMatrix;
368 }
369 
370 template<class Type>
371 vnl_matrix<Type> Math<Type>::CovarianceMatrix(const vnl_matrix<Type> &data)
372 {
373  const vnl_size_t n = data.rows();
374  const vnl_size_t m = data.cols();
375  vnl_size_t norm = 1;
376 
377  if (n > 1)
378  norm = n-1;
379 
380  vnl_matrix<Type> covarianceMatrix(m, m, 0.0);
381  for (vnl_size_t j = 0; j < n; j ++)
382  {
383  vnl_vector<Type> rowVector(data.get_row(j));
384 
385  covarianceMatrix += outer_product(rowVector, rowVector) / norm;
386  }
387 
388  return covarianceMatrix;
389 }
390 
391 #ifndef ITK_ONLY
392 template<class Type>
393 vnl_matrix<Type> Math<Type>::CovarianceMatrix(vtkPoints *points, const vnl_vector<Type> &centroid)
394 {
395  const vnl_size_t n = points->GetNumberOfPoints();
396  vnl_size_t norm = 1;
397 
398  if (n > 1)
399  norm = n-1;
400 
401  if (centroid.size() != 3)
402  {
403  vnl_error_vector_dimension ("Math<Type>::CovarianceMatrix", 3, centroid.size());
404  }
405 
406  vnl_matrix<Type> covarianceMatrix(3, 3, 0.0);
407  for (vnl_size_t j = 0; j < n; j ++)
408  {
409  vnl_vector_fixed<Type, 3> location( points->GetPoint(j) );
410 
411  location -= centroid;
412 
413  covarianceMatrix += outer_product(location.as_vector(), location.as_vector()) / norm;
414  }
415 
416  return covarianceMatrix;
417 }
418 #endif
419 #endif
420 
421 #ifndef VTK_ONLY
422 template<class Type>
423 Type Math<Type>::MahalanobisDistance(const vnl_vector<Type> &source, const vnl_vector<Type> &target)
424 {
425  const vnl_size_t n = source.size();
426  const vnl_size_t m = target.size();
427 
428  if (n != m)
429  {
430  //Throw exception
431  vnl_error_vector_dimension ("Math<Type>::MahalanobisDistance", n, m);
432  }
433 
435  /*vnl_matrix<Type> dataMatrix(2, n, 0.0);
436  dataMatrix.set_row(0, target);
437  dataMatrix.set_row(1, source);
438 
439  // cout << "Compute Centroid" << endl;
440  const vnl_vector<Type> dataCentroid = milx::Math<Type>::Centroid(dataMatrix);
441  cout << "Centroid: " << dataCentroid << endl;
442  // cout << "Compute Covariance Matrix" << endl;
443  vnl_matrix<Type> dataCovariance = milx::Math<Type>::CovarianceMatrix(dataMatrix, dataCentroid);
444  cout << "Covariance: " << dataCovariance.rows() << "x" << dataCovariance.cols() << endl;
445  cout << "Covariance: \n" << dataCovariance << endl;*/
446 
448  vnl_matrix<Type> dataMatrix(n, 2, 0.0);
449  dataMatrix.set_column(0, target);
450  dataMatrix.set_column(1, source);
451 
452  const vnl_vector<Type> dataCentroid = Math<Type>::Centroid(dataMatrix);
453  //cout << "Centroid: " << dataCentroid << endl;
454  vnl_matrix<Type> dataCovariance = Math<Type>::CovarianceMatrix(dataMatrix, dataCentroid);
455  //cout << "Cov: " << dataCovariance.rows() << "x" << dataCovariance.cols() << endl;
456  //cout << "Covariance: \n" << dataCovariance << endl;
457 
459  /*vnl_matrix<Type> dataMatrix(m, 1, 0.0);
460  dataMatrix.set_column(0, target);
461 
462  // const Type centroid = milx::Math<Type>::Centroid(target);
463  // const vnl_vector<Type> dataCentroid(m, centroid);
464  const vnl_vector<Type> dataCentroid = milx::Math<Type>::Centroid(dataMatrix);
465  cout << "Centroid: " << dataCentroid << endl;
466  vnl_matrix<Type> dataCovariance = milx::Math<Type>::CovarianceMatrix(dataMatrix, dataCentroid);
467  cout << "Cov: " << dataCovariance.rows() << "x" << dataCovariance.cols() << endl;
468  cout << "Covariance: \n" << dataCovariance << endl;*/
469 
471  /*vnl_matrix<Type> dataMatrix(1, m, 0.0);
472  dataMatrix.set_row(0, target);
473 
474  // const vnl_vector<Type> dataCentroid = milx::Math<Type>::Centroid(dataMatrix);
475  // const Type centroid = milx::Math<Type>::Centroid(target);
476  // const vnl_vector<Type> dataCentroid(m, centroid);
477  const vnl_vector<Type> dataCentroid(m, 0.0);
478  cout << "Centroid: " << source << endl;
479  vnl_matrix<Type> dataCovariance = milx::Math<Type>::CovarianceMatrix(dataMatrix, dataCentroid);
480  cout << "Cov: " << dataCovariance.rows() << "x" << dataCovariance.cols() << endl;
481  dataCovariance.set_identity();
482  cout << "Covariance: \n" << dataCovariance << endl;*/
483 
485 // vnl_matrix<Type> dataCovariance = milx::Math<Type>::CovarianceMatrix(source, target);
486 
488 // vnl_matrix<Type> dataCovariance = milx::Math<Type>::CovarianceMatrix(target);
489 
490 // vnl_matrix<Type> dataDifference(n, 1, 0.0);
491  vnl_matrix<Type> dataDifference = dataMatrix;
492 // const vnl_vector<Type> sourceZeroMean = source - source.mean();
493 // const vnl_vector<Type> targetZeroMean = target - target.mean();
494 // dataDifference.set_column(0, targetZeroMean - sourceZeroMean);
495 // dataDifference.set_column(0, target - source);
496 
497  //cout << "Compute Inverse Covariance Matrix" << endl;
498  vnl_matrix<Type> dataInvCovariance = vnl_matrix_inverse<Type>(dataCovariance);
499  //cout << "Inv Covariance: \n" << dataInvCovariance << endl;
500 
501 // const vnl_matrix<Type> distance = dataDifference.transpose()*dataInvCovariance*dataDifference;
502  const vnl_matrix<Type> distance = dataDifference*dataInvCovariance*dataDifference.transpose();
503 
504  //cout << "Distance Size: " << distance.rows() << "x" << distance.cols() << endl;
505  //cout << "Distance: " << distance << endl;
506  return 1.0/distance(0,0); //cause of covariance, maximum correlation is returned so invert
507 }
508 
509 template<class Type>
510 Type Math<Type>::MahalanobisDistance(const vnl_vector<Type> &target, const vnl_vector<Type> &mean, const vnl_matrix<Type> &invCovMatrix)
511 {
512  const vnl_size_t n = target.size();
513  const vnl_size_t m = mean.size();
514 
515  if (n != m)
516  {
517  //Throw exception
518  vnl_error_vector_dimension ("Math<Type>::MahalanobisDistance", n, m);
519  }
520 
521  vnl_matrix<Type> dataDifference(n, 1, 0.0);
522  dataDifference.set_column(0, target - mean);
523 
524  const vnl_matrix<Type> distance = dataDifference.transpose()*invCovMatrix*dataDifference;
525 
526  return distance(0,0);
527 }
528 
529 template<class Type>
530 Type Math<Type>::MahalanobisDistance(const vnl_vector<Type> &target, const vnl_vector<Type> &mean, const vnl_matrix<Type> &covMatrix, vnl_matrix<Type> &invCovMatrix)
531 {
532  vnl_matrix<Type> dataInvCovariance = vnl_matrix_inverse<Type>(covMatrix);
533 
534  invCovMatrix = dataInvCovariance;
535 
536  return MahalanobisDistance(target, mean, invCovMatrix);
537 }
538 
539 #ifndef ITK_ONLY
540 template<class Type>
541 Type Math<Type>::MeanSquaredError(vtkPoints *sourcePoints, vtkPoints *targetPoints)
542 {
543  const vnl_size_t numberOfPoints = sourcePoints->GetNumberOfPoints();
544  Type mse = 0.0;
545 
546  for (vnl_size_t v = 0; v < numberOfPoints; v ++)
547  {
548  coordinate p( sourcePoints->GetPoint(v) );
549  coordinate p2( targetPoints->GetPoint(v) );
550 
552  mse += vtkMath::Distance2BetweenPoints(p.data_block(), p2.data_block());
553  }
554  mse /= numberOfPoints;
555 
556  return mse;
557 }
558 #endif
559 #endif
560 
561 #ifdef VTK_ONLY //Code that does not depend on VNL
562 template<class Type>
563 Type Math<Type>::MeanSquaredError(vtkPoints *sourcePoints, vtkPoints *targetPoints)
564 {
565  const size_t numberOfPoints = sourcePoints->GetNumberOfPoints();
566  Type mse = 0.0;
567 
568  for (size_t v = 0; v < numberOfPoints; v ++)
569  {
570  Type p[3], p2[3];
571  sourcePoints->GetPoint(v, p);
572  targetPoints->GetPoint(v, p2);
573 
575  mse += vtkMath::Distance2BetweenPoints(p, p2)/numberOfPoints;
576  }
577 
578  return mse;
579 }
580 #endif
581 
582 } //end namespace milx
583 
584 #endif //__MILXMATH_H
static Type Centroid(const vnl_vector< Type > &data)
Compute the centroid (or the mean) of a data vector.
Definition: milxMath.h:177
static Type MeanSquaredError(vtkPoints *sourcePoints, vtkPoints *targetPoints)
Compute the MSE of the given points sets.
Definition: milxMath.h:541
A general math object for computing common operations such a centroids etc.
Definition: milxMath.h:44
#define SMILI_EXPORT
DLL Function Symbol for Windows. It is empty for other OSes.
Definition: milxGlobal.h:227
static vnl_matrix< Type > CovarianceMatrix(vnl_vector< Type > sourceVector)
Compute the covariance matrix from a vector. EXPERIMENTAL.
Definition: milxMath.h:310
static Type CentroidSize(const vnl_matrix< Type > &data, const vnl_vector< Type > &centroid, bool norm=false)
Compute the centroid size or scale for a series of points.
Definition: milxMath.h:206
static Type MahalanobisDistance(const vnl_vector< Type > &source, const vnl_vector< Type > &target)
Compute the Mahalanobis distance between two vectors with an unknown covariance matrix. EXPERIMENTAL.
Definition: milxMath.h:423