11.1. General Notes

This page discusses some general concepts that are needed to work with pSeven Core.

11.1.1. Blackbox

Some of the pSeven Core tools feature techniques which obtain data from a blackbox — an existing model (gtapprox.Model, gtdf.Model) or a generic function:

To use a function as a blackbox, you have to implement a blackbox class, which works as a wrapper for external function calls. Inherit your class from Blackbox.

Note that GTOpt, due to its complexity, uses its own blackboxes — see ProblemGeneric and other GTOpt problem classes. Adaptive design also supports ProblemGeneric as a blackbox, because the generic Blackbox cannot define constraints.

11.1.2. Options Interface

pSeven Core provides a general options interface (the methods of the Options class) for all tools, which may be used to setup a tool’s instance. For example, if configuring an instance of da.p7core.gtapprox.Builder (GTApprox model builder):

>>> from da.p7core import gtapprox
>>> builder = gtapprox.Builder()
>>> print builder.options
GTApprox/Accelerator                   : 1
GTApprox/AccuracyEvaluation            : 0
GTApprox/Componentwise                 : 0
... ...
>>> builder.options.info("GTApprox/Accelerator")
{'OptionDescription': {'Default': '1', 'Ranges': '[1, 5]', 'Type': 'unsigned', 'Name': 'GTApprox/Accelerator', 'Description': 'Five-position switch to control the trade-off between speed and accuracy. Possible values are from 1 (low speed, highest quality) to 5 (high speed, lower quality).'}}
>>> builder.options.get("GTApprox/Accelerator")
'1'
>>> builder.options.set("GTApprox/Accelerator", 5)
>>> builder.options.get("GTApprox/Accelerator")
'5'

Options may also be specified when calling the main processing method of the tool. Following the example above, it would be da.p7core.gtapprox.Builder.build() — see the options parameter in this method description. Option values specified by the options parameter override those set by da.p7core.Options.set(). For example, here the effective value of GTApprox/Accelerator is 3, not 5:

>>> builder.options.set("GTApprox/Accelerator", 5)
>>> new_options = {"GTApprox/Accelerator": 3}
>>> builder.build(x_sample, y_sample, options=new_options)

A few more general notes:

  • All option names are case-insensitive:

    >>> builder.options.get("GTAPPROX/accelerator")
    '5'
    
  • Option values are not validated by set() — see the method description for details.

  • Options imposing certain requirements (such as GTApprox/ExactFitRequired, GTApprox/LinearityRequired and others alike) only guarantee a specific behavior when the requirement is on. Setting the requirement off does not mean, in general, that the option will be interpreted as an opposite requirement. pSeven Core does not strictly specify the tool’s behavior in the latter case, and it may be changed without notice.

    For example, setting GTApprox/ExactFitRequired to True guarantees an exact-fitting model. On the contrary, setting it to False does not mean that GTApprox starts to prohibit the exact fit: it may still build an exact-fitting model though in general it is free not to do so.

  • Integer and float option values are accepted as strings:

    >>> builder.options.set("GTApprox/Accelerator", "5")
    
  • Boolean options, in addition to genuine Boolean values (True and False), also accept the following synonyms:

    • True synonyms: "true", "yes", "y", "on" (all strings are case-insensitive); any number that evaluates to True following the common Python rules; any numeric literal for such number (a string).
    • False synonyms: "false", "no", "n", "off" (all strings are case-insensitive); any number that evaluates to False following the common Python rules; any numeric literal for such number (a string).

11.1.3. Loggers

A logger is an object that handles log messages from some process (for example, model training).

Custom loggers are classes implemented by user; by default, pSeven Core provides only a simple StreamLogger implementation.

Every custom logger must implement CustomLogger.__call__():

CustomLogger.__call__(self, level, message)

Log message handler.

Parameters:
  • level (int) – log level
  • message (str) – log message
Returns:

user-defined

Log levels are enumerated by da.p7core.loggers.LogLevel.

Example:

class SimpleLogger(object):
  """Simple logger, just prints the received log message and log level."""

  def __call__(self, level, message):
    print '[%d]: %s' % (level, message)

11.1.4. Watchers

In pSeven Core a watcher is a callable object which receives messages from the process it is connected to, such as approximation model training (build(), build_smart()), design of experiments generation (build_doe()), or optimization problem solving (solve()). You can use a watcher to interrupt the watched process, monitor its progress, and get its intermediate results.

By default, pSeven Core provides only a placeholder DefaultWatcher implementation. To use the watcher features, implement your custom watcher and process the report argument it receives from the watched process.

CustomWatcher.__call__(report=None)

Monitoring and interrupt callback.

Parameters:report – data, messages, and state information from the watched process
Returns:interrupt flag
Return type:bool

This method should return True when you want the watched process to continue, or False when you want to interrupt.

Changed in version 6.11: in optimization, the report argument is used to get an intermediate result.

Changed in version 2024.02: intermediate result is fully supported in DoE.

Note

Use report only in this method’s scope. Attributes of report are references to non-persistent C objects, so referencing them out of the scope will lead to errors or obtaining invalid data.

