File Coverage

blib/lib/AI/Fuzzy/Set.pm
Criterion Covered Total %
statement 74 96 77.0
branch 22 40 55.0
condition 9 15 60.0
subroutine 9 14 64.2
pod 0 14 0.0
total 114 179 63.6


line stmt bran cond sub pod time code
1             package AI::Fuzzy::Set;
2              
3             ## Fuzzy Set ####
4              
5             sub new {
6              
7 28     28 0 309 my $class = shift;
8 28         37 my $self = {} ;
9              
10             # accepts a hash of member weights..
11             # ( $members{$member}=$weight )
12              
13 28         40 %{$self->{members}} = @_;
  28         106  
14 28         134 bless $self, $class;
15             }
16              
17             sub membership {
18             # naturally, it returns a fuzzy value - the degree
19             # to wich $item is a member of the set! :)
20              
21 51     51 0 78 my $self = shift;
22 51         44 my $item = shift;
23              
24 51 50       44 if (defined(${$self->{members}}{$item})) {
  51         111  
25 51         46 return ${$self->{members}}{$item};
  51         200  
26             } else {
27 0         0 return 0;
28             }
29             }
30              
31             sub members {
32             # returns list of members, sorted from least membership to greatest
33 10     10 0 61 my $self = shift;
34              
35 10         10 my %l = %{$self->{members}};
  10         43  
36 10         35 return sort { $l{$a} <=> $l{$b} } keys %l;
  79         123  
37             }
38              
39             sub equal {
40             # returns true if the argument set is equal to this one
41 10     10 0 35 my $self = shift;
42 10         12 my $otherset = shift;
43              
44 10         12 my (%us, %them);
45 10 50       24 %us = %{$self->{members}} if (exists $self->{members});
  10         42  
46 10 50       45 %them = %{$otherset->{members}} if (exists $otherset->{members});
  10         32  
47              
48             # for all keys in us and them
49 10         26 foreach my $key (keys (%us), keys (%them)) {
50             # not equal if either set is missing a key
51 47 100 66     182 return 0 unless (exists ($us{$key}) && exists ($them{$key}) );
52              
53             # not equal if the membership of the keys isn't equal
54 45 100       85 return 0 unless (float_equal($us{$key},$them{$key}, 10));
55             }
56              
57             # otherwise they are equal
58 7         37 return 1;
59             }
60              
61             sub union {
62             # returns a set that is the union of us and the argument set
63 8     8 0 25 my $self = shift;
64 8         10 my $otherset = shift;
65              
66 8         7 my (%us, %them, %new);
67 8 50       20 %us = %{$self->{members}} if (exists $self->{members});
  8         33  
68 8 50       22 %them = %{$otherset->{members}} if (exists $otherset->{members});
  8         32  
69              
70             # for all keys in us and them
71 8         20 foreach my $key (keys (%us), keys (%them)) {
72 48 100 66     109 if (not exists $us{$key} and exists $them{$key}) {
73 6         11 $new{$key} = $them{$key};
74 6         9 next;
75             }
76 42 100 66     644 if (not exists $them{$key} and exists $us{$key}) {
77 6         8 $new{$key} = $us{$key};
78 6         8 next;
79             }
80 36 100       77 if ($us{$key} >= $them{$key}) {
81 32         62 $new{$key} = $us{$key};
82             } else {
83 4         9 $new{$key} = $them{$key};
84             }
85             }
86              
87 8         34 return new AI::Fuzzy::Set(%new);
88             }
89              
90             sub intersection {
91             # returns a set that is the intersection of us and the argument set
92 8     8 0 70 my $self = shift;
93 8         8 my $otherset = shift;
94              
95 8         8 my (%us, %them, %new);
96 8 50       23 %us = %{$self->{members}} if (exists $self->{members});
  8         29  
97 8 50       24 %them = %{$otherset->{members}} if (exists $otherset->{members});
  8         21  
98              
99             # for all keys in us and them
100 8         24 foreach my $key (keys (%us), keys (%them)) {
101 47 100 66     165 if (not exists $us{$key} or not exists $them{$key}) {
102 13         17 $new{$key} = 0;
103 13         16 next;
104             }
105 34 100       64 if ($us{$key} <= $them{$key}) {
106 32         56 $new{$key} = $us{$key};
107             } else {
108 2         7 $new{$key} = $them{$key};
109             }
110             }
111              
112 8         31 return new AI::Fuzzy::Set(%new);
113             }
114              
115             sub complement {
116             # returns a set that is the complement of us
117             # requires that the set contain values from 0 to 1
118 4     4 0 9 my $self = shift;
119              
120 4         4 my (%new);
121              
122 4         8 foreach my $member ($self->members) {
123 14         24 my $comp = 1 - $self->membership($member);
124 14 50 33     57 return undef if ($comp < 0 || $comp >1);
125              
126 14         28 $new{$member} = $comp;
127             }
128              
129 4         15 return new AI::Fuzzy::Set(%new);
130             }
131              
132             sub support {
133             # returns the support set.
134             # defined as the set of all elements in our set with a non-zero membership.
135 0     0 0 0 my $self = shift;
136              
137 0         0 my (%support);
138 0         0 foreach my $member ($self->members) {
139 0 0       0 $support{$member}++ if ($self->membership($member) != 0);
140             }
141              
142 0         0 return new AI::Fuzzy::Set(%support);
143             }
144              
145             sub core {
146             # returns the core set.
147             # defined as the set of all elements in our set with full membership
148 0     0 0 0 my $self = shift;
149              
150 0         0 my (%core);
151 0         0 foreach my $member ($self->members) {
152 0 0       0 $core{$member}++ if ($self->membership($member) == 1);
153             }
154              
155 0         0 return new AI::Fuzzy::Set(%core);
156             }
157              
158             sub height {
159             # returns the height of the set
160             # defined as the maximal membership value in our set
161 0     0 0 0 my $self = shift;
162              
163 0         0 my ($max) = 0;
164 0         0 foreach my $member ($self->members) {
165 0 0       0 $max = $self->membership($member) if ($self->membership($member) > $max);
166             }
167              
168 0         0 return $max;
169             }
170              
171             sub is_normal {
172             # Logical return
173             # normal is defined as a set with a height of 1
174 0     0 0 0 my $self = shift;
175              
176 0 0       0 return 1 if ($self->height == 1);
177 0         0 return 0;
178             }
179              
180             sub is_subnormal {
181             # Logical return
182             # normal is defined as a set with a height less than 1
183 0     0 0 0 my $self = shift;
184              
185 0 0       0 return 1 if ($self->height < 1);
186 0         0 return 0;
187             }
188              
189             sub as_string {
190 5     5 0 24 my $self = shift;
191              
192 5         6 my @members;
193 5         10 foreach my $member ($self->members) {
194 33         68 push (@members, "$member/" . $self->membership($member) );
195             }
196              
197 5         135 return join(', ', @members);
198             }
199              
200             sub float_equal {
201 45     45 0 59 my ($A, $B, $dp) = @_;
202              
203             # print sprintf("%.${dp}g", $A). " eq " . sprintf("%.${dp}g", $B) . "\n";
204 45         317 return sprintf("%.${dp}g", $A) eq sprintf("%.${dp}g", $B);
205             }
206              
207             1;
208