view release on metacpan or search on metacpan
Samples/PSOPlatTest.pl view on Meta::CPAN
my $fitValue = $pso->optimize ();
my ($best) = $pso->getBestParticles (1);
my ($fit, @values) = $pso->getParticleBestPos ($best);
my $iters = $pso->getIterationCount ();
print $pso->getSeed();
printf ",# Fit %.5f at (%s) after %d iterations\n",
$fit, join (', ', map {sprintf '%.4f', $_} @values), $iters;
sub calcFit {
my @values = @_;
my $offset = int (-@values / 2);
my $sum;
$sum += ($_ - $offset++)**2 for @values;
return $sum;
}
Samples/PSOTest.pl view on Meta::CPAN
my $fitValue = $pso->optimize ();
my ($best) = $pso->getBestParticles (1);
my ($fit, @values) = $pso->getParticleBestPos ($best);
my $iters = $pso->getIterationCount();
printf "Fit %.4f at (%s) after %d iterations\n",
$fit, join (', ', map {sprintf '%.4f', $_} @values), $iters;
}
sub calcFit {
my @values = @_;
my $offset = int (-@values / 2);
my $sum;
$sum += ($_ - $offset++) ** 2 for @values;
return $sum;
}
lib/AI/ParticleSwarmOptimization.pm view on Meta::CPAN
our @ISA = qw(Exporter);
our @EXPORT = qw();
$AI::ParticleSwarmOptimization::VERSION = '1.006';
use constant kLogBetter => 1;
use constant kLogStall => 2;
use constant kLogIter => 4;
use constant kLogDetail => 8;
use constant kLogIterDetail => (kLogIter | kLogDetail);
sub new {
my ($class, %params) = @_;
my $self = bless {}, $class;
$self->setParams (%params);
return $self;
}
sub setParams {
my ($self, %params) = @_;
if (defined $params{-fitFunc}) {
# Process required parameters - -fitFunc and -dimensions
if ('ARRAY' eq ref $params{-fitFunc}) {
($self->{fitFunc}, @{$self->{fitParams}}) = @{$params{-fitFunc}};
} else {
$self->{fitFunc} = $params{-fitFunc};
}
lib/AI/ParticleSwarmOptimization.pm view on Meta::CPAN
$self->{posMin} = -$self->{posMax} unless defined $self->{posMin};
$self->{meWeight} ||= 0.5;
$self->{themWeight} ||= 0.5;
$self->{inertia} ||= 0.9;
$self->{verbose} ||= 0;
return 1;
}
sub init {
my ($self) = @_;
die "-fitFunc must be set before init or optimize is called"
unless $self->{fitFunc} and 'CODE' eq ref $self->{fitFunc};
die
"-dimensions must be set to 1 or greater before init or optimize is called"
unless $self->{dimensions} and $self->{dimensions} >= 1;
my $seed =
int (exists $self->{randSeed} ? $self->{randSeed} : rand (0xffffffff));
lib/AI/ParticleSwarmOptimization.pm view on Meta::CPAN
die "-posMax must be greater than -posMin"
unless $self->{posMax} > $self->{posMin};
$self->{$_} > 0 or die "-$_ must be greater then 0" for qw/numParticles/;
$self->{deltaMax} = ($self->{posMax} - $self->{posMin}) / 100.0;
return 1;
}
sub optimize {
my ($self, $iterations) = @_;
$iterations ||= $self->{iterations};
$self->init () unless $self->{prtcls};
return $self->_swarm ($iterations);
}
sub getBestParticles {
my ($self, $num) = @_;
my @bests = 0 .. $self->{numParticles} - 1;
my $prtcls = $self->{prtcls};
@bests = sort {$prtcls->[$a]{bestFit} <=> $prtcls->[$b]{bestFit}} @bests;
$num ||= 1;
return @bests[0 .. $num - 1];
}
sub getParticleBestPos {
my ($self, $prtcl) = @_;
return undef if $prtcl >= $self->{numParticles};
$prtcl = $self->{prtcls}[$prtcl];
return ($prtcl->{bestFit}, @{$prtcl->{bestPos}});
}
sub getIterationCount {
my ($self) = @_;
return $self->{iterCount};
}
sub getSeed {
my ($self) = @_;
return $self->{usedRandSeed};
}
sub _initParticles {
my ($self) = @_;
for my $id (0 .. $self->{numParticles} - 1) {
$self->{prtcls}[$id]{id} = $id;
$self->_initParticle ($self->{prtcls}[$id]);
}
}
sub _initParticle {
my ($self, $prtcl) = @_;
# each particle is a hash of arrays with the array sizes being the
# dimensionality of the problem space
for my $d (0 .. $self->{dimensions} - 1) {
$prtcl->{currPos}[$d] =
$self->_randInRange ($self->{posMin}, $self->{posMax});
$prtcl->{velocity}[$d] =
$self->{randStartVelocity}
lib/AI/ParticleSwarmOptimization.pm view on Meta::CPAN
unless (defined $prtcl->{bestFit}) {
$prtcl->{bestPos}[$_] =
$self->_randInRange ($self->{posMin}, $self->{posMax})
for 0 .. $self->{dimensions} - 1;
$prtcl->{bestFit} = $self->_calcPosFit ($prtcl->{bestPos});
}
}
sub _calcPosFit {
my ($self, $pos) = @_;
return $self->{fitFunc}->(@{$self->{fitParams}}, @$pos);
}
sub _swarm {
my ($self, $iterations) = @_;
for my $iter (1 .. $iterations) {
++$self->{iterCount};
last if defined $self->_moveParticles ($iter);
$self->_updateVelocities ($iter);
next if !$self->{exitPlateau} || !defined $self->{bestBest};
if ($iter >= $self->{exitPlateauBurnin} - $self->{exitPlateauWindow}) {
lib/AI/ParticleSwarmOptimization.pm view on Meta::CPAN
my $current = sprintf $format, $self->{bestBest};
#Check if there is a sufficient plateau - stopping iterations if so
last if $mean == $current;
}
return $self->{bestBest};
}
sub _moveParticles {
my ($self, $iter) = @_;
print "Iter $iter\n" if $self->{verbose} & kLogIter;
for my $prtcl (@{$self->{prtcls}}) {
@{$prtcl->{currPos}} = @{$prtcl->{nextPos}};
$prtcl->{currFit} = $prtcl->{nextFit};
my $fit = $prtcl->{currFit};
lib/AI/ParticleSwarmOptimization.pm view on Meta::CPAN
join (', ', map {sprintf '%5.3f', $_} @{$prtcl->{velocity}}),
join (', ', map {sprintf '%5.2f', $_} @{$prtcl->{currPos}})
if $self->{verbose} & kLogDetail;
print "\n";
}
return undef;
}
sub _saveBest {
my ($self, $prtcl, $fit, $iter) = @_;
# for each dimension, set the best position as the current position
@{$prtcl->{bestPos}} = @{$prtcl->{currPos}};
$prtcl->{bestFit} = $fit;
return if !$self->_betterFit ($fit, $self->{bestBest});
if ($self->{verbose} & kLogBetter) {
my $velSq;
$velSq += $_**2 for @{$prtcl->{velocity}};
printf "#%05d: Particle $prtcl->{id} best: %.4f (vel: %.3f)\n",
$iter, $fit, sqrt ($velSq);
}
$self->{bestBest} = $fit;
}
sub _betterFit {
my ($self, $new, $old) = @_;
return !defined ($old) || ($new < $old);
}
sub _updateVelocities {
my ($self, $iter) = @_;
for my $prtcl (@{$self->{prtcls}}) {
my $bestN = $self->{prtcls}[$self->_getBestNeighbour ($prtcl)];
my $velSq;
for my $d (0 .. $self->{dimensions} - 1) {
my $meFactor =
$self->_randInRange (-$self->{meWeight}, $self->{meWeight});
my $themFactor =
lib/AI/ParticleSwarmOptimization.pm view on Meta::CPAN
$self->_initParticle ($prtcl);
printf "#%05d: Particle $prtcl->{id} stalled (%6f)\n", $iter, $vel
if $self->{verbose} & kLogStall;
}
$self->_calcNextPos ($prtcl);
}
}
sub _calcNextPos {
my ($self, $prtcl) = @_;
for my $d (0 .. $self->{dimensions} - 1) {
$prtcl->{nextPos}[$d] = $prtcl->{currPos}[$d] + $prtcl->{velocity}[$d];
if ($prtcl->{nextPos}[$d] < $self->{posMin}) {
$prtcl->{nextPos}[$d] = $self->{posMin};
$prtcl->{velocity}[$d] = 0;
} elsif ($prtcl->{nextPos}[$d] > $self->{posMax}) {
$prtcl->{nextPos}[$d] = $self->{posMax};
$prtcl->{velocity}[$d] = 0;
}
}
$prtcl->{nextFit} = $self->_calcPosFit ($prtcl->{nextPos});
}
sub _randInRange {
my ($self, $min, $max) = @_;
return $min + $self->{rndGen}->rand ($max - $min);
}
sub _getBestNeighbour {
my ($self, $prtcl) = @_;
my $bestNFitness;
my $bestNIndex;
for my $neighbor (0 .. $self->{numNeighbors} - 1) {
my $prtclNIndex = ($prtcl + $neighbor) % $self->{numParticles};
if (!defined ($bestNFitness)
|| $self->{prtcls}[$prtclNIndex]{bestFit} < $bestNFitness)
{
lib/AI/ParticleSwarmOptimization.pm view on Meta::CPAN
dimensions => 3,
);
my $fitValue = $pso->optimize ();
my ($best) = $pso->getBestParticles (1);
my ($fit, @values) = $pso->getParticleBestPos ($best);
printf "Fit %.4f at (%s)\n",
$fit, join ', ', map {sprintf '%.4f', $_} @values;
sub calcFit {
my @values = @_;
my $offset = int (-@values / 2);
my $sum;
$sum += ($_ - $offset++) ** 2 for @values;
return $sum;
}
=head1 Description
lib/AI/ParticleSwarmOptimization.pm view on Meta::CPAN
the fitness function as following elements. User provided parameters are passed
as the first parameters to the fitness function when it is called:
my $pso = AI::ParticleSwarmOptimization->new (
fitFunc => [\&calcFit, $context],
dimensions => 3,
);
...
sub calcFit {
my ($context, @values) = @_;
...
return $fitness;
}
In addition to any user provided parameters the list of values representing the
current particle position in the hyperspace is passed in. There is one value per
hyperspace dimension.
=item I<-inertia>: positive or zero number, optional
t/01_pso_oo.t view on Meta::CPAN
-exitPlateau => 1,
-exitPlateauDP => 3,
-exitPlateauBurnin => 100,
-exitPlateauWindow => 60,
);
my $fitValue = $pso->optimize ();
my $iters = $pso->getIterationCount ();
ok ($iters > 100 && $iters < 350, 'Low plateau ok');
sub fitFunc {
}
sub calcFit {
my @values = @_;
my $offset = int (-@values / 2);
my $sum;
$sum += ($_ - $offset++)**2 for @values;
return $sum;
}
sub mustDie {
my ($test, $name) = @_;
eval $test;
ok (defined $@, $name);
}