AI-NNFlex
view release on metacpan or search on metacpan
lib/AI/NNFlex/Hopfield.pm view on Meta::CPAN
}
##########################################################
# AI::NNFlex::Hopfield::run
##########################################################
# apply activation patterns & calculate activation
# through the network
##########################################################
sub run
{
my $network = shift;
my $inputPatternRef = shift;
my @inputpattern = @$inputPatternRef;
if (scalar @inputpattern != scalar @{$network->{'nodes'}})
{
return "Error: input pattern does not match number of nodes"
}
# apply the pattern to the network
my $counter=0;
foreach my $node (@{$network->{'nodes'}})
{
$node->{'activation'} = $inputpattern[$counter];
$counter++;
}
# Now update the network with activation flow
foreach my $node (@{$network->{'nodes'}})
{
$node->{'activation'}=0;
my $counter=0;
foreach my $connectedNode (@{$node->{'connectednodes'}->{'nodes'}})
{
# hopfield nodes don't have recursive connections
unless ($node == $connectedNode)
{
$node->{'activation'} += $connectedNode->{'activation'} * $node->{'connectednodes'}->{'weights'}->[$counter];
}
$counter++;
}
# bias
$node->{'activation'} += 1 * $node->{'connectednodes'}->{'weights'}->[-1];
my $activationfunction = $node->{'activationfunction'};
$node->{'activation'} = $network->$activationfunction($node->{'activation'});
}
return $network->output;
}
#######################################################
# AI::NNFlex::Hopfield::output
#######################################################
# This needs to be overloaded, because the default
# nnflex output method returns only the rightmost layer
#######################################################
sub output
{
my $network = shift;
my @array;
foreach my $node (@{$network->{'nodes'}})
{
unshift @array,$node->{'activation'};
}
return \@array;
}
########################################################
# AI::NNFlex::Hopfield::learn
########################################################
sub learn
{
my $network = shift;
my $dataset = shift;
# calculate the weights
# turn the dataset into a matrix
my @matrix;
foreach (@{$dataset->{'data'}})
{
push @matrix,$_;
}
my $patternmatrix = Math::Matrix->new(@matrix);
my $inversepattern = $patternmatrix->transpose;
my @minusmatrix;
for (my $rows=0;$rows <(scalar @{$network->{'nodes'}});$rows++)
{
my @temparray;
for (my $cols=0;$cols <(scalar @{$network->{'nodes'}});$cols++)
{
if ($rows == $cols)
{
my $numpats = scalar @{$dataset->{'data'}};
push @temparray,$numpats;
}
else
{
push @temparray,0;
}
}
push @minusmatrix,\@temparray;
}
my $minus = Math::Matrix->new(@minusmatrix);
my $product = $inversepattern->multiply($patternmatrix);
my $weights = $product->subtract($minus);
( run in 0.870 second using v1.01-cache-2.11-cpan-39bf76dae61 )