-
Notifications
You must be signed in to change notification settings - Fork 82
Session: Ranges
Hannes Hauswedell edited this page Feb 5, 2018
·
6 revisions
Ranges (and views) is a proposal for addition to the C++ Standard, likely to be added in C++20. Luckily it is 99% library code and needs no changes to the language so we can use it now already by including a library!
Roughly speaking Ranges and views do what seqan::Infix
and seqan::ModifiedString
do, but in a well-defined manner and with easy composability.
- https://github.com/ericniebler/range-v3
- https://ericniebler.github.io/std/wg21/D4128.html
- https://www.youtube.com/watch?v=mFUXNMfaciE
- install GCC >= 6 or Clang >= 3.7
- clone the above git repository
- build your apps with
-std=c++14
Template code (click to expand)
#include <iostream>
#include <range/v3/all.hpp>
#include <string>
int main()
{
std::string s{"ACGTTTATGT"};
auto complement = [] (auto c)
{
switch (c)
{
case 'a': return 't';
case 'A': return 'T';
case 'c': return 'g';
case 'C': return 'G';
case 'g': return 'c';
case 'G': return 'C';
case 't': return 'a';
case 'T': return 'A';
default: return 'N';
}
};
// make reverse complement view
auto comp_view = // ?
std::cout << comp_view << '\n';
// create infix from [1, 6)
auto comp_view_inf = // ?
std::cout << comp_view_inf << '\n';
// transform back
auto orig_inf = // ?
std::cout << orig_inf << '\n';
return 0;
}
Solution: Click to expand
#include <iostream>
#include <range/v3/all.hpp>
#include <string>
int main()
{
std::string s{"ACGTTTATGT"};
auto complement = [] (auto c)
{
switch (c)
{
case 'a': return 't';
case 'A': return 'T';
case 'c': return 'g';
case 'C': return 'G';
case 'g': return 'c';
case 'G': return 'C';
case 't': return 'a';
case 'T': return 'A';
default: return 'N';
}
};
// make reverse complement view
auto comp_view = s | ranges::view::reverse | ranges::view::transform(complement);
std::cout << comp_view << '\n';
// create infix from [1, 7)
auto comp_view_inf = comp_view | ranges::view::drop(1) | ranges::view::take(5);
std::cout << comp_view_inf << '\n';
// transform back
auto orig_inf = comp_view_inf | ranges::view::reverse | ranges::view::transform(complement);
std::cout << orig_inf << '\n';
return 0;
}
Template code (click to expand)
#include <iostream>
#include <range/v3/all.hpp>
#include <string>
char const translation_table[4][4][4] =
{
{ // a??
{ 'K', 'N', 'K', 'N' }, // aa?
{ 'T', 'T', 'T', 'T' }, // ac?
{ 'R', 'S', 'R', 'S' }, // ag?
{ 'I', 'I', 'M', 'I' } // au?
}, { // c??
{ 'Q', 'H', 'Q', 'H' }, // ca?
{ 'P', 'P', 'P', 'P' }, // cc?
{ 'R', 'R', 'R', 'R' }, // cg?
{ 'L', 'L', 'L', 'L' } // cu?
}, { // g??
{ 'E', 'D', 'E', 'D' }, // ga?
{ 'A', 'A', 'A', 'A' }, // gc?
{ 'G', 'G', 'G', 'G' }, // gg?
{ 'V', 'V', 'V', 'V' } // gu?
}, { // u??
{ '*', 'Y', '*', 'Y' }, // ua?
{ 'S', 'S', 'S', 'S' }, // uc?
{ '*', 'C', 'W', 'C' }, // ug?
{ 'L', 'F', 'L', 'F' } // uu?
}
};
uint8_t ord_value(char c)
{
switch (c)
{
case 'c': case 'C': return 1;
case 'g': case 'G': return 2;
case 't': case 'T': case 'u': case 'U': return 3;
default: return 0;
}
}
int main()
{
std::string s{"ACGTTTATGTTTACGT"};
auto v = //?
std::cout << v << '\n';
return 0;
}
Solution (click to expand)
#include <iostream>
#include <range/v3/all.hpp>
#include <string>
char const translation_table[4][4][4] =
{
{ // a??
{ 'K', 'N', 'K', 'N' }, // aa?
{ 'T', 'T', 'T', 'T' }, // ac?
{ 'R', 'S', 'R', 'S' }, // ag?
{ 'I', 'I', 'M', 'I' } // au?
}, { // c??
{ 'Q', 'H', 'Q', 'H' }, // ca?
{ 'P', 'P', 'P', 'P' }, // cc?
{ 'R', 'R', 'R', 'R' }, // cg?
{ 'L', 'L', 'L', 'L' } // cu?
}, { // g??
{ 'E', 'D', 'E', 'D' }, // ga?
{ 'A', 'A', 'A', 'A' }, // gc?
{ 'G', 'G', 'G', 'G' }, // gg?
{ 'V', 'V', 'V', 'V' } // gu?
}, { // u??
{ '*', 'Y', '*', 'Y' }, // ua?
{ 'S', 'S', 'S', 'S' }, // uc?
{ '*', 'C', 'W', 'C' }, // ug?
{ 'L', 'F', 'L', 'F' } // uu?
}
};
uint8_t ord_value(char c)
{
switch (c)
{
case 'c': case 'C': return 1;
case 'g': case 'G': return 2;
case 't': case 'T': case 'u': case 'U': return 3;
default: return 0;
}
}
int main()
{
std::string s{"ACGTTTATGTTTACGT"};
auto v = s | ranges::view::transform(ord_value)
| ranges::view::chunk(3)
| ranges::view::transform([] (auto chunk_view)
{
if (chunk_view.size() < 3)
return 'X';
else
return translation_table[chunk_view[0]][chunk_view[1]][chunk_view[2]];
});
std::cout << v << '\n';
return 0;
}
Solution 6-frame translation in view-of-views (click to expand)
#include <iostream>
#include <range/v3/all.hpp>
#include <string>
char const translation_table[4][4][4] =
{
{ // a??
{ 'K', 'N', 'K', 'N' }, // aa?
{ 'T', 'T', 'T', 'T' }, // ac?
{ 'R', 'S', 'R', 'S' }, // ag?
{ 'I', 'I', 'M', 'I' } // au?
}, { // c??
{ 'Q', 'H', 'Q', 'H' }, // ca?
{ 'P', 'P', 'P', 'P' }, // cc?
{ 'R', 'R', 'R', 'R' }, // cg?
{ 'L', 'L', 'L', 'L' } // cu?
}, { // g??
{ 'E', 'D', 'E', 'D' }, // ga?
{ 'A', 'A', 'A', 'A' }, // gc?
{ 'G', 'G', 'G', 'G' }, // gg?
{ 'V', 'V', 'V', 'V' } // gu?
}, { // u??
{ '*', 'Y', '*', 'Y' }, // ua?
{ 'S', 'S', 'S', 'S' }, // uc?
{ '*', 'C', 'W', 'C' }, // ug?
{ 'L', 'F', 'L', 'F' } // uu?
}
};
uint8_t ord_value(char c)
{
switch (c)
{
case 'c': case 'C': return 1;
case 'g': case 'G': return 2;
case 't': case 'T': case 'u': case 'U': return 3;
default: return 0;
}
}
int main()
{
std::string s{"ACGTTTATGTTTACGT"};
auto complement = [] (auto c)
{
switch (c)
{
case 'a': return 't';
case 'A': return 'T';
case 'c': return 'g';
case 'C': return 'G';
case 'g': return 'c';
case 'G': return 'C';
case 't': return 'a';
case 'T': return 'A';
default: return 'N';
}
};
auto translate = [] (auto chunk_view)
{
if (chunk_view.size() < 3)
return 'X';
else
return translation_table[chunk_view[0]][chunk_view[1]][chunk_view[2]];
};
// since the views normally resolve to different types, we need to cast to
// any_random_access_view so that they are compatible
// we also wrap every view in a view-of-view so that we can easily concatenate
// without flattening later on
ranges::any_random_access_view<ranges::any_random_access_view<char>> f[3];
for (unsigned i : { 0, 1, 2 })
f[i] = ranges::view::single(s | ranges::view::drop(i)
| ranges::view::transform(ord_value)
| ranges::view::chunk(3)
| ranges::view::transform(translate));
ranges::any_random_access_view<ranges::any_random_access_view<char>> r[3];
for (unsigned i : { 0, 1, 2 })
r[i] = ranges::view::single(s | ranges::view::reverse
| ranges::view::transform(complement)
| ranges::view::drop(i)
| ranges::view::transform(ord_value)
| ranges::view::chunk(3)
| ranges::view::transform(translate));
auto combined = ranges::view::concat(f[0], f[1], f[2], r[0], r[1], r[2]);
std::cout << combined << '\n';
// change string beneath view
s = "ACTTAGCGGC";
// print updated view
std::cout << combined << '\n';
return 0;
}
The last code generates:
[[T,F,M,F,T,X],[R,L,C,L,R],[V,Y,V,Y,X],[T,*,T,*,T,X],[R,K,H,K,R],[V,N,I,N,X]]
[[T,*,R,H,T,X],[L,S,G,I,R],[L,A,A,Y,X],[T,*,A,A,K,X],[R,K,P,L,S],[V,S,R,*,X]]