【发布时间】:2013-10-30 10:18:15
【问题描述】:
我正在比较大小为 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);
}
【问题讨论】:
-
你能发布一些代码吗?这可能类似于嵌套两个循环并扫描您的数据
-
您很可能正在使用二维矩阵来存储 DP。您可以修改它以使用长度为 n 的数组(其中 n 是较小序列的长度)。
-
我们肯定需要看一些代码!正如 ElKamina 所说,可以让它使用 O(min(n, m)) 空间(这个技巧归功于 Dan Hirschberg),尽管这并不是微不足道的——如果你还在继续,我不会费心尝试这种改进将代码保留在 Perl 等慢速解释语言中。
-
代码至少具有二次复杂度(处理 NxM 矩阵)。此外,如果序列大小约为 5000,我们最终将得到一个 25* 1000 * 1000 的数组,大约有 2500 万个条目。每个条目都是一个包含字符串和数字的字典。如果我们假设一个字符串是 32 字节,这意味着仅矩阵就有将近 1GB。使用数字代码而不是“向上”、“向左”等,即使假设数字是 4 个字节,也会使数组大小减少大约 10 倍(“仅”100MB,尽管我没有计算矩阵的开销条目),所以这是我要尝试的第一件事。
标签: perl memory matrix alignment dynamic-programming