I contain a population of parameter-combination Individual objects.

Construct me with a callable evaluation func, a sequence of parameter names, and a sequence of bounds containing 2-tuples that each define the lower and upper limits of the values:

  • func: A callable to which an Individual can send its parameter values and from which it receives a sum-of-squared error float value as a result.
  • names: A sequence of parameter names.
  • bounds: A list of 2-tuples, one for each parameter name. The first element of each tuple is the lower bound of a parameter in the second the upper bound.

The callable func must accept a single 1-D Numpy array as its sole argument and return the sum of squared errors (SSE) as a single float value. To shut down ade, it can return a negative SSE value. If ade is shutting down, it will use None as the argument, and the callable should act accordingly.

kwconstraintsA list of callables that enforce any constraints on your parameter values. See ParameterManager.passesConstraints.
popsizeThe number of individuals per parameter in the population, if not the default.
debugSet True to override my default debug setting and ensure that I show individuals getting replaced.
complaintCallbackA callable that my Reporter calls with an individual and the non-None result of a complaining reporter callback. See Reporter.runCallbacks.
targetFractionSet this to a (small) float to override my default target for the total score of improvements in each iteration.
See:asynqueue.util.DeferredTracker, used to limit concurrency during population setup.
Class Variable N_maxParallel The maximum number of parallel evaluations during population setup. Uses an instance of asynqueue.util.DeferredTracker for concurrency limiting.
Instance Variable popsize The number of individuals per parameter. The population size will scale with the number of parameters, up until Np_max is reached. Default is 10 individuals per parameter.
Instance Variable Np_min Minimum population size, i.e., my total number of individuals. Default is 20.
Instance Variable Np_max Maximum population size. Default is 500, which is really pretty big.
Instance Variable targetFraction The desired total score of improvements in each iteration in order for ade's adaptive algorithm to not change the current differential weight. See replacement and FManager for details. The default is 3%.
Instance Variable debug Set True to show individuals getting replaced. (Results in a very messy log or console display.)
Instance Variable running Indicates my run status: None after instantiation but before setup, True after setup, and False if ade is aborting.
Method __init__ Population(func, names, bounds, constraints=[], popsize=None, debug=False, complaintCallback=None)
Method __getitem__ Sequence-like access to my individuals.
Method __setitem__ Use only this method (item setting) and push to replace individuals.
Method __len__ Sequence-like container of individuals: length.
Method __iter__ Sequence-like container of individuals: iteration.
Method __contains__ Sequence-like container of individuals: "in".
Method __nonzero__ Sequence-like container of individuals: I am True if I have any.
Method iSorted 0 Property: A list of my individuals, sorted by increasing (worsening) SSE.
Method iSorted Property: "Deleting" my sorted list of individuals forces regeneration of the sorted list that will be returned next time the iSorted property is accessed.
Method __repr__ An informative string representation with a text table of my best individuals.
Method clear Wipes out any existing population and sets up everything for a brand new one.
Method limit Limits the individual's parameter values to the bounds in the way that my ParameterManager is configured to do, modifying the individual in place.
Method spawn Spawns a new Individual with the supplied values. If fromUnity is set True, the values are converted from 0-1 range into their proper ranges.
Method abort Aborts my operations ASAP. Repeated calls will release any locks that got acquired since the last call.
Method setup Sets up my initial population using a Latin hypercube to initialize pseudorandom parameter values with minimal clustering.
Method save (Not implemented yet.)
Method addCallback Adds callable func to my reporter's list of functions to call each time there is a significantly better Individual.
Method replacement Records the replacement of an Individual in this generation or iteration.
Method report Provides a message via the log messenger about the supplied Individual, optionally with a comparison to another Individual.
Method waitForReports Returns a Deferred that fires when all reporter callbacks have finished.
Method push Pushes the supplied Individual i onto my population and kicks out the worst individual there to make room.
Method sample Returns a sample of N indices from my population that are unique from each other and from any excluded indices supplied as additional arguments.
Method individuals Immediately returns a list of the individuals at the specified integer index or indices.
Method lock Obtains the locks for individuals at the specified indices, submits a request to acquire them, and returns a Deferred that fires when all of them have been acquired.
Method release Releases any active lock for individuals at the specified index or indices.
Method best Returns my best individual, or None if I have no individuals yet.
Method evalTimes Returns a list of the most recent elapsed evaluation times for each of my individuals that have done evaluations.
N_maxParallel =
The maximum number of parallel evaluations during population setup. Uses an instance of asynqueue.util.DeferredTracker for concurrency limiting.
popsize =
The number of individuals per parameter. The population size will scale with the number of parameters, up until Np_max is reached. Default is 10 individuals per parameter.
Np_min =
Minimum population size, i.e., my total number of individuals. Default is 20.
Np_max =
Maximum population size. Default is 500, which is really pretty big.
targetFraction =
The desired total score of improvements in each iteration in order for ade's adaptive algorithm to not change the current differential weight. See replacement and FManager for details. The default is 3%.
debug =
Set True to show individuals getting replaced. (Results in a very messy log or console display.)
running =
Indicates my run status: None after instantiation but before setup, True after setup, and False if ade is aborting.
def __init__(self, func, names, bounds, constraints=[], popsize=None, debug=False, complaintCallback=None, targetFraction=None):

