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