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 <