通过动态编程实现perl序列对齐
我正在使用动态规划(半全局对齐)比较大小为5500个碱基的引用序列和大小为3600的查询序列,事实上,我对复杂性和性能了解不多,代码正在爆炸,并给我“内存不足”的错误。知道它在较小的序列上正常工作,我的问题是:这种行为是正常的,或者我可能在代码中有另一个问题?如果是正常的,有任何提示来解决这个问题吗?提前谢谢通过动态编程实现perl序列对齐,perl,memory,matrix,alignment,dynamic-programming,Perl,Memory,Matrix,Alignment,Dynamic Programming,我正在使用动态规划(半全局对齐)比较大小为5500个碱基的引用序列和大小为3600的查询序列,事实上,我对复杂性和性能了解不多,代码正在爆炸,并给我“内存不足”的错误。知道它在较小的序列上正常工作,我的问题是:这种行为是正常的,或者我可能在代码中有另一个问题?如果是正常的,有任何提示来解决这个问题吗?提前谢谢 sub semiGlobal { my ( $seq1, $seq2,$MATCH,$MISMATCH,$GAP ) = @_; # initialization: fir
sub semiGlobal {
my ( $seq1, $seq2,$MATCH,$MISMATCH,$GAP ) = @_;
# initialization: first row to 0 ;
my @matrix;
$matrix[0][0]{score} = 0;
$matrix[0][0]{pointer} = "none";
for ( my $j = 1 ; $j <= length($seq1) ; $j++ ) {
$matrix[0][$j]{score} = 0;
$matrix[0][$j]{pointer} = "none";
}
for ( my $i = 1 ; $i <= length($seq2) ; $i++ ) {
$matrix[$i][0]{score} = $GAP * $i;
$matrix[$i][0]{pointer} = "up";
}
# fill
my $max_i = 0;
my $max_j = 0;
my $max_score = 0;
print "seq2: ".length($seq2);
print "seq1: ".length($seq1);
for ( my $i = 1 ; $i <= length($seq2) ; $i++ ) {
for ( my $j = 1 ; $j <= length($seq1) ; $j++ ) {
my ( $diagonal_score, $left_score, $up_score );
# calculate match score
my $letter1 = substr( $seq1, $j - 1, 1 );
my $letter2 = substr( $seq2, $i - 1, 1 );
if ( $letter1 eq $letter2 ) {
$diagonal_score = $matrix[ $i - 1 ][ $j - 1 ]{score} + $MATCH;
}
else {
$diagonal_score = $matrix[ $i - 1 ][ $j - 1 ]{score} + $MISMATCH;
}
# calculate gap scores
$up_score = $matrix[ $i - 1 ][$j]{score} + $GAP;
$left_score = $matrix[$i][ $j - 1 ]{score} + $GAP;
# choose best score
if ( $diagonal_score >= $up_score ) {
if ( $diagonal_score >= $left_score ) {
$matrix[$i][$j]{score} = $diagonal_score;
$matrix[$i][$j]{pointer} = "diagonal";
}
else {
$matrix[$i][$j]{score} = $left_score;
$matrix[$i][$j]{pointer} = "left";
}
}
else {
if ( $up_score >= $left_score ) {
$matrix[$i][$j]{score} = $up_score;
$matrix[$i][$j]{pointer} = "up";
}
else {
$matrix[$i][$j]{score} = $left_score;
$matrix[$i][$j]{pointer} = "left";
}
}
# set maximum score
if ( $matrix[$i][$j]{score} > $max_score ) {
$max_i = $i;
$max_j = $j;
$max_score = $matrix[$i][$j]{score};
}
}
}
my $align1 = "";
my $align2 = "";
my $j = $max_j;
my $i = $max_i;
while (1) {
if ( $matrix[$i][$j]{pointer} eq "none" ) {
$stseq1 = $j;
last;
}
if ( $matrix[$i][$j]{pointer} eq "diagonal" ) {
$align1 .= substr( $seq1, $j - 1, 1 );
$align2 .= substr( $seq2, $i - 1, 1 );
$i--;
$j--;
}
elsif ( $matrix[$i][$j]{pointer} eq "left" ) {
$align1 .= substr( $seq1, $j - 1, 1 );
$align2 .= "-";
$j--;
}
elsif ( $matrix[$i][$j]{pointer} eq "up" ) {
$align1 .= "-";
$align2 .= substr( $seq2, $i - 1, 1 );
$i--;
}
}
$align1 = reverse $align1;
$align2 = reverse $align2;
return ( $align1, $align2, $stseq1 ,$max_j);
}
次半全局{
我的($seq1,$seq2,$MATCH,$MISMATCH,$GAP)=@;
#初始化:第一行为0;
我的@矩阵;
$matrix[0][0]{score}=0;
$matrix[0][0]{pointer}=“无”;
对于(我的$j=1;$j$max_分数){
$max_i=$i;
$max_j=$j;
$max_score=$matrix[$i][$j]{score};
}
}
}
我的$1=“”;
我的$2=“”;
my$j=$max_j;
my$i=$max\u i;
而(1){
if($matrix[$i][$j]{pointer}eq“none”){
$stseq1=$j;
最后;
}
if($matrix[$i][$j]{pointer}eq“对角线”){
$align1.=substr($seq1,$j-1,1);
$align2.=substr($seq2,$i-1,1);
$i--;
$j--;
}
elsif($matrix[$i][$j]{pointer}eq“左”){
$align1.=substr($seq1,$j-1,1);
$align2.=“-”;
$j--;
}
elsif($matrix[$i][$j]{pointer}eq“up”){
$align1.=“-”;
$align2.=substr($seq2,$i-1,1);
$i--;
}
}
$align1=反向$align1;
$align2=反向$align2;
返回($align1、$align2、$stseq1、$max_j);
}
我认为@j_random_hacker和@Ashalynd在大多数Perl实现中使用此算法是正确的。您正在使用的数据类型将使用计算绝对需要的更多内存
因此,这是“正常的”,因为您应该看到这种内存使用情况,因为您是如何用perl编写此算法的。您可能在使用大量内存的周围代码中遇到其他问题,但此算法将使用大量序列严重影响您的内存
您可以按照@Ashalynd的建议,通过更改正在使用的数据类型来解决一些内存问题。您可以尝试将保存分数和指针的哈希更改为数组,并将字符串指针更改为整数值。这样做可能会在保持可读性的同时给您带来一些好处:
use strict;
use warnings;
# define constants for array positions and pointer values
# so the code is still readable.
# (If you have the "Readonly" CPAN module you may want to use it for constants
# instead although none of the downsides of the "constant" pragma apply in this code.)
use constant {
SCORE => 0,
POINTER => 1,
DIAGONAL => 0,
LEFT => 1,
UP => 2,
NONE => 3,
};
...
sub semiGlobal2 {
my ( $seq1, $seq2,$MATCH,$MISMATCH,$GAP ) = @_;
# initialization: first row to 0 ;
my @matrix;
# score and pointer are now stored in an array
# using the defined constants as indices
$matrix[0][0][SCORE] = 0;
# pointer value is now a constant integer
$matrix[0][0][POINTER] = NONE;
for ( my $j = 1 ; $j <= length($seq1) ; $j++ ) {
$matrix[0][$j][SCORE] = 0;
$matrix[0][$j][POINTER] = NONE;
}
for ( my $i = 1 ; $i <= length($seq2) ; $i++ ) {
$matrix[$i][0][SCORE] = $GAP * $i;
$matrix[$i][0][POINTER] = UP;
}
... # continue to make the appropriate changes throughout the code
使用严格;
使用警告;
#为数组位置和指针值定义常量
#因此代码仍然可读。
#(如果您有“只读”CPAN模块,您可能希望将其用于常量
#相反,尽管“常量”pragma的任何缺点都不适用于此代码。)
使用常数{
分数=>0,
指针=>1,
对角线=>0,
左=>1,
上升=>2,
无=>3,
};
...
亚半圆2{
我的($seq1,$seq2,$MATCH,$MISMATCH,$GAP)=@;
#初始化:第一行为0;
我的@矩阵;
#分数和指针现在存储在一个数组中
#使用定义的常量作为索引
$matrix[0][0][SCORE]=0;
#指针值现在是一个常量整数
$matrix[0][0][POINTER]=无;
对于我的$j=1;$J< P >一个可能解决问题的方法是将<代码> @矩阵<代码>与文件捆绑在一起。但是,这将大大减慢程序。
sub semiGlobal {
use Tie::Array::CSV;
tie my @matrix, 'Tie::Array::CSV', 'temp.txt'; # Don't forget to add your own error handler.
my ( $seq1, $seq2,$MATCH,$MISMATCH,$GAP ) = @_;
# initialization: first row to 0 ;
$matrix[0][0] = '0 n';
for ( my $j = 1 ; $j <= length($seq1) ; $j++ ) {
$matrix[0][$j] = '0 n';
}
for ( my $i = 1 ; $i <= length($seq2) ; $i++ ) {
my $score = $GAP * $i;
$matrix[$i][0] = join ' ',$score,'u';
}
#print Dumper(\@matrix);
# fill
my $max_i = 0;
my $max_j = 0;
my $max_score = 0;
print "seq2: ".length($seq2)."\n";
print "seq1: ".length($seq1)."\n";
for ( my $i = 1 ; $i <= length($seq2) ; $i++ ) {
for ( my $j = 1 ; $j <= length($seq1) ; $j++ ) {
my ( $diagonal_score, $left_score, $up_score );
# calculate match score
my $letter1 = substr( $seq1, $j - 1, 1 );
my $letter2 = substr( $seq2, $i - 1, 1 );
my $score = (split / /, $matrix[ $i - 1 ][ $j - 1 ])[0];
if ( $letter1 eq $letter2 ) {
$diagonal_score = $score + $MATCH;
}
else {
$diagonal_score = $score + $MISMATCH;
}
# calculate gap scores
$up_score = (split / /,$matrix[ $i - 1 ][$j])[0] + $GAP;
$left_score = (split / /,$matrix[$i][ $j - 1 ])[0] + $GAP;
# choose best score
if ( $diagonal_score >= $up_score ) {
if ( $diagonal_score >= $left_score ) {
$matrix[$i][$j] = join ' ',$diagonal_score,'d';
}
else {
$matrix[$i][$j] = join ' ', $left_score, 'l';
}
}
else {
if ( $up_score >= $left_score ) {
$matrix[$i][$j] = join ' ', $up_score, 'u';
}
else {
$matrix[$i][$j] = join ' ', $left_score, 'l';
}
}
# set maximum score
if ( (split / /, $matrix[$i][$j])[0] > $max_score ) {
$max_i = $i;
$max_j = $j;
$max_score = (split / /, $matrix[$i][$j])[0];
}
}
}
my $align1 = "";
my $align2 = "";
my $stseq1;
my $j = $max_j;
my $i = $max_i;
while (1) {
my $pointer = (split / /, $matrix[$i][$j])[1];
if ( $pointer eq "n" ) {
$stseq1 = $j;
last;
}
if ( $pointer eq "d" ) {
$align1 .= substr( $seq1, $j - 1, 1 );
$align2 .= substr( $seq2, $i - 1, 1 );
$i--;
$j--;
}
elsif ( $pointer eq "l" ) {
$align1 .= substr( $seq1, $j - 1, 1 );
$align2 .= "-";
$j--;
}
elsif ( $pointer eq "u" ) {
$align1 .= "-";
$align2 .= substr( $seq2, $i - 1, 1 );
$i--;
}
}
$align1 = reverse $align1;
$align2 = reverse $align2;
untie @matrix; # Don't forget to add your own error handler.
unlink 'temp.txt'; # Don't forget to add your own error handler.
return ( $align1, $align2, $stseq1 ,$max_j);
}
次半全局{
使用Tie::Array::CSV;
tie my@matrix、'tie::Array::CSV'、'temp.txt'#别忘了添加自己的错误处理程序。
我的($seq1,$seq2,$MATCH,$MISMATCH,$GAP)=@;
#初始化:第一行为0;
$matrix[0][0]=“0 n”;
对于(我的$j=1;$j$max_分数){
$max_i=$i;
$max_j=$j;
$max_score=(分割/,$matrix[$i][$j])[0];
}
}
}
我的$1=“”;
我的$2=“”;
我的$stseq1;
my$j=$max_j;
my$i=$max\u i;
而(1){
我的$pointer=(拆分/,$matrix[$i][$j])[1];
如果($pointer eq“n”){
$stseq1=$j;
最后;
}
如果($指针式等式“d”){
$align1.=substr($seq1,$j-1,1);
$align2.=substr($seq2,$i-1,1);
$i--;
$j--;
}
elsif($pointer eq“l”){
$align1.=substr($seq1,$j-1,1);
$align2.=“-”;
$j--;
}
elsif($pointer eq“u”){
$align1.=“-”;
$align2.=substr($seq2,$i-1,1);
$i--;
}
}
$align1=反向$align1;
$align2=反向$align2;
解开@matrix;#别忘了添加自己的错误处理程序。
取消链接“temp.txt”;#别忘了添加自己的错误处理程序。
返回($align1、$align2、$stseq1、$max_j);
}
您仍然可以使用原始sub来存储短序列,而切换到此sub来存储长序列。您可以发布一些代码吗?这可能类似于嵌套两个循环并扫描数据。您最有可能使用二维矩阵来存储DP。您可以将其修改为使用长度为n的数组(其中n是较小序列的长度)。我们肯定需要看一些代码!正如ElKamina所说,可以使用O(min(n,m))空间(这个技巧是由Dan Hirschberg完成的),虽然这并不是一件小事——如果您仍然打算将代码保留在像Perl这样的慢速解释语言中,我就不会费心尝试这种改进。代码是从这个链接定制的。代码至少具有二次复杂度(处理NxM矩阵)。此外,如果序列大小约为5000,我们将得到一个包含25*1000*1000~2500万个条目的数组。每个条目都是一个包含字符串和数字的字典。如果我们假设一个字符串是32字节,则意味着m的长度几乎为1GB