AI-ExpertSystem-Advanced
view release on metacpan or search on metacpan
my $ai = AI::ExpertSystem::Advanced->new(
viewer_class => 'terminal',
knowledge_db => $yaml_kdb,
initial_facts => ['I'],
verbose => 1);
$ai->mixed();
$ai->summary();
Attributes
initial_facts
A list/set of initial facts the algorithms start using.
During the forward algorithm the task is to find a list of goals
caused by these initial facts (the only data we have in that
moment).
Lets imagine your knowledge database is about symptoms and diseases.
You need to find what diseases are caused by the symptoms of a
patient, these first symptons are the initial facts.
Initial facts as also asked and inference facts can be negative or
});
my $ai = AI::ExpertSystem::Advanced->new(
viewer_class => 'terminal',
knowledge_db => $yaml_kdb,
initial_facts => ['F', 'J']);
$ai->forward();
$ai->summary();
The forward chaining algorithm is one of the main methods used in Expert
Systems. It starts with a set of variables (known as initial facts) and
reads the available rules.
It will be reading rule by rule and for each one it will compare its
causes with the initial, inference and asked facts. If all of these
causes are in the facts then the rule will be shoot and all of its goals
will be copied/converted to inference facts and will restart reading
from the first rule.
backward()
use AI::ExpertSystem::Advanced;
use AI::ExpertSystem::Advanced::KnowledgeDB::Factory;
my $yaml_kdb = AI::ExpertSystem::Advanced::KnowledgeDB::Factory->new('yaml',
{
filename => 'examples/knowledge_db_one.yaml'
});
my $ai = AI::ExpertSystem::Advanced->new(
viewer_class => 'terminal',
knowledge_db => $yaml_kdb,
goals_to_check => ['J']);
$ai->backward();
$ai->summary();
The backward algorithm starts with a set of *assumed* goals (facts). It
will start reading goal by goal. For each goal it will check if it
exists in the initial, inference and asked facts (see
is_goal_in_our_facts()) for more information).
* If the goal exist then it will be removed from the dictionary, it
will also verify if there are more visited rules to shoot.
If there are still more visited rules to shoot then it will check
from what rule the goal comes from, if it was copied from a rule
then this data will exist. With this information then it will see
how many of the causes of this given rule are still in the
then the amount of causes pending will be reduced by one. Otherwise
(if the amount is 0) then the rule of this last removed goal will be
shoot.
* If the goal doesn't exist in the mentioned facts then the goal will
be searched in the goals of every rule.
In case it finds the rule that has the goal, this rule will be
marked (added) to the list of visited rules (visited_rules) and also
all of its causes will be added to the top of the
goals_to_check_dict and it will start reading again all the goals.
If there's the case where the goal doesn't exist as a goal in the
rules then it will ask the user (via ask_about()) for the existence
of it. If user is not sure about it then the algorithm ends.
mixed()
As its name says, it's a mix of forward() and backward() algorithms, it
requires to have at least one initial fact.
The first thing it does is to run the forward() algorithm (hence the
need of at least one initial fact). If the algorithm fails then the
mixed algorithm also ends unsuccessfully.
Once the first *run* of forward() algorithm happens it starts looking
for any positive inference fact, if only one is found then this ends the
algorithm with the assumption it knows what's happening.
In case no positive inference fact is found then it will start reading
the rules and creating a list of intuitive facts.
For each rule it will get a *certainty factor* of its causes versus the
initial, inference and asked facts. In case the certainity factor is
greater or equal than found_factor then all of its goals will be copied
to the intuitive facts (eg, read it as: it assumes the goals have
something to do with our first initial facts).
Once all the rules are read then it verifies if there are intuitive
facts, if no facts are found then it ends with the intuition, otherwise
it will run the backward() algorithm for each one of these facts (eg,
each fact will be converted to a goal). After each *run* of the
backward() algorithm it will verify for any positive inference fact, if
just one is found then the algorithm ends.
At the end (if there are still no positive inference facts) it will run
the forward() algorithm and restart (by looking again for any positive
inference fact).
A good example to understand how this algorithm is useful is: imagine
you are a doctor and know some of the symptoms of a patient. Probably
with the first symptoms you have you can get to a positive conclusion
(eg that a patient has *X* disease). However in case there's still no
clue, then a set of questions (done by the call of backward()) of
symptons related to the initial symptoms will be asked to the user. For
example, we know that that the patient has a headache but that doesn't
give us any positive answer, what if the patient has flu or another
lib/AI/ExpertSystem/Advanced.pm view on Meta::CPAN
use YAML::Syck qw(Dump);
our $VERSION = '0.03';
=head1 Attributes
=over 4
=item B<initial_facts>
A list/set of initial facts the algorithms start using.
During the forward algorithm the task is to find a list of goals caused
by these initial facts (the only data we have in that moment).
Lets imagine your knowledge database is about symptoms and diseases. You need
to find what diseases are caused by the symptoms of a patient, these first
symptons are the initial facts.
Initial facts as also asked and inference facts can be negative or positive. By
default the initial facts are positive.
lib/AI/ExpertSystem/Advanced.pm view on Meta::CPAN
});
my $ai = AI::ExpertSystem::Advanced->new(
viewer_class => 'terminal',
knowledge_db => $yaml_kdb,
initial_facts => ['F', 'J']);
$ai->forward();
$ai->summary();
The forward chaining algorithm is one of the main methods used in Expert
Systems. It starts with a set of variables (known as initial facts) and reads
the available rules.
It will be reading rule by rule and for each one it will compare its causes
with the initial, inference and asked facts. If all of these causes are in the
facts then the rule will be shoot and all of its goals will be copied/converted
to inference facts and will restart reading from the first rule.
=cut
sub forward {
my ($self) = @_;
confess "Can't do forward algorithm with no initial facts" unless
$self->{'initial_facts_dict'};
my ($more_rules, $current_rule) = (1, undef);
while($more_rules) {
lib/AI/ExpertSystem/Advanced.pm view on Meta::CPAN
}
$self->{'viewer'}->debug("Reading rule $current_rule")
if $self->{'verbose'};
$self->{'viewer'}->debug("More rules to check, checking...")
if $self->{'verbose'};
my $rule_causes = $self->get_causes_by_rule($current_rule);
# any of our rule facts match with our facts to check?
if ($self->compare_causes_with_facts($current_rule)) {
# shoot and start again
$self->shoot($current_rule, 'forward');
# Undef to start reading from the first rule.
$current_rule = undef;
next;
}
}
return 1;
}
=head2 B<backward()>
use AI::ExpertSystem::Advanced;
lib/AI/ExpertSystem/Advanced.pm view on Meta::CPAN
filename => 'examples/knowledge_db_one.yaml'
});
my $ai = AI::ExpertSystem::Advanced->new(
viewer_class => 'terminal',
knowledge_db => $yaml_kdb,
goals_to_check => ['J']);
$ai->backward();
$ai->summary();
The backward algorithm starts with a set of I<assumed> goals (facts). It will
start reading goal by goal. For each goal it will check if it exists in the
initial, inference and asked facts (see L<is_goal_in_our_facts()>) for more
information).
=over 4
=item *
If the goal exist then it will be removed from the dictionary, it will also
verify if there are more visited rules to shoot.
lib/AI/ExpertSystem/Advanced.pm view on Meta::CPAN
amount of causes pending will be reduced by one. Otherwise (if the amount is
0) then the rule of this last removed goal will be shoot.
=item *
If the goal doesn't exist in the mentioned facts then the goal will be searched
in the goals of every rule.
In case it finds the rule that has the goal, this rule will be marked (added)
to the list of visited rules (L<visited_rules>) and also all of its causes
will be added to the top of the L<goals_to_check_dict> and it will start
reading again all the goals.
If there's the case where the goal doesn't exist as a goal in the rules then
it will ask the user (via L<ask_about()>) for the existence of it. If user is
not sure about it then the algorithm ends.
=back
=cut
sub backward {
lib/AI/ExpertSystem/Advanced.pm view on Meta::CPAN
=head2 B<mixed()>
As its name says, it's a mix of L<forward()> and L<backward()> algorithms, it
requires to have at least one initial fact.
The first thing it does is to run the L<forward()> algorithm (hence the need of
at least one initial fact). If the algorithm fails then the mixed algorithm
also ends unsuccessfully.
Once the first I<run> of L<forward()> algorithm happens it starts looking for
any positive inference fact, if only one is found then this ends the algorithm
with the assumption it knows what's happening.
In case no positive inference fact is found then it will start reading the
rules and creating a list of intuitive facts.
For each rule it will get a I<certainty factor> of its causes versus the
initial, inference and asked facts. In case the certainity factor is greater or
equal than L<found_factor> then all of its goals will be copied to the
intuitive facts (eg, read it as: it assumes the goals have something to do with
our first initial facts).
Once all the rules are read then it verifies if there are intuitive facts, if
no facts are found then it ends with the intuition, otherwise it will run the
L<backward()> algorithm for each one of these facts (eg, each fact will be
converted to a goal). After each I<run> of the L<backward()> algorithm it will
verify for any positive inference fact, if just one is found then the algorithm
ends.
At the end (if there are still no positive inference facts) it will run the
L<forward()> algorithm and restart (by looking again for any positive inference
fact).
A good example to understand how this algorithm is useful is: imagine you are
a doctor and know some of the symptoms of a patient. Probably with the first
symptoms you have you can get to a positive conclusion (eg that a patient has
I<X> disease). However in case there's still no clue, then a set of questions
(done by the call of L<backward()>) of symptons related to the initial symptoms
will be asked to the user. For example, we know that that the patient has a
headache but that doesn't give us any positive answer, what if the patient has
flu or another disease? Then a set of these I<related> symptons will be asked
lib/AI/ExpertSystem/Advanced.pm view on Meta::CPAN
=cut
sub summary {
my ($self, $return) = @_;
# any facts we found via inference?
if (scalar @{$self->{'inference_facts'}->{'stack'}} eq 0) {
$self->{'viewer'}->print_error("No inference was possible");
} else {
my $summary = {};
# How the rules started being shot?
my $order = 1;
# So, what rules we shot?
foreach my $shot_rule (sort(keys %{$self->{'shot_rules'}})) {
$summary->{'rules'}->{$shot_rule} = {
order => $order,
};
$order++;
# Get the causes and goals of this rule
my $causes = $self->get_causes_by_rule($shot_rule);
$causes->populate_iterable_array();
lib/AI/ExpertSystem/Advanced/Dictionary.pm view on Meta::CPAN
keys). The I<disadvantage> of it is that it doesn't keeps the order of the
elements, hence the need of C<stack>.
=cut
has 'stack_hash' => (
is => 'ro',
isa => 'HashRef[Str]');
=item B<iterable_array>
Used by the C<iterate()> and C<iterate_reverse()> methods. It starts as a copy
of C<stack> and as the iterate methods start running this array starts getting
I<reduced> until it gets to an empty list.
=back
=cut
has 'iterable_array' => (
is => 'ro',
isa => 'ArrayRef');
=head1 Methods
lib/AI/ExpertSystem/Advanced/KnowledgeDB/Base.pm view on Meta::CPAN
return $self->{'questions'}->{$fact};
}
return undef;
}
=head2 B<get_next_rule($current_rule)>
Returns the ID of the next rule. When there are no more rules to work then
C<undef> should be returned.
When it starts looking for the first rule, C<$current_rule> value will
be C<undef>.
B<NOTE>: Rewrite this method if you are not going to use the C<rules> hash (eg,
you will use a database engine).
=cut
sub get_next_rule {
my ($self, $current_rule) = @_;
my $next_rule;
( run in 0.279 second using v1.01-cache-2.11-cpan-0d8aa00de5b )