Algorithm 如何修改Smith和Waterman perl脚本以加快速度?

Algorithm 如何修改Smith和Waterman perl脚本以加快速度?,algorithm,perl,alignment,bioinformatics,Algorithm,Perl,Alignment,Bioinformatics,我找到了这个perl脚本,但是我有太多的序列要分析。我想知道是否有可能优化它?我在上面发布了NYTProf,看到“计算比赛分数”、“计算差距分数”和“选择最佳分数”花费了很多时间。我必须修改数据结构吗?谢谢你的帮助 包含以下引用的perl脚本: # Smith-Waterman Algorithm # from this website http://etutorials.org/Misc/blast/Part+II+Theory/Chapter+3.+Sequence+Alignme

我找到了这个perl脚本,但是我有太多的序列要分析。我想知道是否有可能优化它?我在上面发布了NYTProf,看到“计算比赛分数”、“计算差距分数”和“选择最佳分数”花费了很多时间。我必须修改数据结构吗?谢谢你的帮助

包含以下引用的perl脚本:

    # Smith-Waterman  Algorithm
# from this website http://etutorials.org/Misc/blast/Part+II+Theory/Chapter+3.+Sequence+Alignment/3.2+Local+Alignment+Smith-Waterman/

# Smith-Waterman  Algorithm

# usage statement
die "usage: $0 <sequence 1> <sequence 2>\n" unless @ARGV == 2;

# get sequences from command line
my ($seq1, $seq2) = @ARGV;

# scoring scheme
my $MATCH    =  1; # +1 for letters that match
my $MISMATCH = -1; # -1 for letters that mismatch
my $GAP      = -1; # -1 for any gap

# initialization
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}   = 0;
    $matrix[$i][0]{pointer} = "none";
}

# fill
my $max_i     = 0;
my $max_j     = 0;
my $max_score = 0;

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;

        if ($diagonal_score <= 0 and $up_score <= 0 and $left_score <= 0) {
            $matrix[$i][$j]{score}   = 0;
            $matrix[$i][$j]{pointer} = "none";
            next; # terminate this iteration of the loop
        }

        # 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};
        }
    }
}

# trace-back

my $align1 = "";
my $align2 = "";

my $j = $max_j;
my $i = $max_i;

