Transition.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /* Transition.cpp
  2. *
  3. * Copyright (C) 1997-2012,2015-2018 Paul Boersma
  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.
  13. * See the GNU 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. #include "Transition.h"
  19. #include "NUM2.h"
  20. #include "Eigen.h"
  21. #include "oo_DESTROY.h"
  22. #include "Transition_def.h"
  23. #include "oo_COPY.h"
  24. #include "Transition_def.h"
  25. #include "oo_EQUAL.h"
  26. #include "Transition_def.h"
  27. #include "oo_CAN_WRITE_AS_ENCODING.h"
  28. #include "Transition_def.h"
  29. #include "oo_WRITE_BINARY.h"
  30. #include "Transition_def.h"
  31. #include "oo_READ_TEXT.h"
  32. #include "Transition_def.h"
  33. #include "oo_READ_BINARY.h"
  34. #include "Transition_def.h"
  35. #include "oo_DESCRIPTION.h"
  36. #include "Transition_def.h"
  37. Thing_implement (Transition, Daata, 0);
  38. void structTransition :: v_info () {
  39. structDaata :: v_info ();
  40. MelderInfo_writeLine (U"Number of states: ", numberOfStates);
  41. }
  42. void structTransition :: v_writeText (MelderFile file) {
  43. texputi32 (file, numberOfStates, U"numberOfStates");
  44. MelderFile_write (file, U"\nstateLabels []: ");
  45. if (numberOfStates < 1) MelderFile_write (file, U"(empty)");
  46. MelderFile_write (file, U"\n");
  47. for (integer i = 1; i <= numberOfStates; i ++) {
  48. MelderFile_write (file, U"\"");
  49. if (stateLabels [i]) MelderFile_write (file, stateLabels [i].get());
  50. MelderFile_write (file, U"\"\t");
  51. }
  52. for (integer i = 1; i <= numberOfStates; i ++) {
  53. MelderFile_write (file, U"\nstate [", i, U"]:");
  54. for (integer j = 1; j <= numberOfStates; j ++) {
  55. MelderFile_write (file, U"\t", data [i] [j]);
  56. }
  57. }
  58. }
  59. void Transition_init (Transition me, integer numberOfStates) {
  60. if (numberOfStates < 1)
  61. Melder_throw (U"Cannot create empty matrix.");
  62. my numberOfStates = numberOfStates;
  63. my stateLabels = autostring32vector (numberOfStates);
  64. my data = MATzero (my numberOfStates, my numberOfStates);
  65. }
  66. autoTransition Transition_create (integer numberOfStates) {
  67. try {
  68. autoTransition me = Thing_new (Transition);
  69. Transition_init (me.get(), numberOfStates);
  70. return me;
  71. } catch (MelderError) {
  72. Melder_throw (U"Transition not created.");
  73. }
  74. }
  75. static void NUMrationalize (double x, integer *numerator, integer *denominator) {
  76. double epsilon = 1e-6;
  77. *numerator = 1;
  78. for (*denominator = 1; *denominator <= 100000; (*denominator) ++) {
  79. double numerator_d = x * *denominator, rounded = round (numerator_d);
  80. if (fabs (rounded - numerator_d) < epsilon) {
  81. *numerator = (integer) rounded;
  82. return;
  83. }
  84. }
  85. *denominator = 0; // failure
  86. }
  87. static void print4 (char *buffer, double value, int iformat, int width, int precision) {
  88. char formatString [40];
  89. if (iformat == 4) {
  90. integer numerator, denominator;
  91. NUMrationalize (value, & numerator, & denominator);
  92. if (numerator == 0)
  93. snprintf (buffer, 40, "0");
  94. else if (denominator > 1)
  95. snprintf (buffer, 40, "%s/%s", Melder8_integer (numerator), Melder8_integer (denominator));
  96. else
  97. snprintf (buffer, 40, "%.7g", value);
  98. } else {
  99. snprintf (formatString, 40, "%%%d.%d%c", width, precision, iformat == 1 ? 'f' : iformat == 2 ? 'e' : 'g');
  100. snprintf (buffer, 40, formatString, value);
  101. }
  102. }
  103. void Transition_drawAsNumbers (Transition me, Graphics g, int iformat, int precision) {
  104. double maxTextWidth = 0, maxTextHeight = 0;
  105. Graphics_setInner (g);
  106. Graphics_setWindow (g, 0.5, my numberOfStates + 0.5, 0.0, 1.0);
  107. double leftMargin = Graphics_dxMMtoWC (g, 1.0);
  108. double lineSpacing = Graphics_dyMMtoWC (g, 1.5 * Graphics_inqFontSize (g) * 25.4 / 72.0);
  109. Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_BOTTOM);
  110. for (integer col = 1; col <= my numberOfStates; col ++) {
  111. if (my stateLabels && my stateLabels [col] && my stateLabels [col] [0]) {
  112. Graphics_text (g, col, 1, my stateLabels [col].get());
  113. if (maxTextHeight == 0.0) maxTextHeight = lineSpacing;
  114. }
  115. }
  116. for (integer row = 1; row <= my numberOfStates; row ++) {
  117. double y = 1 - lineSpacing * (row - 1 + 0.7);
  118. Graphics_setTextAlignment (g, Graphics_RIGHT, Graphics_HALF);
  119. if (my stateLabels && my stateLabels [row]) {
  120. double textWidth = Graphics_textWidth (g, my stateLabels [row].get());
  121. if (textWidth > maxTextWidth) maxTextWidth = textWidth;
  122. Graphics_text (g, 0.5 - leftMargin, y, my stateLabels [row].get());
  123. }
  124. Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
  125. for (integer col = 1; col <= my numberOfStates; col ++) {
  126. char text [40];
  127. print4 (text, my data [row] [col], iformat, 0, precision);
  128. Graphics_text (g, col, y, Melder_peek8to32 (text));
  129. }
  130. }
  131. if (maxTextWidth != 0.0)
  132. Graphics_line (g, 0.5 - maxTextWidth - leftMargin, 1, my numberOfStates + 0.5, 1);
  133. if (maxTextHeight != 0.0)
  134. Graphics_line (g, 0.5, 1 + maxTextHeight, 0.5, 1 - lineSpacing * (my numberOfStates + 0.2));
  135. Graphics_unsetInner (g);
  136. }
  137. static void Transition_transpose (Transition me) {
  138. for (integer i = 1; i < my numberOfStates; i ++) {
  139. for (integer j = i + 1; j <= my numberOfStates; j ++) {
  140. double temp = my data [i] [j];
  141. my data [i] [j] = my data [j] [i];
  142. my data [j] [i] = temp;
  143. }
  144. }
  145. }
  146. void Transition_eigen (Transition me, autoMatrix *out_eigenvectors, autoMatrix *out_eigenvalues) {
  147. bool transposed = false;
  148. try {
  149. autoEigen eigen = Thing_new (Eigen);
  150. Transition_transpose (me);
  151. Eigen_initFromSymmetricMatrix (eigen.get(), my data.get());
  152. Transition_transpose (me);
  153. transposed = true;
  154. autoMatrix eigenvectors = Matrix_createSimple (my numberOfStates, my numberOfStates);
  155. autoMatrix eigenvalues = Matrix_createSimple (my numberOfStates, 1);
  156. for (integer i = 1; i <= my numberOfStates; i ++) {
  157. eigenvalues -> z [i] [1] = eigen -> eigenvalues [i];
  158. for (integer j = 1; j <= my numberOfStates; j ++)
  159. eigenvectors -> z [i] [j] = eigen -> eigenvectors [j] [i];
  160. }
  161. *out_eigenvectors = eigenvectors.move();
  162. *out_eigenvalues = eigenvalues.move();
  163. } catch (MelderError) {
  164. if (transposed)
  165. Transition_transpose (me);
  166. Melder_throw (me, U": eigenvectors not computed.");
  167. }
  168. }
  169. autoTransition Transition_power (Transition me, integer power) {
  170. try {
  171. autoTransition thee = Data_copy (me);
  172. autoTransition him = Data_copy (me);
  173. for (integer ipow = 2; ipow <= power; ipow ++) {
  174. std::swap (his data.at, thy data.at); // OPTIMIZE
  175. for (integer irow = 1; irow <= my numberOfStates; irow ++) {
  176. for (integer icol = 1; icol <= my numberOfStates; icol ++) {
  177. thy data [irow] [icol] = 0.0;
  178. for (integer i = 1; i <= my numberOfStates; i ++) {
  179. thy data [irow] [icol] += his data [irow] [i] * my data [i] [icol];
  180. }
  181. }
  182. }
  183. }
  184. return thee;
  185. } catch (MelderError) {
  186. Melder_throw (me, U": power not computed.");
  187. }
  188. }
  189. autoMatrix Transition_to_Matrix (Transition me) {
  190. try {
  191. autoMatrix thee = Matrix_createSimple (my numberOfStates, my numberOfStates);
  192. for (integer i = 1; i <= my numberOfStates; i ++)
  193. for (integer j = 1; j <= my numberOfStates; j ++)
  194. thy z [i] [j] = my data [i] [j];
  195. return thee;
  196. } catch (MelderError) {
  197. Melder_throw (me, U": not converted to Matrix.");
  198. }
  199. }
  200. autoTransition Matrix_to_Transition (Matrix me) {
  201. try {
  202. if (my nx != my ny)
  203. Melder_throw (U"Matrix should be square.");
  204. autoTransition thee = Transition_create (my nx);
  205. for (integer i = 1; i <= my nx; i ++)
  206. for (integer j = 1; j <= my nx; j ++)
  207. thy data [i] [j] = my z [i] [j];
  208. return thee;
  209. } catch (MelderError) {
  210. Melder_throw (me, U": not converted to Transition.");
  211. }
  212. }
  213. /* End of file Transition.cpp */