my @spectrum = qw/174.0 102.99 71.62 70.53 82.49 69.05 18.94 102.99 71.62 70.53 82.49 69.05 18.94 102.99 71.62 70.53 82.49 69.05 18.94 102.99 71.62 70.53 82.49 69.05 18.94/; my @subsp = qw/102.0 18.94 71.61 82.0 173.0 68.7/; #### REQUEST = 18.94 68.7 71.61 82.0 102.0 173.0 BEST_SUBSP = 18.94 69.05 71.62 82.49 102.99 174.0 SIMILARITY = 2.11 #### #!/usr/bin/perl use warnings; use strict; sub similarity { my ($request, $spectrum, $accuracy, $limit) = @_[0..3]; my $fmt = "%.${accuracy}f"; my @spectrum = @$spectrum; my @request = sort {$a <=> $b} @$request; return 0, [] unless @request; return 0, [] if @spectrum < @request; my %good; foreach my $signal (@request) { my @good; return 0 unless (@good = grep { abs($_-$signal) <= $limit } @spectrum); %good = (%good, map { ($_ => 1) } @good); } @spectrum = sort {$a <=> $b} grep { $good{$_} } @spectrum; my $alpha; my $best_subsp; my $alphabeta; $alphabeta = sub { my ($beta, $spectrum, $subsp, $found) = @_; unless (@$subsp) { $alpha = $beta; $best_subsp = $found; return; } my $compared = $subsp->[0]; foreach my $sign_id (0..$#{$spectrum}) { my $diff = abs($spectrum->[$sign_id] - $compared); next if $diff > $limit; next if defined($alpha) && ($diff + $beta) >= $alpha; $alphabeta->($diff + $beta, [@{$spectrum}[0..$sign_id-1, $sign_id+1..$#{$spectrum}]], [@{$subsp}[1..$#{$subsp}]], [@$found, $spectrum->[$sign_id]], ); } return; }; $alphabeta->(0, \@spectrum, \@request, []); return 0, [] unless defined $alpha; my $max_similarity = sprintf $fmt, $alpha ? @request/$alpha : 1000; return $max_similarity, $best_subsp; } my $limit = 3; my @spectrum = qw/174.0 102.99 71.62 70.53 82.49 69.05 18.94 102.99 71.62 70.53 82.49 69.05 18.94 102.99 71.62 70.53 82.49 69.05 18.94 102.99 71.62 70.53 82.49 69.05 18.94/; my @subsp = qw/102.0 18.94 71.61 82.0 173.0 68.7/; my ($sim, $best) = similarity(\@subsp, \@spectrum, 2, $limit); @subsp = sort {$a <=> $b} @subsp; print <