使用omp优化或提出c ++,c#代码以查找所有类似的k图案

时间:2015-09-30 21:14:56

标签: c# c++ visual-studio-2010 openmp

给定正整数k (k≤50),长度最多为5,000的DNA串代表一个基序,长度最多为50,000的DNA串t代表基因组。

问题在于返回t的所有子字符串t′,以便编辑距离d_E(s,t′)

  

两个字符串之间的编辑距离是最小的基本数   转换一个的操作(插入,删除和替换)   字符串插入另一个,用于instamce s = 'TGCATAT't' = 'ATCCGAT' enter image description here   here is a c++ implementation by user1131146帐户aban   也许最好使用那个??

小于或等于k。每个子字符串应由一对包含在t中的位置,后跟其长度。

例如

2
ACGTAG
ACGGATCGGCATCGT

应输出

1 4
1 5
1 6

对于此示例,k=2结果表示:
对于索引1 to 4d_E(s,t′)=2(加T那么A最后一次t's G

s  = ACGTAG
t' = ACGG

对于索引1 to 5 d_E(s,t′)=2(将G添加到t'结束,然后将索引4处的t's G替换为T

s  = ACGTAG
t' = ACGGA

对于索引1 to 6 d_E(s,t′)=2(最后t's T取消G然后将t's G替换为T

s  = ACGTAG
t' = ACGGAT

获得获得all substrings of a genome that are within a certain fixed distance of the desired motif的解决方案,使用omp并行化解决方案的最佳方法是什么。随着字符串变得越长,程序花费的时间就越长。

我已经使用omp #pragma omp parallel for测试了然后在写入文件部分使用了lock,还#pragma omp critical但是我不知道我是否正确地对其进行了并行化。

void alignment(vector<vi>&a, string &x, string y, int k){
    string tx,ty;
    int i,j;
    int ylen=a[0].size();
    for(i=1;i<a.size();i++){
        for(j=max(1,i-k);j<=min(ylen,i+k);j++){ 
            a[i][j] = max(x[i-1] == y[j-1]?a[i-1][j-1] : (a[i-1][j-1]-1), max(a[i-1][j]-1,a[i][j-1]-1));
        }
    }
}

int main()
{
    int k = 23;
    string s = "AATTAGCTAAGGTGTACGATGTCCCATTGTGTAAGATTAGGAACTCCATTTAGGTTACCTCCGTCTTAAGTGATGGACCGTGGGTAGCTGCGTCCGATGGACTCATGCAGCGCCCGGATACCTGCAGTATTTATTATATAGGTCTGCGCACCAAACGATTTCTTTCGTGGTCGGGATTCCGGGGTCCTCCGCTATTCAGAGAGCTAAATA";
    string t = "ACAATGCAGCAATCCAGCGCCGGAATTTAAGAATAGGTCAGTTTGTAAGGCACTGTTCCCGTTATTCGTAATGCAGTATTAACGTTAATGCTCGAGACCATATTGGACGTCAGTATGCAGACCTGTGCTAGGGTGGTCTATTTCAAGATCACCGAGCTAGGCGCGTGAGCTAACAGGCCGTAATGGTGGCGCCCGCTCCCATAATCACTTCACGAAGCATTAGGTAGACTACCATTTAGGAAGCCCTCTCGCCCGCGTACTGGTTACAGCCCACTACAATGGATACTCCTTACTTCGGTGCAGGCAAGACTTCTACAAAGAAGCGTCCAAGAAGTTGTCGTAGCTCGTTCTTACCCCACCTGTATAAAATTGATCCAGTCGTACATATGACGATGCTGAGCCTCGGACTGGTAAATACAAGTCAAAGGACCAACCCATTACAGTATGAACTACCGGTGG";
    time_t start = time(NULL);
    std::ofstream out("output.txt");
    ifstream someStream( "data.txt" );
    string line;
    getline( someStream, line );    int k = atoi(line.c_str() );
    getline( someStream, line );    string s =line;
    getline( someStream, line );    string t= line;
    int slen=s.length(), tlen=t.length();
    vector<vi>a( slen+1, vi(slen+k+1)); 
    int i,j;
    for(i=1;i<a.size();i++)
        fill(a[i].begin(),a[i].end(),-999),a[i][0]=a[i-1][0]-1;
    #pragma omp parallel for
    {
        for(j=1;j<a[0].size();j++)
        {
            a[0][j]=a[0][j-1]-1;
        }
    }
    //cout << "init";
    time_t endINIT = time(NULL);
    cout<<"Execution Init Time: "<< (double)(endINIT-start)<<" Seconds"<<std::endl;
    //omp_lock_t writelock;
    //omp_init_lock(&writelock);

    #pragma omp parallel for
    {
    for(i=0;i<=tlen-slen+k;i++)
    {
        alignment(a,s,t.substr(i,slen+k),k); 
        for(j=max(0,slen-k);j<=min(slen+k,tlen-i);j++)
        {
            if(a[slen][j]>=-k)
            {

                //omp_set_lock(&writelock);    
                //cout<<(i+1)<<' '<<j<<endl;
                #pragma omp critical 
                {
                    out <<(i+1)<<' '<<j<<endl;
                }
                //omp_unset_lock(&writelock);
            }
        }
    }
    }
    //omp_destroy_lock(&writelock);
    time_t end = time(NULL);
    cout<<"Execution Time: "<< (double)(end-start)<<" Seconds"<<std::endl;  
    out.close();
    return 0;
}

我无法完成此操作或对其进行优化。有没有更好的办法?

1 个答案:

答案 0 :(得分:1)

正如您对帖子的评论中所提到的,为了并行调用alignment,每个帖子都需要拥有自己的a副本。您可以使用firstprivate OpenMP子句执行此操作:

#pragma omp parallel for firstprivate(a)

alignment本身中,您在循环中重复计算,优化程序可能无法消除这些计算。在循环条件中调用a.size并使用min可以计算一次并存储在局部变量中。不断计算a[i]a[i-1]也可以从内循环中解除。

int asize = int(a.size());
for(i = 1; i < asize; i++) {
    int jend = min(ylen, i + k);
    vi &cura = a[i];
    vi &preva = a[i-1];
    for(j = max(1, i - k);j <= jend; j++)
        cura[j] = max(x[i-1] == y[j-1]?preva[j-1] : (preva[j-1]-1), max(preva[j]-1,cura[j-1]-1));
}

Windows标头定义maxmin个宏。如果您正在使用那些(而不是STL中的内联函数),那么也可能不必要地重复代码。

另一个瓶颈可能是比赛的输出,具体取决于找到匹配的频率。提高这一点的一种方法是将i-1,j对存储到一个新的局部变量中(也包含在private子句中),然后使用reduction子句来组合结果(尽管我我不确定如何使用容器。完成for循环后,您可以输出结果,可能先对它们进行排序。

尝试并行化初始化j的{​​{1}}循环可能不值得。代码需要修复以使其工作(也在注释中提到),如果启动线程的开销太大,或者如果多个线程尝试在线程之间存在缓存行争用,则多个线程可能导致它运行得更慢写入内存中几乎相邻的值。如果代码中的示例a[0]是典型的,我只需在一个线程上运行它。

构造s向量时,如果包含的向量,则可以在构造函数中包含a初始值:

-999

然后它下面的初始化循环只需要设置每个包含的向量中第一个元素的值。

这应该是一个开始。注意:代码示例是建议,尚未编译或测试。

编辑我已经通过这项工作了,结果并不是你所希望的。

最初我只是运行你的代码(以获得我的基线性能数字)。使用VC2010,最大化优化,64位编译。

vector<vi> a(slen + 1, vi(slen + k + 1, -999));

由于我没有您的数据文件,因此我随机生成了cl /nologo /W4 /MD /EHsc /Ox /favor:INTEL64 sequencing.cpp 50,000 [AGCT]个字符,t个5,000个,并使用了s个50个。 135秒,没有点击输出。当我将k设置为t加上45,000个随机字符时,我获得了大量点击,对执行时间没有明显影响。

我使用omp(使用s代替firstprivate来获取复制的private的初始值)并使其崩溃。通过查看,我意识到拨打a 的电话取决于之前通话的结果。所以这不能在多个核心上执行。

我确实重写了alignment以删除所有冗余计算,并在执行时间内减少了大约25%( 103秒):

alignment

我做的最后一件事是使用VS2015编译它。这将执行时间再减少了28%,大约 74秒

可以在void alignment(vector<vi>&a, const string &x, const string y, int k){ string tx,ty; int i,j; int ylen=int(a[0].size()); int asize = int(a.size()); for(i = 1; i < asize; i++) { auto xi = x[i - 1]; int jend = min(ylen, i + k); vi &cura = a[i]; const vi &preva = a[i-1]; j = max(1, i - k); auto caj = cura[j - 1]; const auto *yp = &y[j - 1]; auto *pca = &cura[j]; auto *ppj = &preva[j - 1]; for(;j <= jend; j++) { caj = *pca = max(*ppj - (xi != *yp), max(ppj[1] - 1, caj - 1)); ++yp; ++pca; ++ppj; } } } 中进行类似的调整和调整,但对性能没有任何可观察到的影响,因为大部分时间花费在main上。

使用32位二进制文​​件的执行时间类似。

我确实发现,因为alignment可以处理大量数据,所以可能可以在两个(或更多)线程上运行它,并重叠线程的区域使用(这样第二个线程只有在计算完第一个线程的结果后才能访问它们,但是在第一个线程完成整个数组的工作之前。但是,这需要创建自己的线程和一些非常仔细的同步确保正确数据在正确的位置可用的线程。我没有尝试使这项工作。

编辑2 优化版主体的来源:

alignment

int main() { // int k = 50; // string s = "AATTAGCTAAGGTGTACGATGTCCCATTGTGTAAGATTAGGAACTCCATTTAGGTTACCTCCGTCTTAAGTGATGGACCGTGGGTAGCTGCGTCCGATGGACTCATGCAGCGCCCGGATACCTGCAGTATTTATTATATAGGTCTGCGCACCAAACGATTTCTTTCGTGGTCGGGATTCCGGGGTCCTCCGCTATTCAGAGAGCTAAATA"; // string t = "ACAATGCAGCAATCCAGCGCCGGAATTTAAGAATAGGTCAGTTTGTAAGGCACTGTTCCCGTTATTCGTAATGCAGTATTAACGTTAATGCTCGAGACCATATTGGACGTCAGTATGCAGACCTGTGCTAGGGTGGTCTATTTCAAGATCACCGAGCTAGGCGCGTGAGCTAACAGGCCGTAATGGTGGCGCCCGCTCCCATAATCACTTCACGAAGCATTAGGTAGACTACCATTTAGGAAGCCCTCTCGCCCGCGTACTGGTTACAGCCCACTACAATGGATACTCCTTACTTCGGTGCAGGCAAGACTTCTACAAAGAAGCGTCCAAGAAGTTGTCGTAGCTCGTTCTTACCCCACCTGTATAAAATTGATCCAGTCGTACATATGACGATGCTGAGCCTCGGACTGGTAAATACAAGTCAAAGGACCAACCCATTACAGTATGAACTACCGGTGG"; time_t start = time(NULL); std::ofstream out("output.txt"); ifstream someStream( "data.txt" ); string line; getline( someStream, line ); int k = atoi(line.c_str() ); getline( someStream, line ); string s =line; getline( someStream, line ); string t= line; int slen=int(s.length()), tlen=int(t.length()); int i,j; vector<vi> a(slen + 1, vi(slen + k + 1, -999)); a[0][0]=0; for(i=1;i<=slen;i++) a[i][0]=-i; { int ej=int(a[0].size()); for(j=1;j<ej;j++) a[0][j] = -j; } //cout << "init"; time_t endINIT = time(NULL); cout<<"Execution Init Time: "<< (double)(endINIT-start)<<" Seconds"<<std::endl; { int endi=tlen-slen+k; for(i=0;i<=endi;i++) { alignment(a,s,t.substr(i,slen+k),k); int ej=min(slen+k,tlen-i); j=max(0,slen-k); const auto *aj = &a[slen][j]; for(;j<=ej;j++,++aj) { if(*aj>=-k) { //cout<<(i+1)<<' '<<j<<endl; out <<(i+1)<<' '<<j<<endl; } } } } time_t end = time(NULL); cout<<"Execution Time: "<< (double)(end-start)<<" Seconds"<<std::endl; out.close(); return 0; } 的代码与我上面列出的内容没有变化。