view reporter.h @ 509:cc2b97d020b1

Code rearrangements to tease apart library code from C++ audioDB code. There should be precisely no functional changes in this commit. Instead, the only thing that has happened is that all the abstraction violation and other horribleness is concentrated in one place: the include of "audioDB-internals.h" in audioDB.h -- the separation will be complete once that include can be removed. This include is necessary because the command-line binary / SOAP server still does some things directly rather than through an API: not least of which the operations that have not yet been integrated into the API yet, but also some messing around with constants, flags and nominally internal functions. The intent is to remove as many of these as possible and think quite hard about the rest. In the meantime, the library is now much more self-contained: the only things it uses are in the audioDB_API.h and audioDB-internals.h headers; thus there are fewer nasty surprises lurking for readers of the code. The Makefile has been adjusted to take advantage of this rearrangement in the dependencies.
author mas01cr
date Thu, 15 Jan 2009 13:57:33 +0000
parents 23c47e118bc6
children
line wrap: on
line source
#ifndef __REPORTER_H
#define __REPORTER_H

#include <utility>
#include <queue>
#include <set>
#include <functional>
#include <iostream>
#include "ReporterBase.h"
#include "audioDB.h"

typedef struct nnresult {
  unsigned int trackID;
  double dist;
  unsigned int qpos;
  unsigned int spos;
} NNresult;

typedef struct radresult {
  unsigned int trackID;
  unsigned int count;
} Radresult;

bool operator< (const NNresult &a, const NNresult &b) {
  return a.dist < b.dist;
}

bool operator> (const NNresult &a, const NNresult &b) {
  return a.dist > b.dist;
}

bool operator< (const Radresult &a, const Radresult &b) {
  return a.count < b.count;
}

bool operator> (const Radresult &a, const Radresult &b) {
  return a.count > b.count;
}

class Reporter : public ReporterBase {
public:
  virtual ~Reporter() {};
  virtual void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist) = 0;
  // FIXME: this interface is a bit wacky: a relic of previous, more
  // confused times.  Really it might make sense to have separate
  // reporter classes for WS and for stdout, rather than passing this
  // adbQueryResponse thing everywhere; the adb argument is there
  // solely for converting trackIDs into names.  -- CSR, 2007-12-10.
  virtual void report(adb_t *adb, struct soap *soap, void* adbQueryResponse) = 0;
};

template <class T> class pointQueryReporter : public Reporter {
public:
  pointQueryReporter(unsigned int pointNN);
  ~pointQueryReporter();
  void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist);
  void report(adb_t *adb, struct soap *soap, void* adbQueryResponse);
private:
  unsigned int pointNN;
  std::priority_queue< NNresult, std::vector< NNresult >, T> *queue;
};

template <class T> pointQueryReporter<T>::pointQueryReporter(unsigned int pointNN)
  : pointNN(pointNN) {
  queue = new std::priority_queue< NNresult, std::vector< NNresult >, T>;
}

template <class T> pointQueryReporter<T>::~pointQueryReporter() {
  delete queue;
}

template <class T> void pointQueryReporter<T>::add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist) {
  if (!isnan(dist)) {
    NNresult r;
    r.trackID = trackID;
    r.qpos = qpos;
    r.spos = spos;
    r.dist = dist;
    queue->push(r);
    if(queue->size() > pointNN) {
      queue->pop();
    }
  }
}

