#include <iostream>
#include <sstream>
#include <chrono>
#include <regex>
#include <time.h>
#include <stdio.h>
#include <vector>
#include <chrono>
#include <map>
#include <utility>
#include "bm.h"
#include "bmalgo.h"
#include "bmserial.h"
#include "bmrandom.h"
#include "bmsparsevec.h"
#include "bmsparsevec_compr.h"
#include "bmsparsevec_algo.h"
#include "bmsparsevec_serial.h"
#include "bmalgo_similarity.h"
#include "bmsparsevec_util.h"
#include "bmdbg.h"
#include "bmtimer.h"
#include "bmundef.h"
static
void show_help()
{
std::cerr
<< "BitMagic SNP Search Sample Utility (c) 2018" << std::endl
<< "-isnp file-name -- input set file (SNP FASTA) to parse" << std::endl
<< "-svout spase vector output -- sparse vector name to save" << std::endl
<< "-rscout rs-compressed spase vector output -- name to save" << std::endl
<< "-svin sparse vector input -- sparse vector file name to load " << std::endl
<< "-rscin rs-compressed sparse vector input -- file name to load " << std::endl
<< "-diag -- run diagnostics" << std::endl
<< "-timing -- collect timings" << std::endl
;
}
std::string sv_out_name;
std::string rsc_out_name;
std::string sv_in_name;
std::string rsc_in_name;
std::string isnp_name;
bool is_diag = false;
bool is_timing = false;
bool is_bench = false;
static
int parse_args(int argc, char *argv[])
{
for (int i = 1; i < argc; ++i)
{
std::string arg = argv[i];
if ((arg == "-h") || (arg == "--help"))
{
show_help();
return 0;
}
if (arg == "-svout" || arg == "--svout")
{
if (i + 1 < argc)
{
sv_out_name = argv[++i];
}
else
{
std::cerr << "Error: -svout requires file name" << std::endl;
return 1;
}
continue;
}
if (arg == "-rscout" || arg == "--rscout")
{
if (i + 1 < argc)
{
rsc_out_name = argv[++i];
}
else
{
std::cerr << "Error: -rscout requires file name" << std::endl;
return 1;
}
continue;
}
if (arg == "-svin" || arg == "--svin")
{
if (i + 1 < argc)
{
sv_in_name = argv[++i];
}
else
{
std::cerr << "Error: -svin requires file name" << std::endl;
return 1;
}
continue;
}
if (arg == "-rscin" || arg == "--rscin")
{
if (i + 1 < argc)
{
rsc_in_name = argv[++i];
}
else
{
std::cerr << "Error: -rscin requires file name" << std::endl;
return 1;
}
continue;
}
if (arg == "-isnp" || arg == "--isnp" || arg == "-snp" || arg == "--snp")
{
if (i + 1 < argc)
{
isnp_name = argv[++i];
}
else
{
std::cerr << "Error: -isnp requires file name" << std::endl;
return 1;
}
continue;
}
if (arg == "-diag" || arg == "--diag" || arg == "-d" || arg == "--d")
is_diag = true;
if (arg == "-timing" || arg == "--timing" || arg == "-t" || arg == "--t")
is_timing = true;
if (arg == "-bench" || arg == "--bench" || arg == "-b" || arg == "--b")
is_bench = true;
} return 0;
}
typedef bm::sparse_vector<unsigned, bm::bvector<> > sparse_vector_u32;
typedef bm::rsc_sparse_vector<unsigned, sparse_vector_u32 > rsc_sparse_vector_u32;
typedef std::vector<std::pair<unsigned, unsigned> > vector_pairs;
bm::chrono_taker::duration_map_type timing_map;
static
int load_snp_report(const std::string& fname, sparse_vector_u32& sv)
{
bm::chrono_taker tt1("1. parse input SNP chr report", 1, &timing_map);
std::ifstream fin(fname.c_str(), std::ios::in);
if (!fin.good())
return -1;
unsigned rs_id, rs_pos;
size_t idx;
std::string line;
std::string delim = " \t";
std::regex reg("\\s+");
std::sregex_token_iterator it_end;
bm::bvector<> bv_rs;
bv_rs.init();
unsigned rs_cnt = 0;
for (unsigned i = 0; std::getline(fin, line); ++i)
{
if (line.empty() ||
!isdigit(line.front())
)
continue;
std::sregex_token_iterator it(line.begin(), line.end(), reg, -1);
std::vector<std::string> line_vec(it, it_end);
if (line_vec.empty())
continue;
try
{
rs_id = unsigned(std::stoul(line_vec.at(0), &idx));
if (bv_rs.test(rs_id))
{
continue;
}
rs_pos = unsigned(std::stoul(line_vec.at(11), &idx));
bv_rs.set_bit_no_check(rs_id);
sv.set(rs_pos, rs_id);
++rs_cnt;
}
catch (std::exception& )
{
continue;
}
if (rs_cnt % (4 * 1024) == 0)
std::cout << "\r" << rs_cnt << " / " << i; }
std::cout << std::endl;
std::cout << "SNP count=" << rs_cnt << std::endl;
return 0;
}
static
void generate_random_subset(const sparse_vector_u32& sv, std::vector<unsigned>& vect, unsigned count)
{
const sparse_vector_u32::bvector_type* bv_null = sv.get_null_bvector();
bm::random_subset<bm::bvector<> > rand_sampler;
bm::bvector<> bv_sample;
rand_sampler.sample(bv_sample, *bv_null, count);
bm::bvector<>::enumerator en = bv_sample.first();
for (; en.valid(); ++en)
{
unsigned idx = *en;
unsigned v = sv[idx];
vect.push_back(v);
}
}
static
void build_vector_pairs(const sparse_vector_u32& sv, vector_pairs& vp)
{
sparse_vector_u32::const_iterator it = sv.begin();
sparse_vector_u32::const_iterator it_end = sv.end();
for (; it != it_end; ++it)
{
if (!it.is_null())
{
std::pair<unsigned, unsigned> pos2rs = std::make_pair(it.pos(), it.value());
vp.push_back(pos2rs);
}
}
}
static
bool search_vector_pairs(const vector_pairs& vp, unsigned rs_id, unsigned& pos)
{
for (unsigned i = 0; i < vp.size(); ++i)
{
if (vp[i].second == rs_id)
{
pos = vp[i].first;
return true;
}
}
return false;
}
static
void run_benchmark(const sparse_vector_u32& sv, const rsc_sparse_vector_u32& csv)
{
const unsigned rs_sample_count = 2000;
std::vector<unsigned> rs_vect;
generate_random_subset(sv, rs_vect, rs_sample_count);
if (rs_vect.empty())
{
std::cerr << "Benchmark subset empty!" << std::endl;
return;
}
vector_pairs vp;
build_vector_pairs(sv, vp);
bm::bvector<> bv_found1;
bm::bvector<> bv_found2;
bm::bvector<> bv_found3;
bv_found1.init(); bv_found2.init(); bv_found3.init();
if (!sv.empty())
{
bm::chrono_taker tt1("09. rs search (sv)", unsigned(rs_vect.size()), &timing_map);
bm::sparse_vector_scanner<sparse_vector_u32> scanner;
for (unsigned i = 0; i < rs_vect.size(); ++i)
{
unsigned rs_id = rs_vect[i];
unsigned rs_pos;
bool found = scanner.find_eq(sv, rs_id, rs_pos);
if (found)
{
bv_found1.set_bit_no_check(rs_pos);
}
else
{
std::cout << "Error: rs_id = " << rs_id << " not found!" << std::endl;
}
} }
if (!csv.empty())
{
bm::chrono_taker tt1("10. rs search (rsc_sv)", unsigned(rs_vect.size()), &timing_map);
bm::sparse_vector_scanner<rsc_sparse_vector_u32> scanner;
for (unsigned i = 0; i < rs_vect.size(); ++i)
{
unsigned rs_id = rs_vect[i];
unsigned rs_pos;
bool found = scanner.find_eq(csv, rs_id, rs_pos);
if (found)
{
bv_found2.set_bit_no_check(rs_pos);
}
else
{
std::cout << "rs_id = " << rs_id << " not found!" << std::endl;
}
} }
if (vp.size())
{
bm::chrono_taker tt1("11. rs search (std::vector<>)", unsigned(rs_vect.size()), &timing_map);
for (unsigned i = 0; i < rs_vect.size(); ++i)
{
unsigned rs_id = rs_vect[i];
unsigned rs_pos;
bool found = search_vector_pairs(vp, rs_id, rs_pos);
if (found)
{
bv_found3.set_bit_no_check(rs_pos);
}
else
{
std::cout << "rs_id = " << rs_id << " not found!" << std::endl;
}
} }
int res = bv_found1.compare(bv_found2);
if (res != 0)
{
std::cerr << "Error: search discrepancy (sparse search) detected!" << std::endl;
}
res = bv_found1.compare(bv_found3);
if (res != 0)
{
std::cerr << "Error: search discrepancy (std::vector<>) detected!" << std::endl;
}
}
int main(int argc, char *argv[])
{
if (argc < 3)
{
show_help();
return 1;
}
sparse_vector_u32 sv(bm::use_null);
rsc_sparse_vector_u32 csv;
try
{
auto ret = parse_args(argc, argv);
if (ret != 0)
return ret;
if (!isnp_name.empty())
{
auto res = load_snp_report(isnp_name, sv);
if (res != 0)
{
return res;
}
}
if (!sv_in_name.empty())
{
bm::chrono_taker tt1("02. Load sparse vector", 1, &timing_map);
file_load_svector(sv, sv_in_name);
}
if (!rsc_in_name.empty())
{
bm::chrono_taker tt1("03. Load rsc sparse vector", 1, &timing_map);
file_load_svector(csv, rsc_in_name);
}
if (csv.empty() && !sv.empty())
{
sparse_vector_u32 sv2(bm::use_null);
{
bm::chrono_taker tt1("04. rs compress sparse vector", 1, &timing_map);
csv.load_from(sv);
}
{
bm::chrono_taker tt1("05. rs de-compress sparse vector", 1, &timing_map);
csv.load_to(sv2);
}
if (!sv.equal(sv2)) {
std::cerr << "Error: rs-compressed vector check failed!" << std::endl;
return 1;
}
}
if (!sv_out_name.empty() && !sv.empty())
{
bm::chrono_taker tt1("07. Save sparse vector", 1, &timing_map);
sv.optimize();
file_save_svector(sv, sv_out_name);
}
if (!rsc_out_name.empty() && !csv.empty())
{
bm::chrono_taker tt1("08. Save RS sparse vector", 1, &timing_map);
csv.optimize();
file_save_svector(csv, rsc_out_name);
}
if (is_diag) {
if (!sv.empty())
{
std::cout << std::endl
<< "sparse vector statistics:"
<< std::endl;
bm::print_svector_stat(sv, true);
}
if (!csv.empty())
{
std::cout << std::endl
<< "RS compressed sparse vector statistics:"
<< std::endl;
bm::print_svector_stat(csv, true);
}
}
if (is_bench) {
run_benchmark(sv, csv);
}
if (is_timing) {
std::cout << std::endl << "Performance:" << std::endl;
bm::chrono_taker::print_duration_map(timing_map, bm::chrono_taker::ct_ops_per_sec);
}
}
catch (std::exception& ex)
{
std::cerr << "Error:" << ex.what() << std::endl;
return 1;
}
return 0;
}