File Coverage

blib/lib/AI/CBR/Retrieval.pm
Criterion Covered Total %
statement 54 55 98.1
branch 8 12 66.6
condition 4 8 50.0
subroutine 9 9 100.0
pod 5 5 100.0
total 80 89 89.8


line stmt bran cond sub pod time code
1             package AI::CBR::Retrieval;
2              
3 3     3   3246 use warnings;
  3         6  
  3         79  
4 3     3   15 use strict;
  3         6  
  3         86  
5              
6 3     3   16 use List::Util qw(min);
  3         25  
  3         2330  
7              
8             =head1 NAME
9              
10             AI::CBR::Retrieval - retrieve similar cases from a case-base
11              
12              
13             =head1 SYNOPSIS
14              
15             Retrieve solutions for a case from a case-base
16              
17             use AI::CBR::Retrieval;
18              
19             my $r = AI::CBR::Retrieval->new($case, \@case_base);
20             $r->compute_sims();
21             my $solution = $r->most_similar_case();
22             ...
23              
24             =head1 METHODS
25              
26             =head2 new
27              
28             Creates a new object for retrieval.
29             Pass your case specification object as the first parameter.
30             Pass the reference of an array of hash references as the case-base.
31             The hashes should contain all attributes of the specification.
32             These will be called candidate cases internally.
33              
34             =cut
35              
36             sub new {
37 2     2 1 1504 my ($classname, $spec, $candidates) = @_;
38 2 50       11 croak('new case without candidates') unless @$candidates;
39 2 100       16 my $self = {
40             candidates => $candidates,
41             # we accept single specs as hash-ref or composed specs as array-ref
42             # internally both will be handled as a composed array-ref
43             queries => ref $spec eq 'AI::CBR::Case' ? [$spec] : $spec,
44             };
45 2         8 bless $self, $classname;
46 2         6 return $self;
47             }
48              
49              
50             =head2 compute_sims
51              
52             If the case-specification is complete,
53             you may call this method to compute the similarities
54             of all candidate cases to this specification.
55             After this step, each candidate of the case-base will have an
56             additional attribute C<_sim> indicating the similarity.
57              
58             =cut
59              
60             sub compute_sims {
61 2     2 1 13 my ($self) = @_;
62            
63             # pre-allocate variables used in loop
64 2         4 my ($sum_sims, $sum_weights, $att_key, $att, $weight, $x, $y);
65            
66 2         5 my $num_queries = int @{$self->{queries}};
  2         14  
67 2         6 foreach my $candidate (@{$self->{candidates}}) {
  2         6  
68 6         14 $candidate->{_sim} = 1;
69 6         9 foreach my $query (@{$self->{queries}}) {
  6         14  
70 8         13 $sum_sims = 0;
71 8         12 $sum_weights = 0;
72            
73 34         139 ATTRIBUTES:
74 8         11 while(($att_key, $att) = each(%{$query})) {
75 26 50       76 next ATTRIBUTES unless $weight = $att->{weight};
76 26         36 $sum_weights += $weight;
77 26         38 $x = $att->{value};
78 26         59 $y = $candidate->{$att_key};
79 26         82 $sum_sims += $weight * (
80             !defined $x && !defined $y ? 1
81             : !defined $x || !defined $y ? 0
82 26 50 33     228 : &{$att->{sim}}($x, $y, $att->{param} || 0)
    50 33        
      100        
83             );
84             }
85            
86 8         31 $candidate->{_sim} *= _nrt($num_queries, $sum_sims / $sum_weights);
87             }
88             }
89 2         4 my @candidates_sorted = sort { $b->{_sim} <=> $a->{_sim} } @{$self->{candidates}};
  6         77  
  2         15  
90 2         13 $self->{candidates} = \@candidates_sorted;
91             }
92              
93              
94             =head2 RETRIEVAL METHODS
95              
96             Use one of these methods to get the similar cases you are interested into.
97              
98             =head3 most_similar_candidate
99              
100             Returns the most similar candidate.
101             No parameters.
102              
103             =cut
104              
105             sub most_similar_candidate {
106 1     1 1 1543 my ($self) = @_;
107 1         7 return $self->{candidates}->[0];
108             }
109              
110             =head3 n_most_similar_candidates
111              
112             Returns the n most similar candidates.
113             n is the only parameter.
114              
115             =cut
116              
117             sub n_most_similar_candidates {
118 1     1 1 2 my ($self, $n) = @_;
119 1         2 my $last_index = min($n - 1, int @{$self->{candidates}});
  1         12  
120 1         4 return map { $self->{candidates}->[$_] } (0 .. $last_index);
  3         8  
121             }
122              
123             =head3 first_confirmed_candidate
124              
125             Returns the first candidate that is confirmed by a later candidate.
126             Confirmation is based on an attribute value
127             whose key is passed as parameter.
128             In case there is no confirmed candidate at all,
129             simply returns the most similar one.
130              
131             =cut
132              
133             sub first_confirmed_candidate {
134 1     1 1 2 my ($self, $key) = @_;
135 1         1 my %candidate_with;
136             my $value;
137 1         2 foreach my $candidate (@{$self->{candidates}}) {
  1         3  
138 4         7 $value = $candidate->{$key};
139 4 100       9 if($candidate_with{$value}) {
140 1         5 return $candidate_with{$value};
141             } else {
142 3         7 $candidate_with{$value} = $candidate;
143             }
144             }
145              
146             # no confirmed candidate found, fall back
147 0         0 return $self->most_similar_candidate();
148             }
149              
150              
151             # internal method for n-th root
152             sub _nrt {
153 8     8   651 return $_[1] ** (1 / $_[0]);
154             }
155              
156              
157             =head1 SEE ALSO
158              
159             See L for an overview of the framework.
160              
161              
162             =head1 AUTHOR
163              
164             Darko Obradovic, C<< >>
165              
166             =head1 BUGS
167              
168             Please report any bugs or feature requests to C, or through
169             the web interface at L. I will be notified, and then you'll
170             automatically be notified of progress on your bug as I make changes.
171              
172              
173              
174              
175             =head1 SUPPORT
176              
177             You can find documentation for this module with the perldoc command.
178              
179             perldoc AI::CBR::Retrieval
180              
181              
182             You can also look for information at:
183              
184             =over 4
185              
186             =item * RT: CPAN's request tracker
187              
188             L
189              
190             =item * AnnoCPAN: Annotated CPAN documentation
191              
192             L
193              
194             =item * CPAN Ratings
195              
196             L
197              
198             =item * Search CPAN
199              
200             L
201              
202             =back
203              
204              
205             =head1 COPYRIGHT & LICENSE
206              
207             Copyright 2009 Darko Obradovic, all rights reserved.
208              
209             This program is free software; you can redistribute it and/or modify it
210             under the same terms as Perl itself.
211              
212              
213             =cut
214              
215             1; # End of AI::CBR::Retrieval