template <class T> void pointQueryReporter<T>::report(adb_t *adb, struct soap *soap, void *adbQueryResponse) {
  NNresult r;
  std::vector<NNresult> v;
  unsigned int size = queue->size();
  for(unsigned int k = 0; k < size; k++) {
    r = queue->top();
    v.push_back(r);
    queue->pop();
  }
  std::vector<NNresult>::reverse_iterator rit;
      
  if(adbQueryResponse==0) {
    for(rit = v.rbegin(); rit < v.rend(); rit++) {
      r = *rit;
      if(adb)
	std::cout << audiodb_index_key(adb, r.trackID) << " ";
      else
	std::cout << r.trackID << " ";
      std::cout << r.dist << " " << r.qpos << " " << r.spos << std::endl;
    }
  } else {
    adb__queryResponse *response = (adb__queryResponse *) adbQueryResponse;
    response->result.__sizeRlist=size;
    response->result.__sizeDist=size;
    response->result.__sizeQpos=size;
    response->result.__sizeSpos=size;
    response->result.Rlist= (char **) soap_malloc(soap, size * sizeof(char *));
    response->result.Dist = (double *) soap_malloc(soap, size * sizeof(double));
    response->result.Qpos = (unsigned int *) soap_malloc(soap, size * sizeof(unsigned int));
    response->result.Spos = (unsigned int *) soap_malloc(soap, size * sizeof(unsigned int));
    unsigned int k = 0;
    for(rit = v.rbegin(); rit < v.rend(); rit++, k++) {
      r = *rit;
      response->result.Rlist[k] = (char *) soap_malloc(soap, O2_MAXFILESTR);
      response->result.Dist[k] = r.dist;
      response->result.Qpos[k] = r.qpos;
      response->result.Spos[k] = r.spos;
      if(adb)
	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID));
      else
	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID);
    }
  }
}

template <class T> class trackAveragingReporter : public Reporter {
 public:
  trackAveragingReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles);
  ~trackAveragingReporter();
  void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist);
  void report(adb_t *adb, struct soap *soap, void *adbQueryResponse);
 protected:
  unsigned int pointNN;
  unsigned int trackNN;
  unsigned int numFiles;
  std::priority_queue< NNresult, std::vector< NNresult>, T > *queues;  
};

template <class T> trackAveragingReporter<T>::trackAveragingReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles) 
  : pointNN(pointNN), trackNN(trackNN), numFiles(numFiles) {
  queues = new std::priority_queue< NNresult, std::vector< NNresult>, T >[numFiles];
}

template <class T> trackAveragingReporter<T>::~trackAveragingReporter() {
  delete [] queues;
}

template <class T> void trackAveragingReporter<T>::add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist) {
  if (!isnan(dist)) {
    NNresult r;
    r.trackID = trackID;
    r.qpos = qpos;
    r.spos = spos;
    r.dist = dist;
    queues[trackID].push(r);
    if(queues[trackID].size() > pointNN) {
      queues[trackID].pop();
    }
  }
}

template <class T> void trackAveragingReporter<T>::report(adb_t *adb, struct soap *soap, void *adbQueryResponse) {
  std::priority_queue < NNresult, std::vector< NNresult>, T> result;
  for (int i = numFiles-1; i >= 0; i--) {
    unsigned int size = queues[i].size();
    if (size > 0) {
      NNresult r;
      double dist = 0;
      NNresult oldr = queues[i].top();
      for (unsigned int j = 0; j < size; j++) {
        r = queues[i].top();
        dist += r.dist;
        queues[i].pop();
        if (r.dist == oldr.dist) {
          r.qpos = oldr.qpos;
          r.spos = oldr.spos;
        } else {
          oldr = r;
        }
      }
      dist /= size;
      r.dist = dist; // trackID, qpos and spos are magically right already.
      result.push(r);
      if (result.size() > trackNN) {
        result.pop();
      }
    }
  }

  NNresult r;
  std::vector<NNresult> v;
  unsigned int size = result.size();
  for(unsigned int k = 0; k < size; k++) {
    r = result.top();
    v.push_back(r);
    result.pop();
  }
  std::vector<NNresult>::reverse_iterator rit;
      
  if(adbQueryResponse==0) {
    for(rit = v.rbegin(); rit < v.rend(); rit++) {
      r = *rit;
      if(adb)
	std::cout << audiodb_index_key(adb, r.trackID) << " ";
      else
	std::cout << r.trackID << " ";
      std::cout << r.dist << " " << r.qpos << " " << r.spos << std::endl;
    }
  } else {
    adb__queryResponse *response = (adb__queryResponse *) adbQueryResponse;
    response->result.__sizeRlist=size;
    response->result.__sizeDist=size;
    response->result.__sizeQpos=size;
    response->result.__sizeSpos=size;
    response->result.Rlist= (char **) soap_malloc(soap, size * sizeof(char *));
    response->result.Dist = (double *) soap_malloc(soap, size * sizeof(double));
    response->result.Qpos = (unsigned int *) soap_malloc(soap, size * sizeof(unsigned int));
    response->result.Spos = (unsigned int *) soap_malloc(soap, size * sizeof(unsigned int));
    unsigned int k = 0;
    for(rit = v.rbegin(); rit < v.rend(); rit++, k++) {
      r = *rit;
      response->result.Rlist[k] = (char *) soap_malloc(soap, O2_MAXFILESTR);
      response->result.Dist[k] = r.dist;
      response->result.Qpos[k] = r.qpos;
      response->result.Spos[k] = r.spos;
      if(adb)
	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID));
      else
	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID);
    }
  }
}

