Skip to main content

partialwrap: A small Python library providing wrappers for external executables and Python functions so that they can easily be partialised with Pythons functools.partial

Project description

partialwrap -- Wrappers of external executables and Python functions for functools.partial

A small Python library providing wrappers for external executables and Python functions so that they can easily be partialised with Python's functools.partial.

DOI PyPI version License Build Status Coverage Status Documentation Status

About partialwrap

partialwrap is a Python library providing easy wrapper functions to use with Python's functools.partial. It allows to use any external executable as well as any Python function with arbitrary arguments and keywords to be used with libraries that call functions simply in the form func(x). This includes the functions of the scipy.optimize package or external packages such as emcee or pyeee, and allows the use of distributed function evaluations with Python's multiprocessing or via MPI.

Documentation

The complete documentation for partialwrap is available from Read The Docs.

http://partialwrap.readthedocs.org/en/latest/

Quick usage guide

Context

The easiest wrapper in partialwrap is for Python functions.

Consider the Rastrigin function, which is a popular function for performance testing of optimization algorithms: y = a*n + sum_i^n(x_i^2 - a*cos(b*x_i))

    import numpy as np
    def rastrigin(x, a, b=2.*np.pi):
        return a*len(x) + np.sum(x**2 - a*np.cos(b*x))

The Rastrigin function has a global minimum of 0 at all x_i = 0. a influences mainly the depth of the (local and global) minima, whereas b influences mainly the size of the minima.

A common form uses a = 10 and b = 2*pi. The parameters x_i should then be in the interval [-5.12,5.12].

    import numpy as np
    def rastrigin1(x):
        return 10.*len(x) + np.sum(x**2 - 10.*np.cos(2.*np.pi*x))

One could use the scipy.optimize package to try to find the minimum of the Rastrigin function:

    import scipy.optimize as opt
    x0 = np.array([0.5, 0.5]) 
    res = opt.minimize(rastrigin1, x0, method='Nelder-Mead')
    print(res.x)
    # retruns: [0.99497463 0.99498333]
    res = opt.minimize(rastrigin1, x0, method='BFGS') 
    print(res.x)
    # returns: [-7.82960597e-09 -7.82960597e-09]

scipy.optimize allows passing arguments to the function to minimize. One could hence use the general Rastrigin function rastrigin (instead of rastrigin1) to get the same result:

    res = opt.minimize(rastrigin, x0, args=(10.), method='BFGS') 

Simple Python functions

Not all optimizers allow the passing of arguments. And notably scipy.optimize does not allow the passing of keyword arguments. One can use partial of Python's functools in this case:

    from functools import partial

    def call_func_arg_kwarg(func, a, b, x):
       return func(x, a, b=b)

    # Partialise function with fixed parameters
    a = 5.
    b = 4.*np.pi
    partial_rastrigin = partial(call_func_arg_kwarg, rastrigin, a, b)

    res = opt.minimize(partial_rastrigin, x0, method='BFGS')

Figuratively speaking, partial passes a and b to the function call_func_arg_kwarg already during definition. minimize can then simply calls it as partial_rastrigin(x), which finalizes the call to rastrigin(x, a, b=b).

partialwrap provides a convenience function function_wrapper passing all arguments, given as a list, and keyword arguments, given as a dictionary, to arbitrary functions:

    from partialwrap import function_wrapper

    args   = [20.]
    kwargs = {'b': 1.*np.pi}
    rastra = partial(function_wrapper, rastrigin, args, kwargs)

    res = opt.minimize(rastra, x0, method='BFGS')

Masking parameters

A common case in numerical optimization are bound parameters and specifically the exclusion of some well-known or correlated parameters from optimization. partialwrap provides a convenience function function_mask_wrapper to include only the masked parameters in the function evaluation:

    from partialwrap import function_mask_wrapper

    x0      = np.array([0.5,  0.0001, 0.5])
    mask    = np.array([True, False,  True])
    mrastra = partial(function_mask_wrapper, rastrigin, x0, mask, args, kwargs)

    res        = opt.minimize(mrastra, x0[mask], method='BFGS')
    xout       = x0.copy()
    xout[mask] = res.x

The values of x0 will be taken where mask==False.

