Skip to main content

Optimize both discrete and continuous variables using just a continuous optimizer such as scipy.optimize

Project description

wrapdisc

wrapdisc is a Python 3.10 package to wrap a discrete optimization objective such that it can be optimized by a continuous optimizer such as scipy.optimize. It maps the discrete variables into a continuous space, and uses an in-memory cache over the discrete space. Both discrete and continuous variables are supported, and are motivated by Ray Tune's search spaces.

cicd badge

Limitations

The current implementation has these limitations:

  • Additional fixed parameters needed by the objective function are not supported.
  • The wrapped objective function cannot be pickled, and so multiple workers cannot be used for optimization.
  • An unbounded in-memory cache is used over the original objective function, imposing a memory requirement.

Links

Caption Link
Repo https://github.com/impredicative/wrapdisc/
Changelog https://github.com/impredicative/wrapdisc/releases
Package https://pypi.org/project/wrapdisc/

Installation

Python ≥3.10 is required. To install, run:

pip install wrapdisc

Variables

The following classes of variables are available:

Space Usage Description Examples
Discrete ChoiceVar(items) Unordered categorical • fn(["USA", "Panama", "Cayman"])
Discrete GridVar(values) Ordinal (ordered categorical) • fn([2, 4, 8, 16])
• fn(["good", "better", "best"])
Discrete RandintVar(lower, upper) Integer from lower to upper, both inclusive • fn(0, 6)
• fn(3, 9)
• fn(-10, 10)
Discrete QrandintVar(lower, upper, q) Quantized integer from lower to upper in multiples of q • fn(0, 12, 3)
• fn(1, 10, 2)
• fn(-10, 10, 4)
Continuous UniformVar(lower, upper) Float from lower to upper • fn(0.0, 5.11)
• fn(0.2, 4.6)
• fn(-10.0, 10.0)
Continuous QuniformVar(lower, upper, q) Quantized float from lower to upper in multiples of q • fn(0.0, 5.1, 0.3)
• fn(-5.1, -0.2, 0.3)

Usage

Example:

import operator

import scipy.optimize

from wrapdisc import Objective
from wrapdisc.var import ChoiceVar, GridVar, QrandintVar, QuniformVar, RandintVar, UniformVar

def your_mixed_optimization_objective(x: tuple) -> float:
    return float(sum(x_i if isinstance(x_i, (int, float)) else len(str(x_i)) for x_i in x))

wrapped_objective = Objective(
            your_mixed_optimization_objective,
            [
                ChoiceVar(["foobar", "baz"]),
                ChoiceVar([operator.index, abs, operator.invert]),
                GridVar([0.01, 0.1, 1, 10, 100]),
                GridVar(["disagreed", "neutral", "agreed"]),
                RandintVar(-8, 10),
                QrandintVar(1, 10, 2),
                UniformVar(1.2, 3.4),
                QuniformVar(-11.1, 9.99, 0.22),
            ],
        )

result = scipy.optimize.differential_evolution(wrapped_objective, wrapped_objective.bounds, seed=0)
encoded_solution = result.x
decoded_solution = wrapped_objective[encoded_solution]
assert result.fun == wrapped_objective(encoded_solution)
assert result.fun == your_mixed_optimization_objective(decoded_solution)

Output:

>>> wrapped_objective.bounds
((0.0, 1.0), (0.0, 1.0), (0.0, 1.0), (0.0, 1.0), (0.0, 1.0), (-0.49999999999999994, 4.499999999999999), (-0.49999999999999994, 2.4999999999999996), (-8.499999999999998, 10.499999999999998), (1.0000000000000002, 10.999999999999998), (1.2, 3.4), (-11.109999999999998, 10.009999999999998))
>>> result
     fun: 16.210000000000004
     jac: array([0.        , 0.        , 0.        , 0.        , 0.        ,
       0.        , 0.        , 0.        , 0.        , 1.00000009,
       0.        ])
 message: 'Optimization terminated successfully.'
    nfev: 7284
     nit: 43
 success: True
       x: array([  0.29493233,   0.88254257,   0.12721268,   0.48978776,
         0.39078759,  -0.04540115,   1.87464003,  -8.02943494,
         1.02999311,   1.2       , -10.98560722])

>>> decoded_solution
('baz', <built-in function abs>, 0.01, 'agreed', -8, 2, 1.2, -11.0)
>>> your_mixed_optimization_objective(decoded_solution)
16.210000000000004

>>> wrapped_objective.cache_info
CacheInfo(hits=217, misses=7067, maxsize=None, currsize=7067)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wrapdisc-1.0.2.tar.gz (21.4 kB view hashes)

Uploaded Source

Built Distribution

wrapdisc-1.0.2-py3-none-any.whl (20.5 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page