// Another type of trackAveragingReporter that reports all pointNN nearest neighbours
template <class T> class trackSequenceQueryNNReporter : public trackAveragingReporter<T> {
 protected:
  using trackAveragingReporter<T>::numFiles;
  using trackAveragingReporter<T>::queues;
  using trackAveragingReporter<T>::trackNN;
  using trackAveragingReporter<T>::pointNN;
 public:
  trackSequenceQueryNNReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles);
  void report(adb_t *adb, struct soap *soap, void *adbQueryResponse);
};

template <class T> trackSequenceQueryNNReporter<T>::trackSequenceQueryNNReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles)
:trackAveragingReporter<T>(pointNN, trackNN, numFiles){}

template <class T> void trackSequenceQueryNNReporter<T>::report(adb_t *adb, struct soap *soap, void *adbQueryResponse) {
  std::priority_queue < NNresult, std::vector< NNresult>, T> result;
  std::priority_queue< NNresult, std::vector< NNresult>, std::less<NNresult> > *point_queues 
    = new std::priority_queue< NNresult, std::vector< NNresult>, std::less<NNresult> >[numFiles];
  
  for (int i = numFiles-1; i >= 0; i--) {
    unsigned int size = queues[i].size();
    if (size > 0) {
      NNresult r;
      double dist = 0;
      NNresult oldr = queues[i].top();
      for (unsigned int j = 0; j < size; j++) {
        r = queues[i].top();
        dist += r.dist;
	point_queues[i].push(r);
	queues[i].pop();
        if (r.dist == oldr.dist) {
          r.qpos = oldr.qpos;
          r.spos = oldr.spos;
        } else {
          oldr = r;
        }
      }
      dist /= size;
      r.dist = dist; // trackID, qpos and spos are magically right already.
      result.push(r);
      if (result.size() > trackNN) {
        result.pop();
      }
    }
  }

  NNresult r;
  std::vector<NNresult> v;
  unsigned int size = result.size();
  for(unsigned int k = 0; k < size; k++) {
    r = result.top();
    v.push_back(r);
    result.pop();
  }
  std::vector<NNresult>::reverse_iterator rit;
  std::priority_queue< NNresult, std::vector< NNresult>, std::greater<NNresult> > point_queue;      
  NNresult rk;

  if(adbQueryResponse==0) {
    for(rit = v.rbegin(); rit < v.rend(); rit++) {
      r = *rit;
      if(adb)
	std::cout << audiodb_index_key(adb, r.trackID) << " ";
      else
	std::cout << r.trackID << " ";
      std::cout << r.dist << std::endl;
      unsigned int qsize = point_queues[r.trackID].size();
      // Reverse the order of the points stored in point_queues
      for(unsigned int k=0; k < qsize; k++){
	point_queue.push( point_queues[r.trackID].top() );
	point_queues[r.trackID].pop();
      }
      
      for(unsigned int k = 0; k < qsize; k++) {
	rk = point_queue.top();
	std::cout << rk.dist << " " << rk.qpos << " " << rk.spos << std::endl;
	point_queue.pop();
      }
    }
  } else {
    adb__queryResponse *response = (adb__queryResponse *) adbQueryResponse;
    response->result.__sizeRlist=size*pointNN;
    response->result.__sizeDist=size*pointNN;
    response->result.__sizeQpos=size*pointNN;
    response->result.__sizeSpos=size*pointNN;
    response->result.Rlist= (char **) soap_malloc(soap, size * pointNN * sizeof(char *));
    response->result.Dist = (double *) soap_malloc(soap, size * pointNN * sizeof(double));
    response->result.Qpos = (unsigned int *) soap_malloc(soap, size * pointNN * sizeof(unsigned int));
    response->result.Spos = (unsigned int *) soap_malloc(soap, size * pointNN * sizeof(unsigned int));
    unsigned int k = 0;
    // Loop over returned tracks
    for(rit = v.rbegin(); rit < v.rend(); rit++) {
      r = *rit;
      // Reverse the order of the points stored in point_queues
      unsigned int qsize=point_queues[r.trackID].size();
      while(qsize--){
	point_queue.push(point_queues[r.trackID].top());
	point_queues[r.trackID].pop();
      }
      qsize=point_queue.size();
      unsigned int numReports = pointNN;
      while(numReports--){ // pop the rest of the points
	if(qsize)
	  rk = point_queue.top(); // Take one point from the top of the queue
	else{
	  rk.dist = 1000000000.0;
	  rk.qpos = 0xFFFFFFFF;
	  rk.spos = 0xFFFFFFFF;
	}
	  
	response->result.Rlist[k] = (char *) soap_malloc(soap, O2_MAXFILESTR);
	response->result.Dist[k] = rk.dist;
	response->result.Qpos[k] = rk.qpos;
	response->result.Spos[k] = rk.spos;
	if(qsize){
	  if(adb)
	    snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID));
	  else
	    snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID);	
	  point_queue.pop();
	  qsize--;
	}
	else
	  snprintf(response->result.Rlist[k], O2_MAXFILESTR, "NULL");		  
	k++;
      }
    }
  }
  // clean up
  delete[] point_queues;
}

