Skip to content

Commit 5594898

Browse files
committed
countlets v1.3, slight optimisation in klets.cpp
1 parent ae178c3 commit 5594898

5 files changed

Lines changed: 62 additions & 31 deletions

File tree

ChangeLog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
2019-05-04 Benjamin Jean-Marie Tremblay <benjmtremblay@gmail.com
2+
3+
* faster char to int conversion in klets.cpp
4+
* countlets is much faster when providing alphabet (using unordered_map)
5+
* countlets version bumped to 1.3
6+
17
2019-05-04 Benjamin Jean-Marie Tremblay <benjmtremblay@gmail.com>
28

39
* Don't bother and try to fill edges of unconnected vertices (shuffle_euler)

README

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,9 @@ This utility counts the total number of k-lets in the input sequence. Be aware
4545
that the total number of k-lets is n^k, where n is the alphabet length. For use
4646
cases involving memory constraints, providing the sequence alphabet ahead of
4747
time will allow countlets to count k-lets while only needing to load k + 1
48-
letters into memory at a time (at the cost of speed for higher k values). When
49-
the alphabet is provided, it will typically never take up more than several MBs
50-
of memory. Optionally, k-lets with counts of zero can be ommitted from the
51-
output.
48+
letters into memory at a time. When the alphabet is provided, it will typically
49+
never take up more than several MBs of memory. Optionally, k-lets with counts of
50+
zero can be ommitted from the output.
5251

5352
Example usage:
5453

src/countlets.cpp

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@
2525
#include <string>
2626
#include <set>
2727
#include <unistd.h>
28-
#include <map>
28+
#include <unordered_map>
2929
#include "klets.hpp"
3030
using namespace std;
3131

