AI-PSO

 view release on metacpan or  search on metacpan

lib/AI/PSO.pm  view on Meta::CPAN

require Exporter;

our @ISA = qw(Exporter);

our @EXPORT = qw(
    pso_set_params
    pso_register_fitness_function
    pso_optimize
    pso_get_solution_array
);

our $VERSION = '0.86';


######################## BEGIN MODULE CODE #################################

#---------- BEGIN GLOBAL PARAMETERS ------------

#-#-# search parameters #-#-#
my $numParticles  = 'null';            # This is the number of particles that actually search the problem hyperspace
my $numNeighbors  = 'null';            # This is the number of neighboring particles that each particle shares information with
                                       # which must obviously be less than the number of particles and greater than 0.
                                         # TODO: write code to preconstruct different topologies.  Such as fully connected, ring, star etc.
                                         #       Currently, neighbors are chosen by a simple hash function.  
                                         #       It would be fun (no theoretical benefit that I know of) to play with different topologies.
my $maxIterations = 'null';            # This is the maximum number of optimization iterations before exiting if the fitness goal is never reached.
my $exitFitness   = 'null';            # this is the exit criteria.  It must be a value between 0 and 1.
my $dimensions    = 'null';            # this is the number of variables the user is optimizing


#-#-# pso position parameters #-#-#
my $deltaMin       = 'null';           # This is the minimum scalar position change value when searching
my $deltaMax       = 'null';           # This is the maximum scalar position change value when searching

#-#-# my 'how much do I trust myself verses my neighbors' parameters #-#-#
my $meWeight   = 'null';               # 'individuality' weighting constant (higher weight (than group) means trust individual more, neighbors less)
my $meMin      = 'null';               # 'individuality' minimum random weight (this should really be between 0, 1)
my $meMax      = 'null';               # 'individuality' maximum random weight (this should really be between 0, 1)
my $themWeight = 'null';               # 'social' weighting constant (higher weight (than individual) means trust group more, self less)
my $themMin    = 'null';               # 'social' minimum random weight (this should really be between 0, 1)
my $themMax    = 'null';               # 'social' maximum random weight (this should really be between 0, 1)

my $psoRandomRange = 'null';           # PSO::.86 new variable to support original unmodified algorithm
my $useModifiedAlgorithm = 'null';

#-#-# user/debug parameters #-#-#
my $verbose    = 0;                    # This one defaults for obvious reasons...

#NOTE: $meWeight and $themWeight should really add up to a constant value.  
#      Swarm Intelligence defines a 'pso random range' constant and then computes two random numbers
#      within this range by first getting a random number and then subtracting it from the range.
#      e.g. 
#           $randomRange = 4.0
#           $meWeight   = random(0, $randomRange);
#           $themWeight = $randomRange - $meWeight.
#
#

#----------   END  GLOBAL PARAMETERS ------------

#---------- BEGIN GLOBAL DATA STRUCTURES --------
#
# a particle is a hash of arrays of positions and velocities:
#
# The position of a particle in the problem hyperspace is defined by the values in the position array...
# You can think of each array value as being a dimension,
# so in N-dimensional hyperspace, the size of the position vector is N
# 
# A particle updates its position according the Euler integration equation for physical motion:
#   Xi(t) = Xi(t-1) + Vi(t)
#   The velocity portion of this contains the stochastic elements of PSO and is defined as:
#   Vi(t) = Vi(t-1)  +  P1*[pi - Xi(t-1)]  +  P2*[pg - Xi(t-1)]
#   where P1 and P2 add are two random values who's sum adds up to the PSO random range (4.0)
#   and pi is the individual's best location
#   and pg is the global (or neighborhoods) best position
#
#   The velocity vector is obviously updated before the position vector...
#
#
my @particles = ();
my $user_fitness_function;
my @solution = ();
#----------   END GLOBAL DATA STRUCTURES --------


#---------- BEGIN EXPORTED SUBROUTINES ----------

#
# pso_set_params
#  - sets the global module parameters from the hash passed in
#
sub pso_set_params(%) {
    my (%params) = %{$_[0]};
    my $retval = 0;

    #no strict 'refs';
    #foreach my $key (keys(%params)) {
    #    $$key = $params{$key};
    #}
    #use strict 'refs';

    $numParticles   = defined($params{numParticles})   ? $params{numParticles}   : 'null';
    $numNeighbors   = defined($params{numNeighbors})   ? $params{numNeighbors}   : 'null';
    $maxIterations  = defined($params{maxIterations})  ? $params{maxIterations}  : 'null';
    $dimensions     = defined($params{dimensions})     ? $params{dimensions}     : 'null';
    $exitFitness    = defined($params{exitFitness})    ? $params{exitFitness}    : 'null';
    $deltaMin       = defined($params{deltaMin})       ? $params{deltaMin}       : 'null';
    $deltaMax       = defined($params{deltaMax})       ? $params{deltaMax}       : 'null';
    $meWeight       = defined($params{meWeight})       ? $params{meWeight}       : 'null';
    $meMin          = defined($params{meMin})          ? $params{meMin}          : 'null';
    $meMax          = defined($params{meMax})          ? $params{meMax}          : 'null';
    $themWeight     = defined($params{themWeight})     ? $params{themWeight}     : 'null';
    $themMin        = defined($params{themMin})        ? $params{themMin}        : 'null';
    $themMax        = defined($params{themMax})        ? $params{themMax}        : 'null';

    $psoRandomRange = defined($params{psoRandomRange}) ? $params{psoRandomRange} : 'null';

    $verbose        = defined($params{verbose})        ? $params{verbose}        : $verbose;

    my $param_string;
	if($psoRandomRange =~ m/null/) {
		$param_string =  "$numParticles:$numNeighbors:$maxIterations:$dimensions:$exitFitness:$deltaMin:$deltaMax:$meWeight:$meMin:$meMax:$themWeight:$themMin:$themMax";
	} else {
		$param_string =  "$numParticles:$numNeighbors:$maxIterations:$dimensions:$exitFitness:$deltaMin:$deltaMax:$psoRandomRange";
	}
    
    $retval = 1 if($param_string =~ m/null/);

    return $retval;
}


#
# pso_register_fitness_function
#  - sets the user-defined callback fitness function
#
sub pso_register_fitness_function($) {
    my ($func) = @_;
    $user_fitness_function = new Callback(\&{"main::$func"});
    return 0;
}




( run in 3.303 seconds using v1.01-cache-2.11-cpan-140bd7fdf52 )