External executables

partialwrap provides wrapper functions to work with external executables: partialwrap.exe_wrapper and partialwrap.exe_mask_wrapper.

partialwrap writes the sampled parameter sets into files that can be read by the external program. The program writes its result to a file that will then be read by partialwrap in return. This means partialwrap needs to have a function parameterwriter that writes the parameter file parameterfile needed by the executable exe. It then needs to have a function outputreader for reading the output file outputfile of the external executable exe.

Consider for simplicity an external Python program (e.g. rastrigin1.py) that calculates the Rastrigin function with a = 10 and b = 2*pi, reading in an arbitrary number of parameters x_i from a parameterfile = params.txt and writing its output into an outputfile = out.txt:

    # File: rastrigin1.py

    # Rastrigin function a=10, b=2*pi
    import numpy as np
    def rastrigin1(x):
        return 10.*len(x) + np.sum(x**2 - 10.*np.cos(2.*np.pi*x))

    # read parameters
    from partialwrap import standard_parameter_reader
    x = standard_parameter_reader('params.txt')

    # calc function
    y = rastrigin1(x)

    # write output file
    with open('out.txt', 'w') as ff:
        print(y, file=ff)

This program can be called on the command line with:

    python rastrigin1.py

The external program can be used with Python's functools.partial and the wrapper function partialwrap.exe_wrapper:

    from functools import partial
    from partialwrap import exe_wrapper, standard_parameter_writer, standard_output_reader
	
    rastrigin_exe  = ['python3', 'rastrigin1.py']
    parameterfile  = 'params.txt'
    outputfile     = 'out.txt'
    rastrigin_wrap = partial(exe_wrapper, rastrigin_exe,
                             parameterfile, standard_parameter_writer,
                             outputfile, standard_output_reader, {})

    x0  = [0.1, 0.2, 0.3]
    res = opt.minimize(rastrigin_wrap, x0, method='BFGS')

partialwrap.standard_parameter_reader and partialwrap.standard_parameter_writer are convenience functions that read and write one parameter per line in a file without a header. The function partialwrap.standard_output_reader simply reads one value from a file without header. The empty dictionary at the end is explained in the userguide.

One can easily imagine to replace the Python program rastrigin1.py by any compiled executable from C, Fortran or alike. See the userguide for details.

Installation

The easiest way to install is via pip:

    pip install partialwrap

See the installation instructions in the documentation for more information.

Requirements:

License

partialwrap is distributed under the MIT License.
See the LICENSE file for details.

Copyright (c) 2016-2021 Matthias Cuntz

The project structure is based on a template provided by Sebastian Müller.

Contributing to partialwrap

Users are welcome to submit bug reports, feature requests, and code contributions to this project through GitHub.

More information is available in the Contributing guidelines.

Download files

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

Source Distribution

partialwrap-1.7.tar.gz (26.9 kB view details)

Uploaded Source

Built Distribution

partialwrap-1.7-py3-none-any.whl (18.4 kB view details)

Uploaded Python 3

File details

Details for the file partialwrap-1.7.tar.gz.

File metadata

  • Download URL: partialwrap-1.7.tar.gz
  • Upload date:
  • Size: 26.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.9.13

File hashes

Hashes for partialwrap-1.7.tar.gz
Algorithm Hash digest
SHA256 2840d4890aa98f992ad96bfd27713c7095e943670f12499eb4d3be5d80e5cd97
MD5 11d72f4511504c0ba4ae86f4ede367a3
BLAKE2b-256 31faaeb2582f9f4fed29e5cbdb2ecf292f9881fcbddfacacd3e3177800fb3c25

See more details on using hashes here.

File details

Details for the file partialwrap-1.7-py3-none-any.whl.

File metadata

  • Download URL: partialwrap-1.7-py3-none-any.whl
  • Upload date:
  • Size: 18.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.9.13

File hashes

Hashes for partialwrap-1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 75e6f7506659aee33caf864f19db71de7b015fd045a15945bdbb080283a63304
MD5 c3f18242504ae5eecfbddf73f1672d80
BLAKE2b-256 d5c5e0e35d82fbed01be968a535f6691972e90b008749f6213203f54c1615896

See more details on using hashes here.

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