/********************** Radius Reporters **************************/

class triple{
 public:
  unsigned int a;
  unsigned int b;
  unsigned int c;

  triple(void);
  triple(unsigned int, unsigned int, unsigned int);
  unsigned int first();
  unsigned int second();
  unsigned int third();
};

triple& make_triple(unsigned int, unsigned int, unsigned int);

triple::triple(unsigned int a, unsigned int b, unsigned int c):a(a),b(b),c(c){}

unsigned int triple::first(){return a;}
unsigned int triple::second(){return b;}
unsigned int triple::third(){return c;}

triple::triple():a(0),b(0),c(0){}

bool operator< (const triple &t1, const triple &t2) {
  return ((t1.a < t2.a) ||
	  ((t1.a == t2.a) && ((t1.b < t2.b) ||
			      ((t1.b == t2.b) && (t1.c < t2.c)))));
}
bool operator== (const triple &t1, const triple &t2) {
  return ((t1.a == t2.a) && (t1.b == t2.b) && (t1.c == t2.c));
}

triple& make_triple(unsigned int a, unsigned int b, unsigned int c){
  triple* t = new triple(a,b,c);
  return *t;
}

// track Sequence Query Radius Reporter
// only return tracks and retrieved point counts
class trackSequenceQueryRadReporter : public Reporter { 
public:
  trackSequenceQueryRadReporter(unsigned int trackNN, unsigned int numFiles);
  ~trackSequenceQueryRadReporter();
  void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist);
  void report(adb_t *adb, struct soap *soap, void *adbQueryResponse);
 protected:
  unsigned int trackNN;
  unsigned int numFiles;
  std::set<std::pair<unsigned int, unsigned int> > *set;
  std::set< triple > *set_triple;
  unsigned int *count;
};

trackSequenceQueryRadReporter::trackSequenceQueryRadReporter(unsigned int trackNN, unsigned int numFiles):
  trackNN(trackNN), numFiles(numFiles) {
  set = new std::set<std::pair<unsigned int, unsigned int> >;
  set_triple = new std::set<triple, std::less<triple> >;
  count = new unsigned int[numFiles];
  for (unsigned i = 0; i < numFiles; i++) {
    count[i] = 0;
  }
}

trackSequenceQueryRadReporter::~trackSequenceQueryRadReporter() {
  delete set;
  delete set_triple;
  delete [] count;
}

