PSO algorithm is the core of the framework. There are a number of tools (blocks, script and observers) to monitor and control the PSO algorithm behaviour. Here we will look mainly into the script, the others are described elsewhere.

 1. User level

The PSO is visually presented as tab in main paged control. Central part contains the blocks, or the right are observers and on the left there are PSO Run bar and PSO console under it.
First lets deal with Run bar (from left to right):
  • Button with menu : Options dialog (screenshot below); Open props, Save props - saves and reload all props of all blocks in *.prop file; Mute - mute all the blocks in one switch. While the PSO is running the button turns into animated bee to indicate that PSO is progressing.
  • Preview button: shows the test function chart in Outside observer; When Pause button is down that Preview button turns into Next button which allows the user to advance one iteration.
  • Pause button: pause PSO algorithm progress in order to investigate properties and observers. Click Next to go forward one iteration. Un-press Pause to continue.
  • Run button: run PSO algorithm, the animated bee on the left indicates the progress. If click while it's pressed, the PSO will stop, so the next click will restart it.

The PSO console is under Run bar. In its normal state the console is just a log window. When the user double click on it additional controls appear (the image on the right).

Top bar allows the user to save, erase or turn on/off the log. At the bottom: Eval tab is for evaluating expression (or variable) in the script. The Exec tab is for executing some code. If you need some results out, use print command and they will be out in the log. Open and Save button are for opening and saving some code.

The code (in Exec) is normal Python code with any possible extensions, plus access to properties:
<block.name>.getP('<prop.name>') returns property value and <block.name>.setP('<prop.name>', <value>) to set a value to a property.
Another Bee22 related object is "pso", the possible methods for that object you can see under the Options images. Most of the methods allow only read-only access.

Options:

  • General tab provide options to control where and if the properties of the block will be opened and saved.
  • Block tab: location of the blocks, enter a number (1 to 8) right to each block name, any location can room more than one block
  • Tracker tab: tracker is normally used for debugging, but it can be used for other purposes. It records (traces) a number of PSO and particle parameters in Excel (you must have one) for the first n iterations (right). The user must check the box on left to initiate the tracking for the next PSO run, after which the checkbox will go off.

2. Developer level

PSO is implemented (at least the default behaviour) in pso_algo.pas

PSO object methods and properties

procedure Init(NumberOfParticles: integer = 0; ForceReset: boolean = false);
                // particle & variables init; once per optim, AFTER blocks init
                // if NumberOfParticles is the same as in the previous Init, ForceReset will recreate the particles anyway
function GetItf: ITestFunc; // inteface to test function
procedure setParticleCount(NumberOfParticles: integer);
function GetVaiablesCount: integer;
procedure optimize(maximumIterations: integer=0; aTolerance: double = 0.0); // the point of it all
function getBestFitness(): double;
procedure updateVariablesToBest();
procedure stop();
function IsRunning: boolean;
function OnTarget: boolean; // true if the target from testFunc.objective is hit with tolerance testFunc.epsilon
function OutCount: integer; // counter of particles went out search space and reinitrodused back
function GetStatus: rOptimRslt; // record of optimization results

property Variables: TVariableList read FVariables; // working variable
property Particles: TParticleList read FParticles; // total swarm (create/destroy)
property SubSw: TSubSw read FSubSw; // over-lapping or not sub-swarms (only ref to particles)
property SwarmBestEverPos: TDoubleDynArray read FSwarmBestEverPos write FSwarmBestEverPos;
property SwarmBestEverFitness: double read FSwarmBestEverFitness write FSwarmBestEverFitness;
property ShouldStop: boolean read GetShouldStop; // stop request
property ParticleCount: integer read FParticleCount;
property Iterations: integer read GetIterations;
property MaxIterations: integer read GetMaxIterations write SetMaxIterations;
property Tolerance: double read fTolerance; // only for internal (default) use
property Equidist: boolean read fEquidist; // equal particle distribution at start
property User1: double read fUser1 write fUser1; // only for internal (default) use
 

The optimize procedure has to be examine thoroughly, many important calls are there, including all DoChange(-1) principal calls for all pso blocks.

procedure TPSO.optimize(maximumIterations: integer=0; aTolerance: double = 0.0);
var
  swarmBest, prt: TParticle; ctrl: TController; iMdl: IblkModel;
  swarmBestFitness, fitness, a: double; i: integer;
begin
  fTolerance:= aTolerance;
  if maximumIterations>0 then
  FMaxIterations := maximumIterations;
  if FMaxIterations=0 then
  FMaxIterations := defaultIterations;
  ctrl:= TController(Controller);
try
  if ShouldStop then exit;
  FIterations := 0; // utils init
  fRunning:= true;
  while (FIterations < FMaxIterations) and (not ShouldStop) do // THE MAIN LOOP
  begin
    Inc(FIterations);
    ObserverList.VisualUpdate(self); // update observers
    if ShouldStop then break;
    if Assigned(FOnBeforeIteration) then OnBeforeIteration(self); // before event
    if Assigned(TestFuncBlock) then TestFuncBlock.DoChange(-1); // empty for now

    // extract swarm params for particles speed calculations
    iMdl:= ctrl.modelByFork('precalc'); // precalc fork
    if Assigned(iMdl) then iMdl.DoChange(-1)
    else begin // default action {
    swarmBest:= FParticles.BestPrt(true); // recalc
    // update global EVER best
    if swarmBest.getFitness > FSwarmBestEverFitness then
    begin
      FSwarmBestEverFitness := swarmBest.getFitness;
      FSwarmBestEverPos:= swarmBest.getPosition();
    end;
  end; // default action }
  if ShouldStop then break;

  // update all FParticles - MAIN speed adjustment
  for prt in FParticles do
    prt.update(FSwarmBestEverPos); // all prt blocks are in here

  if ShouldStop then break;
  if Assigned(FOnAfterIteration) and not ShouldStop then OnAfterIteration(self); // after event
  if Assigned(TermCondBlock) then TermCondBlock.DoChange(-1)
  else begin // default action {
    // termination conditions
    if Tolerance>1.0E-100 then // if 0 only iters number terminates
    begin
      if (FParticles.StdDevDistance(SwarmBestEverPos)<Tolerance) then TermCond:= 'small spot';
      if FParticles.Speed(spdMax)<Tolerance then TermCond:= 'immobil. ('+F2S(FParticles.Speed(spdMax))+')';
    end;
  end; // default action }

  if ShouldStop or (TermCond<>'') then break;
  end; // end of MAIN loop
  finally
    if TermCond='' then
      if ShouldStop
        then TermCond:= 'User stop (iters='+IntToStr(Iterations)+')'
        else TermCond:= 'max iters ('+IntToStr(Iterations)+')';

    // finish with global best found in Variables
    if not ShouldStop then updateVariablesToBest();
    fRunning:= false;
  end;
end;