Population(func, names, bounds, constraints=[], popsize=None, debug=False, complaintCallback=None)

def __getitem__(self, k):

Sequence-like access to my individuals.

def __setitem__(self, k, i):

Use only this method (item setting) and push to replace individuals.

def __len__(self):

Sequence-like container of individuals: length.

My length will be equal to my Np attribute unless setup has not been completed.

def __iter__(self):

Sequence-like container of individuals: iteration.

def __contains__(self, i):

Sequence-like container of individuals: "in".

def __nonzero__(self):

Sequence-like container of individuals: I am True if I have any.

@property
def iSorted 0(self):

Property: A list of my individuals, sorted by increasing (worsening) SSE.

@iSorted.deleter
def iSorted(self):

Property: "Deleting" my sorted list of individuals forces regeneration of the sorted list that will be returned next time the iSorted property is accessed.

def __repr__(self):

An informative string representation with a text table of my best individuals.

def clear(self):

Wipes out any existing population and sets up everything for a brand new one.

def limit(self, i):

Limits the individual's parameter values to the bounds in the way that my ParameterManager is configured to do, modifying the individual in place.

def spawn(self, values, fromUnity=False):

Spawns a new Individual with the supplied values. If fromUnity is set True, the values are converted from 0-1 range into their proper ranges.

def abort(self, ignoreReporter=False):

Aborts my operations ASAP. Repeated calls will release any locks that got acquired since the last call.

Reporter.abort calls this with ignoreReporter set True to avoid infinite recursion.

def setup(self, uniform=False, blank=False, filePath=None):

Sets up my initial population using a Latin hypercube to initialize pseudorandom parameter values with minimal clustering.

Unless uniform is set, that is. Then each parameter values is just uniformly random without regard to the others.

With parameter constraints, the Latin hypercube doesn't work that well. The initial values matrix must be refreshed, perhaps many times. But it may still be better than uniform initial population sampling.

TODO: Load from filePath.

Sets my running flag True and returns a Deferred that fires when the population has been set up, with True if it's ready to go and setup didn't get aborted.

kwuniformUse uniform random variates instead of a Latin hypercube (LHS). Using LHS (the default) is usually better because initializes pseudorandom parameter values with minimal clustering.
blankSet True to give the initial individuals an infinite placeholder SSE instead of being evaluated.
def save(self, filePath):

(Not implemented yet.)

This will save my individuals to a data file at filePath in a way that can repopulate a new instance of me with those same individuals and without any evaluations being required.

def addCallback(self, func, *args, **kw):

