Skip to content

Commit 5eceeb0

Browse files
authored
Merge pull request #97 from SGSSGene/feat/more_flexible_fmindex
feat: making BiFMIndex slightly more flexible
2 parents e5b90da + 47e587a commit 5eceeb0

22 files changed

Lines changed: 255 additions & 802 deletions

src/fmindex-collection/fmindex/BiFMIndex.h

Lines changed: 81 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,29 @@
1414

1515
namespace fmc {
1616

17-
template <size_t TSigma, template <size_t> typename String = string::FlattenedBitvectors_512_64k, SparseArray_c SparseArray = suffixarray::SparseArray<std::tuple<uint32_t, uint32_t>>>
17+
template <size_t TSigma, template <size_t> typename String = string::FlattenedBitvectors_512_64k, SparseArray_c SparseArray = suffixarray::SparseArray<std::tuple<uint32_t, uint32_t>>, bool TDelim=true, bool TReuseRev=false>
1818
requires String_c<String<TSigma>>
1919
struct BiFMIndex {
2020
using ADEntry = SparseArray::value_t;
2121

22+
using NoDelim = BiFMIndex<TSigma, String, SparseArray, false, TReuseRev>;
23+
using ReuseRev = BiFMIndex<TSigma, String, SparseArray, TDelim, true>;
24+
2225
static size_t constexpr Sigma = TSigma;
23-
static size_t constexpr FirstSymb = 1;
26+
static size_t constexpr FirstSymb = TDelim?1:0;
2427

28+
// Set RevBwtType to std::nullptr_t to indicate that it should not be used
29+
using RevBwtType = std::conditional_t<TReuseRev, std::nullptr_t, String<Sigma>>;
2530
String<Sigma> bwt;
26-
String<Sigma> bwtRev;
31+
RevBwtType bwtRev;
2732
std::array<size_t, Sigma+1> C{};
2833
SparseArray annotatedArray;
2934

3035
BiFMIndex() = default;
3136
BiFMIndex(BiFMIndex&&) noexcept = default;
3237

3338
BiFMIndex(std::span<uint8_t const> _bwt, std::span<uint8_t const> _bwtRev, SparseArray _annotatedArray)
39+
requires(!TReuseRev)
3440
: bwt{_bwt}
3541
, bwtRev{_bwtRev}
3642
, C{computeC(bwt)}
@@ -42,32 +48,46 @@ struct BiFMIndex {
4248
}
4349
}
4450

45-
BiFMIndex(Sequence auto const& _sequence, SparseArray const& _annotatedSequence, size_t _threadNbr, bool omegaSorting = false) {
51+
BiFMIndex(std::span<uint8_t const> _bwt, SparseArray _annotatedArray)
52+
requires(TReuseRev)
53+
: bwt{_bwt}
54+
, C{computeC(bwt)}
55+
, annotatedArray{std::move(_annotatedArray)}
56+
{}
57+
58+
59+
BiFMIndex(Sequence auto const& _sequence, SparseArray const& _annotatedSequence, size_t _threadNbr, bool mirrorInput = false) {
4660
if (_sequence.size() >= std::numeric_limits<size_t>::max()/2) {
4761
throw std::runtime_error{"sequence is longer than what this system is capable of handling"};
4862
}
4963

64+
bool omegaSorting = !TDelim; // Use omega sorting if no delimiter is being used
65+
5066
// copy text into custom buffer
51-
auto inputText = createInputText(_sequence, omegaSorting);
67+
auto inputText = createInputText(_sequence, omegaSorting, mirrorInput);
5268

5369
// create bwt, bwtRev and annotatedArray
5470
auto [_bwt, _annotatedArray] = createBWTAndAnnotatedArray(inputText, _annotatedSequence, _threadNbr, omegaSorting);
55-
#if defined(__GNUC__) && !defined(__clang__)
56-
#pragma GCC diagnostic push
57-
#pragma GCC diagnostic ignored "-Wstringop-overflow"
58-
std::ranges::reverse(inputText);
59-
#pragma GCC diagnostic pop
6071

61-
#else
62-
std::ranges::reverse(inputText);
6372

64-
#endif
65-
auto _bwtRev = createBWT(inputText, _threadNbr, omegaSorting);
66-
decltype(inputText){}.swap(inputText); // inputText memory can be deleted
73+
if constexpr (!TReuseRev) {
74+
#if defined(__GNUC__) && !defined(__clang__)
75+
#pragma GCC diagnostic push
76+
#pragma GCC diagnostic ignored "-Wstringop-overflow"
77+
std::ranges::reverse(inputText);
78+
#pragma GCC diagnostic pop
79+
80+
#else
81+
std::ranges::reverse(inputText);
82+
83+
#endif
84+
auto _bwtRev = createBWT(inputText, _threadNbr, omegaSorting);
85+
decltype(inputText){}.swap(inputText); // inputText memory can be deleted
86+
bwtRev = {_bwtRev};
87+
}
6788

6889
// initialize this BiFMIndex properly
6990
bwt = {_bwt};
70-
bwtRev = {_bwtRev};
7191
C = computeC(bwt);
7292
annotatedArray = std::move(_annotatedArray);
7393
}
@@ -78,10 +98,9 @@ struct BiFMIndex {
7898
* \param _input a list of sequences
7999
* \param samplingRate rate of the sampling
80100
*/
81-
BiFMIndex(Sequences auto const& _input, size_t samplingRate, size_t threadNbr, bool useDelimiters = true, size_t seqOffset = 0) {
82-
101+
BiFMIndex(Sequences auto const& _input, size_t samplingRate, size_t threadNbr, size_t seqOffset = 0, bool mirrorInput = false) {
83102
auto [totalSize, inputText, inputSizes] = [&]() {
84-
if (useDelimiters) {
103+
if (TDelim) {
85104
return createSequences(_input);
86105
} else {
87106
return createSequencesWithoutDelimiter(_input);
@@ -97,31 +116,58 @@ struct BiFMIndex {
97116
assert(inputSizes.size() < refId);
98117
}
99118

100-
auto annotatedSequence = SparseArray {
101-
std::views::iota(size_t{0}, totalSize) | std::views::transform([&](size_t) -> std::optional<ADEntry> {
102-
assert(refId < inputSizes.size());
103-
assert(pos < inputSizes[refId]);
119+
auto size = totalSize;
120+
if (mirrorInput) size = size*2;
104121

105-
auto ret = std::optional<ADEntry>{std::nullopt};
106122

107-
if (pos % samplingRate == 0) {
108-
ret = std::make_tuple(refId+seqOffset, pos);
109-
}
110-
111-
++pos;
112-
if (inputSizes[refId] == pos) {
113-
refId += 1;
114-
pos = 0;
123+
auto annotatedSequence = SparseArray {
124+
std::views::iota(size_t{0}, size) | std::views::transform([&](size_t phase) -> std::optional<ADEntry> {
125+
if (phase < totalSize) { // going forward
126+
assert(refId < inputSizes.size());
127+
assert(pos < inputSizes[refId]);
128+
129+
auto ret = std::optional<ADEntry>{std::nullopt};
130+
131+
if (pos % samplingRate == 0) {
132+
ret = std::make_tuple(refId+seqOffset, pos);
133+
}
134+
135+
++pos;
136+
if (inputSizes[refId] == pos) {
137+
refId += 1;
138+
pos = 0;
139+
}
140+
return ret;
141+
} else { // going backwards
142+
if (phase == totalSize) { // reset values
143+
pos = 0;
144+
refId = 0;
145+
}
146+
147+
assert(refId < inputSizes.size());
148+
assert(pos < inputSizes[inputSizes.size() - refId - 1]);
149+
150+
auto ret = std::optional<ADEntry>{std::nullopt};
151+
152+
if (pos % samplingRate == 0) {
153+
ret = std::make_tuple(inputSizes.size()*2 - refId+seqOffset-1, inputSizes[refId] - pos-1);
154+
}
155+
156+
++pos;
157+
if (inputSizes[inputSizes.size() - refId - 1] == pos) {
158+
refId += 1;
159+
pos = 0;
160+
}
161+
return ret;
115162
}
116-
return ret;
117163
})
118164
};
119165

120-
*this = BiFMIndex{inputText, annotatedSequence, threadNbr, !useDelimiters};
166+
*this = BiFMIndex{inputText, annotatedSequence, threadNbr, mirrorInput};
121167
}
122168

123169
auto operator=(BiFMIndex const&) -> BiFMIndex& = delete;
124-
auto operator=(BiFMIndex&&) noexcept -> BiFMIndex& = default;
170+
auto operator=(BiFMIndex&& _other) noexcept -> BiFMIndex& = default;
125171

126172
size_t size() const {
127173
return bwt.size();

src/fmindex-collection/fmindex/BiFMIndexCursor.h

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,38 @@ struct BiFMIndexCursor {
5858
}
5959

6060
auto extendRight() const -> std::array<BiFMIndexCursor, Sigma> {
61-
auto const& bwt = index->bwtRev;
62-
auto [rs1, prs1] = bwt.all_ranks_and_prefix_ranks(lbRev);
63-
auto [rs2, prs2] = bwt.all_ranks_and_prefix_ranks(lbRev+len);
64-
65-
for (size_t i{0}; i < rs1.size(); ++i) {
66-
rs1[i] += index->C[i];
67-
rs2[i] += index->C[i];
68-
}
69-
70-
auto cursors = std::array<BiFMIndexCursor, Sigma>{};
71-
for (size_t i{0}; i < Sigma; ++i) {
72-
cursors[i] = BiFMIndexCursor{*index, lb + prs2[i] - prs1[i], rs1[i], rs2[i] - rs1[i]};
61+
// Reuse bwt if bwtrev is not available
62+
if constexpr (std::same_as<typename Index::RevBwtType, std::nullptr_t>) {
63+
auto const& bwt = index->bwt;
64+
auto [rs1, prs1] = bwt.all_ranks_and_prefix_ranks(lbRev);
65+
auto [rs2, prs2] = bwt.all_ranks_and_prefix_ranks(lbRev+len);
66+
67+
for (size_t i{0}; i < rs1.size(); ++i) {
68+
rs1[i] += index->C[i];
69+
rs2[i] += index->C[i];
70+
}
71+
72+
auto cursors = std::array<BiFMIndexCursor, Sigma>{};
73+
for (size_t i{0}; i < Sigma; ++i) {
74+
cursors[i] = BiFMIndexCursor{*index, lb + prs2[i] - prs1[i], rs1[i], rs2[i] - rs1[i]};
75+
}
76+
return cursors;
77+
} else {
78+
auto const& bwt = index->bwtRev;
79+
auto [rs1, prs1] = bwt.all_ranks_and_prefix_ranks(lbRev);
80+
auto [rs2, prs2] = bwt.all_ranks_and_prefix_ranks(lbRev+len);
81+
82+
for (size_t i{0}; i < rs1.size(); ++i) {
83+
rs1[i] += index->C[i];
84+
rs2[i] += index->C[i];
85+
}
86+
87+
auto cursors = std::array<BiFMIndexCursor, Sigma>{};
88+
for (size_t i{0}; i < Sigma; ++i) {
89+
cursors[i] = BiFMIndexCursor{*index, lb + prs2[i] - prs1[i], rs1[i], rs2[i] - rs1[i]};
90+
}
91+
return cursors;
7392
}
74-
return cursors;
7593
}
7694
void prefetchLeft() const {
7795
}
@@ -87,12 +105,33 @@ struct BiFMIndexCursor {
87105
return newCursor;
88106
}
89107
auto extendRight(size_t symb) const -> BiFMIndexCursor {
90-
auto& bwt = index->bwtRev;
91-
size_t newLb = lb + bwt.prefix_rank(lbRev+len, symb) - bwt.prefix_rank(lbRev, symb);
92-
size_t newLbRev = bwt.rank(lbRev, symb);
93-
size_t newLen = bwt.rank(lbRev+len, symb) - newLbRev;
94-
auto newCursor = BiFMIndexCursor{*index, newLb, newLbRev + index->C[symb], newLen};
95-
return newCursor;
108+
if constexpr (std::same_as<typename Index::RevBwtType, std::nullptr_t>) {
109+
auto const& bwt = index->bwt;
110+
size_t newLb = lb + bwt.prefix_rank(lbRev+len, symb) - bwt.prefix_rank(lbRev, symb);
111+
size_t newLbRev = bwt.rank(lbRev, symb);
112+
size_t newLen = bwt.rank(lbRev+len, symb) - newLbRev;
113+
auto newCursor = BiFMIndexCursor{*index, newLb, newLbRev + index->C[symb], newLen};
114+
return newCursor;
115+
} else {
116+
auto const& bwt = index->bwtRev;
117+
size_t newLb = lb + bwt.prefix_rank(lbRev+len, symb) - bwt.prefix_rank(lbRev, symb);
118+
size_t newLbRev = bwt.rank(lbRev, symb);
119+
size_t newLen = bwt.rank(lbRev+len, symb) - newLbRev;
120+
auto newCursor = BiFMIndexCursor{*index, newLb, newLbRev + index->C[symb], newLen};
121+
return newCursor;
122+
}
123+
}
124+
125+
auto symbolLeft() const -> size_t {
126+
return index->bwt.symbol(lb);
127+
}
128+
auto symbolRight() const -> size_t {
129+
// Reuse bwt if bwtrev is not available
130+
if constexpr (std::same_as<typename Index::RevBwtType, std::nullptr_t>) {
131+
return index->bwt.symbol(lbRev);
132+
} else {
133+
return index->bwtRev.symbol(lbRev);
134+
}
96135
}
97136
};
98137

src/fmindex-collection/fmindex/BinaryMirroredBiFMIndex.h

Lines changed: 0 additions & 118 deletions
This file was deleted.

0 commit comments

Comments
 (0)