User not logged in - login - register
Home Calendar Books School Tool Photo Gallery Message Boards Users Statistics Advertise Site Info
go to bottom | |
 Message Boards » » C++ mathy question Page [1]  
JeffreyBSG
All American
10165 Posts
user info
edit post

Hi, guys. Okay, I'm a grad student in mathematics, and I'm trying to determine the asymptotic growth of the interval profile of a suffix tree. I've written a simulation in C++, but it pretty much sucks since I suck at coding. So I'm hoping you guys can help me improve its efficiency.

We're looking at a suffix tree with n leaves, and we want to know how many internal nodes there are on the kth level. k is an integer which will be in the neighborhood of log(n).

We start with three parameters,
n (a big fucking integer, on the order of 10^6 or larger.)
p (a probability, i.e. real number between 0 and 1),
alpha (a positive number around 1.)

We then define the integer k=alpha*log(n) (rounded to the nearest integer.)

To get our internal profile, then, we
1. Construct a random binary string of X consisting of n+k-1 entries, with each entry taking value 1 with probability p, 0 with probability 1-p.
2. Consider the n consecutive substrings of length k of X, i.e. X(1...k), X(2...k+1), ... , X(n...n+k-1), and count how many of these substrings appear at least twice. This is M_{n,k}, the internal profile, our variable of interest.
3. Estimate the asymptotic variance of M_{n,k} by running this simulation a bunch of times for really fucking big n.

My approach is to convert each substring to an integer on [0,2^k - 1], and then store it in a set. And if it's already in the set (i.e. it's appeared as an earlier substring) I put it in another set, the size of which is, at the end, my profile. But I'm sure I'm doing this super-inefficiently. I'm an amateur programmer at best. Here's the second of my code in which I build my n successive substrings and then count how many appear more than once by the placing of each in sets. but if you could suggest a better method, that would be awesome.

Also, I don't know anything about pointers, so I can't build the fucking tree. And I'm not sure if that would be optimal.

int n=1000000;
int k=round(log(n));
int p=.75;
int profilesize=0;
int curval=0;
int wordmask=0;
std::set myset;
std::set profileset;

// building the first k characters of our string, and converting them into an integer on [0, 2^k -1]
for (int i=0; icurval=1-floor((float)rand()/(p*RAND_MAX));
wordmask=wordmask+curval*pow(2,i);
}

