通过动态编程实现perl序列对齐

通过动态编程实现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

我正在使用动态规划(半全局对齐)比较大小为5500个碱基的引用序列和大小为3600的查询序列,事实上,我对复杂性和性能了解不多,代码正在爆炸,并给我“内存不足”的错误。知道它在较小的序列上正常工作,我的问题是:这种行为是正常的,或者我可能在代码中有另一个问题?如果是正常的,有任何提示来解决这个问题吗?提前谢谢

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