Proximity.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /* Proximity.cpp
  2. *
  3. * Copyright (C) 1993-2018 David Weenink
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /*
  19. djmw 20020813 GPL header
  20. djmw 20040309 Removed assertion 'numberOfPoints> 0' in Proximity_init
  21. */
  22. #include "Configuration.h"
  23. #include "Distance.h"
  24. #include "Proximity_and_Distance.h"
  25. #include "TableOfReal_extensions.h"
  26. #include "NUM2.h"
  27. Thing_implement (Proximity, TableOfReal, 0);
  28. void Proximity_init (Proximity me, integer numberOfPoints) {
  29. TableOfReal_init (me, numberOfPoints, numberOfPoints);
  30. TableOfReal_setSequentialRowLabels (me, 0, 0, nullptr, 1, 1);
  31. TableOfReal_setSequentialColumnLabels (me, 0, 0, nullptr, 1, 1);
  32. }
  33. Thing_implement (Dissimilarity, Proximity, 0);
  34. static double Dissimilarity_getAverage (Dissimilarity me) {
  35. longdouble sum = 0.0;
  36. integer numberOfPositives = 0;
  37. for (integer i = 1; i <= my numberOfRows - 1; i ++) {
  38. for (integer j = i + 1; j <= my numberOfRows; j ++) {
  39. double proximity = 0.5 * (my data [i] [j] + my data [j] [i]);
  40. if (proximity > 0.0) {
  41. numberOfPositives ++;
  42. sum += proximity;
  43. }
  44. }
  45. }
  46. return numberOfPositives > 0 ? (double) sum / numberOfPositives : undefined;
  47. }
  48. autoDissimilarity Dissimilarity_create (integer numberOfPoints) {
  49. try {
  50. autoDissimilarity me = Thing_new (Dissimilarity);
  51. Proximity_init (me.get(), numberOfPoints);
  52. return me;
  53. } catch (MelderError) {
  54. Melder_throw (U"Dissimilarity not created.");
  55. }
  56. }
  57. autoDissimilarity Dissimilarity_createLetterRExample (double noiseStd) {
  58. try {
  59. autoConfiguration r = Configuration_createLetterRExample (1);
  60. autoDistance d = Configuration_to_Distance (r.get());
  61. autoDissimilarity me = Distance_to_Dissimilarity (d.get());
  62. Thing_setName (me.get(), U"R");
  63. for (integer i = 1; i <= my numberOfRows - 1; i ++) {
  64. for (integer j = i + 1; j <= my numberOfRows; j ++) {
  65. double dis = my data [i] [j];
  66. my data [j] [i] = my data [i] [j] = dis * dis + 5.0 + NUMrandomUniform (0.0, noiseStd);
  67. }
  68. }
  69. return me;
  70. } catch (MelderError) {
  71. Melder_throw (U"Dissimilarity for letter R example not created.");
  72. }
  73. }
  74. double Dissimilarity_getAdditiveConstant (Dissimilarity me) {
  75. double additiveConstant = undefined;
  76. try {
  77. integer nPoints = my numberOfRows, nPoints2 = 2 * nPoints;
  78. Melder_require (nPoints > 0, U"Matrix part should not be empty.");
  79. // Return c = average dissimilarity in case of failure
  80. additiveConstant = Dissimilarity_getAverage (me);
  81. Melder_require (isdefined (additiveConstant), U"There are no positive dissimilarities.");
  82. autoMAT wd (nPoints, nPoints, kTensorInitializationType::ZERO);
  83. autoMAT wdsqrt (nPoints, nPoints, kTensorInitializationType::ZERO);
  84. // The matrices D & D1/2 with distances (squared and linear)
  85. for (integer i = 1; i <= nPoints - 1; i ++) {
  86. for (integer j = i + 1; j <= nPoints; j ++) {
  87. double proximity = (my data [i] [j] + my data [j] [i]) / 2.0;
  88. wdsqrt [j] [i] = wdsqrt [i] [j] = - proximity / 2.0; // djmw 20180830
  89. wd [j] [i] = wd [i] [j] = - proximity * proximity / 2.0;
  90. }
  91. }
  92. MATdoubleCentre_inplace (wdsqrt.get());
  93. MATdoubleCentre_inplace (wd.get());
  94. // Calculate the B matrix according to eq. 6
  95. autoMAT b (nPoints2, nPoints2, kTensorInitializationType::ZERO);
  96. for (integer i = 1; i <= nPoints; i ++) {
  97. for (integer j = 1; j <= nPoints; j ++) {
  98. b [i] [nPoints + j] = 2.0 * wd [i] [j];
  99. b [nPoints + i] [nPoints + j] = -4.0 * wdsqrt [i] [j];
  100. b [nPoints + i] [i] = -1.0;
  101. }
  102. }
  103. // Get eigenvalues
  104. autoVEC eigenvalues_re, eigenvalues_im;
  105. MAT_getEigenSystemFromGeneralMatrix (b.get(), nullptr, nullptr, & eigenvalues_re, & eigenvalues_im);
  106. // Get largest real eigenvalue
  107. double largestEigenvalue = - fabs (eigenvalues_re [1]);
  108. integer numberOfRealEigenvalues = 0;
  109. for (integer i = 1; i <= nPoints2; i ++) {
  110. if (eigenvalues_im [i] == 0.0) {
  111. ++ numberOfRealEigenvalues;
  112. if (eigenvalues_re [i] > largestEigenvalue)
  113. largestEigenvalue = eigenvalues_re [i];
  114. }
  115. }
  116. Melder_require (largestEigenvalue >= 0, U"The largest eigenvalue should not be negative.");
  117. additiveConstant = largestEigenvalue;
  118. return additiveConstant;
  119. } catch (MelderError) {
  120. Melder_throw (U"Additive constant not calculated.");
  121. }
  122. }
  123. autoSimilarity Similarity_create (integer numberOfPoints) {
  124. try {
  125. autoSimilarity me = Thing_new (Similarity);
  126. Proximity_init (me.get(), numberOfPoints);
  127. return me;
  128. } catch (MelderError) {
  129. Melder_throw (U"Similarity not created.");
  130. }
  131. }
  132. /* End of file Proximity.cpp */