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.

My targetFraction attribute determines how much success challengers must have to maintain the status quo in adaptive mode. Consider the default of 2.5%: In a population of 100, that is reached with a score of 2.5, which can be achieved, for example, with

  • ten challengers winning with a rounded improvement ratio of 1; or
  • one challenger winning with an rir of 2 and five with an rir of 1; or
  • just one challenger winning with an rir of 3.
  • Or, if you're somehow positioned at a subtle transition in the fitness landscape along just the right multi-dimensional angle, fully half of the challengers winning with an rir of 0. (Unlikely!)
ParametersconstraintsA single callable object (function, method, class instance with __call__ method), or a sequence of such objects, that enforce(s) any constraints on your parameter values. See ParameterManager.passesConstraints. Instead of a sequence, you can use an instance of constraints.Constraints.
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 Alsoasynqueue.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 Nd The number of parameters for each individual.
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 2%. (Previously, it was 2.5% but that seemed too strict for the application the author is mostly using ADE for.)
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)
Class Method load Returns a new instance of me with values initialized from the original version that was pickled and written with BZ2 compression to filePath.
Method __getstate__ For pickling. Note that neither the user-supplied evaluation function nor any complaint callback function is included.
Method __setstate__ For unpickling.
Method save Writes a BZ2-compressed pickled version of me to the specified filePath.
Method __getitem__ Sequence-like access to my individuals.
Method __setitem__ Use only this method (item setting) to replace individuals in my iList.
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 __bool__ Sequence-like container of individuals: I am True if I have any.
Method KS 0 Property: A list of indices to iList, sorted by increasing (worsening) SSE of the individuals there. The best individual will have the first index in KS.
Method KS Property: "Deleting" my SSE-sorted list of indices forces regeneration of it the next time the KS property is accessed. It also "deletes" iSorted.
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 kBest Property: The index to iList of the best individual. None if I have no individuals yet.
Method __repr__ An informative string representation with a text table of my best individuals.
Method evalFunc A wrapper for the user-supplied evaluation function.
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 initialize Invalidates the last sort of my individuals, sets my running flag to True, and prints/logs a representation of my populated instance.
Method setup Sets up my initial population using a Latin hypercube to initialize pseudorandom parameter values with minimal clustering.
Method addCallback Adds callable func to my reporter's list of functions to call each time there is a significantly better Individual.
Method setConstraints Sets the constraint checkers maintained by my ParameterManager instance pm to the callable function(s), method(s), or object(s) supplied as one or more args.
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 one.
Method waitForReports Returns a Deferred that fires when all reporter callbacks have finished. (And also History updates.)
Method showFailedConstraint Outputs a progress character to indicate a failed constraint.
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.
Method _keepStatusQuo Returns True with a probability that increases as score approaches my statusQuoteScore.
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.
Nd =
The number of parameters for each individual.
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 2%. (Previously, it was 2.5% but that seemed too strict for the application the author is mostly using ADE for.)
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)

@classmethod
def load(cls, filePath, **kw):

Returns a new instance of me with values initialized from the original version that was pickled and written with BZ2 compression to filePath.

The pickled version will not have a reference to the evaluation func that was supplied to the original version in its constructor, nor to any complaintCallback. If you want to do further evaluations, you can supply a reference to those functions (or even a different one, though that would be weird) with the func and complaintCallback keywords.

Note: For some mysterious reason, the DE algorithm seems to run significantly slower when resuming with a population that has been loaded using this method than with one initialized from scratch.

ParametersfuncEvaluation function, specify if you want to resume evaluations. All individuals in the loaded population should have their SSEs re-evaluated if anything at all has changed about that function.
complaintCallbackCallback function for complaining about new-best reports during resumed evaluations.
boundsA list of bounds to update my restored ParameterManager object with. Specify if you refined the parameter bounds since the last run and want to resume evaluations with the refined bounds. Each Individual in the new instance will have its values limited to the new bounds with a call to Population.limit.
See Alsosave for the way to create compressed pickles of an instance of me.
def __getstate__(self):

For pickling. Note that neither the user-supplied evaluation function nor any complaint callback function is included.

def __setstate__(self, state):

For unpickling.

def save(self, filePath):

Writes a BZ2-compressed pickled version of me to the specified filePath.