3232
void usage() {
3333
printf(
34-
"countlets v1.2 Copyright (C) 2019 Benjamin Jean-Marie Tremblay \n"
34+
"countlets v1.3 Copyright (C) 2019 Benjamin Jean-Marie Tremblay \n"
3535
" \n"
3636
"Usage: countlets [options] -i [filename] -o [filename] \n"
3737
" echo [string] | countlets [options] > [filename] \n"
@@ -42,23 +42,23 @@ void usage() {
4242
" format. \n"
4343
" -a <str> A string containing all of the alphabet letters present in the \n"
4444
" sequence. This allows the program not to have to load the entire \n"
45-
" sequence into memory to find all of the unique letters. The downside\n"
46-
" is that runtime increases more with increasing k. \n"
45+
" sequence into memory to find all of the unique letters. \n"
4746
" -k <int> K-let size. Defaults to 1. \n"
4847
" -n Don't print k-lets with counts of zero. \n"
4948
" -h Show usage. \n"
5049
);
5150
}
5251

53-
map<string, unsigned int> count_stream(istream &input, vector<string> klets,
52+
unordered_map<string, unsigned int> count_stream(istream &input, vector<string> klets,
5453
unsigned int k) {
5554

5655
char l;
5756

5857
string let;
5958
let.reserve(k + 1);
6059

61-
map<string, unsigned int> counts;
60+
unordered_map<string, unsigned int> counts;
61+
counts.reserve(klets.size());
6262
for (size_t i = 0; i < klets.size(); ++i) {
6363
counts[klets[i]] = 0;
6464
}
@@ -199,7 +199,7 @@ int main(int argc, char **argv) {
199199

200200
/* this version only keeps k+1 characters in memory */
201201

202-
map<string, unsigned int> counts;
202+
unordered_map<string, unsigned int> counts;
203203

204204
if (alph.length() < 1) {
205205
cerr << "Error: could not parse -a option" << endl;
@@ -228,17 +228,15 @@ int main(int argc, char **argv) {
228228
cerr << "Warning: foreign character(s) encountered" << endl;
229229
}
230230

231-
map<string, unsigned int>::iterator it;
232-
233231
if (has_out) {
234-
for (it = counts.begin(); it != counts.end(); ++it) {
235-
if (it->second > 0 || !nozero)
236-
outfile << it->first << "\t" << it->second << endl;
232+
for (size_t i = 0; i < klets.size(); ++i) {
233+
if (counts[klets[i]] > 0 || !nozero)
234+
outfile << klets[i] << "\t" << counts[klets[i]] << "\t" << endl;
237235
}
238236
} else {
239-
for (it = counts.begin(); it != counts.end(); ++it) {
240-
if (it->second > 0 || !nozero)
241-
cout << it->first << "\t" << it->second << endl;
237+
for (size_t i = 0; i < klets.size(); ++i) {
238+
if (counts[klets[i]] > 0 || !nozero)
239+
cout << klets[i] << "\t" << counts[klets[i]] << "\t" << endl;
242240
}
243241
}
244242

src/klets.cpp

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,14 @@
2424
#include <iomanip>
2525
#include <cmath>
2626
#include <algorithm>
27+
#include <unordered_map>
2728
using namespace std;
2829

30+
#ifdef ADD_TIMERS
31+
#include <chrono>
32+
using Clock = chrono::high_resolution_clock;
33+
#endif
34+
2935
vector<string> make_klets(vector<char> lets_uniq, unsigned int k) {
3036

3137
size_t alphlen = lets_uniq.size();
@@ -68,25 +74,35 @@ vector<unsigned int> count_klets(vector<char> letters, vector<char> lets_uniq,
6874
* sequence in memory.
6975
*/
7076

77+
#ifdef ADD_TIMERS
78+
auto t0 = Clock::now();
79+
cerr << ">BEGIN count_klets()" << endl;
80+
#endif
81+
7182
size_t seqlen = letters.size();
7283
unsigned int nlets = pow(alphlen, k);
73-
vector<unsigned int> intletters;
84+
unsigned int l, counter;
7485
vector<unsigned int> let_counts(nlets, 0);
86+
vector<unsigned int> intletters;
7587
intletters.reserve(seqlen);
88+
unordered_map<char, unsigned int> let2int;
89+
let2int.reserve(lets_uniq.size());
7690

77-
for (size_t i = 0; i < seqlen; ++i) {
78-
79-
for (size_t j = 0; j < alphlen; ++j) {
80-
if (letters[i] == lets_uniq[j]) {
81-
intletters.push_back(j);
82-
break;
83-
}
84-
}
91+
for (size_t i = 0; i < lets_uniq.size(); ++i) {
92+
let2int[lets_uniq[i]] = (unsigned int)i;
93+
}
8594

95+
for (size_t i = 0; i < seqlen; ++i) {
96+
intletters.push_back(let2int[letters[i]]);
8697
}
8798

88-
unsigned int l;
89-
unsigned int counter;
99+
#ifdef ADD_TIMERS
100+
auto t1 = Clock::now();
101+
cerr << " lets->ints\t"
102+
<< chrono::duration_cast<chrono::microseconds>(t1 - t0).count()
103+
<< " us" << endl;
104+
#endif
105+
90106
for (size_t i = 0; i < seqlen - k + 1; ++i) {
91107

92108
l = 0; counter = 0;
@@ -98,6 +114,17 @@ vector<unsigned int> count_klets(vector<char> letters, vector<char> lets_uniq,
98114

99115
}
100116

117+
#ifdef ADD_TIMERS
118+
auto t2 = Clock::now();
119+
cerr << " count loop\t"
120+
<< chrono::duration_cast<chrono::microseconds>(t2 - t1).count()
121+
<< " us" << endl;
122+
cerr << " ---\n fun total\t"
123+
<< chrono::duration_cast<chrono::microseconds>(t2 - t0).count()
124+
<< " us" << endl;
125+
cerr << ">END count_klets()" << endl;
126+
#endif
127+
101128
return let_counts;
102129

103130
}

src/shuffle_euler.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ string shuffle_euler(vector<char> letters, default_random_engine gen, unsigned i
214214
bool verbose) {
215215

216216
#ifdef ADD_TIMERS
217-
cerr << ">shuffler_euler()" << endl;
217+
cerr << ">BEGIN shuffler_euler()" << endl;
218218
auto t0 = Clock::now();
219219
#endif
220220

@@ -341,6 +341,7 @@ string shuffle_euler(vector<char> letters, default_random_engine gen, unsigned i
341341
cerr << " ---\n fun total\t"
342342
<< chrono::duration_cast<chrono::microseconds>(t16 - t0).count()
343343
<< " us" << endl;
344+
cerr << ">END shuffler_euler()" << endl;
344345
#endif
345346

346347
return out;

0 commit comments

Comments
 (0)