1 /* Distributions.cpp
2 *
3 * Copyright (C) 1997-2012,2014,2015,2016,2017 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
19 #include "Distributions.h"
20
21 Thing_implement (Distributions, TableOfReal, 0);
22
v_info()23 void structDistributions :: v_info () {
24 structDaata :: v_info ();
25 MelderInfo_writeLine (U"Number of distributions: ", numberOfColumns);
26 MelderInfo_writeLine (U"Number of values: ", numberOfRows);
27 }
28
Distributions_create(integer numberOfRows,integer numberOfColumns)29 autoDistributions Distributions_create (integer numberOfRows, integer numberOfColumns) {
30 try {
31 autoDistributions me = Thing_new (Distributions);
32 TableOfReal_init (me.get(), numberOfRows, numberOfColumns);
33 return me;
34 } catch (MelderError) {
35 Melder_throw (U"Distributions not created.");
36 }
37 }
38
Distributions_checkSpecifiedColumnNumberWithinRange(Distributions me,integer columnNumber)39 void Distributions_checkSpecifiedColumnNumberWithinRange (Distributions me, integer columnNumber) {
40 if (columnNumber < 1)
41 Melder_throw (me, U": the specified column number is ", columnNumber, U", but should be at least 1.");
42 if (columnNumber > my numberOfColumns)
43 Melder_throw (me, U": the specified column number is ", columnNumber, U", but should be at most my number of columns (", my numberOfColumns, U").");
44 }
45
Distributions_peek(Distributions me,integer column,conststring32 * out_string,integer * out_number)46 void Distributions_peek (Distributions me, integer column, conststring32 *out_string, integer *out_number) {
47 Distributions_checkSpecifiedColumnNumberWithinRange (me, column);
48 if (my numberOfRows < 1)
49 Melder_throw (me, U": I have no candidates.");
50 longdouble total = 0.0;
51 for (integer irow = 1; irow <= my numberOfRows; irow ++) {
52 total += (longdouble) my data [irow] [column];
53 }
54 if (total <= 0.0)
55 Melder_throw (me, U": the total weight of column ", column, U" is not positive.");
56 integer irow;
57 do {
58 double rand = NUMrandomUniform (0, (double) total);
59 longdouble sum = 0.0;
60 for (irow = 1; irow <= my numberOfRows; irow ++) {
61 sum += my data [irow] [column];
62 if (rand <= sum) break;
63 }
64 } while (irow > my numberOfRows); // guard against rounding errors
65 if (! my rowLabels [irow])
66 Melder_throw (me, U": no string in row ", irow, U".");
67 if (out_string)
68 *out_string = my rowLabels [irow].get();
69 if (out_number)
70 *out_number = irow;
71 }
72
Distributions_getProbability(Distributions me,conststring32 string,integer column)73 double Distributions_getProbability (Distributions me, conststring32 string, integer column) {
74 integer row, rowOfString = 0;
75 longdouble total = 0.0;
76 if (column < 1 || column > my numberOfColumns) return undefined;
77 for (row = 1; row <= my numberOfRows; row ++) {
78 total += my data [row] [column];
79 if (my rowLabels [row] && str32equ (my rowLabels [row].get(), string))
80 rowOfString = row;
81 }
82 if (total <= 0.0) return undefined;
83 if (rowOfString == 0) return 0.0;
84 return my data [rowOfString] [column] / (double) total;
85 }
86
Distributionses_getMeanAbsoluteDifference(Distributions me,Distributions thee,integer column)87 double Distributionses_getMeanAbsoluteDifference (Distributions me, Distributions thee, integer column) {
88 if (column < 1 || column > my numberOfColumns || column > thy numberOfColumns ||
89 my numberOfRows != thy numberOfRows) return undefined;
90 longdouble total = 0.0;
91 for (integer irow = 1; irow <= my numberOfRows; irow ++) {
92 total += (longdouble) fabs (my data [irow] [column] - thy data [irow] [column]);
93 }
94 return (double) total / my numberOfRows;
95 }
96
unicize(Distributions me)97 static void unicize (Distributions me) {
98 /* Must have been sorted beforehand. */
99 integer nrow = 0, ifrom = 1;
100 for (integer irow = 1; irow <= my numberOfRows; irow ++) {
101 if (irow == my numberOfRows || !! my rowLabels [irow] != !! my rowLabels [irow + 1] ||
102 my rowLabels [irow] && ! str32equ (my rowLabels [irow].get(), my rowLabels [irow + 1].get()))
103 {
104 /*
105 Detected a change.
106 */
107 nrow ++;
108 integer ito = irow;
109 /*
110 Move row 'ifrom' to 'nrow'. May be the same row.
111 */
112 if (ifrom != nrow) {
113 my rowLabels [nrow] = my rowLabels [ifrom].move();
114 for (integer icol = 1; icol <= my numberOfColumns; icol ++)
115 my data [nrow] [icol] = my data [ifrom] [icol];
116 }
117 /*
118 Purge rows from 'ifrom'+1 to 'ito'.
119 */
120 for (integer j = ifrom + 1; j <= ito; j ++) {
121 my rowLabels [j]. reset();
122 for (integer icol = 1; icol <= my numberOfColumns; icol ++)
123 my data [nrow] [icol] += my data [j] [icol];
124 }
125 ifrom = ito + 1;
126 }
127 }
128 my numberOfRows = nrow;
129 }
130
Distributions_addTwo(Distributions me,Distributions thee)131 autoDistributions Distributions_addTwo (Distributions me, Distributions thee) {
132 try {
133 autoDistributions him = TablesOfReal_append (me, thee).static_cast_move<structDistributions>();
134 TableOfReal_sortByLabel (him.get(), 0, 0);
135 unicize (him.get());
136 return him;
137 } catch (MelderError) {
138 Melder_throw (me, U" & ", thee, U": not added.");
139 }
140 }
141
Distributions_addMany(OrderedOf<structDistributions> * me)142 autoDistributions Distributions_addMany (OrderedOf<structDistributions>* me) {
143 try {
144 autoDistributions thee = TablesOfReal_appendMany ((OrderedOf<structTableOfReal>*) me).static_cast_move<structDistributions>(); // FIXME cast
145 TableOfReal_sortByLabel (thee.get(), 0, 0);
146 unicize (thee.get());
147 return thee;
148 } catch (MelderError) {
149 Melder_throw (U"Distributions objects not added.");
150 }
151 }
152
153 /* End of file Distributions.cpp */
154