From a7ffcd8d513e4886633f9d36d12dcdaa7722ea6d Mon Sep 17 00:00:00 2001 From: leandro Date: Thu, 27 Jun 2019 18:06:55 +0100 Subject: [PATCH 1/4] #151 --- include/kmergraphwithcoverage.h | 16 ++++++++++++---- src/kmergraphwithcoverage.cpp | 24 ++++++++++++++++-------- src/pangenome/pangraph.cpp | 4 ++-- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/include/kmergraphwithcoverage.h b/include/kmergraphwithcoverage.h index 6a33ce29..fd3be754 100644 --- a/include/kmergraphwithcoverage.h +++ b/include/kmergraphwithcoverage.h @@ -22,7 +22,7 @@ class KmerGraphWithCoverage { private: //each coverage is represented as a std::vector, each position of the vector representing the coverage of a sample //each coverage of a sample is represented by a std::pair, for the forward and reverse reads coverage of that sample - std::vector>> nodeIndex2SampleCoverage; + std::vector>> nodeIndex2SampleCoverage; uint32_t exp_depth_covg; float binomial_parameter_p; float negative_binomial_parameter_p; @@ -48,13 +48,18 @@ class KmerGraphWithCoverage { virtual ~KmerGraphWithCoverage() = default; //getter + //TODO: we should return a uint16_t instead of a uint32_t, but I did not want to change the interface + //TODO: converting uint16_t to uint32_t is safe anyway + //TODO: some parts of the code accumulates under the type of this variable, so it might be dangerous to change to uint16_t wihtout careful analysis + //TODO: leaving to uint32_t to be safe uint32_t get_covg(uint32_t node_id, bool strand, uint32_t sample_id) const; + uint32_t get_num_reads() const { return num_reads; } uint32_t get_total_number_samples() const {return total_number_samples; } //setters void increment_covg(uint32_t node_id, bool strand, uint32_t sample_id); - void set_covg(uint32_t node_id, uint32_t value, bool strand, uint32_t sample_id); + void set_covg(uint32_t node_id, uint16_t value, bool strand, uint32_t sample_id); void set_exp_depth_covg(const uint32_t); void set_binomial_parameter_p(const float); void set_negative_binomial_parameters(const float &, const float &); @@ -62,8 +67,11 @@ class KmerGraphWithCoverage { void set_num_reads(uint32_t num_reads) { this->num_reads = num_reads; } void zeroCoverages() { - for (auto &sampleCoverage: nodeIndex2SampleCoverage) - sampleCoverage = std::vector>(total_number_samples); + for (auto &sampleCoverage: nodeIndex2SampleCoverage) { + sampleCoverage = std::vector>(total_number_samples); + sampleCoverage.shrink_to_fit(); //tries to make this information as compact as possible (TODO: use sdsl?) + } + } float nbin_prob(uint32_t, const uint32_t &sample_id); diff --git a/src/kmergraphwithcoverage.cpp b/src/kmergraphwithcoverage.cpp index 0ffebc03..acb4bf05 100644 --- a/src/kmergraphwithcoverage.cpp +++ b/src/kmergraphwithcoverage.cpp @@ -5,6 +5,7 @@ #include /* NULL */ #include /* srand, rand */ #include +#include #include #include @@ -36,10 +37,15 @@ void KmerGraphWithCoverage::set_binomial_parameter_p(const float e_rate) { void KmerGraphWithCoverage::increment_covg(uint32_t node_id, bool strand, uint32_t sample_id) { assert(this->nodeIndex2SampleCoverage[node_id].size() > sample_id); + //get a pointer to the value we want to increment + uint16_t* coverage_ptr = nullptr; if (strand) - this->nodeIndex2SampleCoverage[node_id][sample_id].first++; + coverage_ptr = &(this->nodeIndex2SampleCoverage[node_id][sample_id].first); else - this->nodeIndex2SampleCoverage[node_id][sample_id].second++; + coverage_ptr = &(this->nodeIndex2SampleCoverage[node_id][sample_id].second); + + if ((*coverage_ptr) < UINT16_MAX) //checks if it is safe to increase the coverage (no overflow) + ++(*coverage_ptr); } uint32_t KmerGraphWithCoverage::get_covg(uint32_t node_id, bool strand, uint32_t sample_id) const { @@ -48,12 +54,12 @@ uint32_t KmerGraphWithCoverage::get_covg(uint32_t node_id, bool strand, uint32_t return 0; if (strand) - return this->nodeIndex2SampleCoverage[node_id][sample_id].first; + return (uint32_t)(this->nodeIndex2SampleCoverage[node_id][sample_id].first); else - return this->nodeIndex2SampleCoverage[node_id][sample_id].second; + return (uint32_t)(this->nodeIndex2SampleCoverage[node_id][sample_id].second); } -void KmerGraphWithCoverage::set_covg(uint32_t node_id, uint32_t value, bool strand, uint32_t sample_id) { +void KmerGraphWithCoverage::set_covg(uint32_t node_id, uint16_t value, bool strand, uint32_t sample_id) { assert(this->nodeIndex2SampleCoverage[node_id].size() > sample_id); if (strand) this->nodeIndex2SampleCoverage[node_id][sample_id].first = value; @@ -416,6 +422,7 @@ void KmerGraphWithCoverage::save(const std::string &filepath, const std::shared_ } //TODO: THIS SHOULD BE RECODED, WE ARE DUPLICATING CODE HERE (SEE KmerGraph::load())!!! +//TODO: remove this method? void KmerGraphWithCoverage::load(const std::string &filepath) { //TODO: this might be dangerous, recode this? auto kmer_prg = const_cast(this->kmer_prg); @@ -425,7 +432,8 @@ void KmerGraphWithCoverage::load(const std::string &filepath) { std::string line; std::vector split_line; std::stringstream ss; - uint32_t id = 0, covg, from, to; + uint32_t id = 0, from, to; + uint16_t covg; prg::Path p; uint32_t num_nodes = 0; @@ -466,9 +474,9 @@ void KmerGraphWithCoverage::load(const std::string &filepath) { if (kmer_prg->k == 0 and p.length() > 0) { kmer_prg->k = p.length(); } - covg = stoi(split(split_line[3], "FC:i:")[0]); + covg = (uint16_t)(stoul(split(split_line[3], "FC:i:")[0])); set_covg(n->id, covg, 0, sample_id); - covg = stoi(split(split_line[4], "RC:i:")[0]); + covg = (uint16_t)(stoul(split(split_line[4], "RC:i:")[0])); set_covg(n->id, covg, 1, sample_id); if (split_line.size() >= 6) { n->num_AT = std::stoi(split_line[5]); diff --git a/src/pangenome/pangraph.cpp b/src/pangenome/pangraph.cpp index 06f473a0..2404e315 100644 --- a/src/pangenome/pangraph.cpp +++ b/src/pangenome/pangraph.cpp @@ -346,8 +346,8 @@ void pangenome::Graph::copy_coverages_to_kmergraphs(const Graph &ref_pangraph, c for (auto & kmergraph_node_ptr : pangraph_node.kmer_prg_with_coverage.kmer_prg->nodes){ const auto &knode_id = kmergraph_node_ptr->id; assert(knode_id < ref_node.kmer_prg_with_coverage.kmer_prg->nodes.size()); - pangraph_node.kmer_prg_with_coverage.set_covg(knode_id, ref_node.kmer_prg_with_coverage.get_covg(knode_id, 0, ref_sample_id), 0, sample_id); - pangraph_node.kmer_prg_with_coverage.set_covg(knode_id, ref_node.kmer_prg_with_coverage.get_covg(knode_id, 1, ref_sample_id), 1, sample_id); + pangraph_node.kmer_prg_with_coverage.set_covg(knode_id, (uint16_t)(ref_node.kmer_prg_with_coverage.get_covg(knode_id, 0, ref_sample_id)), 0, sample_id); + pangraph_node.kmer_prg_with_coverage.set_covg(knode_id, (uint16_t)(ref_node.kmer_prg_with_coverage.get_covg(knode_id, 1, ref_sample_id)), 1, sample_id); } } } From 8b4899acf605e3207fc38a021b64e1e0cedfdcd6 Mon Sep 17 00:00:00 2001 From: leandro Date: Fri, 28 Jun 2019 14:03:07 +0100 Subject: [PATCH 2/4] Adding more clarifications about the return type of KmerGraphWithCoverage::get_covg() --- include/kmergraphwithcoverage.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/include/kmergraphwithcoverage.h b/include/kmergraphwithcoverage.h index fd3be754..faeb8055 100644 --- a/include/kmergraphwithcoverage.h +++ b/include/kmergraphwithcoverage.h @@ -47,13 +47,19 @@ class KmerGraphWithCoverage { KmerGraphWithCoverage& operator=(KmerGraphWithCoverage&& other) = default; //move assignment operator virtual ~KmerGraphWithCoverage() = default; - //getter - //TODO: we should return a uint16_t instead of a uint32_t, but I did not want to change the interface - //TODO: converting uint16_t to uint32_t is safe anyway - //TODO: some parts of the code accumulates under the type of this variable, so it might be dangerous to change to uint16_t wihtout careful analysis - //TODO: leaving to uint32_t to be safe + //getters + /* + TODO: we should return a uint16_t instead of a uint32_t, but I did not want to change the interface, as it can be dangerous + WARNING: some parts of the code accumulates under the type of this return value, + so it might be dangerous to change to uint16_t without careful analysis. + e.g.: I can see summing a bunch of coverage and potentially getting a value larger than 65535, + which would incur overflow and bugs. + NOTE: converting uint16_t to uint32_t is safe anyway, so it is fine to leave like this + NOTE: the advantage of returning a uint16_t here is a negligible improvement in RAM usage, so I don't think it is + worth the risk now + TODO: leaving return type as uint32_t to be safe for now, need a recheck later + */ uint32_t get_covg(uint32_t node_id, bool strand, uint32_t sample_id) const; - uint32_t get_num_reads() const { return num_reads; } uint32_t get_total_number_samples() const {return total_number_samples; } From ea80fac3c03b8870d77aaa56921d0e4100aab272 Mon Sep 17 00:00:00 2001 From: leandro Date: Fri, 28 Jun 2019 15:25:05 +0100 Subject: [PATCH 3/4] Adding a test for get_covg(), set_covg() and increment_covg() --- test/kmergraphwithcoverage_test.cpp | 86 +++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/test/kmergraphwithcoverage_test.cpp b/test/kmergraphwithcoverage_test.cpp index a844662c..39e7cc13 100644 --- a/test/kmergraphwithcoverage_test.cpp +++ b/test/kmergraphwithcoverage_test.cpp @@ -9,6 +9,7 @@ #include #include #include +#include using namespace prg; @@ -105,6 +106,91 @@ TEST(KmerGraphWithCoverageTest, assign) { EXPECT_EQ(kmergraph2, kmergraph2); }*/ +TEST(KmerGraphWithCoverageTest, get_and_set_increment_covg){ + //create a kmergraph with 5 nodes + const uint32_t nb_of_nodes = 5; + KmerGraph kmergraph; + + auto create_kmergraph_helper = [&](uint32_t node_index) { + std::deque interval = {Interval(node_index, node_index)}; + prg::Path path; + path.initialize(interval); + kmergraph.add_node(path); + }; + + for (uint32_t node_index=0; node_index < nb_of_nodes; ++node_index) + create_kmergraph_helper(node_index); + + //create a KmerGraphWithCoverage on 10 samples + const uint32_t nb_of_samples = 10; + KmerGraphWithCoverage kmergraph_with_coverage(&kmergraph, nb_of_samples); + + //function that will help to check the coverages in the tests + using Nodeindex_Strand_Sampleindex_Tuple = std::tuple; + std::map expected_coverage; + auto check_coverages = [&]() { + //verifies all coverage matches expected_coverage + //if the tuple does not exist, then the expected_coverage is assumed to be 0 (as per std::map::operator[] and uint16_t default constructor) + for (uint32_t node_index=0; node_index < nb_of_nodes; ++node_index) { + for (uint32_t sample_index=0; sample_index Date: Tue, 2 Jul 2019 23:20:00 +0100 Subject: [PATCH 4/4] Implementing suggestions by Michael at https://github.com/rmcolq/pandora/pull/152 --- include/kmergraphwithcoverage.h | 12 +- src/kmergraphwithcoverage.cpp | 32 ++-- test/kmergraphwithcoverage_test.cpp | 233 +++++++++++++++++++--------- 3 files changed, 183 insertions(+), 94 deletions(-) diff --git a/include/kmergraphwithcoverage.h b/include/kmergraphwithcoverage.h index faeb8055..d0f920d6 100644 --- a/include/kmergraphwithcoverage.h +++ b/include/kmergraphwithcoverage.h @@ -22,7 +22,7 @@ class KmerGraphWithCoverage { private: //each coverage is represented as a std::vector, each position of the vector representing the coverage of a sample //each coverage of a sample is represented by a std::pair, for the forward and reverse reads coverage of that sample - std::vector>> nodeIndex2SampleCoverage; + std::vector>> node_index_to_sample_coverage; uint32_t exp_depth_covg; float binomial_parameter_p; float negative_binomial_parameter_p; @@ -36,7 +36,7 @@ class KmerGraphWithCoverage { //constructor, destructors, etc KmerGraphWithCoverage(KmerGraph * kmer_prg, uint32_t total_number_samples=1) : - nodeIndex2SampleCoverage(kmer_prg->nodes.size()), + node_index_to_sample_coverage(kmer_prg->nodes.size()), exp_depth_covg{0}, binomial_parameter_p{1}, negative_binomial_parameter_p{0.015}, negative_binomial_parameter_r{2}, thresh{-25}, total_number_samples{total_number_samples}, num_reads{0}, kmer_prg{kmer_prg} { assert(kmer_prg != nullptr); zeroCoverages(); @@ -59,13 +59,13 @@ class KmerGraphWithCoverage { worth the risk now TODO: leaving return type as uint32_t to be safe for now, need a recheck later */ - uint32_t get_covg(uint32_t node_id, bool strand, uint32_t sample_id) const; + uint32_t get_covg(uint32_t node_id, bool is_forward, uint32_t sample_id) const; uint32_t get_num_reads() const { return num_reads; } uint32_t get_total_number_samples() const {return total_number_samples; } //setters - void increment_covg(uint32_t node_id, bool strand, uint32_t sample_id); - void set_covg(uint32_t node_id, uint16_t value, bool strand, uint32_t sample_id); + void increment_covg(uint32_t node_id, bool is_forward, uint32_t sample_id); + void set_covg(uint32_t node_id, uint16_t value, bool is_forward, uint32_t sample_id); void set_exp_depth_covg(const uint32_t); void set_binomial_parameter_p(const float); void set_negative_binomial_parameters(const float &, const float &); @@ -73,7 +73,7 @@ class KmerGraphWithCoverage { void set_num_reads(uint32_t num_reads) { this->num_reads = num_reads; } void zeroCoverages() { - for (auto &sampleCoverage: nodeIndex2SampleCoverage) { + for (auto &sampleCoverage: node_index_to_sample_coverage) { sampleCoverage = std::vector>(total_number_samples); sampleCoverage.shrink_to_fit(); //tries to make this information as compact as possible (TODO: use sdsl?) } diff --git a/src/kmergraphwithcoverage.cpp b/src/kmergraphwithcoverage.cpp index acb4bf05..68b5b178 100644 --- a/src/kmergraphwithcoverage.cpp +++ b/src/kmergraphwithcoverage.cpp @@ -34,37 +34,37 @@ void KmerGraphWithCoverage::set_binomial_parameter_p(const float e_rate) { //cout << "using p: " << p << endl; } -void KmerGraphWithCoverage::increment_covg(uint32_t node_id, bool strand, uint32_t sample_id) { - assert(this->nodeIndex2SampleCoverage[node_id].size() > sample_id); +void KmerGraphWithCoverage::increment_covg(uint32_t node_id, bool is_forward, uint32_t sample_id) { + assert(this->node_index_to_sample_coverage[node_id].size() > sample_id); //get a pointer to the value we want to increment uint16_t* coverage_ptr = nullptr; - if (strand) - coverage_ptr = &(this->nodeIndex2SampleCoverage[node_id][sample_id].first); + if (is_forward) + coverage_ptr = &(this->node_index_to_sample_coverage[node_id][sample_id].first); else - coverage_ptr = &(this->nodeIndex2SampleCoverage[node_id][sample_id].second); + coverage_ptr = &(this->node_index_to_sample_coverage[node_id][sample_id].second); if ((*coverage_ptr) < UINT16_MAX) //checks if it is safe to increase the coverage (no overflow) ++(*coverage_ptr); } -uint32_t KmerGraphWithCoverage::get_covg(uint32_t node_id, bool strand, uint32_t sample_id) const { +uint32_t KmerGraphWithCoverage::get_covg(uint32_t node_id, bool is_forward, uint32_t sample_id) const { - if (this->nodeIndex2SampleCoverage[node_id].size() <= sample_id) + if (this->node_index_to_sample_coverage[node_id].size() <= sample_id) return 0; - if (strand) - return (uint32_t)(this->nodeIndex2SampleCoverage[node_id][sample_id].first); + if (is_forward) + return (uint32_t)(this->node_index_to_sample_coverage[node_id][sample_id].first); else - return (uint32_t)(this->nodeIndex2SampleCoverage[node_id][sample_id].second); + return (uint32_t)(this->node_index_to_sample_coverage[node_id][sample_id].second); } -void KmerGraphWithCoverage::set_covg(uint32_t node_id, uint16_t value, bool strand, uint32_t sample_id) { - assert(this->nodeIndex2SampleCoverage[node_id].size() > sample_id); - if (strand) - this->nodeIndex2SampleCoverage[node_id][sample_id].first = value; +void KmerGraphWithCoverage::set_covg(uint32_t node_id, uint16_t value, bool is_forward, uint32_t sample_id) { + assert(this->node_index_to_sample_coverage[node_id].size() > sample_id); + if (is_forward) + this->node_index_to_sample_coverage[node_id][sample_id].first = value; else - this->nodeIndex2SampleCoverage[node_id][sample_id].second = value; + this->node_index_to_sample_coverage[node_id][sample_id].second = value; } @@ -377,7 +377,7 @@ void KmerGraphWithCoverage::save_covg_dist(const std::string &filepath) { const KmerNode &kmer_node = *kmer_node_ptr; uint32_t sample_id = 0; - for (const auto &sample_coverage: nodeIndex2SampleCoverage[kmer_node.id]) { + for (const auto &sample_coverage: node_index_to_sample_coverage[kmer_node.id]) { handle << kmer_node.id << " " << sample_id << " " << sample_coverage.first << " " diff --git a/test/kmergraphwithcoverage_test.cpp b/test/kmergraphwithcoverage_test.cpp index 39e7cc13..73d39bff 100644 --- a/test/kmergraphwithcoverage_test.cpp +++ b/test/kmergraphwithcoverage_test.cpp @@ -13,6 +13,73 @@ using namespace prg; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//helper functions - used inside the tests to simplify them, and help with their readability and understanding +//e.g. inside a test, it is better for a reader to read one line: +//KmerGraph kmergraph = create_kmergraph(nb_of_nodes); +//than 5+ lines which achieves this +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//create a kmergraph with the given nb of nodes +KmerGraph create_kmergraph(uint32_t nb_of_nodes) { + KmerGraph kmergraph; + + for (uint32_t node_index = 0; node_index < nb_of_nodes; ++node_index) { + std::deque interval = {Interval(node_index, node_index)}; + prg::Path path; + path.initialize(interval); + kmergraph.add_node(path); + } + + return kmergraph; +} + + +using Nodeindex_Strand_Sampleindex_Tuple = std::tuple; + +//function that will help to check the coverages in the tests +void check_coverages(const KmerGraphWithCoverage &kmergraph_with_coverage, + std::map &expected_coverage, + uint32_t nb_of_nodes, uint32_t nb_of_samples) { + //verifies all coverage matches expected_coverage + //if the tuple does not exist, then the expected_coverage is assumed to be 0 (as per std::map::operator[] and uint16_t default constructor) + for (uint32_t node_index = 0; node_index < nb_of_nodes; ++node_index) { + for (uint32_t sample_index = 0; sample_index < nb_of_samples; ++sample_index) { + EXPECT_EQ(kmergraph_with_coverage.get_covg(node_index, 0, sample_index), + expected_coverage[make_tuple(node_index, 0, sample_index)]); + EXPECT_EQ(kmergraph_with_coverage.get_covg(node_index, 1, sample_index), + expected_coverage[make_tuple(node_index, 1, sample_index)]); + } + } +} + +//set the coverage in both kmergraph_with_coverage and expected_coverage +void set_covg_helper (KmerGraphWithCoverage &kmergraph_with_coverage, + std::map &expected_coverage, + uint32_t node_id, uint16_t value, bool strand, uint32_t sample_id) { + kmergraph_with_coverage.set_covg(node_id, value, strand, sample_id); + expected_coverage[make_tuple(node_id, strand, sample_id)] = value; +} + +//increment the coverage in both kmergraph_with_coverage and expected_coverage +void increment_covg_helper(KmerGraphWithCoverage &kmergraph_with_coverage, + std::map &expected_coverage, + uint32_t node_id, bool is_forward, uint32_t sample_id) { + auto old_covg = kmergraph_with_coverage.get_covg(node_id, is_forward, sample_id); + kmergraph_with_coverage.increment_covg(node_id, is_forward, sample_id); + expected_coverage[make_tuple(node_id, is_forward, sample_id)] = old_covg + 1; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//helper functions +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + + /*TEST(KmerGraphWithCoverageTest, equals) { KmerGraph kmergraph1, kmergraph2; deque d = {Interval(0, 3)}; @@ -106,88 +173,110 @@ TEST(KmerGraphWithCoverageTest, assign) { EXPECT_EQ(kmergraph2, kmergraph2); }*/ -TEST(KmerGraphWithCoverageTest, get_and_set_increment_covg){ - //create a kmergraph with 5 nodes + +TEST(KmerGraphWithCoverageTest, noCoverageSetAllCoverageShouldBe0) { const uint32_t nb_of_nodes = 5; - KmerGraph kmergraph; + KmerGraph kmergraph = create_kmergraph(nb_of_nodes); + const uint32_t nb_of_samples = 10; + KmerGraphWithCoverage kmergraph_with_coverage(&kmergraph, nb_of_samples); + std::map expected_coverage; - auto create_kmergraph_helper = [&](uint32_t node_index) { - std::deque interval = {Interval(node_index, node_index)}; - prg::Path path; - path.initialize(interval); - kmergraph.add_node(path); - }; + //expect all coverages to be 0 + check_coverages(kmergraph_with_coverage, expected_coverage, nb_of_nodes, nb_of_samples); +} + +TEST(KmerGraphWithCoverageTest, severalRamdomCoveragesSet) { + const uint32_t nb_of_nodes = 5; + KmerGraph kmergraph = create_kmergraph(nb_of_nodes); + const uint32_t nb_of_samples = 10; + KmerGraphWithCoverage kmergraph_with_coverage(&kmergraph, nb_of_samples); + std::map expected_coverage; - for (uint32_t node_index=0; node_index < nb_of_nodes; ++node_index) - create_kmergraph_helper(node_index); + //set some random coverages and verify if they are all correctly set + set_covg_helper(kmergraph_with_coverage, expected_coverage, 0, 100, 0, 5); + set_covg_helper(kmergraph_with_coverage, expected_coverage, 0, 150, 1, 5); + set_covg_helper(kmergraph_with_coverage, expected_coverage, 1, 789, 1, 9); + set_covg_helper(kmergraph_with_coverage, expected_coverage, 2, 120, 0, 3); + set_covg_helper(kmergraph_with_coverage, expected_coverage, 3, 130, 0, 2); + set_covg_helper(kmergraph_with_coverage, expected_coverage, 4, 780, 1, 7); + + check_coverages(kmergraph_with_coverage, expected_coverage, nb_of_nodes, nb_of_samples); +} - //create a KmerGraphWithCoverage on 10 samples +TEST(KmerGraphWithCoverageTest, maximumCoverageSet) { + const uint32_t nb_of_nodes = 5; + KmerGraph kmergraph = create_kmergraph(nb_of_nodes); const uint32_t nb_of_samples = 10; KmerGraphWithCoverage kmergraph_with_coverage(&kmergraph, nb_of_samples); + std::map expected_coverage; + + //setup the maximum coverage + set_covg_helper(kmergraph_with_coverage, expected_coverage, 4, UINT16_MAX, 0, 1); + set_covg_helper(kmergraph_with_coverage, expected_coverage, 4, UINT16_MAX, 1, 1); + + check_coverages(kmergraph_with_coverage, expected_coverage, nb_of_nodes, nb_of_samples); +} + - //function that will help to check the coverages in the tests - using Nodeindex_Strand_Sampleindex_Tuple = std::tuple; +TEST(KmerGraphWithCoverageTest, minimumCoverageSet) { + const uint32_t nb_of_nodes = 5; + KmerGraph kmergraph = create_kmergraph(nb_of_nodes); + const uint32_t nb_of_samples = 10; + KmerGraphWithCoverage kmergraph_with_coverage(&kmergraph, nb_of_samples); std::map expected_coverage; - auto check_coverages = [&]() { - //verifies all coverage matches expected_coverage - //if the tuple does not exist, then the expected_coverage is assumed to be 0 (as per std::map::operator[] and uint16_t default constructor) - for (uint32_t node_index=0; node_index < nb_of_nodes; ++node_index) { - for (uint32_t sample_index=0; sample_index expected_coverage; + + + //set some random coverages + set_covg_helper(kmergraph_with_coverage, expected_coverage, 0, 100, 0, 5); + set_covg_helper(kmergraph_with_coverage, expected_coverage, 0, 150, 1, 5); + set_covg_helper(kmergraph_with_coverage, expected_coverage, 1, 789, 1, 9); + set_covg_helper(kmergraph_with_coverage, expected_coverage, 2, 120, 0, 3); + set_covg_helper(kmergraph_with_coverage, expected_coverage, 3, 130, 0, 2); + set_covg_helper(kmergraph_with_coverage, expected_coverage, 4, 780, 1, 7); + set_covg_helper(kmergraph_with_coverage, expected_coverage, 3, 0, 0, 1); + set_covg_helper(kmergraph_with_coverage, expected_coverage, 3, 0, 1, 1); + //test increment coverage + increment_covg_helper(kmergraph_with_coverage, expected_coverage, 0, 0, 5); + increment_covg_helper(kmergraph_with_coverage, expected_coverage, 0, 1, 5); + increment_covg_helper(kmergraph_with_coverage, expected_coverage, 1, 1, 9); + increment_covg_helper(kmergraph_with_coverage, expected_coverage, 2, 0, 3); + increment_covg_helper(kmergraph_with_coverage, expected_coverage, 3, 0, 2); + increment_covg_helper(kmergraph_with_coverage, expected_coverage, 4, 1, 7); + increment_covg_helper(kmergraph_with_coverage, expected_coverage, 3, 0, 1); + increment_covg_helper(kmergraph_with_coverage, expected_coverage, 3, 1, 1); + + check_coverages(kmergraph_with_coverage, expected_coverage, nb_of_nodes, nb_of_samples); +} + + +TEST(KmerGraphWithCoverageTest, incrementCoverageAboveMaximumValue) { + const uint32_t nb_of_nodes = 5; + KmerGraph kmergraph = create_kmergraph(nb_of_nodes); + const uint32_t nb_of_samples = 10; + KmerGraphWithCoverage kmergraph_with_coverage(&kmergraph, nb_of_samples); + std::map expected_coverage; + + set_covg_helper(kmergraph_with_coverage, expected_coverage, 2, UINT16_MAX, 0, 9); //first set to max value + check_coverages(kmergraph_with_coverage, expected_coverage, nb_of_nodes, nb_of_samples); kmergraph_with_coverage.increment_covg(2, 0, 9); //now try to increment + EXPECT_EQ(kmergraph_with_coverage.get_covg(2, 0, 9), UINT16_MAX); //should still be UINT16_MAX - check_coverages(); //to be sure nothing changed + check_coverages(kmergraph_with_coverage, expected_coverage, nb_of_nodes, nb_of_samples); //to be sure nothing changed }