Note that the user-supplied evaluation function will not be included in the pickled version. However, you can supply it as a keyword to load.

def __getitem__(self, k):

Sequence-like access to my individuals.

def __setitem__(self, k, i):

Use only this method (item setting) to replace individuals in my iList.

The only other place my iList is ever manipulated directly is the addIndividual function of setup.

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 __bool__(self):

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

@property
def KS 0(self):

Property: A list of indices to iList, sorted by increasing (worsening) SSE of the individuals there. The best individual will have the first index in KS.

@KS.deleter
def KS(self):

Property: "Deleting" my SSE-sorted list of indices forces regeneration of it the next time the KS property is accessed. It also "deletes" iSorted.

@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.

@property
def kBest(self):

Property: The index to iList of the best individual. None if I have no individuals yet.

def __repr__(self):

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

def evalFunc(self, values, xSSE=None):

A wrapper for the user-supplied evaluation function.

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.

Note: The individual's population status is not considered or affected. If it's a population member, you will want to re-evaluate it and invalidate my sort with a del self.KS or del self.iSorted if its SSE has changed.

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 initialize(self):

Invalidates the last sort of my individuals, sets my running flag to True, and prints/logs a representation of my populated instance.

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

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.

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.

ParametersuniformUse 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 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 AlsoReporter.addCallback.
def setConstraints(self, *args):

Sets the constraint checkers maintained by my ParameterManager instance pm to the callable function(s), method(s), or object(s) supplied as one or more args.

What you supply as arguments will replace any constraint checking already in place, so make sure you everything you want is included.

All constraints, and only those constraints, defined by this call will need to be be satisfied with each parameter combination. To clear any existing constraints, call with no args.

See AlsoParameterManager.setConstraints.
def _keepStatusQuo(self, score):

Returns True with a probability that increases as score approaches my statusQuoteScore.

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 give very little weight to an rir of zero, which indicates that the challenger was better but still has an equivalent SSE, i.e., is no more than 2% better with the default value of Reporter.minDiff. See Reporter.isEquivSSE.

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

An rir of 3 also gets disproportionately more weight, five times as much as rir=1. 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.4x) 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 5.0. But if you see just one non-X individual with a "8" character, the score will be 7.5. That one amazing success story counts 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.")

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

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

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

If no individual at all is supplied, reports on my best one, forcing callbacks to run even if the best individual's SSE is equivalent to the last-reported one's.

Gets the ratio from a call to my Reporter instance, and does a call to replacement with it if the new individual is better. Returns (for unit testing convenience) the ratio.

ParametersnoProgressSet True to suppress printing/logging a progress character.
forceSet True to force callbacks to run even if the reported SSE is considered equivalent to the previous best one.
See AlsoReporter.
def waitForReports(self):

Returns a Deferred that fires when all reporter callbacks have finished. (And also History updates.)

def showFailedConstraint(self):

Outputs a progress character to indicate a failed constraint.

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, **kw):

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

The randomBase keyword lets you use a significant improvement offered by ADE: Non-uniform probability of base individual selection. Implementation is done by an instance of ProbabilitySampler.

The traditional DE/best/1/bin and DE/rand/1/bin are really opposite extremes of what can be a continuous range of base individual selection regimes. By specifying a float value for randomBase between 0.0 and 1.0, you can select a regime anywhere in that range.

The higher the value, the more uniform the probability distribution is. Setting it to near 0.0 makes it much more likely that the index of the best individual or one nearly as good will be chosen. Setting it to near 1.0 makes the worst individual nearly as likely to be chosen as the best.

A randomBase value of 0.5 is a compromise between DE/best/1/bin and DE/rand/1/bin. With that setting, the probability of an individual having its index selected will gradually drop as it gets worse in the SSE rankings. As randomBase goes above 0.5, the probability will take longer to start dropping, until at 1.0 it doesn't drop at all. As randomBase goes below 0.5, the probability will start dropping sooner, until at 0.0 it drops to zero for anything but the best individual.

ParametersrandomBaseSample probability uniformity value between 0.0 (only the best individual is ever selected) and 1.0 (uniform probability). Setting it False is equivalent to 0.0, and setting it True (the default) is equivalent to 1.0.
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.

API Documentation for ade, generated by pydoctor at 2022-11-17 13:13:22.