annotate sample.cpp @ 279:dee55886eca0 sampling

make the RNG a part of the audioDB object. Easier to deal with memory discipline and initialization (though note the FIXME comment in audioDB::initTables()). Also initialize the RNG from the current time. A mature implementation would use a proper source of entropy...
author mas01cr
date Wed, 02 Jul 2008 13:53:23 +0000
parents d9dba57becd4
children
rev   line source
mas01cr@266 1 #include "audioDB.h"
mas01cr@266 2
mas01cr@268 3 #include <gsl/gsl_sf.h>
mas01cr@278 4 #include <gsl/gsl_rng.h>
mas01cr@268 5
mas01cr@276 6 static
mas01cr@273 7 double yfun(double d) {
mas01cr@268 8 return gsl_sf_log(d) - gsl_sf_psi(d);
mas01cr@268 9 }
mas01cr@276 10
mas01cr@276 11 static
mas01cr@273 12 double yinv(double y) {
mas01cr@268 13 double a = 1.0e-5;
mas01cr@268 14 double b = 1000.0;
mas01cr@268 15
mas01cr@268 16 double ay = yfun(a);
mas01cr@268 17 double by = yfun(b);
mas01cr@268 18
mas01cr@268 19 double c, cy;
mas01cr@268 20
mas01cr@276 21 /* FIXME: simple binary search; there's probably some clever solver
mas01cr@276 22 in gsl somewhere which is less sucky. */
mas01cr@268 23 while ((b - a) > 1.0e-5) {
mas01cr@268 24 c = (a + b) / 2;
mas01cr@268 25 cy = yfun(c);
mas01cr@268 26 if (cy > y) {
mas01cr@268 27 a = c;
mas01cr@268 28 ay = cy;
mas01cr@268 29 } else {
mas01cr@268 30 b = c;
mas01cr@268 31 by = cy;
mas01cr@268 32 }
mas01cr@268 33 }
mas01cr@268 34
mas01cr@268 35 return c;
mas01cr@268 36 }
mas01cr@268 37
mas01cr@279 38 unsigned audioDB::random_track(unsigned *propTable, unsigned total) {
mas01cr@266 39 /* FIXME: make this O(1) by using the alias-rejection method, or
mas01cr@266 40 some other sensible method of sampling from a discrete
mas01cr@266 41 distribution. */
mas01cr@278 42 double thing = gsl_rng_uniform(rng);
mas01cr@266 43 unsigned sofar = 0;
mas01cr@266 44 for (unsigned int i = 0; i < dbH->numFiles; i++) {
mas01cr@266 45 sofar += propTable[i];
mas01cr@266 46 if (thing < ((double) sofar / (double) total)) {
mas01cr@266 47 return i;
mas01cr@266 48 }
mas01cr@266 49 }
mas01cr@266 50 error("fell through in random_track()");
mas01cr@266 51
mas01cr@266 52 /* FIXME: decorate error's declaration so that this isn't necessary */
mas01cr@266 53 return 0;
mas01cr@266 54 }
mas01cr@266 55
mas01cr@266 56 void audioDB::sample(const char *dbName) {
mas01cr@266 57 initTables(dbName, 0);
mas01cr@266 58
mas01cr@266 59 // build track offset table (FIXME: cut'n'pasted from query.cpp)
mas01cr@266 60 off_t *trackOffsetTable = new off_t[dbH->numFiles];
mas01cr@266 61 unsigned cumTrack=0;
mas01cr@266 62 for(unsigned int k = 0; k < dbH->numFiles; k++){
mas01cr@266 63 trackOffsetTable[k] = cumTrack;
mas01cr@266 64 cumTrack += trackTable[k] * dbH->dim;
mas01cr@266 65 }
mas01cr@266 66
mas01cr@266 67 unsigned *propTable = new unsigned[dbH->numFiles];
mas01cr@266 68 unsigned total = 0;
mas01cr@270 69 unsigned count = 0;
mas01cr@266 70
mas01cr@266 71 for (unsigned int i = 0; i < dbH->numFiles; i++) {
mas01cr@266 72 /* what kind of a stupid language doesn't have binary max(), let
mas01cr@266 73 alone nary? */
mas01cr@266 74 unsigned int prop = trackTable[i] - sequenceLength + 1;
mas01cr@266 75 prop = prop > 0 ? prop : 0;
mas01cr@270 76 if (prop > 0)
mas01cr@270 77 count++;
mas01cr@266 78 propTable[i] = prop;
mas01cr@266 79 total += prop;
mas01cr@266 80 }
mas01cr@266 81
mas01cr@266 82 if (total == 0) {
mas01cr@266 83 error("no sequences of this sequence length in the database", dbName);
mas01cr@266 84 }
mas01cr@266 85
mas01cr@266 86 unsigned int vlen = dbH->dim * sequenceLength;
mas01cr@266 87 double *v1 = new double[vlen];
mas01cr@266 88 double *v2 = new double[vlen];
mas01cr@266 89 double v1norm, v2norm, v1v2;
mas01cr@266 90
mas01cr@266 91 double sumdist = 0;
mas01cr@266 92 double sumlogdist = 0;
mas01cr@266 93
mas01cr@270 94 for (unsigned int i = 0; i < nsamples;) {
mas01cr@279 95 unsigned track1 = random_track(propTable, total);
mas01cr@279 96 unsigned track2 = random_track(propTable, total);
mas01cr@266 97
mas01cr@271 98 if(track1 == track2)
mas01cr@271 99 continue;
mas01cr@271 100
mas01cr@278 101 unsigned i1 = gsl_rng_uniform_int(rng, propTable[track1]);
mas01cr@278 102 unsigned i2 = gsl_rng_uniform_int(rng, propTable[track2]);
mas01cr@266 103
mas01cr@266 104 VERB_LOG(1, "%d %d, %d %d | ", track1, i1, track2, i2);
mas01cr@266 105
mas01cr@266 106 /* FIXME: this seeking, reading and distance calculation should
mas01cr@266 107 share more code with the query loop */
mas01cr@266 108 lseek(dbfid, dbH->dataOffset + trackOffsetTable[track1] * sizeof(double) + i1 * dbH->dim * sizeof(double), SEEK_SET);
mas01cr@266 109 read(dbfid, v1, dbH->dim * sequenceLength * sizeof(double));
mas01cr@266 110
mas01cr@266 111 lseek(dbfid, dbH->dataOffset + trackOffsetTable[track2] * sizeof(double) + i2 * dbH->dim * sizeof(double), SEEK_SET);
mas01cr@266 112 read(dbfid, v2, dbH->dim * sequenceLength * sizeof(double));
mas01cr@266 113
mas01cr@266 114 v1norm = 0;
mas01cr@266 115 v2norm = 0;
mas01cr@266 116 v1v2 = 0;
mas01cr@266 117
mas01cr@266 118 for (unsigned int j = 0; j < vlen; j++) {
mas01cr@266 119 v1norm += v1[j]*v1[j];
mas01cr@266 120 v2norm += v2[j]*v2[j];
mas01cr@266 121 v1v2 += v1[j]*v2[j];
mas01cr@266 122 }
mas01cr@266 123
mas01cr@266 124 /* FIXME: we must deal with infinities better than this; there
mas01cr@266 125 could be all sorts of NaNs from arbitrary features. Best
mas01cr@266 126 include power thresholds or something... */
mas01cr@266 127 if(isfinite(v1norm) && isfinite(v2norm) && isfinite(v1v2)) {
mas01cr@266 128
mas01cr@266 129 VERB_LOG(1, "%f %f %f | ", v1norm, v2norm, v1v2);
mas01cr@266 130 /* assume normalizedDistance == true for now */
mas01cr@266 131 /* FIXME: not convinced that the statistics we calculated in
mas01cr@271 132 TASLP paper are technically valid for normalizedDistance */
mas01cr@271 133
mas01cr@269 134 double dist = 2 - 2 * v1v2 / sqrt(v1norm * v2norm);
mas01cr@271 135 // double dist = v1norm + v2norm - 2*v1v2;
mas01cr@271 136
mas01cr@266 137 VERB_LOG(1, "%f %f\n", dist, log(dist));
mas01cr@266 138 sumdist += dist;
mas01cr@266 139 sumlogdist += log(dist);
mas01cr@266 140 i++;
mas01cr@266 141 } else {
mas01cr@273 142 VERB_LOG(1, "infinity/NaN found: %f %f %f\n", v1norm, v2norm, v1v2);
mas01cr@266 143 }
mas01cr@266 144 }
mas01cr@266 145
mas01cr@270 146 /* FIXME: the mean isn't really what we should be reporting here */
mas01cr@270 147 unsigned meanN = total / count;
mas01cr@270 148
mas01cr@270 149 double sigma2 = sumdist / (sequenceLength * dbH->dim * nsamples);
mas01cr@270 150 double d = 2 * yinv(log(sumdist/nsamples) - sumlogdist/nsamples);
mas01cr@268 151
mas01cr@266 152 std::cout << "Summary statistics" << std::endl;
mas01cr@270 153 std::cout << "number of samples: " << nsamples << std::endl;
mas01cr@266 154 std::cout << "sum of distances (S): " << sumdist << std::endl;
mas01cr@266 155 std::cout << "sum of log distances (L): " << sumlogdist << std::endl;
mas01cr@271 156
mas01cr@271 157 /* FIXME: we'll also want some more summary statistics based on
mas01cr@271 158 propTable, for the minimum-of-X estimate */
mas01cr@270 159 std::cout << "mean number of applicable sequences (N): " << meanN << std::endl;
mas01cr@268 160 std::cout << std::endl;
mas01cr@268 161 std::cout << "Estimated parameters" << std::endl;
mas01cr@271 162 std::cout << "sigma^2: " << sigma2 << "; ";
mas01cr@271 163 std::cout << "Msigma^2: " << sumdist / nsamples << std::endl;
mas01cr@268 164 std::cout << "d: " << d << std::endl;
mas01cr@270 165
mas01cr@270 166 double logw = (2 / d) * gsl_sf_log(-gsl_sf_log(0.99));
mas01cr@270 167 double logxthresh = gsl_sf_log(sumdist / nsamples) + logw
mas01cr@270 168 - (2 / d) * gsl_sf_log(meanN)
mas01cr@270 169 - gsl_sf_log(d/2)
mas01cr@270 170 - (2 / d) * gsl_sf_log(2 / d)
mas01cr@270 171 + (2 / d) * gsl_sf_lngamma(d / 2);
mas01cr@270 172
mas01cr@270 173 std::cout << "track xthresh: " << exp(logxthresh) << std::endl;
mas01cr@266 174
mas01cr@266 175 delete[] propTable;
mas01cr@266 176 delete[] v1;
mas01cr@266 177 delete[] v2;
mas01cr@266 178 }