File Coverage

lib/AI/Prolog/KnowledgeBase.pm
Criterion Covered Total %
statement 48 158 30.3
branch 6 36 16.6
condition 0 6 0.0
subroutine 12 26 46.1
pod 0 17 0.0
total 66 243 27.1


line stmt bran cond sub pod time code
1             package AI::Prolog::KnowledgeBase;
2             $REVISION = '$Id: KnowledgeBase.pm,v 1.5 2005/06/25 23:06:53 ovid Exp $';
3             $VERSION = '0.02';
4 13     13   6218 use strict;
  13         25  
  13         414  
5 13     13   62 use warnings;
  13         25  
  13         417  
6 13     13   72 use Carp qw( confess carp );
  13         22  
  13         761  
7              
8 13     13   67 use Hash::Util 'lock_keys';
  13         25  
  13         168  
9              
10 13     13   703 use aliased 'AI::Prolog::Engine';
  13         30  
  13         77  
11 13     13   1834 use aliased 'AI::Prolog::Parser';
  13         97  
  13         64  
12 13     13   1854 use aliased 'AI::Prolog::TermList::Clause';
  13         22  
  13         54  
13              
14             sub new {
15 22     22 0 164 my $self = bless {
16             ht => {},
17             primitives => {}, # only uses keys
18             oldIndex => "",
19             } => shift;
20 22         163 lock_keys %$self;
21 22         305 return $self;
22             }
23              
24 1     1 0 36 sub ht { shift->{ht} } # temp hack XXX
25              
26             sub to_string {
27 0     0 0 0 my $self = shift;
28 0         0 return "{"
29             . (
30 0         0 join ', ' => map { join '=' => $_->[0], $_->[1] }
31 0         0 sort { $a->[2] <=> $b->[2] }
32 0         0 map { [ $_, $self->_sortable_term( $self->{_vardict}{$_} ) ] }
33 0         0 keys %{ $self->{ht} }
34             ) . "}";
35             }
36              
37             sub _sortable_term {
38 0     0   0 my ( $self, $term ) = @_;
39 0         0 my $string = $term->to_string;
40 0         0 my $number = substr $string => 1;
41 0         0 return $string, $number;
42             }
43              
44             sub put {
45 0     0 0 0 my ( $self, $key, $termlist ) = @_;
46 0         0 $self->{ht}{$key} = $termlist;
47             }
48              
49 0     0 0 0 sub elements { [ values %{ shift->{ht} } ] }
  0         0  