Adds callable func to my reporter's list of functions to call each time there is a significantly better Individual.

See:Reporter.addCallback.
def replacement(self, rir=None, sqs=None):

Records the replacement of an Individual in this generation or iteration.

Call with an integer rounded improvement ratio in a loser's SSE vs. the successful challenger's SSE, unless you are calling to inquire about whether the status quo F value(s) should be maintained or to set my statusQuoteScore with the sqs keyword.

Three types of calls

The rounded improvement ratio rir indicates how much better the challenger is than the individual it replaced. I use that ratio to adjust a running score for the current iteration to inform the status quo inquiry that will occur when the iteration is done, unless I'm not running in adaptive mode.

You can set my target statusQuoScore by setting sqs to a (small) float value. That will replace my default value for future evaluation of replacement individuals.

Finally, a status quo inquiry is a call with no keywords set. I will determine if the replacements that occurred in the previous generation/iteration were enough to warrant maintaining the status quo, and then reset the record. You will receive a result of True if the status quote should be maintained.

The status quo should be maintained if several small improvements are made, or fewer larger ones, with the required number and/or size increasing for a larger population. For small populations where even a single improvement would be significant, the probability of status quo maintenance increases with smaller population and will sometimes happen even with no improvements for a given generation or iteration.

Improvement Ratios

An rir of 1 indicates that the successful challenger was better (i.e., lower) and not considered equivalent to that of the individual it replaced, and that its SSE was no better than 1.5x as good (2/3 as high) as the replaced individual's SSE. An rir of 2 indicates that the challenger had an SSE between 1.5x and 2.5x better than (2/5 to 2/3 as high as) the individual it replaced.

I don't give much weight to an rir of 1. The improvement is pretty modest and could be as little as 2% (assuming Reporter.minDiff=0.02, the default). An rir of 2 gets five times as much weight as that.

An rir of 3 also gets disproportionately more weight, nearly twice as much as rir=2. Beyond that, though, the weight scales in a nearly linear fashion. For example, an rir of 9 adds just a little more than three times to the score (3.67x) as rir=3 does.

Here's a practical example, with a population of 100 individuals: If you see 10 "1" characters on the screen for one iteration with other 90 being "X," your ratio score for that iteration will be 2.5. But if you see just one non-X individual with a "8" character, the score will be 7.25. That one amazing success story counts far more in a sea of failures than a bunch of marginal improvements, which is kind of how evolution works in real life. (See the literature around "hopeful monsters.")

kwrirA rounded improvement ratio obtained from a call to msgRatio, where the numerator is the SSE of the individual that was replaced and the denominator is the SSE of its successful challenger.
See:report, which calls this.
def report(self, iNew=None, iOld=None):

Provides a message via the log messenger about the supplied Individual, optionally with a comparison to another Individual.

If no second individual is supplied, the comparison will be with the best individual thus far reported on.

Gets the ratio from a call to my Reporter instance, and does a call to replacement with it if the new individual is better.

def waitForReports(self):

Returns a Deferred that fires when all reporter callbacks have finished.

def push(self, i):

Pushes the supplied Individual i onto my population and kicks out the worst individual there to make room.

def sample(self, N, *exclude):

Returns a sample of N indices from my population that are unique from each other and from any excluded indices supplied as additional arguments.

def individuals(self, *indices):

Immediately returns a list of the individuals at the specified integer index or indices.

def lock(self, *indices):

Obtains the locks for individuals at the specified indices, submits a request to acquire them, and returns a Deferred that fires when all of them have been acquired.

Release the locks (as soon as possible) by calling release with the indices that are locked.

If I'm shutting down, the returned Deferred fires immediately.

def release(self, *indices):

Releases any active lock for individuals at the specified index or indices.

If no indices are supplied, releases all active locks. (This is for aborting only.)

def best(self):

Returns my best individual, or None if I have no individuals yet.

def evalTimes(self):

Returns a list of the most recent elapsed evaluation times for each of my individuals that have done evaluations.