给定正整数k (k≤50)
,长度最多为5,000
的DNA串代表一个基序,长度最多为50,000
的DNA串t代表基因组。
问题在于返回t的所有子字符串t′
,以便编辑距离d_E(s,t′)
两个字符串之间的编辑距离是最小的基本数 转换一个的操作(插入,删除和替换) 字符串插入另一个,用于instamce
s = 'TGCATAT'
和t' = 'ATCCGAT'
here is a c++ implementation by user1131146帐户aban 也许最好使用那个??
小于或等于k
。每个子字符串应由一对包含在t
中的位置,后跟其长度。
2
ACGTAG
ACGGATCGGCATCGT
应输出
1 4
1 5
1 6
对于此示例,k=2
结果表示:
对于索引1 to 4
,d_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;
}
我无法完成此操作或对其进行优化。有没有更好的办法?
答案 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标头定义max
和min
个宏。如果您正在使用那些(而不是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;
}
的代码与我上面列出的内容没有变化。