void trackSequenceQueryRadReporter::add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist) {
  std::set<std::pair<unsigned int, unsigned int> >::iterator it;
  std::pair<unsigned int, unsigned int> pair = std::make_pair(trackID, qpos); // only count this once
  std::set<triple>::iterator it2;
  triple triple;

  triple = make_triple(trackID, qpos, spos); // only count this once
  
  // Record unique <trackID,qpos,spos> triples (record one collision from all hash tables)
  it2 = set_triple->find(triple);

  if(it2 == set_triple->end()){
    set_triple->insert(triple);    

    it = set->find(pair);
    if (it == set->end()) {
      set->insert(pair);
      count[trackID]++; // only count if <tackID,qpos> pair is unique
    }
  }
}

void trackSequenceQueryRadReporter::report(adb_t *adb, struct soap *soap, void *adbQueryResponse) {
  std::priority_queue < Radresult, std::vector<Radresult>, std::greater<Radresult> > result;
  // KLUDGE: doing this backwards in an attempt to get the same
  // tiebreak behaviour as before.
  for (int i = numFiles-1; i >= 0; i--) {
    Radresult r;
    r.trackID = i;
    r.count = count[i];
    if(r.count > 0) {
      result.push(r);
      if (result.size() > trackNN) {
        result.pop();
      }
    }
  }

  Radresult r;
  std::vector<Radresult> v;
  unsigned int size = result.size();
  for(unsigned int k = 0; k < size; k++) {
    r = result.top();
    v.push_back(r);
    result.pop();
  }
  std::vector<Radresult>::reverse_iterator rit;
      
  if(adbQueryResponse==0) {
    for(rit = v.rbegin(); rit < v.rend(); rit++) {
      r = *rit;
      if(adb)
	std::cout << audiodb_index_key(adb, r.trackID) << " ";
      else
	std::cout << r.trackID << " ";
      std::cout << r.count << std::endl;
    }
  } else {
    adb__queryResponse *response = (adb__queryResponse *) adbQueryResponse;
    response->result.__sizeRlist=size;
    response->result.__sizeDist=size;
    response->result.__sizeQpos=size;
    response->result.__sizeSpos=size;
    response->result.Rlist= (char **) soap_malloc(soap, size * sizeof(char *));
    response->result.Dist = (double *) soap_malloc(soap, size * sizeof(double));
    response->result.Qpos = (unsigned int *) soap_malloc(soap, size * sizeof(unsigned int));
    response->result.Spos = (unsigned int *) soap_malloc(soap, size * sizeof(unsigned int));
    unsigned int k = 0;
    for(rit = v.rbegin(); rit < v.rend(); rit++, k++) {
      r = *rit;
      response->result.Rlist[k] = (char *) soap_malloc(soap, O2_MAXFILESTR);
      response->result.Dist[k] = 0;
      response->result.Qpos[k] = 0;
      response->result.Spos[k] = r.count;
      if(adb)
	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID));
      else
	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID);
    }
  }
}

// track Sequence Query Radius NN Reporter
// retrieve tracks ordered by query-point matches (one per track per query point)
//
// as well as sorted n-NN points per retrieved track
class trackSequenceQueryRadNNReporter : public Reporter { 
public:
  trackSequenceQueryRadNNReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles);
  ~trackSequenceQueryRadNNReporter();
  void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist);
  void report(adb_t *adb, struct soap *soap, void *adbQueryResponse);
 protected:
  unsigned int pointNN;
  unsigned int trackNN;
  unsigned int numFiles;
  std::set<std::pair<unsigned int, unsigned int> > *set;
  std::set< triple > *set_triple;
  std::priority_queue< NNresult, std::vector< NNresult>, std::less<NNresult> > *point_queues;
  unsigned int *count;
};

trackSequenceQueryRadNNReporter::trackSequenceQueryRadNNReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles):
pointNN(pointNN), trackNN(trackNN), numFiles(numFiles) {
  // Where to count Radius track matches (one-to-one)
  set = new std::set<std::pair<unsigned int, unsigned int> >;
  set_triple = new std::set<triple, std::less<triple> >;
  // Where to insert individual point matches (one-to-many)
  point_queues = new std::priority_queue< NNresult, std::vector< NNresult>, std::less<NNresult> >[numFiles];
  
  count = new unsigned int[numFiles];
  for (unsigned i = 0; i < numFiles; i++) {
    count[i] = 0;
  }
}

trackSequenceQueryRadNNReporter::~trackSequenceQueryRadNNReporter() {
  delete set;
  delete set_triple;
  delete [] count;
}

