mas01mc@292: #ifndef __REPORTER_H mas01mc@292: #define __REPORTER_H mas01mc@292: mas01cr@239: #include mas01cr@239: #include mas01cr@239: #include mas01cr@239: #include mas01mc@292: #include mas01mc@292: #include "ReporterBase.h" mas01mc@292: #include "audioDB.h" mas01cr@239: mas01cr@239: typedef struct nnresult { mas01cr@239: unsigned int trackID; mas01cr@239: double dist; mas01cr@239: unsigned int qpos; mas01cr@239: unsigned int spos; mas01cr@239: } NNresult; mas01cr@239: mas01cr@239: typedef struct radresult { mas01cr@239: unsigned int trackID; mas01cr@239: unsigned int count; mas01cr@239: } Radresult; mas01cr@239: mas01cr@239: bool operator< (const NNresult &a, const NNresult &b) { mas01cr@239: return a.dist < b.dist; mas01cr@239: } mas01cr@239: mas01cr@239: bool operator> (const NNresult &a, const NNresult &b) { mas01cr@239: return a.dist > b.dist; mas01cr@239: } mas01cr@239: mas01cr@239: bool operator< (const Radresult &a, const Radresult &b) { mas01cr@239: return a.count < b.count; mas01cr@239: } mas01cr@239: mas01mc@275: bool operator> (const Radresult &a, const Radresult &b) { mas01mc@275: return a.count > b.count; mas01mc@275: } mas01mc@275: mas01mc@292: class Reporter : public ReporterBase { mas01cr@239: public: mas01cr@239: virtual ~Reporter() {}; mas01cr@239: virtual void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist) = 0; mas01cr@239: // FIXME: this interface is a bit wacky: a relic of previous, more mas01cr@239: // confused times. Really it might make sense to have separate mas01cr@239: // reporter classes for WS and for stdout, rather than passing this mas01cr@498: // adbQueryResponse thing everywhere; the adb argument is there mas01cr@498: // solely for converting trackIDs into names. -- CSR, 2007-12-10. mas01cr@508: virtual void report(adb_t *adb, struct soap *soap, void* adbQueryResponse) = 0; mas01cr@239: }; mas01cr@239: mas01cr@239: template class pointQueryReporter : public Reporter { mas01cr@239: public: mas01cr@239: pointQueryReporter(unsigned int pointNN); mas01cr@239: ~pointQueryReporter(); mas01cr@239: void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist); mas01cr@508: void report(adb_t *adb, struct soap *soap, void* adbQueryResponse); mas01cr@239: private: mas01cr@239: unsigned int pointNN; mas01cr@239: std::priority_queue< NNresult, std::vector< NNresult >, T> *queue; mas01cr@239: }; mas01cr@239: mas01cr@239: template pointQueryReporter::pointQueryReporter(unsigned int pointNN) mas01cr@239: : pointNN(pointNN) { mas01cr@239: queue = new std::priority_queue< NNresult, std::vector< NNresult >, T>; mas01cr@239: } mas01cr@239: mas01cr@239: template pointQueryReporter::~pointQueryReporter() { mas01cr@239: delete queue; mas01cr@239: } mas01cr@239: mas01cr@239: template void pointQueryReporter::add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist) { mas01cr@242: if (!isnan(dist)) { mas01cr@242: NNresult r; mas01cr@242: r.trackID = trackID; mas01cr@242: r.qpos = qpos; mas01cr@242: r.spos = spos; mas01cr@242: r.dist = dist; mas01cr@242: queue->push(r); mas01cr@242: if(queue->size() > pointNN) { mas01cr@242: queue->pop(); mas01cr@242: } mas01cr@239: } mas01cr@239: } mas01cr@239: mas01cr@508: template void pointQueryReporter::report(adb_t *adb, struct soap *soap, void *adbQueryResponse) { mas01cr@239: NNresult r; mas01cr@239: std::vector v; mas01cr@239: unsigned int size = queue->size(); mas01cr@239: for(unsigned int k = 0; k < size; k++) { mas01cr@239: r = queue->top(); mas01cr@239: v.push_back(r); mas01cr@239: queue->pop(); mas01cr@239: } mas01cr@239: std::vector::reverse_iterator rit; mas01cr@239: mas01cr@239: if(adbQueryResponse==0) { mas01cr@239: for(rit = v.rbegin(); rit < v.rend(); rit++) { mas01cr@239: r = *rit; mas01cr@498: if(adb) mas01cr@498: std::cout << audiodb_index_key(adb, r.trackID) << " "; mas01mc@292: else mas01mc@292: std::cout << r.trackID << " "; mas01cr@239: std::cout << r.dist << " " << r.qpos << " " << r.spos << std::endl; mas01cr@239: } mas01cr@239: } else { mas01cr@498: adb__queryResponse *response = (adb__queryResponse *) adbQueryResponse; mas01cr@498: response->result.__sizeRlist=size; mas01cr@498: response->result.__sizeDist=size; mas01cr@498: response->result.__sizeQpos=size; mas01cr@498: response->result.__sizeSpos=size; mas01cr@508: response->result.Rlist= (char **) soap_malloc(soap, size * sizeof(char *)); mas01cr@508: response->result.Dist = (double *) soap_malloc(soap, size * sizeof(double)); mas01cr@508: response->result.Qpos = (unsigned int *) soap_malloc(soap, size * sizeof(unsigned int)); mas01cr@508: response->result.Spos = (unsigned int *) soap_malloc(soap, size * sizeof(unsigned int)); mas01cr@239: unsigned int k = 0; mas01cr@239: for(rit = v.rbegin(); rit < v.rend(); rit++, k++) { mas01cr@239: r = *rit; mas01cr@508: response->result.Rlist[k] = (char *) soap_malloc(soap, O2_MAXFILESTR); mas01cr@498: response->result.Dist[k] = r.dist; mas01cr@498: response->result.Qpos[k] = r.qpos; mas01cr@498: response->result.Spos[k] = r.spos; mas01cr@498: if(adb) mas01cr@498: snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID)); mas01mc@292: else mas01cr@498: snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID); mas01cr@239: } mas01cr@239: } mas01cr@239: } mas01cr@239: mas01cr@239: template class trackAveragingReporter : public Reporter { mas01cr@239: public: mas01cr@239: trackAveragingReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles); mas01cr@239: ~trackAveragingReporter(); mas01cr@239: void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist); mas01cr@508: void report(adb_t *adb, struct soap *soap, void *adbQueryResponse); mas01mc@249: protected: mas01cr@239: unsigned int pointNN; mas01cr@239: unsigned int trackNN; mas01cr@239: unsigned int numFiles; mas01cr@239: std::priority_queue< NNresult, std::vector< NNresult>, T > *queues; mas01cr@239: }; mas01cr@239: mas01cr@239: template trackAveragingReporter::trackAveragingReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles) mas01cr@239: : pointNN(pointNN), trackNN(trackNN), numFiles(numFiles) { mas01cr@239: queues = new std::priority_queue< NNresult, std::vector< NNresult>, T >[numFiles]; mas01cr@239: } mas01cr@239: mas01cr@239: template trackAveragingReporter::~trackAveragingReporter() { mas01cr@239: delete [] queues; mas01cr@239: } mas01cr@239: mas01cr@239: template void trackAveragingReporter::add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist) { mas01cr@242: if (!isnan(dist)) { mas01cr@242: NNresult r; mas01cr@242: r.trackID = trackID; mas01cr@242: r.qpos = qpos; mas01cr@242: r.spos = spos; mas01cr@242: r.dist = dist; mas01cr@242: queues[trackID].push(r); mas01cr@242: if(queues[trackID].size() > pointNN) { mas01cr@242: queues[trackID].pop(); mas01cr@242: } mas01cr@239: } mas01cr@239: } mas01cr@239: mas01cr@508: template void trackAveragingReporter::report(adb_t *adb, struct soap *soap, void *adbQueryResponse) { mas01cr@239: std::priority_queue < NNresult, std::vector< NNresult>, T> result; mas01cr@239: for (int i = numFiles-1; i >= 0; i--) { mas01cr@239: unsigned int size = queues[i].size(); mas01cr@239: if (size > 0) { mas01cr@239: NNresult r; mas01cr@239: double dist = 0; mas01cr@239: NNresult oldr = queues[i].top(); mas01cr@239: for (unsigned int j = 0; j < size; j++) { mas01cr@239: r = queues[i].top(); mas01cr@239: dist += r.dist; mas01cr@239: queues[i].pop(); mas01cr@239: if (r.dist == oldr.dist) { mas01cr@239: r.qpos = oldr.qpos; mas01cr@239: r.spos = oldr.spos; mas01cr@239: } else { mas01cr@239: oldr = r; mas01cr@239: } mas01cr@239: } mas01cr@239: dist /= size; mas01cr@239: r.dist = dist; // trackID, qpos and spos are magically right already. mas01cr@239: result.push(r); mas01cr@239: if (result.size() > trackNN) { mas01cr@239: result.pop(); mas01cr@239: } mas01cr@239: } mas01cr@239: } mas01cr@239: mas01cr@239: NNresult r; mas01cr@239: std::vector v; mas01cr@239: unsigned int size = result.size(); mas01cr@239: for(unsigned int k = 0; k < size; k++) { mas01cr@239: r = result.top(); mas01cr@239: v.push_back(r); mas01cr@239: result.pop(); mas01cr@239: } mas01cr@239: std::vector::reverse_iterator rit; mas01cr@239: mas01cr@239: if(adbQueryResponse==0) { mas01cr@239: for(rit = v.rbegin(); rit < v.rend(); rit++) { mas01cr@239: r = *rit; mas01cr@498: if(adb) mas01cr@498: std::cout << audiodb_index_key(adb, r.trackID) << " "; mas01mc@292: else mas01mc@292: std::cout << r.trackID << " "; mas01cr@239: std::cout << r.dist << " " << r.qpos << " " << r.spos << std::endl; mas01cr@239: } mas01cr@239: } else { mas01cr@498: adb__queryResponse *response = (adb__queryResponse *) adbQueryResponse; mas01cr@498: response->result.__sizeRlist=size; mas01cr@498: response->result.__sizeDist=size; mas01cr@498: response->result.__sizeQpos=size; mas01cr@498: response->result.__sizeSpos=size; mas01cr@508: response->result.Rlist= (char **) soap_malloc(soap, size * sizeof(char *)); mas01cr@508: response->result.Dist = (double *) soap_malloc(soap, size * sizeof(double)); mas01cr@508: response->result.Qpos = (unsigned int *) soap_malloc(soap, size * sizeof(unsigned int)); mas01cr@508: response->result.Spos = (unsigned int *) soap_malloc(soap, size * sizeof(unsigned int)); mas01cr@239: unsigned int k = 0; mas01cr@239: for(rit = v.rbegin(); rit < v.rend(); rit++, k++) { mas01cr@239: r = *rit; mas01cr@508: response->result.Rlist[k] = (char *) soap_malloc(soap, O2_MAXFILESTR); mas01cr@498: response->result.Dist[k] = r.dist; mas01cr@498: response->result.Qpos[k] = r.qpos; mas01cr@498: response->result.Spos[k] = r.spos; mas01cr@498: if(adb) mas01cr@498: snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID)); mas01mc@292: else mas01cr@498: snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID); mas01cr@239: } mas01cr@239: } mas01cr@239: } mas01cr@239: mas01mc@249: // Another type of trackAveragingReporter that reports all pointNN nearest neighbours mas01mc@249: template class trackSequenceQueryNNReporter : public trackAveragingReporter { mas01mc@249: protected: mas01mc@249: using trackAveragingReporter::numFiles; mas01mc@249: using trackAveragingReporter::queues; mas01mc@249: using trackAveragingReporter::trackNN; mas01mc@249: using trackAveragingReporter::pointNN; mas01mc@248: public: mas01mc@248: trackSequenceQueryNNReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles); mas01cr@508: void report(adb_t *adb, struct soap *soap, void *adbQueryResponse); mas01mc@248: }; mas01mc@248: mas01mc@249: template trackSequenceQueryNNReporter::trackSequenceQueryNNReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles) mas01mc@249: :trackAveragingReporter(pointNN, trackNN, numFiles){} mas01mc@248: mas01cr@508: template void trackSequenceQueryNNReporter::report(adb_t *adb, struct soap *soap, void *adbQueryResponse) { mas01mc@248: std::priority_queue < NNresult, std::vector< NNresult>, T> result; mas01mc@292: std::priority_queue< NNresult, std::vector< NNresult>, std::less > *point_queues mas01mc@292: = new std::priority_queue< NNresult, std::vector< NNresult>, std::less >[numFiles]; mas01mc@249: mas01mc@248: for (int i = numFiles-1; i >= 0; i--) { mas01mc@248: unsigned int size = queues[i].size(); mas01mc@248: if (size > 0) { mas01mc@248: NNresult r; mas01mc@248: double dist = 0; mas01mc@248: NNresult oldr = queues[i].top(); mas01mc@248: for (unsigned int j = 0; j < size; j++) { mas01mc@248: r = queues[i].top(); mas01mc@248: dist += r.dist; mas01mc@248: point_queues[i].push(r); mas01mc@249: queues[i].pop(); mas01mc@248: if (r.dist == oldr.dist) { mas01mc@248: r.qpos = oldr.qpos; mas01mc@248: r.spos = oldr.spos; mas01mc@248: } else { mas01mc@248: oldr = r; mas01mc@248: } mas01mc@248: } mas01mc@248: dist /= size; mas01mc@248: r.dist = dist; // trackID, qpos and spos are magically right already. mas01mc@248: result.push(r); mas01mc@248: if (result.size() > trackNN) { mas01mc@248: result.pop(); mas01mc@248: } mas01mc@248: } mas01mc@248: } mas01mc@248: mas01mc@248: NNresult r; mas01mc@248: std::vector v; mas01mc@248: unsigned int size = result.size(); mas01mc@248: for(unsigned int k = 0; k < size; k++) { mas01mc@248: r = result.top(); mas01mc@248: v.push_back(r); mas01mc@248: result.pop(); mas01mc@248: } mas01mc@248: std::vector::reverse_iterator rit; mas01mc@264: std::priority_queue< NNresult, std::vector< NNresult>, std::greater > point_queue; mas01mc@324: NNresult rk; mas01mc@264: mas01mc@248: if(adbQueryResponse==0) { mas01mc@248: for(rit = v.rbegin(); rit < v.rend(); rit++) { mas01mc@248: r = *rit; mas01cr@498: if(adb) mas01cr@498: std::cout << audiodb_index_key(adb, r.trackID) << " "; mas01mc@292: else mas01mc@292: std::cout << r.trackID << " "; mas01cr@498: std::cout << r.dist << std::endl; mas01mc@264: unsigned int qsize = point_queues[r.trackID].size(); mas01mc@264: // Reverse the order of the points stored in point_queues mas01mc@264: for(unsigned int k=0; k < qsize; k++){ mas01mc@264: point_queue.push( point_queues[r.trackID].top() ); mas01mc@264: point_queues[r.trackID].pop(); mas01mc@264: } mas01mc@264: mas01mc@264: for(unsigned int k = 0; k < qsize; k++) { mas01mc@324: rk = point_queue.top(); mas01mc@248: std::cout << rk.dist << " " << rk.qpos << " " << rk.spos << std::endl; mas01mc@264: point_queue.pop(); mas01mc@248: } mas01mc@248: } mas01mc@248: } else { mas01cr@498: adb__queryResponse *response = (adb__queryResponse *) adbQueryResponse; mas01cr@498: response->result.__sizeRlist=size*pointNN; mas01cr@498: response->result.__sizeDist=size*pointNN; mas01cr@498: response->result.__sizeQpos=size*pointNN; mas01cr@498: response->result.__sizeSpos=size*pointNN; mas01cr@508: response->result.Rlist= (char **) soap_malloc(soap, size * pointNN * sizeof(char *)); mas01cr@508: response->result.Dist = (double *) soap_malloc(soap, size * pointNN * sizeof(double)); mas01cr@508: response->result.Qpos = (unsigned int *) soap_malloc(soap, size * pointNN * sizeof(unsigned int)); mas01cr@508: response->result.Spos = (unsigned int *) soap_malloc(soap, size * pointNN * sizeof(unsigned int)); mas01mc@248: unsigned int k = 0; mas01mc@324: // Loop over returned tracks mas01mc@324: for(rit = v.rbegin(); rit < v.rend(); rit++) { mas01mc@248: r = *rit; mas01mc@324: // Reverse the order of the points stored in point_queues mas01mc@324: unsigned int qsize=point_queues[r.trackID].size(); mas01mc@324: while(qsize--){ mas01mc@324: point_queue.push(point_queues[r.trackID].top()); mas01mc@324: point_queues[r.trackID].pop(); mas01mc@324: } mas01mc@324: qsize=point_queue.size(); mas01mc@324: unsigned int numReports = pointNN; mas01mc@324: while(numReports--){ // pop the rest of the points mas01mc@324: if(qsize) mas01mc@324: rk = point_queue.top(); // Take one point from the top of the queue mas01mc@324: else{ mas01mc@324: rk.dist = 1000000000.0; mas01mc@324: rk.qpos = 0xFFFFFFFF; mas01mc@324: rk.spos = 0xFFFFFFFF; mas01mc@324: } mas01mc@324: mas01cr@508: response->result.Rlist[k] = (char *) soap_malloc(soap, O2_MAXFILESTR); mas01cr@498: response->result.Dist[k] = rk.dist; mas01cr@498: response->result.Qpos[k] = rk.qpos; mas01cr@498: response->result.Spos[k] = rk.spos; mas01mc@324: if(qsize){ mas01cr@498: if(adb) mas01cr@498: snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID)); mas01mc@324: else mas01cr@498: snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID); mas01mc@324: point_queue.pop(); mas01mc@324: qsize--; mas01mc@324: } mas01mc@324: else mas01cr@498: snprintf(response->result.Rlist[k], O2_MAXFILESTR, "NULL"); mas01mc@324: k++; mas01mc@324: } mas01mc@248: } mas01mc@248: } mas01mc@248: // clean up mas01mc@248: delete[] point_queues; mas01mc@248: } mas01mc@250: mas01mc@292: /********************** Radius Reporters **************************/ mas01mc@250: mas01mc@292: class triple{ mas01mc@292: public: mas01mc@292: unsigned int a; mas01mc@292: unsigned int b; mas01mc@292: unsigned int c; mas01mc@292: mas01mc@292: triple(void); mas01mc@292: triple(unsigned int, unsigned int, unsigned int); mas01mc@292: unsigned int first(); mas01mc@292: unsigned int second(); mas01mc@292: unsigned int third(); mas01mc@292: }; mas01mc@292: mas01mc@292: triple& make_triple(unsigned int, unsigned int, unsigned int); mas01mc@292: mas01mc@292: triple::triple(unsigned int a, unsigned int b, unsigned int c):a(a),b(b),c(c){} mas01mc@292: mas01mc@292: unsigned int triple::first(){return a;} mas01mc@292: unsigned int triple::second(){return b;} mas01mc@292: unsigned int triple::third(){return c;} mas01mc@292: mas01mc@292: triple::triple():a(0),b(0),c(0){} mas01mc@292: mas01mc@292: bool operator< (const triple &t1, const triple &t2) { mas01mc@292: return ((t1.a < t2.a) || mas01mc@292: ((t1.a == t2.a) && ((t1.b < t2.b) || mas01mc@292: ((t1.b == t2.b) && (t1.c < t2.c))))); mas01mc@292: } mas01mc@292: bool operator== (const triple &t1, const triple &t2) { mas01mc@292: return ((t1.a == t2.a) && (t1.b == t2.b) && (t1.c == t2.c)); mas01mc@292: } mas01mc@292: mas01mc@292: triple& make_triple(unsigned int a, unsigned int b, unsigned int c){ mas01mc@292: triple* t = new triple(a,b,c); mas01mc@292: return *t; mas01mc@292: } mas01mc@292: mas01mc@292: // track Sequence Query Radius Reporter mas01mc@292: // only return tracks and retrieved point counts mas01mc@292: class trackSequenceQueryRadReporter : public Reporter { mas01mc@250: public: mas01mc@292: trackSequenceQueryRadReporter(unsigned int trackNN, unsigned int numFiles); mas01mc@292: ~trackSequenceQueryRadReporter(); mas01mc@250: void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist); mas01cr@508: void report(adb_t *adb, struct soap *soap, void *adbQueryResponse); mas01mc@250: protected: mas01mc@250: unsigned int trackNN; mas01mc@250: unsigned int numFiles; mas01mc@292: std::set > *set; mas01mc@292: std::set< triple > *set_triple; mas01mc@250: unsigned int *count; mas01mc@250: }; mas01mc@250: mas01mc@292: trackSequenceQueryRadReporter::trackSequenceQueryRadReporter(unsigned int trackNN, unsigned int numFiles): mas01mc@292: trackNN(trackNN), numFiles(numFiles) { mas01mc@292: set = new std::set >; mas01mc@292: set_triple = new std::set >; mas01mc@250: count = new unsigned int[numFiles]; mas01mc@250: for (unsigned i = 0; i < numFiles; i++) { mas01mc@250: count[i] = 0; mas01mc@250: } mas01mc@250: } mas01mc@250: mas01mc@292: trackSequenceQueryRadReporter::~trackSequenceQueryRadReporter() { mas01mc@250: delete set; mas01mc@292: delete set_triple; mas01mc@250: delete [] count; mas01mc@250: } mas01mc@250: mas01mc@292: void trackSequenceQueryRadReporter::add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist) { mas01mc@292: std::set >::iterator it; mas01mc@292: std::pair pair = std::make_pair(trackID, qpos); // only count this once mas01mc@292: std::set::iterator it2; mas01mc@292: triple triple; mas01mc@250: mas01mc@292: triple = make_triple(trackID, qpos, spos); // only count this once mas01mc@292: mas01mc@292: // Record unique triples (record one collision from all hash tables) mas01mc@292: it2 = set_triple->find(triple); mas01mc@250: mas01mc@292: if(it2 == set_triple->end()){ mas01mc@292: set_triple->insert(triple); mas01mc@292: mas01mc@292: it = set->find(pair); mas01mc@292: if (it == set->end()) { mas01mc@292: set->insert(pair); mas01mc@292: count[trackID]++; // only count if pair is unique mas01mc@292: } mas01mc@250: } mas01mc@250: } mas01mc@250: mas01cr@508: void trackSequenceQueryRadReporter::report(adb_t *adb, struct soap *soap, void *adbQueryResponse) { mas01mc@275: std::priority_queue < Radresult, std::vector, std::greater > result; mas01mc@250: // KLUDGE: doing this backwards in an attempt to get the same mas01mc@250: // tiebreak behaviour as before. mas01mc@250: for (int i = numFiles-1; i >= 0; i--) { mas01mc@250: Radresult r; mas01mc@250: r.trackID = i; mas01mc@250: r.count = count[i]; mas01mc@250: if(r.count > 0) { mas01mc@250: result.push(r); mas01mc@250: if (result.size() > trackNN) { mas01mc@250: result.pop(); mas01mc@250: } mas01mc@250: } mas01mc@250: } mas01mc@250: mas01mc@250: Radresult r; mas01mc@250: std::vector v; mas01mc@250: unsigned int size = result.size(); mas01mc@250: for(unsigned int k = 0; k < size; k++) { mas01mc@250: r = result.top(); mas01mc@250: v.push_back(r); mas01mc@250: result.pop(); mas01mc@250: } mas01mc@292: std::vector::reverse_iterator rit; mas01mc@292: mas01mc@292: if(adbQueryResponse==0) { mas01mc@292: for(rit = v.rbegin(); rit < v.rend(); rit++) { mas01mc@292: r = *rit; mas01cr@498: if(adb) mas01cr@498: std::cout << audiodb_index_key(adb, r.trackID) << " "; mas01mc@292: else mas01mc@292: std::cout << r.trackID << " "; mas01mc@292: std::cout << r.count << std::endl; mas01mc@292: } mas01cr@498: } else { mas01cr@498: adb__queryResponse *response = (adb__queryResponse *) adbQueryResponse; mas01cr@498: response->result.__sizeRlist=size; mas01cr@498: response->result.__sizeDist=size; mas01cr@498: response->result.__sizeQpos=size; mas01cr@498: response->result.__sizeSpos=size; mas01cr@508: response->result.Rlist= (char **) soap_malloc(soap, size * sizeof(char *)); mas01cr@508: response->result.Dist = (double *) soap_malloc(soap, size * sizeof(double)); mas01cr@508: response->result.Qpos = (unsigned int *) soap_malloc(soap, size * sizeof(unsigned int)); mas01cr@508: response->result.Spos = (unsigned int *) soap_malloc(soap, size * sizeof(unsigned int)); mas01mc@307: unsigned int k = 0; mas01mc@307: for(rit = v.rbegin(); rit < v.rend(); rit++, k++) { mas01mc@307: r = *rit; mas01cr@508: response->result.Rlist[k] = (char *) soap_malloc(soap, O2_MAXFILESTR); mas01cr@498: response->result.Dist[k] = 0; mas01cr@498: response->result.Qpos[k] = 0; mas01cr@498: response->result.Spos[k] = r.count; mas01cr@498: if(adb) mas01cr@498: snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID)); mas01mc@307: else mas01cr@498: snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID); mas01mc@307: } mas01mc@292: } mas01mc@292: } mas01mc@292: mas01mc@292: // track Sequence Query Radius NN Reporter mas01mc@292: // retrieve tracks ordered by query-point matches (one per track per query point) mas01mc@292: // mas01mc@292: // as well as sorted n-NN points per retrieved track mas01mc@292: class trackSequenceQueryRadNNReporter : public Reporter { mas01mc@292: public: mas01mc@292: trackSequenceQueryRadNNReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles); mas01mc@292: ~trackSequenceQueryRadNNReporter(); mas01mc@292: void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist); mas01cr@508: void report(adb_t *adb, struct soap *soap, void *adbQueryResponse); mas01mc@292: protected: mas01mc@292: unsigned int pointNN; mas01mc@292: unsigned int trackNN; mas01mc@292: unsigned int numFiles; mas01mc@292: std::set > *set; mas01mc@292: std::set< triple > *set_triple; mas01mc@292: std::priority_queue< NNresult, std::vector< NNresult>, std::less > *point_queues; mas01mc@292: unsigned int *count; mas01mc@292: }; mas01mc@292: mas01mc@292: trackSequenceQueryRadNNReporter::trackSequenceQueryRadNNReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles): mas01mc@292: pointNN(pointNN), trackNN(trackNN), numFiles(numFiles) { mas01mc@292: // Where to count Radius track matches (one-to-one) mas01mc@292: set = new std::set >; mas01mc@292: set_triple = new std::set >; mas01mc@292: // Where to insert individual point matches (one-to-many) mas01mc@292: point_queues = new std::priority_queue< NNresult, std::vector< NNresult>, std::less >[numFiles]; mas01mc@292: mas01mc@292: count = new unsigned int[numFiles]; mas01mc@292: for (unsigned i = 0; i < numFiles; i++) { mas01mc@292: count[i] = 0; mas01mc@292: } mas01mc@292: } mas01mc@292: mas01mc@292: trackSequenceQueryRadNNReporter::~trackSequenceQueryRadNNReporter() { mas01mc@292: delete set; mas01mc@292: delete set_triple; mas01mc@292: delete [] count; mas01mc@292: } mas01mc@292: mas01mc@292: void trackSequenceQueryRadNNReporter::add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist) { mas01mc@292: std::set >::iterator it; mas01mc@292: std::set::iterator it2; mas01mc@292: std::pair pair; mas01mc@292: triple triple; mas01mc@292: NNresult r; mas01mc@292: mas01mc@292: pair = std::make_pair(trackID, qpos); // only count this once mas01mc@292: triple = make_triple(trackID, qpos, spos); // only count this once mas01mc@292: // Record unique triples (record one collision from all hash tables) mas01mc@292: it2 = set_triple->find(triple); mas01mc@292: if(it2 == set_triple->end()){ mas01mc@292: set_triple->insert(triple); mas01mc@292: // Record all matching points (within radius) mas01mc@292: // Record counts of pairs mas01mc@292: it = set->find(pair); mas01mc@292: if (it == set->end()) { mas01mc@292: set->insert(pair); mas01mc@292: count[trackID]++; mas01mc@307: } mas01mc@307: if (!isnan(dist)) { mas01mc@307: r.trackID = trackID; mas01mc@307: r.qpos = qpos; mas01mc@307: r.dist = dist; mas01mc@307: r.spos = spos; mas01mc@307: point_queues[trackID].push(r); mas01mc@307: if(point_queues[trackID].size() > pointNN) mas01mc@307: point_queues[trackID].pop(); mas01mc@292: } mas01mc@292: } mas01mc@292: } mas01mc@292: mas01cr@508: void trackSequenceQueryRadNNReporter::report(adb_t *adb, struct soap *soap, void *adbQueryResponse) { mas01mc@292: std::priority_queue < Radresult, std::vector, std::greater > result; mas01mc@292: // KLUDGE: doing this backwards in an attempt to get the same mas01mc@292: // tiebreak behaviour as before. mas01mc@292: Radresult r; mas01mc@292: NNresult rk; mas01mc@307: std::vector v; mas01mc@307: unsigned int size; mas01mc@292: mas01mc@307: if(pointNN>1){ mas01mc@307: for (int i = numFiles-1; i >= 0; i--) { mas01mc@307: r.trackID = i; mas01mc@307: r.count = count[i]; mas01mc@307: if(r.count > 0) { mas01mc@307: cout.flush(); mas01mc@307: result.push(r); mas01mc@307: if (result.size() > trackNN) { mas01mc@307: result.pop(); mas01mc@307: } mas01mc@292: } mas01mc@292: } mas01mc@307: mas01mc@307: size = result.size(); mas01mc@307: for(unsigned int k = 0; k < size; k++) { mas01mc@307: r = result.top(); mas01mc@307: v.push_back(r); mas01mc@307: result.pop(); mas01mc@307: } mas01mc@292: } mas01mc@307: else{ mas01mc@307: // Instantiate a 1-NN trackAveragingNN reporter mas01mc@307: trackSequenceQueryNNReporter >* rep = new trackSequenceQueryNNReporter >(1, trackNN, numFiles); mas01mc@307: // Add all the points we've got to the reporter mas01mc@307: for(unsigned int i=0; iadd_point(i, rk.qpos, rk.spos, rk.dist); mas01mc@307: point_queues[i].pop(); mas01mc@307: } mas01mc@307: } mas01mc@307: // Report mas01cr@508: rep->report(adb, soap, adbQueryResponse); mas01mc@307: // Exit mas01mc@307: delete[] point_queues; mas01mc@307: return; mas01mc@292: } mas01mc@264: mas01mc@264: mas01mc@264: // Traverse tracks in descending order of count cardinality mas01mc@250: std::vector::reverse_iterator rit; mas01mc@264: std::priority_queue< NNresult, std::vector< NNresult>, std::greater > point_queue; mas01mc@264: mas01mc@250: if(adbQueryResponse==0) { mas01mc@250: for(rit = v.rbegin(); rit < v.rend(); rit++) { mas01mc@250: r = *rit; mas01cr@498: if(adb) mas01cr@498: std::cout << audiodb_index_key(adb, r.trackID) << " "; mas01mc@292: else mas01mc@292: std::cout << r.trackID << " "; mas01mc@292: std::cout << r.count << std::endl; mas01mc@264: mas01mc@264: // Reverse the order of the points stored in point_queues mas01mc@264: unsigned int qsize=point_queues[r.trackID].size(); mas01mc@264: for(unsigned int k=0; k < qsize; k++){ mas01mc@264: point_queue.push(point_queues[r.trackID].top()); mas01mc@264: point_queues[r.trackID].pop(); mas01mc@264: } mas01mc@264: for(unsigned int k=0; k < qsize; k++){ mas01mc@292: rk = point_queue.top(); mas01mc@250: std::cout << rk.dist << " " << rk.qpos << " " << rk.spos << std::endl; mas01mc@264: point_queue.pop(); mas01mc@250: } mas01mc@250: } mas01cr@498: } else { mas01cr@498: adb__queryResponse *response = (adb__queryResponse *) adbQueryResponse; mas01cr@498: response->result.__sizeRlist=size*pointNN; mas01cr@498: response->result.__sizeDist=size*pointNN; mas01cr@498: response->result.__sizeQpos=size*pointNN; mas01cr@498: response->result.__sizeSpos=size*pointNN; mas01cr@508: response->result.Rlist= (char **) soap_malloc(soap, size * pointNN * sizeof(char *)); mas01cr@508: response->result.Dist = (double *) soap_malloc(soap, size * pointNN * sizeof(double)); mas01cr@508: response->result.Qpos = (unsigned int *) soap_malloc(soap, size * pointNN * sizeof(unsigned int)); mas01cr@508: response->result.Spos = (unsigned int *) soap_malloc(soap, size * pointNN * sizeof(unsigned int)); mas01mc@307: unsigned int k = 0; mas01mc@307: // Loop over returned tracks mas01mc@324: for(rit = v.rbegin(); rit < v.rend(); rit++) { mas01mc@307: r = *rit; mas01mc@307: // Reverse the order of the points stored in point_queues mas01mc@307: unsigned int qsize=point_queues[r.trackID].size(); mas01mc@307: while(qsize--){ mas01mc@307: point_queue.push(point_queues[r.trackID].top()); mas01mc@307: point_queues[r.trackID].pop(); mas01mc@307: } mas01mc@307: qsize=point_queue.size(); mas01mc@324: unsigned int numReports = pointNN; mas01mc@324: while(numReports--){ // pop the rest of the points mas01mc@324: if(qsize) mas01mc@324: rk = point_queue.top(); // Take one point from the top of the queue mas01mc@324: else{ mas01mc@324: rk.dist = 1000000000.0; mas01mc@324: rk.qpos = 0xFFFFFFFF; mas01mc@324: rk.spos = 0xFFFFFFFF; mas01mc@324: } mas01mc@324: mas01cr@508: response->result.Rlist[k] = (char *) soap_malloc(soap, O2_MAXFILESTR); mas01cr@498: response->result.Dist[k] = rk.dist; mas01cr@498: response->result.Qpos[k] = rk.qpos; mas01cr@498: response->result.Spos[k] = rk.spos; mas01mc@324: if(qsize){ mas01cr@498: if(adb) mas01cr@498: snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID)); mas01mc@324: else mas01cr@498: snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID); mas01mc@324: point_queue.pop(); mas01mc@324: qsize--; mas01mc@324: } mas01mc@324: else mas01cr@498: snprintf(response->result.Rlist[k], O2_MAXFILESTR, "NULL"); mas01mc@324: k++; mas01mc@324: } mas01mc@307: } mas01mc@307: } mas01mc@264: delete[] point_queues; mas01mc@250: } mas01mc@263: mas01mc@264: /********** ONE-TO-ONE REPORTERS *****************/ mas01mc@263: mas01mc@264: // track Sequence Query Radius NN Reporter One-to-One mas01mc@264: // for each query point find the single best matching target point in all database mas01mc@264: // report qpos, spos and trackID mas01mc@263: class trackSequenceQueryRadNNReporterOneToOne : public Reporter { mas01mc@263: public: mas01mc@263: trackSequenceQueryRadNNReporterOneToOne(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles); mas01mc@263: ~trackSequenceQueryRadNNReporterOneToOne(); mas01mc@263: void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist); mas01cr@508: void report(adb_t *adb, struct soap *soap, void *adbQueryResponse); mas01mc@263: protected: mas01mc@263: unsigned int pointNN; mas01mc@263: unsigned int trackNN; mas01mc@263: unsigned int numFiles; mas01mc@263: std::set< NNresult > *set; mas01mc@263: std::vector< NNresult> *point_queue; mas01mc@263: unsigned int *count; mas01mc@263: mas01mc@263: }; mas01mc@263: mas01mc@263: trackSequenceQueryRadNNReporterOneToOne::trackSequenceQueryRadNNReporterOneToOne(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles): mas01mc@263: pointNN(pointNN), trackNN(trackNN), numFiles(numFiles) { mas01mc@263: // Where to count Radius track matches (one-to-one) mas01mc@263: set = new std::set< NNresult >; mas01mc@263: // Where to insert individual point matches (one-to-many) mas01mc@263: point_queue = new std::vector< NNresult >; mas01mc@263: mas01mc@263: count = new unsigned int[numFiles]; mas01mc@263: for (unsigned i = 0; i < numFiles; i++) { mas01mc@263: count[i] = 0; mas01mc@263: } mas01mc@263: } mas01mc@263: mas01mc@263: trackSequenceQueryRadNNReporterOneToOne::~trackSequenceQueryRadNNReporterOneToOne() { mas01mc@263: delete set; mas01mc@263: delete [] count; mas01mc@263: } mas01mc@263: mas01mc@263: void trackSequenceQueryRadNNReporterOneToOne::add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist) { mas01mc@263: std::set< NNresult >::iterator it; mas01mc@263: NNresult r; mas01mc@264: mas01mc@263: r.qpos = qpos; mas01mc@263: r.trackID = trackID; mas01mc@263: r.spos = spos; mas01mc@263: r.dist = dist; mas01mc@263: mas01mc@263: if(point_queue->size() < r.qpos + 1){ mas01mc@263: point_queue->resize( r.qpos + 1 ); mas01mc@263: (*point_queue)[r.qpos].dist = 1e6; mas01mc@263: } mas01mc@263: mas01mc@263: if (r.dist < (*point_queue)[r.qpos].dist) mas01mc@263: (*point_queue)[r.qpos] = r; mas01mc@263: mas01mc@263: } mas01mc@263: mas01cr@508: void trackSequenceQueryRadNNReporterOneToOne::report(adb_t *adb, struct soap *soap, void *adbQueryResponse) { mas01mc@263: if(adbQueryResponse==0) { mas01mc@263: std::vector< NNresult >::iterator vit; mas01mc@263: NNresult rk; mas01mc@263: for( vit = point_queue->begin() ; vit < point_queue->end() ; vit++ ){ mas01mc@263: rk = *vit; mas01mc@263: std::cout << rk.dist << " " mas01mc@263: << rk.qpos << " " mas01mc@292: << rk.spos << " "; mas01cr@498: if(adb) mas01cr@498: std::cout << audiodb_index_key(adb, rk.trackID) << " "; mas01mc@292: else mas01mc@292: std::cout << rk.trackID << " "; mas01mc@292: std::cout << std::endl; mas01mc@263: } mas01mc@263: } else { mas01mc@263: // FIXME mas01mc@263: } mas01mc@263: } mas01mc@292: mas01mc@292: #endif