Added RLCSA index option
[SXSI/TextCollection.git] / incbwt / lcp_test.cpp
diff --git a/incbwt/lcp_test.cpp b/incbwt/lcp_test.cpp
new file mode 100644 (file)
index 0000000..5444a97
--- /dev/null
@@ -0,0 +1,244 @@
+#include <algorithm>
+#include <cstdlib>
+#include <ctime>
+#include <fstream>
+#include <iostream>
+
+#include "rlcsa.h"
+#include "misc/utils.h"
+
+
+using namespace CSA;
+
+
+int main(int argc, char** argv)
+{
+  std::cout << "RLCSA LCP test" << std::endl;
+  if(argc < 5)
+  {
+    std::cout << "Usage: lcp_test basename queries runs modes [random_seed]" << std::endl;
+    std::cout << std::endl;
+    std::cout << "Supported modes:" << std::endl;
+    std::cout << "d -- Direct LCP" << std::endl;
+    std::cout << "p -- PLCP" << std::endl;
+    std::cout << "s -- Sampled LCP" << std::endl;
+    std::cout << "h -- Hybrid: PLCP and Sampled LCP" << std::endl;
+    std::cout << "l -- Locate" << std::endl;
+    std::cout << "v -- Verify results" << std::endl;
+    std::cout << std::endl;
+    return 1;
+  }
+
+  std::string base_name = argv[1];
+  std::cout << "Base name: " << base_name << std::endl;
+  usint queries = atoi(argv[2]);
+  std::cout << "Number of queries: " << queries << std::endl;
+  usint runs = std::max(1, atoi(argv[3]));
+  std::cout << "Number of test runs: " << runs << std::endl;
+
+  std::string mode_string(argv[4]);
+  usint modes = 0;
+  bool mode_direct  = (mode_string.find('d') != std::string::npos);
+  bool mode_plcp    = (mode_string.find('p') != std::string::npos);
+  bool mode_sampled = (mode_string.find('s') != std::string::npos);
+  bool mode_hybrid  = (mode_string.find('h') != std::string::npos);
+  bool mode_locate  = (mode_string.find('l') != std::string::npos);
+  bool mode_verify  = (mode_string.find('v') != std::string::npos);
+  std::cout << "Modes: ";
+  if(mode_direct)  { std::cout << "direct "; modes++; }
+  if(mode_plcp)    { std::cout << "plcp "; modes++; }
+  if(mode_sampled) { std::cout << "sampled "; modes++; }
+  if(mode_hybrid)  { std::cout << "hybrid "; modes++; }
+  if(mode_locate)  { std::cout << "locate "; }
+  if(mode_verify)  { std::cout << "verify"; }
+  std::cout << std::endl;
+
+  usint seed = 0xDEADBEEF;
+  if(argc > 5)
+  {
+    seed = atoi(argv[5]);
+  }
+  std::cout << "Random seed: " << seed << std::endl; 
+  std::cout << std::endl;
+  if(modes == 0 || queries == 0) { return 0; }
+
+  RLCSA rlcsa(base_name);
+  if((mode_plcp || mode_hybrid) && !rlcsa.supportsLocate())
+  {
+    std::cerr << "Error: Locate is not supported!" << std::endl;
+    return 2;
+  }
+  rlcsa.printInfo();
+  rlcsa.reportSize(true);
+
+  RLEVector* plcp = 0;
+  if(mode_plcp || mode_hybrid)
+  {
+    std::string plcp_name = base_name + PLCP_EXTENSION;
+    std::ifstream plcp_file(plcp_name.c_str(), std::ios_base::binary);
+    if(!plcp_file)
+    {
+      std::cerr << "Error: Cannot open PLCP file!" << std::endl;
+      return 3;
+    }
+    plcp = new RLEVector(plcp_file);
+    std::cout << "PLCP:            " << (plcp->reportSize() / (double)MEGABYTE) << " MB" << std::endl;
+    plcp_file.close();
+  }
+
+  LCPSamples* lcp = 0;
+  if(mode_sampled)
+  {
+    std::string lcp_name = base_name + LCP_SAMPLES_EXTENSION;
+    std::ifstream lcp_file(lcp_name.c_str(), std::ios_base::binary);
+    if(!lcp_file)
+    {
+      std::cerr << "Error: Cannot open LCP sample file!" << std::endl;
+      delete plcp;
+      return 4;
+    }
+    lcp = new LCPSamples(lcp_file);
+    std::cout << "Sampled LCP:     " << (lcp->reportSize() / (double)MEGABYTE) << " MB" << std::endl;
+    lcp_file.close();
+  }
+
+  LCPSamples* minimal = 0;
+  if(mode_hybrid)
+  {
+    std::string minimal_name = base_name + ".minimal";
+    std::ifstream minimal_file(minimal_name.c_str(), std::ios_base::binary);
+    if(!minimal_file)
+    {
+      std::cerr << "Error: Cannot open minimal LCP sample file!" << std::endl;
+      delete plcp; delete lcp;
+      return 5;
+    }
+    minimal = new LCPSamples(minimal_file);
+    std::cout << "Minimal samples: " << (minimal->reportSize() / (double)MEGABYTE) << " MB" << std::endl;
+    minimal_file.close();
+  }
+  std::cout << std::endl;
+
+  srand(seed);
+  usint* positions = new usint[queries];
+  usint* results1 = new usint[queries];
+  usint* results2 = new usint[queries];
+  usint* results3 = new usint[queries];
+  usint* results4 = new usint[queries];
+  usint* results5 = new usint[queries];
+  for(usint i = 0; i < queries; i++)
+  {
+    positions[i] = rand() % rlcsa.getSize();
+  }
+  double start, time;
+
+  if(mode_direct)
+  {
+    std::cout << "Direct LCP computation:" << std::endl;
+    for(usint j = 0; j < runs; j++)
+    {
+      start = readTimer();
+      for(usint i = 0; i < queries; i++)
+      {
+        results1[i] = rlcsa.lcpDirect(positions[i]);
+      }
+      time = readTimer() - start;
+      std::cout << queries << " queries in " << time << " seconds (" << (queries / time) << " / s)" << std::endl;
+    }
+    std::cout << std::endl;
+  }
+
+  if(mode_plcp)
+  {
+    std::cout << "Using PLCP:" << std::endl;
+    RLEVector::Iterator iter(*plcp);
+    for(usint j = 0; j < runs; j++)
+    {
+      start = readTimer();
+      for(usint i = 0; i < queries; i++)
+      {
+        usint pos = rlcsa.locate(positions[i]);
+        results2[i] = iter.select(pos) - 2 * pos;
+      }
+      time = readTimer() - start;
+      std::cout << queries << " queries in " << time << " seconds (" << (queries / time) << " / s)" << std::endl;
+    }
+    std::cout << std::endl;
+  }
+
+  if(mode_sampled)
+  {
+    std::cout << "Using Sampled LCP:" << std::endl;
+    for(usint j = 0; j < runs; j++)
+    {
+      start = readTimer();
+      for(usint i = 0; i < queries; i++)
+      {
+        results3[i] = rlcsa.lcp(positions[i], *lcp);
+      }
+      time = readTimer() - start;
+      std::cout << queries << " queries in " << time << " seconds (" << (queries / time) << " / s)" << std::endl;
+    }
+    std::cout << std::endl;
+  }
+
+  if(mode_hybrid)
+  {
+    std::cout << "Using hybrid approach:" << std::endl;
+    for(usint j = 0; j < runs; j++)
+    {
+      start = readTimer();
+      for(usint i = 0; i < queries; i++)
+      {
+        results4[i] = rlcsa.lcp(positions[i], *minimal, *plcp);
+      }
+      time = readTimer() - start;
+      std::cout << queries << " queries in " << time << " seconds (" << (queries / time) << " / s)" << std::endl;
+    }
+    std::cout << std::endl;
+  }
+
+  if(mode_locate)
+  {
+    std::cout << "Locate:" << std::endl;
+    for(usint j = 0; j < runs; j++)
+    {
+      start = readTimer();
+      for(usint i = 0; i < queries; i++)
+      {
+        results5[i] = rlcsa.locate(positions[i]);
+      }
+      time = readTimer() - start;
+      std::cout << queries << " queries in " << time << " seconds (" << (queries / time) << " / s)" << std::endl;
+    }
+    std::cout << std::endl;
+  }
+
+  if(mode_verify && modes > 1)
+  {
+    for(usint i = 0; i < queries; i++)
+    {
+      bool ok = true;
+      ok &= !mode_direct  | !mode_plcp    | (results1[i] == results2[i]);
+      ok &= !mode_direct  | !mode_sampled | (results1[i] == results3[i]);
+      ok &= !mode_direct  | !mode_hybrid  | (results1[i] == results4[i]);
+      ok &= !mode_plcp    | !mode_sampled | (results2[i] == results3[i]);
+      ok &= !mode_plcp    | !mode_hybrid  | (results2[i] == results4[i]);
+      ok &= !mode_sampled | !mode_hybrid  | (results3[i] == results4[i]);
+      if(!ok)
+      {
+        std::cout << "Query " << i << ": LCP[" << positions[i] << "] = ";
+        if(mode_direct)  { std::cout << results1[i] << " (direct) ";  }
+        if(mode_plcp)    { std::cout << results2[i] << " (plcp) ";    }
+        if(mode_sampled) { std::cout << results3[i] << " (sampled) "; }
+        if(mode_hybrid)  { std::cout << results4[i] << " (hybrid) ";  }
+        std::cout << std::endl;
+      }
+    }
+  }
+
+  delete[] positions;
+  delete[] results1; delete[] results2; delete[] results3; delete[] results4; delete[] results5;
+  delete plcp; delete lcp; delete minimal;
+  return 0;
+}