Modifiers
Modifiers give a different view to other classes.
Modifiers can be used to change the elements of a container without touching them. For example, someone
gave you an algorithm that works on 2 arbitrary strings, but you want to use it for the special pair of a string and its
reverse (left-to-right mirror). The classical approach would be to make a copy of the one string,
where all elements are mirrored from left to right and call the algorithm with both strings. With modifiers you
can create the reverse in O(1) extra memory without copying the original string. This can be handy if the original
sequence is large.
Modifiers implement a certain concept (e.g. Container, Iterator, ...) or class interface (String, ...)
and thus can be used as such. The mirror modifier is already part of SeqAn and implements the
class interface of String and can be used in every algorithm that works on strings.
The ModifiedString is a modifier that implements the String interface and thus can be used like a
String. It has 2 template parameters. The first one specifies a sequence type (e.g. String, Segment, ...)
and the second one specifies the modifiers behaviour. That can be ModReverse for mirroring a string left to right
or ModView for applying a function to every single character (like 'C'->'G', 'A'->'T', ...).
We begin with the example from the first section. We have a given string:
and want to get the reverse. So we need a ModifiedString specialized with String<char> and ModReverse.
We create the modifier and link it with myString with:
The result is:
cout << myModifier << endl;
amanaP-lanac a ,nalp a ,nam A
To verify that we didn't copy myString , we replace an infix of the original string and see that, as a side effect, the modified string has also changed:
cout << myString << endl;
cout << myModifier << endl;
amanaP-lanac a ,nalp retsam a ,nam A
Click here to see the complete source code of the ModReverse example.
Another specialization of the ModifiedString is the ModView modifier. Assume we need all characters of
myString to be in upper case without copying myString . In SeqAn you first create a functor (a STL unary function)
which converts a character to its upper-case character:
{
inline char operator()(char x) const
{
if (('a' <= x) && (x <= 'z')) return (x + ('A' - 'a'));
return x;
}
};
and then create a ModifiedString specialized with ModView<MyFunctor> :
The result is:
cout << myModifier << endl;
A MAN, A PLAN, A CANAL-PANAMA
The upper-case functor and some other predefined functors are part of SeqAn (in seqan/modifier/modifier_functors.h) already.
The following functors can be used as argument for ModView:
Converts each character of type | |
Converts each character to type | |
Converts each nucleotide to its complementary nucleotide | |
The same for the Dna5 alphabet | |
Converts the type of each character from |
So instead of defining our own functor we could have used a predefined one:
Click here to see the complete source code of the ModView example.
For some common usage modifiers you can use the following shortcuts:
We have seen how a ModifiedString can be used to modify strings without touching or copying original data.
The same can be done with iterators. The ModifiedIterator implements the Iterator concept and
thus can be used in every algorithm or data structure that expects an iterator. In fact, we have already used
the ModifiedIterator unknowingly in the examples above, as in our cases the ModifiedString returns
a corresponding ModifiedIterator via the Iterator meta-function. The main work is done in
the ModifiedIterator, whereas the ModifiedString only overloads the begin and end.
Normally, you are going to use the ModifiedString and maybe the result of its Iterator meta-function
instead of a ModifiedIterator directly.
As modifiers implement a certain concept and depend on classes of this concept, they can be chained to
create a new modifier. We have seen how the ModifiedString specialized with ModReverse and ModView
can be used. Now we want to combine them to create a modifier for the reverse complement of a Dna string.
We begin with the original string:
Then we define the modifier that complements a Dna string:
This modifier now should be reversed from left to right:
The original string can be given via setValue or to the constructor.
The result is:
cout << myReverseComplement << endl;
infix(myString, 1, 1) = "cgt";
cout << myString << endl;
cout << myReverseComplement << endl;
CCGTAAT
ACGTTTACGG
CCGTAAACGT
Using a predefined shortcut, the whole example could be reduced to:
cout << myString << endl;
cout << DnaStringReverseComplement(myString) << endl;
Click here to see the complete source code of the nested modifiers example.
SeqAn - Sequence Analysis Library - www.seqan.de