// generating n strings from this base-string, each time lopping off the first character // and adding the last, then checking to see if this is a string we've already
// encountered by examining our list of encountered strings
for (int i=0; icurval=1-floor((float)rand()/(p*RAND_MAX));
wordmask=wordmask/2 + curval*pow(2,k-1);
if( myset.find(wordmask) != myset.end() ){
profileset.insert(wordmask);}
else{myset.insert(wordmask);}

profilesize =profileset.size();

The variable "profilesize" is our final variable; then we generate it a shitload of times for large values of n, and try to estimate its variance empirically. Any help that could be offered would be appreciated.

4/19/2014 11:01:32 PM

JeffreyBSG
All American
10165 Posts
user info
edit post

k

4/19/2014 11:02:49 PM

JeffreyBSG
All American
10165 Posts
user info
edit post

4/19/2014 11:11:53 PM

moron
All American
33726 Posts
user info
edit post

Why are you generating a word mask and looking for it in the set, rather than iterating through the set and counting substrings of the length you're looking for?

4/20/2014 12:19:34 AM

JeffreyBSG
All American
10165 Posts
user info
edit post

maybe I'm misunderstanding your question, but I'm converting substrings to wordmasks because it seems impractical to compare the jth substring to the previous j-1 substrings, letter by letter, just to see if it matches

in essence, by converting to wordmatch, I'm allowing myself to test whether two k-strings are identical simply by comparing two integers.

maybe that's suboptimal, though.

4/20/2014 12:24:44 AM

moron
All American
33726 Posts
user info
edit post

Okay perhaps I don't understand your problem...

But you have a string of size 1000000
You have substrings of length 6 (let's say) that is every 6-length substring in your string
And
You want to know which 6-length substring is the most common
Or
You want to know how many times each 6-length substring occurs

Or neither of these?

4/20/2014 12:34:06 AM

JeffreyBSG
All American
10165 Posts
user info
edit post

Quote :
"You have substrings of length 6 (let's say) that is every 6-length substring in your string
"


Yes, every consecutive substring of length 6, just to be absolutely clear. If my string were made of English letters and started
boobsvagina....
my first three substrings would be
boobsv
oobsva
obsvag

Quote :
"And
You want to know which 6-length substring is the most common
Or
You want to know how many times each 6-length substring occurs

Or neither of these?"


Neither. I want to know how many substrings appear at least twice.

Thanks for taking an interest in this, definitely. I'm messing with multiset right now, but I suck at C++.

4/20/2014 12:37:31 AM

moron
All American
33726 Posts
user info
edit post

Okay, it looks to me like you're randomly generating a substring:

for (int i=0; icurval=1-floor((float)rand()/(p*RAND_MAX));
wordmask=wordmask+curval*pow(2,i);
}

The looking for this random string in your set of existing substrings:

if( myset.find(wordmask) != myset.end() ){
profileset.insert(wordmask);}
else{myset.insert(wordmask);}


Is this correct?

If you have a set of existing substrings (set myset) (or is this the full string? it doesn't matter either way), why not look through that set for occurrences of 2 or more of that substring, rather than generating a substring, then looking to see if it exists?

It's like if your string is boobsvagina

you generate the random substring "cat" then see if it's in boobsvagina?

basically, in the process of generating "myset" you can implicitly keep count of how many of each element has been added. then just read out the counts, discarding any that's <2.

[Edited on April 20, 2014 at 12:58 AM. Reason : ]

4/20/2014 12:44:30 AM

moron
All American
33726 Posts
user info
edit post

http://en.cppreference.com/w/cpp/container/map

You can modify your existing thing to use a map instead, where the "value" you're storing is the count.

What you're doing with the 2 sets is not extraordinarily different, or more computationally intensive.

It just doesn't make sense to generate a random substring, look for it in the set, when you have the full set, and you can just look for substrings that are duplicates of each other (if that's what you're doing).

[Edited on April 20, 2014 at 12:56 AM. Reason : ]

4/20/2014 12:56:25 AM

JeffreyBSG
All American
10165 Posts
user info
edit post

Quote :
"Okay, it looks to me like you're randomly generating a substring:

...

The looking for this random string in your set of existing substrings:

...
"


More or less correct, yes. I should be clear, though: I don't have my whole giant string constructed at the beginning. Instead I generate the first substring randomly, then lop of the first letter and generate a new last letter, i.e. I take "boobsv," lop off the b and randomly generates a g so the new substring is "oobsva." I'm using the substrings to generate the master string, which is fine because they're all I care about, and the behavior of the system is the same.

Quote :
"
If you have a set of existing substrings (set myset), why not look through that set for occurrences of 2 or more of that substring, rather than generating a substring, then looking to see if it exists?[

It's like if your string is boobsvagina

you generate the random substring "cat" then see if it's in boobsvagina?
"


Okay, first of all, if my current substring is "cat", that means that my previous substring was "hca" or something that ended in ca.

You're right that I should just stick all my substrings in a set and then count how many appear twice or more. I guess the difficulty was that sets can only contain one of an element, so I built a set to contain the first occurrence of an element, then for every element, if it was in that set I put it another set which contained things that appeared at least twice. This "looking for every element" business was really inefficient.

Multiset can hold multiple copies of the same element; hopefully it'll be vastly more efficient.

4/20/2014 12:57:46 AM

moron
All American
33726 Posts
user info
edit post

so you have the super-long string stored some where, you know your substrings are length k:
psuedocode:

std::map substringKCountsMap;

while(i=0,i+k<superLongString.length(),i++){

   newMapKey=readSuperLongString(i,i+k);


   if (substringKCounts.contains(newMapKey)) substringKCountsMap[newMapKey]++;

   else substringKCountsMap.add({newMapKey,0})

}

foreach(countedSubstring in substringKCountsMap){

   if (countedSubstring.value()>2) printf(countedSubstring.key);

}

Also, this problem is VERY parallelizable, if you wanted to make this threaded, it'd run a lot faster (probably).



[Edited on April 20, 2014 at 1:10 AM. Reason : ]

4/20/2014 1:07:56 AM

JeffreyBSG
All American
10165 Posts
user info
edit post

the ideas of the pseudocode all make sense...I'll try to translate them into some sensible C tomorrow. thanks a lot.

also, I have no idea in the world how I would exploit parallelizability (that's way beyond the scope of my C++ knowledge), but I know what parallizing is (I think) and that's cool that it's possible here.

I'd love to bang out some results for n=10^10 or something. that would be the shit.

4/20/2014 1:17:52 AM

moron
All American
33726 Posts
user info
edit post

cool

just make sure to look at this: http://en.cppreference.com/w/cpp/container/map

It's a key-value pair structure, it makes your life easier.

map is the sister structure to std::set and is nearly drop-in replacement for using the std::set that you're already using.

http://stackoverflow.com/questions/205945/why-does-the-c-stl-not-provide-any-tree-containers

Both are implemented with binary trees, so it doesn't matter either that you don't know pointers, C++ has this taken care of for you

4/20/2014 1:21:23 AM

JeffreyBSG
All American
10165 Posts
user info
edit post

I checked out "map" and tried for a bit to implement it, but got kinda stuck (didn't try for all that long, admittedly...my students have an exam tomorrow and bombared me with questions.)

also, I'm not entirely clear how I can store my monstrous (ideally, > 10^7 entries) binary string, or in what format. but I'm still tinkering with it.

just an update. thanks for the suggestion that I use map, I checked out the links and I'm sure it'll all become clear soonish.

4/21/2014 12:14:47 AM

moron
All American
33726 Posts
user info
edit post

Storing 10^7 bits is pretty trivial... That's like a megabyte of data.

A map is just a dictionary, or a lookup table. Or is it the implementation you're more having issue with?

4/21/2014 1:12:41 AM

Shadowrunner
All American
18332 Posts
user info
edit post

This sounds tractable analytically; are you simulating it to check your work?

4/21/2014 11:56:04 AM

JeffreyBSG
All American
10165 Posts
user info
edit post

^^
yeah, but the thing is , I want to generate a random string of 10^7 bits of data. In fact, I want to generate dozens or hundreds of them, all within the same program, since I'm trying to simulate the statistical properties of a random variable depending on a random enormous string of data.

I guess I'm not sure how/where to store the gigantic base-string. C++ flatly refuses to store it as an array, of course, and that's kinda the only structure I'm familiar with.

^
yeah, I think it's tractable, but nobody's done it yet. this is my thesis, actually. I'm not precisely checking my work; it's more, I want to get a feel for what's happening, how this variable behaves for certain ranges of k/log(n). The expectation is more or less understood; I'm looking at the variance.

4/21/2014 4:55:46 PM

moron
All American
33726 Posts
user info
edit post

Isn't there anyone in your department that can sit down and help you? These programming problems aren't very big ones to overcome, a senior computer engineering student, or computer science student can help you figure them out easily.

4/21/2014 5:30:07 PM

lewisje
All American
9196 Posts
user info
edit post

Quote :
"I don't know anything about pointers"
http://cslibrary.stanford.edu/104/

4/21/2014 7:33:10 PM

JeffreyBSG
All American
10165 Posts
user info
edit post

yeah, I'm sure there is. I just randomly decided to ask TWW first though, for some reason

4/21/2014 9:55:46 PM

aaronburro
Sup, B
52713 Posts
user info
edit post

seriously, like moron is saying, use a map. A tree is not what you want in this scenario. You want something with a fast lookup, and a binary tree has O(log2(n)) lookup time (normal case) while a map has O(1). Even better, you have no need for pointers with a map, especially one that's already made for you like what moron suggested.

Also, I'd suggest going away from C++ for this for the time being, unless you have a background in it. You'd probably have better luck banging out the basics in java or C#, and those will keep you away from nastier bugs that are easy to write in C++ when you're just starting out. Both java and C# have a dictionary (or map) as part of the base libraries, too.

Another word of advice would be not to build your string as you go along. Generate your huge random string first, and then pass it in to the algorithm that analyzes it. This will be much more parallelizable (and trivially so, at that), and it has the added benefit of allowing you to easily pass in your own strings for any "weird cases" that you might want to explore. It's also going to run faster, even with the worst possible implementations. At the end of the day, you want to analyze a random string, so it doesn't matter if the string is generated as you go or if it's generated all at once.

4/22/2014 12:19:46 AM

moron
All American
33726 Posts
user info
edit post

map is still implemented as a binary tree, to my knowledge, not a hash table.

A hash table would be a great option for this too, assuming he could find a good hashing algorithm. If he couldn't, there would be memory issues if he tried to scale it up.

This is easy in C#, but C# is so Microsofty...

[Edited on April 22, 2014 at 12:32 AM. Reason : ]

4/22/2014 12:31:14 AM

lewisje
All American
9196 Posts
user info
edit post

javascript man

javascript

4/22/2014 2:20:12 AM

 Message Boards » Tech Talk » C++ mathy question Page [1]  
go to top | |
Admin Options : move topic | lock topic

© 2024 by The Wolf Web - All Rights Reserved.
The material located at this site is not endorsed, sponsored or provided by or on behalf of North Carolina State University.
Powered by CrazyWeb v2.38 - our disclaimer.