void trackSequenceQueryRadNNReporter::add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist) {
  std::set<std::pair<unsigned int, unsigned int> >::iterator it;
  std::set<triple>::iterator it2;
  std::pair<unsigned int, unsigned int> pair;
  triple triple;
  NNresult r;

  pair = std::make_pair(trackID, qpos); // only count this once  
  triple = make_triple(trackID, qpos, spos); // only count this once
  // Record unique <trackID,qpos,spos> triples (record one collision from all hash tables)
  it2 = set_triple->find(triple);  
  if(it2 == set_triple->end()){    
    set_triple->insert(triple);    
    // Record all matching points (within radius)
    // Record counts of <trackID,qpos> pairs
    it = set->find(pair);
    if (it == set->end()) {
      set->insert(pair);
      count[trackID]++;
    }
    if (!isnan(dist)) {
      r.trackID = trackID;
      r.qpos = qpos;
      r.dist = dist;
      r.spos = spos;
      point_queues[trackID].push(r);
      if(point_queues[trackID].size() > pointNN)
	point_queues[trackID].pop();
    }
  }
}

void trackSequenceQueryRadNNReporter::report(adb_t *adb, struct soap *soap, void *adbQueryResponse) {
  std::priority_queue < Radresult, std::vector<Radresult>, std::greater<Radresult> > result;
  // KLUDGE: doing this backwards in an attempt to get the same
  // tiebreak behaviour as before.
  Radresult r;
  NNresult rk;
  std::vector<Radresult> v;
  unsigned int size;

  if(pointNN>1){
    for (int i = numFiles-1; i >= 0; i--) {
      r.trackID = i;
      r.count = count[i];
      if(r.count > 0) {
	cout.flush();
	result.push(r);
	if (result.size() > trackNN) {
	  result.pop();
	}
      }
    }
    
    size = result.size();
    for(unsigned int k = 0; k < size; k++) {
      r = result.top();
      v.push_back(r);
      result.pop();
    }
  }
  else{
    // Instantiate a 1-NN trackAveragingNN reporter
    trackSequenceQueryNNReporter<std::less <NNresult> >* rep = new trackSequenceQueryNNReporter<std::less <NNresult> >(1, trackNN, numFiles);
    // Add all the points we've got to the reporter
    for(unsigned int i=0; i<numFiles; i++){
      int qsize = point_queues[i].size();
      while(qsize--){
	rk = point_queues[i].top();
	rep->add_point(i, rk.qpos, rk.spos, rk.dist);
	point_queues[i].pop();
      }	
    }
    // Report
    rep->report(adb, soap, adbQueryResponse);
    // Exit
    delete[] point_queues;
    return;
  }


  // Traverse tracks in descending order of count cardinality
  std::vector<Radresult>::reverse_iterator rit;
  std::priority_queue< NNresult, std::vector< NNresult>, std::greater<NNresult> > point_queue;

  if(adbQueryResponse==0) {
    for(rit = v.rbegin(); rit < v.rend(); rit++) {
      r = *rit;
      if(adb)
	std::cout << audiodb_index_key(adb, r.trackID) << " ";
      else
	std::cout << r.trackID << " ";
      std::cout << r.count << std::endl;

      // Reverse the order of the points stored in point_queues
      unsigned int qsize=point_queues[r.trackID].size();
      for(unsigned int k=0; k < qsize; k++){
	point_queue.push(point_queues[r.trackID].top());
	point_queues[r.trackID].pop();
      }
      for(unsigned int k=0; k < qsize; k++){
	rk = point_queue.top();
	std::cout << rk.dist << " " << rk.qpos << " " << rk.spos << std::endl;
	point_queue.pop();
      }
    }
  } else {
    adb__queryResponse *response = (adb__queryResponse *) adbQueryResponse;
    response->result.__sizeRlist=size*pointNN;
    response->result.__sizeDist=size*pointNN;
    response->result.__sizeQpos=size*pointNN;
    response->result.__sizeSpos=size*pointNN;
    response->result.Rlist= (char **) soap_malloc(soap, size * pointNN * sizeof(char *));
    response->result.Dist = (double *) soap_malloc(soap, size * pointNN * sizeof(double));
    response->result.Qpos = (unsigned int *) soap_malloc(soap, size * pointNN * sizeof(unsigned int));
    response->result.Spos = (unsigned int *) soap_malloc(soap, size * pointNN * sizeof(unsigned int));
    unsigned int k = 0;
    // Loop over returned tracks
    for(rit = v.rbegin(); rit < v.rend(); rit++) {
      r = *rit;
      // Reverse the order of the points stored in point_queues
      unsigned int qsize=point_queues[r.trackID].size();
      while(qsize--){
	point_queue.push(point_queues[r.trackID].top());
	point_queues[r.trackID].pop();
      }
      qsize=point_queue.size();
      unsigned int numReports = pointNN;
      while(numReports--){ // pop the rest of the points
	if(qsize)
	  rk = point_queue.top(); // Take one point from the top of the queue
	else{
	  rk.dist = 1000000000.0;
	  rk.qpos = 0xFFFFFFFF;
	  rk.spos = 0xFFFFFFFF;
	}
	  
	response->result.Rlist[k] = (char *) soap_malloc(soap, O2_MAXFILESTR);
	response->result.Dist[k] = rk.dist;
	response->result.Qpos[k] = rk.qpos;
	response->result.Spos[k] = rk.spos;
	if(qsize){
	  if(adb)
	    snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID));
	  else
	    snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID);	
	  point_queue.pop();
	  qsize--;
	}
	else
	  snprintf(response->result.Rlist[k], O2_MAXFILESTR, "NULL");
	k++;
      }
    }
 }
  delete[] point_queues;
}

