AI-ExpertSystem-Advanced

 view release on metacpan or  search on metacpan

MANIFEST  view on Meta::CPAN

examples/backward.pl
examples/example.pl
examples/forward.pl
examples/knowledge_db_one.yaml
examples/mixed.pl
inc/Module/Install.pm
inc/Module/Install/Base.pm
inc/Module/Install/Can.pm
inc/Module/Install/Fetch.pm
inc/Module/Install/Makefile.pm
inc/Module/Install/Metadata.pm
inc/Module/Install/Win32.pm
inc/Module/Install/WriteAll.pm
lib/AI/ExpertSystem/Advanced.pm
lib/AI/ExpertSystem/Advanced/Dictionary.pm
lib/AI/ExpertSystem/Advanced/KnowledgeDB/Base.pm
lib/AI/ExpertSystem/Advanced/KnowledgeDB/Factory.pm
lib/AI/ExpertSystem/Advanced/KnowledgeDB/YAML.pm
lib/AI/ExpertSystem/Advanced/Viewer/Base.pm
lib/AI/ExpertSystem/Advanced/Viewer/Factory.pm
lib/AI/ExpertSystem/Advanced/Viewer/Terminal.pm

Makefile.PL  view on Meta::CPAN

use inc::Module::Install;

# Define metadata
name        'AI-ExpertSystem-Advanced';
all_from    'lib/AI/ExpertSystem/Advanced.pm';

# Specific dependencies
requires    'Moose'             => '0.87';
requires    'YAML::Syck'        => '1.07';
requires    'List::MoreUtils'   => '0.22';
requires    'Class::Factory'    => '1.05';

no_index directory => 'examples';

README  view on Meta::CPAN

    mixed algorithms

DESCRIPTION
    Inspired in AI::ExpertSystem::Simple but with additional features:

    *   Uses backward, forward and mixed algorithms.

    *   Offers different views, so user can interact with the expert system
        via a terminal or with a friendly user interface.

    *   The knowledge database can be stored in any format such as YAML, XML
        or databases. You just need to choose what driver to use and you are
        done.

    *   Uses certainty factors.

SYNOPSIS
    An example of the mixed algorithm:

        use AI::ExpertSystem::Advanced;
        use AI::ExpertSystem::Advanced::KnowledgeDB::Factory;

