97 my_search_reverse1(search_reverse(options.strand1)),
98 my_search_reverse2(search_reverse(options.strand2)),
99 my_constant1(template_seq1, template_length1, options.strand1),
100 my_constant2(template_seq2, template_length2, options.strand2),
101 my_max_mm1(options.max_mismatches1),
102 my_max_mm2(options.max_mismatches2),
103 my_randomized(options.random),
104 my_use_first(options.use_first)
106 auto num_options = barcode_pool1.
size();
107 if (num_options != barcode_pool2.
size()) {
108 throw std::runtime_error(
"both barcode pools should be of the same length");
110 my_counts.resize(num_options);
114 const auto& regions = my_constant1.forward_variable_regions();
115 if (regions.size() != 1) {
116 throw std::runtime_error(
"expected one variable region in the first constant template");
118 len1 = regions[0].second - regions[0].first;
119 if (len1 != barcode_pool1.
length()) {
120 throw std::runtime_error(
"length of variable sequences (" + std::to_string(barcode_pool1.length()) +
121 ") should be the same as the variable region (" + std::to_string(len1) +
")");
127 const auto& regions = my_constant2.forward_variable_regions();
128 if (regions.size() != 1) {
129 throw std::runtime_error(
"expected one variable region in the second constant template");
131 len2 = regions[0].second - regions[0].first;
132 if (len2 != barcode_pool2.length()) {
133 throw std::runtime_error(
"length of variable sequences (" + std::to_string(barcode_pool2.length()) +
134 ") should be the same as the variable region (" + std::to_string(len2) +
")");
139 std::vector<std::string> combined;
140 combined.reserve(num_options);
145 auto ptr1 = barcode_pool1[i];
146 if (my_search_reverse1) {
148 current += complement_base<true, true>(ptr1[len1 - j - 1]);
151 current.insert(current.end(), ptr1, ptr1 + len1);
154 auto ptr2 = barcode_pool2[i];
155 if (my_search_reverse2) {
157 current += complement_base<true, true>(ptr2[len2 - j - 1]);
160 current.insert(current.end(), ptr2, ptr2 + len2);
163 combined.push_back(std::move(current));
167 BarcodePool combined_set(combined);
168 my_varlib = SegmentedBarcodeSearch<2>(
170 std::array<SeqLength, 2>{ len1, len2 },
172 typename SegmentedBarcodeSearch<2>::Options bopt;
173 bopt.max_mismatches = { my_max_mm1, my_max_mm2 };
174 bopt.duplicates = options.duplicates;
175 bopt.reverse =
false;
182 bool my_search_reverse1, my_search_reverse2;
184 ScanTemplate<max_size_> my_constant1, my_constant2;
185 SegmentedBarcodeSearch<2> my_varlib;
186 int my_max_mm1, my_max_mm2;
189 bool my_use_first =
true;
191 std::vector<Count> my_counts;
200 State(
typename std::vector<Count>::size_type n) : counts(n) {}
202 std::vector<Count> counts;
205 std::pair<std::string, int> first_match;
206 std::vector<std::pair<std::string, int> > second_matches;
207 std::string combined;
210 typename SegmentedBarcodeSearch<2>::State details;
213 State initialize()
const {
214 return State(my_counts.size());
217 void reduce(State& s) {
218 my_varlib.reduce(s.details);
219 auto csize = my_counts.size();
220 for (
decltype(csize) i = 0; i < csize; ++i) {
221 my_counts[i] += s.counts[i];
226 constexpr static bool use_names =
false;
232 static void fill_store(std::pair<std::string, int>& first_match,
const char* start,
const char* end,
int mm) {
233 first_match.first.clear();
234 first_match.first.insert(first_match.first.end(), start, end);
235 first_match.second = mm;
239 static void fill_store(std::vector<std::pair<std::string, int> >& second_matches,
const char* start,
const char* end,
int mm) {
240 second_matches.emplace_back(std::string(start, end), mm);
244 template<
class Store>
245 static bool inner_process(
247 const ScanTemplate<max_size_>& constant,
250 typename ScanTemplate<max_size_>::State& deets,
253 while (!deets.finished) {
254 constant.next(deets);
256 if (deets.reverse_mismatches <= max_mm) {
257 const auto& reg = constant.reverse_variable_regions()[0];
258 auto start = against + deets.position;
259 fill_store(store, start + reg.first, start + reg.second, deets.reverse_mismatches);
263 if (deets.forward_mismatches <= max_mm) {
264 const auto& reg = constant.forward_variable_regions()[0];
265 auto start = against + deets.position;
266 fill_store(store, start + reg.first, start + reg.second, deets.forward_mismatches);
274 bool process_first(State& state,
const std::pair<const char*, const char*>& against1,
const std::pair<const char*, const char*>& against2)
const {
275 auto deets1 = my_constant1.initialize(against1.first, against1.second - against1.first);
276 auto deets2 = my_constant2.initialize(against2.first, against2.second - against2.first);
278 state.second_matches.clear();
279 typedef decltype(state.second_matches.size()) Size;
281 auto checker = [&](Size idx2) ->
bool {
282 const auto& current2 = state.second_matches[idx2];
283 state.combined = state.first_match.first;
284 state.combined += current2.first;
285 my_varlib.search(state.combined, state.details, std::array<int, 2>{ my_max_mm1 - state.first_match.second, my_max_mm2 - current2.second });
288 ++state.counts[state.details.index];
300 while (inner_process(my_search_reverse1, my_constant1, my_max_mm1, against1.first, deets1, state.first_match)) {
301 if (!deets2.finished) {
305 while (inner_process(my_search_reverse2, my_constant2, my_max_mm2, against2.first, deets2, state.second_matches)) {
306 if (checker(state.second_matches.size() - 1)) {
310 if (state.second_matches.empty()) {
316 for (Size i = 0, end = state.second_matches.size(); i < end; ++i) {
327 std::pair<BarcodeIndex, int> process_best(State& state,
const std::pair<const char*, const char*>& against1,
const std::pair<const char*, const char*>& against2)
const {
328 auto deets1 = my_constant1.initialize(against1.first, against1.second - against1.first);
329 auto deets2 = my_constant2.initialize(against2.first, against2.second - against2.first);
334 state.second_matches.clear();
335 while (inner_process(my_search_reverse2, my_constant2, my_max_mm2, against2.first, deets2, state.second_matches)) {}
338 int best_mismatches = my_max_mm1 + my_max_mm2 + 1;
339 auto num_second_matches = state.second_matches.size();
341 if (!state.second_matches.empty()) {
342 while (inner_process(my_search_reverse1, my_constant1, my_max_mm1, against1.first, deets1, state.first_match)) {
343 for (
decltype(num_second_matches) i = 0; i < num_second_matches; ++i) {
344 const auto& current2 = state.second_matches[i];
346 state.combined = state.first_match.first;
347 state.combined += current2.first;
348 my_varlib.search(state.combined, state.details, std::array<int, 2>{ my_max_mm1 - state.first_match.second, my_max_mm2 - current2.second });
351 int cur_mismatches = state.details.mismatches + state.first_match.second + current2.second;
352 if (cur_mismatches < best_mismatches) {
353 chosen = state.details.index;
354 best_mismatches = cur_mismatches;
355 }
else if (cur_mismatches == best_mismatches && chosen != state.details.index) {
363 return std::make_pair(chosen, best_mismatches);
370 bool process(State& state,
const std::pair<const char*, const char*>& r1,
const std::pair<const char*, const char*>& r2)
const {
374 found = process_first(state, r1, r2);
375 if (!found && my_randomized) {
376 found = process_first(state, r2, r1);
380 auto best = process_best(state, r1, r2);
382 auto best2 = process_best(state, r2, r1);
385 }
else if (best.second == best2.second && best.first != best2.first) {
392 ++state.counts[best.first];