When a watcher is connected to a GTOpt Solver or GTDoE Generator(), the received report contains a result update flag and can be used to obtain an intermediate result. For usage, see the Intermediate result example.

When interrupted by a watcher, solve() and build_doe() return an intermediate result when possible. You can read the result’s status to check whether the interrupt was received.

GTOpt and GTDoE also call the watcher once they have the final result ready, right before they return the result. That final call ignores the watcher’s return value (never interrupts), since the process is actually finished at the moment. In this final call, if you get the intermediate result through the watcher, it is the same object that the main process (GTOpt, GTDoE) returns.

When a watcher is connected to a GTApprox Builder (see gtapprox.Builder.set_watcher()), report is a dictionary that can contain any of the following (all keys are optional):

  • Training progress estimate (the "progress" key) — a float in range from 0 (just started) to 1 (completed).
  • Training details (the "training phase" key) — a dictionary with additional information about trained submodels.
  • If you run build_smart(), report also includes information on the current best model.

When interrupted by a watcher, Builder methods return an intermediate model when possible. Note that this model may miss certain features — for example, accuracy evaluation or internal validation may be not available even if they were required by your option settings. When it is not possible to return any model, these methods raise the UserTerminated exception on interrupt.

11.1.5. Status

The statuses described in this section are used by pSeven Core Generic Tools both internally and in the public interface. In particular, gtdoe.Result, and gtopt.Result have a status attribute. This attribute is a Status object — one of the statuses defined in the status module.

Statuses can be tested for equiality, for example:

>>> result1.status == result2.status  # True if both results have the same status
>>> from da.p7core import status
>>> result.status != status.NANINF_PROBLEM  # True if result status is not "NaN/Inf problem"

A status has integer and string representations:

>>> s = status.INFEASIBLE_PROBLEM
>>> print "'%s' status ID is: %d" % (s, s)
'Infeasible problem' status ID is: 2

Integer representation is the same as Status.id.

Note that due to Python’s peculiarities, a status compares to Boolean and numeric values:

>>> type(status.SUCCESS), status.SUCCESS.id
(da.p7core.status.Status, 0)
>>> status.SUCCESS == 0.0  # Do not use!
True
>>> status.SUCCESS == False  # Do not use!
True
>>> status.SUCCESS == True  # Do not use!
False
>>> result.status == status.SUCCESS  # Correct

This should be avoided. Compare a status with a status only; if you absolutely need a numeric comparison, use id.

11.1.6. License Usage

pSeven Core has a flexible licensing system where a license contains a pool of method-specific features. To users, this means that there is no need to get a full-featured license if you only use a few methods or solve problems of a certain type.

License features are requested when you create an object of a class that contains licensed methods. This object captures related features, if they are available, and holds them until destroyed. You can see which features were requested and captured using the general license information interface, for example:

>>> from da.p7core import gtopt  # no license requests
>>> solver = gtopt.Solver()  # requests features and captures them if available
>>> lic = solver.license.features()  # get feature info
>>> lic
{'DA_MACROS_GTOPT_MO': True,
 'DA_MACROS_GTOPT_RDO': False,
 'DA_MACROS_GTOPT_SO': True}
>>> lic.keys()  # all requested features
['DA_MACROS_GTOPT_SO', 'DA_MACROS_GTOPT_MO', 'DA_MACROS_GTOPT_RDO']
>>> [k for k in lic.keys() if lic[k]]  # only available (captured) features
['DA_MACROS_GTOPT_SO', 'DA_MACROS_GTOPT_MO']
>>> del(solver)  # releases features when the instance is garbage collected

Constructors do not test feature availability — for example, if the license is not available, you just get:

>>> solver = gtopt.Solver()  # assume no license; creating instance is yet allowed
>>> solver.license.features()  # shows no features found
{'DA_MACROS_GTOPT_MO': False,
 'DA_MACROS_GTOPT_RDO': False,
 'DA_MACROS_GTOPT_SO': False}

In the example above, feature availability would be tested only when you call solve():

>>> solver.solve(some_problem)  # raises exception since there is no license
LicenseError: License feature DA_MACROS_GTOPT_SO not found!

Changed in version 3.4: features are counted on a per-process (instead of per-object) basis.

Since version 3.4, feature use count increases only once for every process that captures a feature. Most importantly, this means that if you create multiple models in the same script, related features are counted once, despite every model captures these features. For example:

>>> from da.p7core import gtapprox
>>> builder = gtapprox.Builder()  # requests and captures the build feature
>>> m1 = builder.build(x1, f1)  # captures available model features, increases count
>>> m2 = builder.build(x2, f2)  # captures available model features, does not increase count

However, if the models are created by two different scripts running in parallel, each model increases the feature count.

Note

Simultaneously running a number of pSeven Core processes, which create many objects with licensed methods and request licenses from the same server, may sometimes cause license errors. See section License in Known Issues for details.

Tables below provide summary information on license features, related classes and methods.

GTApprox

