Slides from a tutorial presented at SSCI 2015. Discussions around the reimplementation of CIlib using functional programming to address problems associated with achieving reproducible scientific research and results.
library to help with PSO research ▸ Called PSOLib, written in Java ▸ Some similarities were noticed between PSO and other population based algorithms. ▸ These similarities were combined into a new library called the Computational Intelligence Library (CIlib)
a simulator for users ▸ XML definitions were passed to the simulator ▸ Allowed for simple experimentation ▸ Numerous example XML specifications to work from ▸ One single place to define algorithm stopping conditions, measurements and benchmark problems
Multi-population based algorithms ▸ Multi-Objective Optimisation ▸ Niching algorithms ▸ Cooperative algorithms ▸ Neural Networks ▸ Very large collection of established benchmark functions ▸ Unified control parameter usage and representation
of Stopping Conditions ▸ Selection of Measurements ▸ Output results automatically to a file based persistence ▸ Allows for use of custom code, provided it is accessible on classpath
is, several problems developed as a result of it ▸ Random number generator (PRNG) ▸ Java bean style instance creation (very verbose declaration files and java source code) ▸ Complex object interactions, concurrency and mutable state ▸ Additions resulted in a large amount of additional work
inheritance, is a massive problem. Reflection schemes translated to property names. /** * Get the current strategy to perform personal best updates. * @return The current {@link PersonalBestUpdateStrategy}. */ PersonalBestUpdateStrategy getPersonalBestUpdateStrategy(); /** * Set the strategy to perform personal best updates. * @param personalBestUpdateStrategy The instance to set. */ void setPersonalBestUpdateStrategy(PersonalBestUpdateStrategy personalBestUpdateStrategy);
data output to text files as a default is very, very restrictive ▸ Concurrency for executing experiments could result in very strange behaviour ▸ Did not effectively use the underlying hardware (CPUs etc) ▸ Scripting the simulator was difficult and cumbersome ▸ Many configuration errors only manifested during runtime
Replicating experiments, given an XML definition, is not simple. PRNG seed values etc ▸ Possible to create an experiment with the wrong usage of object instances, by accident ▸ Difficult to verify correct ahead of time ▸ Tests can only be defined for specific use cases / examples
to talk about algorithms and implementations without necessarily considering the complications ▸ Worry about how to run them later ▸ Very important aspects to get right: ▸ Correctness Principled design to promote intuitive usage ▸ Experimental reproducibility Not being able to reproduce experimental results is utterly useless ▸ Type safety The ability to exploit types to prevent errors by making the construction of error states impossible
users should be able to replace parts they don’t like easily ▸ Library should be highly modular. Only include what is required ▸ Other community projects that can provide missing pieces should be used - good open source attitude ▸ The library should be as expressive as possible
of complexity and composition is much more flexible (the expression problem) ▸ We decided to instead focus on data structures that encourage correctness and consistency ▸ First class functions were therefore a requirement, but Java does not fully address this (even in JDK8). The only statically compiled language that matched our needs at the time is Scala, which supports higher-kinded types
in programming ▸ The best way to minimise state in a program is to simply not use it! ▸ Scala is a language that merges object orientated and functional programming. We focus on functional programming as it can provide better guarantees for us ▸ Functional programming has strong foundations in mathematics, which is really nothing more than a boon to productivity and correctness
of computation, using rich data structures, governed by laws formalised in mathematics ▸ The standard Scala libraries are, however, hopelessly insufficient - we rely on some fantastic open source libraries to bridge the gap ▸ Complexities should be hidden within the library code, making user usage simpler ▸ Testing should be done by using property based testing, where the test is a specification of invariants and the test system generates test data for us, identifying many, many more edge and invalid cases
abstracts the concept of getters and setters ▸ Allows the ability to “zoom” into a nested data structure ▸ Any changes in to the zoomed data will result in an updated nested data structure ▸ We use lenses to emulate row-polymorphism
using a Position ▸ A Position can only be one of two possible cases ▸ Point - A single point in a hyper-dimensional search space ▸ Solution - A point in the hyper-dimensional space that has been quantified. It includes a fitness and a list of violated constraints
which is a combination of the candidate solution together with some “state” ▸ The state should contain all the additional data that the Entity is tracking for the given algorithm. Eg: velocity, memory, etc ▸ Individual pieces of state are manipulated with Lenses ▸ Having the state accessed by lenses also means we can restrict the type of Entity instance used in a given function case class Entity[S,A](state: S, pos: Position[A])
CIlib ▸ It tracks the effect of randomness, but doesn’t describe how the randomness is applied, nor which PRNG to use ▸ RVar provides some guarantees ▸ It is stack safe to prevent problems with stack overflow ▸ Providing the same seeded PRNG will provide the same result when executed
it forms the base computation within CIlib ▸ As an argument, it accepts a PRNG in order to execute ▸ Has several useful functions that are commonly used: ▸ choose ▸ shuffle ▸ sample ▸ etc
is a generator to produce values from a given probability distribution ▸ Gaussian / Cauchy / Uniform / Gamma / Exponential / Lognormal / etc ▸ Standard versions exist with predefined parameters
RVar. Step is defined to be a single operations within an algorithm definition ▸ Step adds two parameters to a computation ▸ The optimisation scheme to use: Min / Max ▸ The Eval instance that quantifies the quality of a Position
additional state that is managed during the execution of the algorithm ▸ It’s simple to extend Step to contain some additional state ▸ This is known as StepS ▸ It is important to note that this state is localised to the computation
for algorithms ▸ Iterations may either be “synchronous” or “asynchronous” ▸ Important to note that synchronous iteration may be fully parallelised, whereas asynchronous iteration cannot be as asynchronous iteration uses the current collection of entities in the computation
passing an algorithm to one of the several functions that create an Iteration ▸ The Iteration converts the signature of an algorithm to: ▸ M in the above is a computational context, which generally is a Step, StepS or RVar, but any valid context is possible List[A] => M[List[A]]
on ▸ Co-operative algorithms ▸ Neural networks ▸ Niching and multi-swarm ▸ Benchmark problems (implementing current standard functions and allowing for benchmark function composition) ▸ There is currently a released version, 2.0.0-M1, which is available for use. New versions are currently scheduled for publication