README  view on Meta::CPAN

                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
        positive. By default the initial facts are positive.

        Keep in mind that the data contained in this array can be the IDs or
        the name of the fact.

        This array will be converted to initial_facts_dict. And all the data
        (ids or or names) will be made of only IDs.

            my $ai = AI::ExpertSystem::Advanced->new(
                    viewer_class => 'terminal',
                    knowledge_db => $yaml_kdb,
                    initial_facts => ['I', ['F', '-'], ['G', '+']);

        As you can see if you want to provide the sign of a fact, just
        *encapsulate* it in an array, the first item should be the fact and
        the second one the sign.

    initial_facts_dict
        This dictionary (see AI::ExpertSystem::Advanced::Dictionary has the
        sasme data of initial_facts but with the additional feature(s) of
        proviing iterators and a quick way to find elements.

    goals_to_check
            my $ai = AI::ExpertSystem::Advanced->new(
                    viewer_class => 'terminal',
                    knowledge_db => $yaml_kdb,
                    goals_to_check => ['J']);

        When doing the backward() algorithm it's required to have at least
        one goal (aka hypothesis).

        This could be pretty similar to initial_facts, with the difference
        that the initial facts are used more with the causes of the rules
        and this one with the goals (usually one in a well defined knowledge
        database).

        The same rule of initial_facts apply here, you can provide the sign
        of the facts and you can provide the id or the name of them.

        From our example of symptoms and diseases lets imagine we have the
        hypothesis that a patient has flu, we don't know the symptoms it
        has, we want the expert system to keep asking us for them to make
        sure that our hypothesis is correct (or incorrect in case there's
        not enough information).

    goals_to_check_dict
        Very similar to goals_to_check (and indeed of initial_facts_dict).
        We want to make the job easier.

        It will be a dictionary made of the data of goals_to_check.

    inference_facts
        Inference facts are basically the core of an expert system. These
        are facts that are found and copied when a set of facts (initial,
        inference or asked) match with the causes of a goal.

        inference_facts is a AI::ExpertSystem::Advanced::Dictionary, it will
        store the name of the fact, the rule that caused these facts to be
        copied to this dictionary, the sign and the algorithm that triggered
        it.

    knowledge_db
        The object reference of the knowledge database
        AI::ExpertSystem::Advanced is using.

    asked_facts
        During the backward() algorithm there will be cases when there's no
        clarity if a fact exists. In these cases the backward() will be
        asking the user (via automation or real questions) if a fact exists.

        Going back to the initial_facts example of symptoms and diseases.
        Imagine the algorithm is checking a rule, some of the facts of the
        rule make a match with the ones of initial_facts or inference_facts

README  view on Meta::CPAN

        provided by AI::ExpertSystem::Advanced::Viewer::Factory.

    viewer_class
        Is the the class name of the viewer.

        You can decide to use the viewers
        AI::ExpertSystem::Advanced::Viewer::Factory offers, in this case you
        can pass the object or only the name of your favorite viewer.

    found_factor
        In your knowledge database you can give different *weights* to the
        facts of each rule (eg to define what facts have more *priority*).
        During the mixed() algorithm it will be checking what causes are
        found in the inference_facts and in the asked_facts dictionaries,
        then the total number of matches (or total number of certainity
        factors of each rule) will be compared versus the value of this
        factor, if it's higher or equal then the rule will be triggered.

        You can read the documentation of the mixed() algorithm to know the
        two ways this factor can be used.

README  view on Meta::CPAN

    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
        goals_to_check_dict.

        In case there are still causes of this rule in goals_to_check_dict
        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.

inc/Module/Install/Metadata.pm  view on Meta::CPAN

#line 1
package Module::Install::Metadata;

use strict 'vars';
use Module::Install::Base ();

use vars qw{$VERSION @ISA $ISCORE};
BEGIN {
	$VERSION = '0.91';
	@ISA     = 'Module::Install::Base';
	$ISCORE  = 1;
}

inc/Module/Install/Metadata.pm  view on Meta::CPAN

	my $type = shift;
	push @{ $self->{values}->{no_index}->{$type} }, @_ if $type;
	return $self->{values}->{no_index};
}

sub read {
	my $self = shift;
	$self->include_deps( 'YAML::Tiny', 0 );

	require YAML::Tiny;
	my $data = YAML::Tiny::LoadFile('META.yml');

	# Call methods explicitly in case user has already set some values.
	while ( my ( $key, $value ) = each %$data ) {
		next unless $self->can($key);
		if ( ref $value eq 'HASH' ) {
			while ( my ( $module, $version ) = each %$value ) {
				$self->can($key)->($self, $module => $version );
			}
		} else {
			$self->can($key)->($self, $value);
		}
	}
	return $self;

inc/Module/Install/Metadata.pm  view on Meta::CPAN

}

sub write_mymeta_yaml {
	my $self = shift;

	# We need YAML::Tiny to write the MYMETA.yml file
	unless ( eval { require YAML::Tiny; 1; } ) {
		return 1;
	}

	# Generate the data
	my $meta = $self->_write_mymeta_data or return 1;

	# Save as the MYMETA.yml file
	print "Writing MYMETA.yml\n";
	YAML::Tiny::DumpFile('MYMETA.yml', $meta);
}

sub write_mymeta_json {
	my $self = shift;

	# We need JSON to write the MYMETA.json file
	unless ( eval { require JSON; 1; } ) {
		return 1;
	}

	# Generate the data
	my $meta = $self->_write_mymeta_data or return 1;

	# Save as the MYMETA.yml file
	print "Writing MYMETA.json\n";
	Module::Install::_write(
		'MYMETA.json',
		JSON->new->pretty(1)->canonical->encode($meta),
	);
}

sub _write_mymeta_data {
	my $self = shift;

	# If there's no existing META.yml there is nothing we can do
	return undef unless -f 'META.yml';

	# We need Parse::CPAN::Meta to load the file
	unless ( eval { require Parse::CPAN::Meta; 1; } ) {
		return undef;
	}

lib/AI/ExpertSystem/Advanced.pm  view on Meta::CPAN


Uses backward, forward and mixed algorithms.

=item *

Offers different views, so user can interact with the expert system via a
terminal or with a friendly user interface.

=item *

The knowledge database can be stored in any format such as YAML, XML or
databases. You just need to choose what driver to use and you are done.

=item *

Uses certainty factors.

=back

=head1 SYNOPSIS

An example of the mixed algorithm:

lib/AI/ExpertSystem/Advanced.pm  view on Meta::CPAN


=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.

Keep in mind that the data contained in this array can be the IDs or the name
of the fact.

This array will be converted to L<initial_facts_dict>. And all the data (ids or
or names) will be made of only IDs.

    my $ai = AI::ExpertSystem::Advanced->new(
            viewer_class => 'terminal',
            knowledge_db => $yaml_kdb,
            initial_facts => ['I', ['F', '-'], ['G', '+']);

As you can see if you want to provide the sign of a fact, just I<encapsulate>
it in an array, the first item should be the fact and the second one the
sign.

=cut
has 'initial_facts' => (
        is => 'rw',
        isa => 'ArrayRef[Str]',
        default => sub { return []; });

=item B<initial_facts_dict>

This dictionary (see L<AI::ExpertSystem::Advanced::Dictionary> has the sasme
data of L<initial_facts> but with the additional feature(s) of proviing
iterators and a quick way to find elements.

=cut
has 'initial_facts_dict' => (
        is => 'ro',
        isa => 'AI::ExpertSystem::Advanced::Dictionary');

=item B<goals_to_check>

    my $ai = AI::ExpertSystem::Advanced->new(
            viewer_class => 'terminal',
            knowledge_db => $yaml_kdb,
            goals_to_check => ['J']);

When doing the L<backward()> algorithm it's required to have at least one goal
(aka hypothesis).

This could be pretty similar to L<initial_facts>, with the difference that the
initial facts are used more with the causes of the rules and this one with
the goals (usually one in a well defined knowledge database).

The same rule of L<initial_facts> apply here, you can provide the sign of the
facts and you can provide the id or the name of them.

From our example of symptoms and diseases lets imagine we have the hypothesis
that a patient has flu, we don't know the symptoms it has, we want the
expert system to keep asking us for them to make sure that our hypothesis
is correct (or incorrect in case there's not enough information).

=cut
has 'goals_to_check' => (
        is => 'rw',
        isa => 'ArrayRef[Str]',
        default => sub { return []; });

=item B<goals_to_check_dict>

Very similar to L<goals_to_check> (and indeed of L<initial_facts_dict>). We
want to make the job easier.

It will be a dictionary made of the data of L<goals_to_check>.

=cut
has 'goals_to_check_dict' => (
        is => 'ro',
        isa => 'AI::ExpertSystem::Advanced::Dictionary');

=item B<inference_facts>

Inference facts are basically the core of an expert system. These are facts
that are found and copied when a set of facts (initial, inference or asked)

lib/AI/ExpertSystem/Advanced.pm  view on Meta::CPAN

store the name of the fact, the rule that caused these facts to be copied to
this dictionary, the sign and the algorithm that triggered it.

=cut
has 'inference_facts' => (
        is => 'ro',
        isa => 'AI::ExpertSystem::Advanced::Dictionary');
       
=item B<knowledge_db>

The object reference of the knowledge database L<AI::ExpertSystem::Advanced> is
using.

=cut
has 'knowledge_db' => (
        is => 'rw',
        isa => 'AI::ExpertSystem::Advanced::KnowledgeDB::Base',
        required => 1);

=item B<asked_facts>

lib/AI/ExpertSystem/Advanced.pm  view on Meta::CPAN

viewer.

=cut
has 'viewer_class' => (
        is => 'rw',
        isa => 'Str',
        default => 'terminal');

=item B<found_factor>

In your knowledge database you can give different I<weights> to the facts of
each rule (eg to define what facts have more I<priority>). During the
L<mixed()> algorithm it will be checking what causes are found in the
L<inference_facts> and in the L<asked_facts> dictionaries, then the total
number of matches (or total number of certainity factors of each rule) will
be compared versus the value of this factor, if it's higher or equal then the
rule will be triggered.

You can read the documentation of the L<mixed()> algorithm to know the two
ways this factor can be used.

lib/AI/ExpertSystem/Advanced.pm  view on Meta::CPAN

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.

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 L<goals_to_check_dict>.

In case there are still causes of this rule in L<goals_to_check_dict> 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.

=item *

If the goal doesn't exist in the mentioned facts then the goal will be searched

lib/AI/ExpertSystem/Advanced/KnowledgeDB/Base.pm  view on Meta::CPAN

# Author(s): Pablo Fischer (pfischer@cpan.org)
# Created: 11/29/2009 19:14:28 PST 19:14:28
package AI::ExpertSystem::Advanced::KnowledgeDB::Base;

=head1 NAME

AI::ExpertSystem::Advanced::KnowledgeDB::Base - Base class for knowledge DBs.

=head1 DESCRIPTION

All knowledge databases that L<AI::ExpertSystem::Advanced> uses should extend
from this class.

This base class implements the basic methods required for extracting the rules,
causes, goals and questions from the a plain text knowledge database, eg, all
the records remain in the application memory instead of a database engine such
as MySQL or SQLite.

=cut
use Moose;
use AI::ExpertSystem::Advanced::Dictionary;

our $VERSION = '0.03';

=head1 Attributes

=over 4

=item B<rules>

This hash has the rules contained in the knowledge database. It's populated
when an instance of L<AI::ExpertSystem::Advanced::KnowledgeDB::Base> is
created.

B<TIP>: There's no sense in filling this hash if you are going to be using a
database engine such as MySQL, SQLite or others. The hash is useful if your
knowledge database will remain in application memory.

=cut
has 'rules' => (
        is => 'ro',
        isa => 'HashRef');

=item B<questions>

Similar and same concept of C<rules>, but this will have a list (if available)
of what questions should be done to certain facts.

lib/AI/ExpertSystem/Advanced/KnowledgeDB/Base.pm  view on Meta::CPAN

=cut
has 'questions' => (
        is => 'ro',
        isa => 'HashRef',
        default => sub { return {}; });

=head1 Methods

=head2 B<read()>

This method reads the knowledge database. This is the only method you need to
define even if you are going to load the database in memory or if you are
going to query it.

=cut
sub read {
    confess "You can't call KnowedgeDB::Base! (abstract method)";
}

=head2 B<rule_goals($rule)>

Returns all the goals (usually only one) of the given C<$rule>.

The goals B<should> be returned as a L<AI::ExpertSystem::Advanced::Dictionary>.

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 rule_goals {
    my ($self, $rule) = @_;

    if (!defined $self->{'rules'}->[$rule]) {
        confess "Rule $rule does not exist";
    }
    my @facts;
    # Get all the facts of this goal (usually only one)

lib/AI/ExpertSystem/Advanced/KnowledgeDB/Base.pm  view on Meta::CPAN

}

=head2 B<rule_causes($rule)>

Returns all the causes of the given C<$rule>.

Same as C<rule_goals()>, the causes should be returned as a
L<AI::ExpertSystem::Advanced::Dictionary>.

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 rule_causes {
    my ($self, $rule) = @_;

    if (!defined $self->{'rules'}->[$rule]) {
        confess "Rule $rule does not exist";
    }
    my @facts;
    # Get all the facts of this cause

lib/AI/ExpertSystem/Advanced/KnowledgeDB/Base.pm  view on Meta::CPAN

}

=head2 B<find_rule_by_goal($goal)>

Looks for the first rule that has the given C<goal> in its goals.

If a rule is found then its number is returned, otherwise C<undef> is
returned.

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 find_rule_by_goal {
    my ($self, $goal) = @_;

    my $rule_counter = 0;
    foreach my $rule (@{$self->{'rules'}}) {
        foreach my $rule_goal (@{$rule->{'goals'}}) {
            # Look in id and name for the match
            foreach my $look_in (qw(id name)) {

lib/AI/ExpertSystem/Advanced/KnowledgeDB/Base.pm  view on Meta::CPAN

    }
    return undef;
}

=head2 B<get_question($fact)>

Looks for a question about the given C<$fact>. If a question exists then this is
returned, otherwise C<undef> is returned.

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_question {
    my ($self, $fact) = @_;

    if (defined $self->{'questions'}->{$fact}) {
        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;
    if (defined $current_rule) {
        $next_rule = $current_rule+1;
    } else {
        $next_rule = 0;

lib/AI/ExpertSystem/Advanced/KnowledgeDB/Factory.pm  view on Meta::CPAN

# Author(s): Pablo Fischer (pfischer@cpan.org)
# Created: 11/29/2009 19:12:25 PST 19:12:25
package AI::ExpertSystem::Advanced::KnowledgeDB::Factory;

=head1 NAME

AI::ExpertSystem::Advanced::KnowledgeDB::Factory - Knowledge DB driver factory

=head1 DESCRIPTION

Uses the factory pattern to create instances of knowledge database drivers.

=head1 SYNOPSIS

    use AI::ExpertSystem::Advanced::KnowledgeDB::Factory;

    my $yaml_kdb = AI::ExpertSystem::Advanced::KnowledgeDB::Factory->new('yaml',
        {
            filename => 'examples/knowledge_db_one.yaml'
        });

lib/AI/ExpertSystem/Advanced/KnowledgeDB/YAML.pm  view on Meta::CPAN

# Author(s): Pablo Fischer (pfischer@cpan.org)
# Created: 12/13/2009 16:12:43 PST 16:12:43
package AI::ExpertSystem::Advanced::KnowledgeDB::YAML;

=head1 NAME

AI::ExpertSystem::Advanced::KnowledgeDB::YAML - YAML Knowledge DB driver

=head1 DESCRIPTION

A YAML knowledge database driver.

It reads a given YAML file and looks for the I<rules> hash key. All of the
elements of C<rules> (causes and goals) are copied to the C<rules> hash
key of L<AI::ExpertSystem::Advanced::KnowledgeDB::Base>.

If no rules are found then it ends unsuccessfully.

It also looks for any available questions under the I<questions> hash key,
however if no questions are found then they are not copied :-)

lib/AI/ExpertSystem/Advanced/KnowledgeDB/YAML.pm  view on Meta::CPAN

=cut
has 'filename' => (
        is => 'rw',
        isa => 'Str',
        required => 1);

# Called when the object gets created
sub BUILD {
    my ($self) = @_;

    my $data = LoadFile($self->{'filename'});
    if (defined $data->{'rules'}) {
        $self->{'rules'} = $data->{'rules'}
    } else {
        confess "Couldn't find any rules in $self->{'filename'}";
    }

    if (defined $data->{'questions'}) {
        $self->{'questions'} = $data->{'questions'};
    }
}

=head1 AUTHOR
 
Pablo Fischer (pablo@pablo.com.mx).

=head1 COPYRIGHT
 
Copyright (C) 2010 by Pablo Fischer.

lib/AI/ExpertSystem/Advanced/Viewer/Factory.pm  view on Meta::CPAN

# Created: 11/29/2009 19:12:25 PST 19:12:25
package AI::ExpertSystem::Advanced::Viewer::Factory;

=head1 NAME

AI::ExpertSystem::Advanced::Viewer::Factory - Viewer factory

=head1 DESCRIPTION

Uses the factory pattern to create viewer instances. The viewer instances are
useful (and required) to show data to the user.

=cut
use strict;
use warnings;
use Class::Factory;
use base qw(Class::Factory);

our $VERSION = '0.01';

sub new {



( run in 0.601 second using v1.01-cache-2.11-cpan-a5abf4f5562 )