Feature Required by
gtapprox.Builder.license
DA_MACROS_GTAPPROX_BUILD1 build() and build_smart()2 to train any model
gtapprox.Model.license
DA_MACROS_GTAPPROX_AE3 calc_ae() and grad_ae(); GTApproxModelCalcAE() and GTApproxModelGradAE(); GTApproxModel.calcAE() and GTApproxModel.calcGradAE()
DA_MACROS_GTAPPROX_CALC1 calc() and grad(); GTApproxModelCalc() and GTApproxModelGrad(); GTApproxModel.calc() and GTApproxModel.calcGrad()
DA_MACROS_GTAPPROX_EXPORT_C export_to() if format is C99_PROGRAM, C99_HEADER, or C99_SOURCE
DA_MACROS_GTAPPROX_EXPORT_CS export_to() if format is CSHARP_SOURCE
DA_MACROS_GTAPPROX_EXPORT_MEX export_to() if format is OCTAVE_MEX
DA_MACROS_GTAPPROX_EXPORT_OCT export_to() if format is OCTAVE
DA_MACROS_GTAPPROX_SMOOTH smooth(), smooth_anisotropic(), and smooth_errbased()

1 DA_MACROS_GTAPPROX_BUILD and DA_MACROS_GTAPPROX_CALC are also required by GTSDA Analyzer when you use a methods which train and evaluate a GTApprox model internally. These methods include:

2 build_smart() also requires the DA_MACROS_GTOPT_SO license feature (see GTOpt license features).

3 DA_MACROS_GTAPPROX_AE is also required by GTSDA Analyzer when you use any of the methods listed above and additionally set GTApprox/AccuracyEvaluation on, using the approx_options argument to rank() or select().

GTDF

Feature Required by
gtdf.Builder.license
DA_MACROS_GTDF_BUILD build() to train any model
gtdf.Model.license
DA_MACROS_GTDF_AE calc_ae()
DA_MACROS_GTDF_CALC calc() and grad()

GTDoE

Feature Required by
gtdoe.Generator.license
DA_MACROS_GTDOE_ADAPTIVE generate() and build_doe()1 for all adaptive generation techniques
DA_MACROS_GTDOE_GENERATE2 generate() and build_doe() for all space-filling generation techniques

1 build_doe() also requires GTOpt license features for the Adaptive Design technique (GTDoE/Technique set to "AdaptiveDesign"). This technique uses GTOpt internally in order to optimize the design point distribution, based on the design response evaluations received from a blackbox. Required GTOpt feature depends on the number of response functions (design outputs): DA_MACROS_GTOPT_SO if there is a single response only, and DA_MACROS_GTOPT_MO in the case of 2 or more responses.

2 DA_MACROS_GTDOE_GENERATE is also required by GTSDA Analyzer when you use rank() in the blackbox mode and specify a technique which performs initial sampling of the blackbox. These techniques include:

GTDR

Feature Required by
gtdr.Builder.license
DA_MACROS_GTDR_BUILD build() to train any model (codec)
gtdr.Model.license
DA_MACROS_GTDR_COMPRESS compress() and gradCompress()
DA_MACROS_GTDR_DECOMPRESS decompress() and gradDecompress()
DA_MACROS_GTDR_EXPORT_C compress_export_to() and decompress_export_to() if format is C99_PROGRAM, C99_HEADER, or C99_SOURCE
DA_MACROS_GTDR_EXPORT_MEX compress_export_to() and decompress_export_to() if format is OCTAVE_MEX
DA_MACROS_GTDR_EXPORT_OCT compress_export_to() and decompress_export_to() if format is OCTAVE

GTOpt

Feature Required by
gtopt.Solver.license
DA_MACROS_GTOPT_MO1 solve() for multi-objective problems (size_f() is 2 or more)
DA_MACROS_GTOPT_RDO solve() for robust optimization problems (size_s() is not 0);
DA_MACROS_GTOPT_SO1, 2 solve() for single-objective problems (size_f() is 1); does not limit the number of problem variables and constraints

1 GTOpt license features are also required by GTDoE Generator for the Adaptive Design technique. This technique uses GTOpt internally in order to optimize the design point distribution, based on the design response evaluations received from a blackbox. Required GTOpt feature depends on the number of response functions (design outputs): DA_MACROS_GTOPT_SO if there is a single response only, and DA_MACROS_GTOPT_MO in the case of 2 or more responses.

2 The DA_MACROS_GTOPT_SO feature is also required by GTApprox Builder for build_smart() (see Smart Training).

GTSDA

Feature Required by
gtsda.Analyzer.license
DA_MACROS_GTSDA_CHECK check()
DA_MACROS_GTSDA_RANK rank()1, 2
DA_MACROS_GTSDA_SELECT select()3

1 rank() also requires the following GTApprox license features when using a technique that trains and evaluates a GTApprox model internally:

2 rank() also requires the DA_MACROS_GTDOE_GENERATE feature when you use it in the blackbox mode and specify a technique which performs initial sampling of the blackbox. These techniques include:

3 select() also requires the following GTApprox license features:

  • DA_MACROS_GTAPPROX_BUILD and DA_MACROS_GTAPPROX_CALC — in all modes, and
  • DA_MACROS_GTAPPROX_AE if you additionally set GTApprox/AccuracyEvaluation on, using the approx_options argument.