50              
51             sub reset {
52 0     0 0 0 my $self = shift;
53 0         0 $self->{ht} = {};
54 0         0 $self->{primitives} = {};
55 0         0 $self->{oldIndex} = '';
56             }
57              
58             sub consult {
59 0     0 0 0 my ( $self, $program ) = @_;
60 0         0 $self->{oldIndex} = '';
61 0         0 return Parser->consult( $program, $self );
62             }
63              
64             sub add_primitive {
65 243     243 0 349 my ( $self, $clause ) = @_;
66 243         550 my $term = $clause->term;
67 243         697 my $predicate = $term->predicate;
68 243         602 my $c = $self->{ht}{$predicate};
69 243 100       417 if ($c) {
70 9         62 while ( $c->next_clause ) {
71 0         0 $c = $c->next_clause;
72             }
73 9         34 $c->next_clause($clause);
74             }
75             else {
76 234         604 $self->{primitives}{$predicate} = 1;
77 234         760 $self->{ht}{$predicate} = $clause;
78             }
79             }
80              
81             sub add_clause {
82 151     151 0 214 my ( $self, $clause ) = @_;
83 151         360 my $term = $clause->term;
84 151         437 my $predicate = $term->predicate;
85 151 50       454 if ( $self->{primitives}{$predicate} ) {
86 0         0 carp("Trying to modify primitive predicate: $predicate");
87 0         0 return;
88             }
89 151 100       367 unless ( $predicate eq $self->{oldIndex} ) {
90 108         455 delete $self->{ht}{$predicate};
91 108         296 $self->{ht}{$predicate} = $clause;
92 108         296 $self->{oldIndex} = $predicate;
93             }
94             else {
95 43         111 my $c = $self->{ht}{$predicate};
96 43         166 while ( $c->next_clause ) {
97 0         0 $c = $c->next_clause;
98             }
99 43         120 $c->next_clause($clause);
100             }
101             }
102              
103             sub assert {
104 0     0 0 0 my ( $self, $term ) = @_;
105 0         0 $term = $term->clean_up;
106              
107             # XXX whoops. Need to check exact semantics in Term
108 0         0 my $newC = Clause->new( $term->deref, undef );
109              
110 0         0 my $predicate = $term->predicate;
111 0 0       0 if ( $self->{primitives}{$predicate} ) {
112 0         0 carp("Trying to assert a primitive: $predicate");
113 0         0 return;
114             }
115 0         0 my $c = $self->{ht}{$predicate};
116 0 0       0 if ($c) {
117 0         0 while ( $c->next_clause ) {
118 0         0 $c = $c->next_clause;
119             }
120 0         0 $c->next_clause($newC);
121             }
122             else {
123 0         0 $self->{ht}{$predicate} = $newC;
124             }
125             }
126              
127             sub asserta {
128 0     0 0 0 my ( $self, $term ) = @_;
129 0         0 my $predicate = $term->predicate;
130 0 0       0 if ( $self->{primitives}{$predicate} ) {
131 0         0 carp("Trying to assert a primitive: $predicate");
132 0         0 return;
133             }
134 0         0 $term = $term->clean_up;
135 0         0 my $newC = Clause->new( $term->deref, undef );
136 0         0 my $c = $self->{ht}{$predicate};
137 0         0 $newC->next_clause($c);
138 0         0 $self->{ht}{$predicate} = $newC;
139             }
140              
141             sub retract {
142 0     0 0 0 my ( $self, $term, $stack ) = @_;
143 0         0 my $newC = Clause->new( $term, undef ); #, undef);
144 0         0 my $predicate = $term->predicate;
145 0 0       0 if ( exists $self->{primitives}{$predicate} ) {
146 0         0 carp("Trying to retract a primitive: $predicate");
147 0         0 return;
148             }
149 0         0 my $cc;
150 0         0 my $c = $self->{ht}{$predicate};
151              
152 0         0 while ($c) {
153 0         0 my $vars = [];
154 0         0 my $xxx = $c->term->refresh($vars);
155 0         0 my $top = @{$stack};
  0         0  
156              
157 0 0       0 if ( $xxx->unify( $term, $stack ) ) {
158 0 0       0 if ($cc) {
    0          
159 0         0 $cc->next_clause( $c->next_clause );
160             }
161             elsif ( !$c->next_clause ) {
162 0         0 delete $self->{ht}{$predicate};
163             }
164             else {
165 0         0 $self->{ht}{$predicate} = $c->next_clause;
166             }
167 0         0 return 1;
168             }
169 0         0 for ( my $i = @{$stack} - $top; $i > 0; $i-- ) {
  0         0  
170 0         0 my $t = pop @{$stack};
  0         0  
171 0         0 $t->unbind;
172             }
173 0         0 $cc = $c;
174 0         0 $c = $c->next_clause;
175             }
176 0         0 return;
177             }
178              
179             sub retractall {
180 0     0 0 0 my ( $self, $term, $arity ) = @_;
181 0         0 my $predicate = $term->predicate;
182 0 0       0 if ( $self->{primitives}{$predicate} ) {
183 0         0 carp("Trying to retractall primitives: $predicate");
184 0         0 return;
185             }
186 0         0 delete $self->{ht}{$predicate};
187 0         0 return 1;
188             }
189              
190             sub get {
191 117     117 0 220 my ( $self, $term ) = @_;
192 117 50       280 my $key = ref $term ? $term->to_string : $term;
193 117         546 return $self->{ht}{$key};
194             }
195              
196             sub set {
197 0     0 0   my ( $self, $term, $value ) = @_;
198 0 0         my $key = ref $term ? $term->to_string : $term;
199 0           $self->{ht}{$key} = $value->clean_up;
200             }
201              
202 0     0     sub _print { print @_ }
203              
204             sub dump {
205 0     0 0   my ( $self, $full ) = @_;
206 0           my $i = 1;
207 0           while ( my ( $key, $value ) = each %{ $self->{ht} } ) {
  0            
208 0 0 0       next if !$full && ( $self->{primitives}{$key} || $value->is_builtin );
      0        
209 0 0         if ( $value->isa(Clause) ) {
210 0           _print( $i++ . ". $key: \n" );
211 0           do {
212 0           _print( " " . $value->term->to_string );
213 0 0         if ( $value->next ) {
214 0           _print( " :- " . $value->next->to_string );
215             }
216 0           _print(".\n");
217 0           $value = $value->next_clause;
218             } while ($value);
219             }
220             else {
221 0           _print( $i++ . ". $key = $value\n" );
222             }
223             }
224 0           _print("\n");
225             }
226              
227             sub list {
228 0     0 0   my ( $self, $predicate ) = @_;
229 0           print "\n$predicate: \n";
230 0 0         my $head = $self->{ht}{$predicate}
231             or warn "Cannot list unknown predicate ($predicate)";
232 0           while ($head) {
233 0           print " " . $head->term->to_string;
234 0 0         if ( $head->next ) {
235 0           print " :- " . $head->next->to_string;
236             }
237 0           print ".\n";
238 0           $head = $head->next_clause;
239             }
240             }
241              
242             1;
243              
244             __END__