Here's the simulation version:
package fun;
import java.util.HashSet;
import java.util.Random;
import dna.AminoAcid;
public class ProbShared2 {
public static void main(String args[]){
int k=Integer.parseInt(args[0]);
int len1=Integer.parseInt(args[1]);
int len2=Integer.parseInt(args[2]);
int rounds=Integer.parseInt(args[3]);
System.out.println("Probability: "+simulate(k, len1, len2, rounds));
}
static double simulate(int k, int len1, int len2, int rounds){
int successes=0;
final HashSet<Long> set=new HashSet<Long>();
for(int i=0; i<rounds; i++){
successes+=simulateOnePair(k, len1, len2, set);
}
return successes/(double)rounds;
}
static int simulateOnePair(int k, int len1, int len2, HashSet<Long> set){
set.clear();
final int shift=2*k;
final long mask=~((-1L)<<shift);
long kmer=0;
int len=0;
byte[] bases=randomSequence(len2);
for(int i=0; i<bases.length; i++){
byte b=bases[i];
long x=baseToNumber[b];
kmer=((kmer<<2)|x)&mask;
if(x<0){len=0;}else{len++;}
if(len>=k){
set.add(kmer);
}
}
bases=randomSequence(len1);
for(int i=0; i<bases.length; i++){
byte b=bases[i];
long x=baseToNumber[b];
kmer=((kmer<<2)|x)&mask;
if(x<0){len=0;}else{len++;}
if(len>=k){
if(set.contains(kmer)){return 1;}
}
}
return 0;
}
static byte[] randomSequence(int len){
byte[] array=new byte[len];
for(int i=0; i<len; i++){
int number=randy.nextInt(4);
array[i]=numberToBase[number];
}
return array;
}
static final Random randy=new Random();
static final byte[] numberToBase=AminoAcid.numberToBase;
static final byte[] baseToNumber=AminoAcid.baseToNumber;
}
Note that the answers are diverging slightly, so my initial solution does not appear to be quite correct. This could be due to the fact that kmers are not randomly distributed; some clump more tightly than others.
C:\temp>java fun.ProbShared 3 10 17
Cardinality 1: 8
Cardinality 2: 13
Probability: 0.8521277771213935
C:\temp>java fun.ProbShared2 3 10 17 1000000
Probability: 0.850832
C:\temp>java fun.ProbShared 9 180 200
Cardinality 1: 172
Cardinality 2: 192
Probability: 0.11844142052318785
C:\temp>java fun.ProbShared2 9 180 200 1000000
Probability: 0.094511
Gamblers have a similar problem - for example in the case of finding the odds of getting heads n times in a row in m tries of flipping a coin. This problem with the coins was solved by de Moivre in 1738 (for details see the post at math.stackexchange.com). I implemented this in Python (might be helpful) [but I'm not sure this is right]:
Thanks for your answer in python, its easier for me that way. I need to think through this a bit more, but are you sure that this is correct ?
Although I don't fully understand the formula yet, I feel like this is the probability to find a specific k-mer of sequence A in sequence B, which is different than the common substring problem. For instance, what would happen with that setup ?
The longer I think about your problem, the more doubts I have concerning the answer I gave you. I need to think this through too :) I changed my answer to a comment. Please let me know if you find the solution (the problem is very interesting).
Sure. I just found that this problem has a name (Common Substrings in Random Strings) and a with a quick google search, that paper. Didn't read it yet, will update.