while (1) {
    last if $matrix[$i][$j]{pointer} eq "none";

    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;
print "$align1\n";
print "$align2\n";
史密斯-沃特曼算法 #从本网站http://etutorials.org/Misc/blast/Part+II+理论/第+3章+顺序+对齐/3.2+局部+对齐+史密斯-沃特曼/ #史密斯-沃特曼算法 #使用说明 除非@ARGV==2,否则为“用法:$0\n”; #从命令行获取序列 my($seq1,$seq2)=@ARGV; #计分制 我的$MATCH=1;#+1表示匹配的字母 我的美元错配=-1;#-1表示不匹配的字母 我的$GAP=-1;#-1.任何差距 #初始化 我的@矩阵; $matrix[0][0]{score}=0; $matrix[0][0]{pointer}=“无”;
对于(my$j=1;$j),您可以尝试避免反复做相同的事情

  • 与从序列中删除单个字符不同,您可以尝试在循环之前将序列拆分为字符,而不是使用最可能更快的索引访问

    例如:

    my $string = "Hello, how are you?";
    my @chars = split //, $string;  # Or: unpack 'a*', $string
    print "Eighth char: $chars[7]\n";
    
  • my$letter2=substr($seq2,$i-1,1);
    可以转到外循环,因为
    j
    内循环从不改变

    for(my $i = 1; $i <= length($seq2); $i++) {
        my $letter2 = substr($seq2, $i-1, 1);
        for(my $j = 1; $j <= length($seq1); $j++) {
    
  • 对于
    指针
    的值,使用整数代替字符串。您可以使用常量使其可读

    use constant {
       POINTER_NONE => 0,
       POINTER_LEFT => 1,
       ...
    };
    
  • 预先计算
    $j-1
    $i-1
    也可能带来一点好处

  • 请注意您应该在每次更改前后对代码进行分析,以查看速度是否提高


    所有这些都是微小的改进。真正的问题是你有一个二次算法。

    你可以尝试避免重复做同样的事情

  • 与从序列中删除单个字符不同,您可以尝试在循环之前将序列拆分为字符,而不是使用最可能更快的索引访问

    例如:

    my $string = "Hello, how are you?";
    my @chars = split //, $string;  # Or: unpack 'a*', $string
    print "Eighth char: $chars[7]\n";
    
  • my$letter2=substr($seq2,$i-1,1);
    可以转到外循环,因为
    j
    内循环从不改变

    for(my $i = 1; $i <= length($seq2); $i++) {
        my $letter2 = substr($seq2, $i-1, 1);
        for(my $j = 1; $j <= length($seq1); $j++) {
    
  • 对于
    指针
    的值,使用整数代替字符串。您可以使用常量使其可读

    use constant {
       POINTER_NONE => 0,
       POINTER_LEFT => 1,
       ...
    };
    
  • 预先计算
    $j-1
    $i-1
    也可能带来一点好处

  • 请注意您应该在每次更改前后对代码进行分析,以查看速度是否提高


    所有这些都是微小的改进。真正的问题是你有一个二次算法。

    真正的问题是你有一个二次算法。它天生就很慢。但是,该算法是解决最长公共子串问题的动态方法的变体,你做得再好不过了

    也就是说,这是一个具有以下特性的实现:

    • 将内存量从O(M*N)减少到O(M+N)
    • 返回所有可能的解决方案(无需额外费用!!!)
    • 在Perl中应该尽可能快


    真正的问题是,你有一个二次算法。它本质上是缓慢的。然而,该算法是解决最长公共子串问题的动态方法的一个变种,你不能做得更好

    也就是说,这是一个具有以下特性的实现:

    • 将内存量从O(M*N)减少到O(M+N)
    • 返回所有可能的解决方案(无需额外费用!!!)
    • 在Perl中应该尽可能快


    用C重写它?它已经用“C风格的Perl”编写了很多,并且它没有使用任何很难翻译成C的Perlish习语。谢谢你的建议,但不幸的是,我不是C程序员!使用现有的S-W实现,它是用C编写的?为什么你必须使用这个特定的脚本?你是对的,这是一个好主意。事实上,我有另一个perl脚本运行这个脚本d解析结果。但是我也可以调用C脚本!谢谢你的建议。用C重写它?它已经用“C风格的Perl”编写了很多,并且它没有使用任何很难翻译成C的Perlish习语。谢谢你的建议,但不幸的是,我不是C程序员!使用现有的S-W实现,它是用C编写的?为什么你必须使用这个特定的脚本?你是对的,这是一个好主意。事实上,我有另一个perl脚本运行这个脚本d解析结果。但是我也可以调用C脚本!谢谢你的建议。谢谢你的建议。关于你的第二点,我将尝试解决它。但是你对预先计算
    $j-1
    意味着什么呢?做
    我的$jm1=$j-1;
    ,然后使用
    $jm1
    ,而不是
    $j-1
    。我认为这里节省的是噪音。一个更好的主意可能是对我的$i(0..length($seq2)-1)使用
    而不是对我的$i(1..length($seq2))@MrSmith42,我希望你不介意我的添加。如果你介意,请随时回复。你“真正的问题是你有一个二次算法。”,该算法是解决最长公共子串问题的动态方法的一种变体。你做得再好不过了。(也就是说,虽然是O(N*M)处理时间,但它能在这段时间内找到所有解,而不仅仅是一个。)我认为可以减少代码使用的内存,但我看不到有任何方法可以显著减少处理时间。好的,谢谢ikegami的建议。我不确定如何减少分析时间,但我会使用您的所有注释。也许我可以尝试使用称为此的脚本来解析我的文件。谢谢又是你!谢谢你的建议