Quickstart#

partialwrap: a small Python library providing wrappers for external executables to be used easily with Python’s functools.partial().

DOI PyPI version Conda version License Build Status Coverage Status

About partialwrap#

partialwrap is a Python library providing easy wrapper functions to use with Python’s functools.partial(). Partial’s ingenious mechanism allows to use even very complex functions with many arguments and keyword arguments with routines that need functions in the simple form func(x). This includes Python’s map() function, the minimizers in scipy.optimize, and plenty of third-party modules such as emcee or pyeee. partialwrap allows to use any external executable as well as any Python function with arbitrary arguments and keywords to be used with functools.partial(). It also allows to use the executables or functions with easy parallelization of code with, for example, the parallel map function of the multiprocessing module or via the Message Passing Interface (MPI) mpi4py.

Quick usage guide#

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

partialwrap writes the input arguments to the wrapper functions into files that can be read by the external executable. The executable should write 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 in the form needed by the executable exe. It then also needs to have a function outputreader for reading the output file outputfile of the external executable, perhaps calculating an objective function value.

Take the Rastrigin function (https://en.wikipedia.org/wiki/Rastrigin_function), which is a popular function for performance testing of optimization algorithms: \(y = a \cdot n + \sum_i^n (x_i^2 - a \cos(b \cdot x_i))\). It 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]\).

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
import numpy as np
from partialwrap import standard_parameter_reader

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

# read parameters
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 (if params.txt is present) with:

python3 rastrigin1.py

The external program calculating the Rastrigin function could, of course, also be written in any compiled language such as C or Fortran. See the User Guide for details. The external program, here the Python version, can be used with Python’s functools.partial() and the wrapper function exe_wrapper():

import scipy.optimize as opt
from functools import partial
from partialwrap import exe_wrapper
from partialwrap import standard_parameter_writer, standard_output_reader

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

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

The scipy.optimize function minimize() passes its sampled parameters to exe_wrapper, which writes it to the file parameterfile = ‘params.txt’. It then calls rastrigin_exe = ‘python3 rastrigin1.py’ and reads its outputfile = ‘out.txt’. standard_parameter_reader() and standard_parameter_writer() are convenience functions that read and write one parameter per line in a file without a header. The empty dictionary at the end is explained in the User Guide.

More elaborate input/output of the external program can simply be done by replacing standard_parameter_reader() and standard_parameter_writer() with appropriate functions, while the rest stays pretty much the same.

Installation#

The easiest way to install is via pip:

pip install partialwrap

or via conda:

conda install -c conda-forge partialwrap

Requirements#

License#

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

Copyright (c) 2016-2023 Matthias Cuntz

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

Index and Tables#