update public distribution
based on internal repository c9a2ac8 2019-01-03 16:04:57 +0100 tagged rev-master-2.0.0
This commit is contained in:
155
pmsco/optimizers/table.py
Normal file
155
pmsco/optimizers/table.py
Normal file
@@ -0,0 +1,155 @@
|
||||
"""
|
||||
@package pmsco.table
|
||||
table scan optimization handler
|
||||
|
||||
the table scan scans through an explicit table of model parameters.
|
||||
it can be used to recalculate models from a previous optimization run on different scans,
|
||||
or as an interface to external optimizers.
|
||||
new elements can be added to the table while the calculation loop is in progress.
|
||||
|
||||
though the concepts _population_ and _optimization_ are not intrinsic to a table scan,
|
||||
the classes defined here inherit from the generic population class and optimization handler.
|
||||
this is done to share as much code as possible between the different optimizers.
|
||||
the only difference is that the table optimizer does not generate models internally.
|
||||
instead, it loads them (possibly repeatedly) from a file or asks the project code to provide the data.
|
||||
|
||||
@author Matthias Muntwiler, matthias.muntwiler@psi.ch
|
||||
|
||||
@copyright (c) 2015-18 by Paul Scherrer Institut @n
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); @n
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
import logging
|
||||
import numpy as np
|
||||
import pmsco.optimizers.population as population
|
||||
from pmsco.helpers import BraceMessage as BMsg
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TablePopulation(population.Population):
|
||||
"""
|
||||
population generated from explicit values.
|
||||
|
||||
this class maintains a population that is updated from a table of explicit values.
|
||||
the table can be static (defined at the start of the optimization process)
|
||||
or dynamic (new models appended during the optimization process).
|
||||
|
||||
for each generation, the table is read and the next models are imported into the population.
|
||||
the class de-duplicates the table, i.e. models with equal parameters as a previous one are not calculated again.
|
||||
it is, thus, perfectly fine that new models are appended to the table rather than overwrite previous entries.
|
||||
|
||||
the table can be built from the following data sources:
|
||||
|
||||
@arg (numpy.ndarray): structured array that can be added to self.positions,
|
||||
having at least the columns defining the model parameters.
|
||||
@arg (sequence of dict, numpy.ndarray, numpy.void, named tuple):
|
||||
each element must be syntactically compatible with a dict
|
||||
that holds the model parameters.
|
||||
@arg (str): file name that contains a table in the same format as
|
||||
@ref pmsco.optimizers.population.Population.save_array produces.
|
||||
@arg (callable): a function that returns one of the above objects
|
||||
(or None to mark the end of the table).
|
||||
|
||||
the data source is passed as an argument to the self.setup() method.
|
||||
structured arrays and sequences cannot be modified after they are passed to `setup`.
|
||||
this means that the complete table must be known at the start of the process.
|
||||
|
||||
the most flexible way is to pass a function that generates a structured array in each call.
|
||||
this would even allow to include a non-standard optimization algorithm.
|
||||
the function is best defined in the custom project class.
|
||||
the population calls it every time before a new generation starts.
|
||||
to end the optimization process, it simply returns None.
|
||||
|
||||
the table can also be defined in an external file, e.g. as calculated by other programs or edited manually.
|
||||
the table file can either remain unchanged during the optimization process,
|
||||
or new models can be added while the optimization is in progress.
|
||||
in the latter case, note that there is no reliable synchronization of file access.
|
||||
|
||||
first, writing to the file must be as short as possible.
|
||||
the population class has a read timeout of ten seconds.
|
||||
|
||||
second, because it is impossible to know whether the file has been read or not,
|
||||
new models should be _appended_ rather than _overwrite_ previous ones.
|
||||
the population class automatically skips models that have already been read.
|
||||
|
||||
this class supports does not support seeding.
|
||||
although, a seed file is accepted, it is not used.
|
||||
patching is allowed, but there is normally no advantage over modifying the table.
|
||||
|
||||
the domain is used to define the model parameters and the parameter range.
|
||||
models violating the parameter domain are ignored.
|
||||
"""
|
||||
|
||||
## @var table_source
|
||||
# data source of the model table
|
||||
#
|
||||
# this can be any object accepted by @ref pmsco.optimizers.population.Population.import_positions,
|
||||
# e.g. a file name, a numpy structured array, or a function returning a structured array.
|
||||
# see the class description for details.
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
initialize the population object.
|
||||
|
||||
"""
|
||||
super(TablePopulation, self).__init__()
|
||||
self.table_source = None
|
||||
self.position_constrain_mode = 'error'
|
||||
|
||||
def setup(self, size, domain, **kwargs):
|
||||
"""
|
||||
set up the population arrays, parameter domain and data source.
|
||||
|
||||
@param size: requested number of particles.
|
||||
this does not need to correspond to the number of table entries.
|
||||
on each generation the population loads up to this number of new entries from the table source.
|
||||
|
||||
@param domain: definition of initial and limiting model parameters
|
||||
expected by the cluster and parameters functions.
|
||||
@arg domain.start: not used.
|
||||
@arg domain.min: minimum values allowed.
|
||||
@arg domain.max: maximum values allowed.
|
||||
@arg domain.step: not used.
|
||||
|
||||
the following arguments are keyword arguments.
|
||||
the method also accepts the inherited arguments for seeding. they do not have an effect, however.
|
||||
|
||||
@param table_source: data source of the model table.
|
||||
this can be any object accepted by @ref pmsco.optimizers.population.Population.import_positions,
|
||||
e.g. a file name, a numpy structured array, or a function returning a structured array.
|
||||
see the class description for details.
|
||||
|
||||
@return: None
|
||||
"""
|
||||
super(TablePopulation, self).setup(size, domain, **kwargs)
|
||||
self.table_source = kwargs['table_source']
|
||||
|
||||
def advance_population(self):
|
||||
"""
|
||||
advance the population by one step.
|
||||
|
||||
this methods re-imports the table file
|
||||
and copies the table to current population.
|
||||
|
||||
@return: None
|
||||
"""
|
||||
self.import_positions(self.table_source)
|
||||
self.advance_from_import()
|
||||
super(TablePopulation, self).advance_population()
|
||||
|
||||
|
||||
class TableModelHandler(population.PopulationHandler):
|
||||
"""
|
||||
model handler which implements the table algorithm.
|
||||
|
||||
"""
|
||||
def __init__(self):
|
||||
super(TableModelHandler, self).__init__()
|
||||
self._pop = TablePopulation()
|
||||
Reference in New Issue
Block a user