/********** ONE-TO-ONE REPORTERS *****************/

// track Sequence Query Radius NN Reporter One-to-One
// for each query point find the single best matching target point in all database
// report qpos, spos and trackID
class trackSequenceQueryRadNNReporterOneToOne : public Reporter { 
public:
  trackSequenceQueryRadNNReporterOneToOne(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles);
  ~trackSequenceQueryRadNNReporterOneToOne();
  void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist);
  void report(adb_t *adb, struct soap *soap, void *adbQueryResponse);
 protected:
  unsigned int pointNN;
  unsigned int trackNN;
  unsigned int numFiles;
  std::set< NNresult > *set;
  std::vector< NNresult> *point_queue;
  unsigned int *count;

};

trackSequenceQueryRadNNReporterOneToOne::trackSequenceQueryRadNNReporterOneToOne(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles):
pointNN(pointNN), trackNN(trackNN), numFiles(numFiles) {
  // Where to count Radius track matches (one-to-one)
  set = new std::set< NNresult >; 
  // Where to insert individual point matches (one-to-many)
  point_queue = new std::vector< NNresult >;
  
  count = new unsigned int[numFiles];
  for (unsigned i = 0; i < numFiles; i++) {
    count[i] = 0;
  }
}

trackSequenceQueryRadNNReporterOneToOne::~trackSequenceQueryRadNNReporterOneToOne() {
  delete set;
  delete [] count;
}

void trackSequenceQueryRadNNReporterOneToOne::add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist) {
  std::set< NNresult >::iterator it;
  NNresult r;

  r.qpos = qpos;
  r.trackID = trackID;
  r.spos = spos;
  r.dist = dist;

  if(point_queue->size() < r.qpos + 1){
    point_queue->resize( r.qpos + 1 );
    (*point_queue)[r.qpos].dist = 1e6;
  }

  if (r.dist < (*point_queue)[r.qpos].dist)
    (*point_queue)[r.qpos] = r;

}

void trackSequenceQueryRadNNReporterOneToOne::report(adb_t *adb, struct soap *soap, void *adbQueryResponse) {
  if(adbQueryResponse==0) {
    std::vector< NNresult >::iterator vit;
    NNresult rk;
    for( vit = point_queue->begin() ; vit < point_queue->end() ; vit++ ){
      rk = *vit;
      std::cout << rk.dist << " " 
		<< rk.qpos << " " 
		<< rk.spos << " ";
      if(adb)
	std::cout << audiodb_index_key(adb, rk.trackID) << " ";
      else
	std::cout << rk.trackID << " "; 
      std::cout << std::endl;
      }
  } else {
    // FIXME
  }
}

#endif