From c99e4de754b9d83bd1b7d480c4f828c1a409b227 Mon Sep 17 00:00:00 2001 From: Mavo <matthias.volk@rwth-aachen.de> Date: Wed, 25 May 2016 18:58:06 +0200 Subject: [PATCH] Updated pybind11 Former-commit-id: 67536bae0529efc652f07e0422bd4f6ca7b0e288 --- stormpy/resources/pybind11/.travis.yml | 1 + stormpy/resources/pybind11/CMakeLists.txt | 47 +- stormpy/resources/pybind11/LICENSE | 2 +- stormpy/resources/pybind11/README.md | 3 + .../resources/pybind11/conda.recipe/bld.bat | 2 - .../resources/pybind11/conda.recipe/build.sh | 3 - .../resources/pybind11/conda.recipe/meta.yaml | 26 - .../pybind11/docs/_static/theme_overrides.css | 4 + stormpy/resources/pybind11/docs/advanced.rst | 553 +++++++++++++----- stormpy/resources/pybind11/docs/basics.rst | 110 ++-- stormpy/resources/pybind11/docs/benchmark.rst | 17 +- stormpy/resources/pybind11/docs/changelog.rst | 46 +- .../docs/{cmake.rst => compiling.rst} | 56 +- stormpy/resources/pybind11/docs/conf.py | 6 +- stormpy/resources/pybind11/docs/faq.rst | 154 ++++- stormpy/resources/pybind11/docs/index.rst | 10 +- .../docs/pybind11_vs_boost_python1.png | Bin 0 -> 44653 bytes .../docs/pybind11_vs_boost_python2.png | Bin 0 -> 41121 bytes stormpy/resources/pybind11/docs/release.rst | 20 +- stormpy/resources/pybind11/example/eigen.cpp | 73 +++ stormpy/resources/pybind11/example/eigen.py | 44 ++ stormpy/resources/pybind11/example/eigen.ref | 18 + .../resources/pybind11/example/example.cpp | 12 +- .../resources/pybind11/example/example1.cpp | 2 +- .../resources/pybind11/example/example1.ref | 4 +- .../resources/pybind11/example/example10.cpp | 7 +- .../resources/pybind11/example/example10.py | 5 + .../resources/pybind11/example/example10.ref | 3 + .../resources/pybind11/example/example11.cpp | 27 +- .../resources/pybind11/example/example11.py | 10 +- .../resources/pybind11/example/example11.ref | 10 +- .../resources/pybind11/example/example12.cpp | 18 +- .../resources/pybind11/example/example12.ref | 2 +- .../resources/pybind11/example/example13.cpp | 2 +- .../resources/pybind11/example/example14.cpp | 50 +- .../resources/pybind11/example/example14.py | 28 +- .../resources/pybind11/example/example14.ref | 24 +- .../resources/pybind11/example/example15.cpp | 2 +- .../resources/pybind11/example/example15.py | 2 +- .../resources/pybind11/example/example16.cpp | 2 +- .../resources/pybind11/example/example17.cpp | 36 ++ .../resources/pybind11/example/example17.py | 40 ++ .../resources/pybind11/example/example17.ref | 10 + .../resources/pybind11/example/example2.cpp | 2 +- .../resources/pybind11/example/example3.cpp | 2 +- .../resources/pybind11/example/example3.ref | 20 +- .../resources/pybind11/example/example4.cpp | 2 +- .../resources/pybind11/example/example5.cpp | 6 +- .../resources/pybind11/example/example5.ref | 2 +- .../resources/pybind11/example/example6.cpp | 2 +- .../resources/pybind11/example/example6.ref | 6 +- .../resources/pybind11/example/example7.cpp | 16 +- .../resources/pybind11/example/example8.cpp | 2 +- .../resources/pybind11/example/example9.cpp | 2 +- stormpy/resources/pybind11/example/issues.cpp | 108 +++- stormpy/resources/pybind11/example/issues.py | 29 + stormpy/resources/pybind11/example/issues.ref | 12 +- .../pybind11/include/pybind11/attr.h | 19 +- .../pybind11/include/pybind11/cast.h | 263 ++++++--- .../pybind11/include/pybind11/common.h | 146 +++-- .../pybind11/include/pybind11/complex.h | 4 +- .../pybind11/include/pybind11/descr.h | 2 +- .../pybind11/include/pybind11/eigen.h | 281 +++++++++ .../pybind11/include/pybind11/functional.h | 8 +- .../pybind11/include/pybind11/numpy.h | 70 ++- .../pybind11/include/pybind11/operators.h | 2 +- .../pybind11/include/pybind11/pybind11.h | 335 +++++++---- .../pybind11/include/pybind11/pytypes.h | 174 ++++-- .../resources/pybind11/include/pybind11/stl.h | 4 +- .../pybind11/include/pybind11/stl_bind.h | 349 +++++++++++ .../pybind11/include/pybind11/typeid.h | 2 +- .../resources/pybind11/pybind11/__init__.py | 4 +- .../resources/pybind11/pybind11/_version.py | 2 +- stormpy/resources/pybind11/setup.py | 4 +- .../resources/pybind11/tools/FindEigen3.cmake | 81 +++ stormpy/resources/pybind11/tools/mkdoc.py | 200 ++++--- 76 files changed, 2863 insertions(+), 789 deletions(-) delete mode 100644 stormpy/resources/pybind11/conda.recipe/bld.bat delete mode 100644 stormpy/resources/pybind11/conda.recipe/build.sh delete mode 100644 stormpy/resources/pybind11/conda.recipe/meta.yaml rename stormpy/resources/pybind11/docs/{cmake.rst => compiling.rst} (71%) create mode 100644 stormpy/resources/pybind11/docs/pybind11_vs_boost_python1.png create mode 100644 stormpy/resources/pybind11/docs/pybind11_vs_boost_python2.png create mode 100644 stormpy/resources/pybind11/example/eigen.cpp create mode 100644 stormpy/resources/pybind11/example/eigen.py create mode 100644 stormpy/resources/pybind11/example/eigen.ref create mode 100644 stormpy/resources/pybind11/example/example17.cpp create mode 100644 stormpy/resources/pybind11/example/example17.py create mode 100644 stormpy/resources/pybind11/example/example17.ref create mode 100644 stormpy/resources/pybind11/include/pybind11/eigen.h create mode 100644 stormpy/resources/pybind11/include/pybind11/stl_bind.h create mode 100644 stormpy/resources/pybind11/tools/FindEigen3.cmake diff --git a/stormpy/resources/pybind11/.travis.yml b/stormpy/resources/pybind11/.travis.yml index 9a9088fa8..e52319742 100644 --- a/stormpy/resources/pybind11/.travis.yml +++ b/stormpy/resources/pybind11/.travis.yml @@ -3,6 +3,7 @@ sudo: false cache: directories: - $HOME/.cache/pip + - ccache addons: apt: sources: diff --git a/stormpy/resources/pybind11/CMakeLists.txt b/stormpy/resources/pybind11/CMakeLists.txt index 2996e537b..3f10bd375 100644 --- a/stormpy/resources/pybind11/CMakeLists.txt +++ b/stormpy/resources/pybind11/CMakeLists.txt @@ -28,7 +28,7 @@ string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7) if (NOT ${PYBIND11_PYTHON_VERSION} STREQUAL "") find_package(PythonLibs ${PYBIND11_PYTHON_VERSION} EXACT) - if (NOT PythonLibs_FOUND) + if (NOT PYTHONLIBS_FOUND) find_package(PythonLibs ${PYBIND11_PYTHON_VERSION} REQUIRED) endif() else() @@ -84,24 +84,31 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR "${CMAKE_CXX_COMPILER_ID}" set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") endif() -# Include path for Python header files -include_directories(${PYTHON_INCLUDE_DIR}) + +# Check if Eigen is available +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tools") +find_package(Eigen3 QUIET) # Include path for pybind11 header files include_directories(include) +# Include path for Python header files +include_directories(${PYTHON_INCLUDE_DIR}) + set(PYBIND11_HEADERS include/pybind11/attr.h include/pybind11/cast.h include/pybind11/common.h include/pybind11/complex.h include/pybind11/descr.h + include/pybind11/eigen.h include/pybind11/functional.h include/pybind11/numpy.h include/pybind11/operators.h include/pybind11/pybind11.h include/pybind11/pytypes.h include/pybind11/stl.h + include/pybind11/stl_bind.h include/pybind11/typeid.h ) @@ -122,9 +129,19 @@ set(PYBIND11_EXAMPLES example/example14.cpp example/example15.cpp example/example16.cpp + example/example17.cpp example/issues.cpp ) +if (EIGEN3_FOUND) + include_directories(${EIGEN3_INCLUDE_DIR}) + list(APPEND PYBIND11_EXAMPLES example/eigen.cpp) + add_definitions(-DPYBIND11_TEST_EIGEN) + message(STATUS "Building Eigen testcase") +else() + message(STATUS "NOT Building Eigen testcase") +endif() + # Create the binding library add_library(example SHARED ${PYBIND11_HEADERS} @@ -148,17 +165,19 @@ endforeach() if (WIN32) if (MSVC) - # /bigobj is needed for bigger binding projects due to the limit to 64k - # addressable sections. /MP enables multithreaded builds (relevant when - # there are many files). - set_target_properties(example PROPERTIES COMPILE_FLAGS "/MP /bigobj ") - - if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) - # Enforce size-based optimization and link time code generation on MSVC - # (~30% smaller binaries in experiments). - set_target_properties(example APPEND_STRING PROPERTY COMPILE_FLAGS "/Os /GL ") - set_target_properties(example APPEND_STRING PROPERTY LINK_FLAGS "/LTCG ") - endif() + # /MP enables multithreaded builds (relevant when there are many files), /bigobj is + # needed for bigger binding projects due to the limit to 64k addressable sections + set_property(TARGET example APPEND PROPERTY COMPILE_OPTIONS /MP /bigobj) + # Enforce size-based optimization and link time code generation on MSVC + # (~30% smaller binaries in experiments); do nothing in debug mode. + set_property(TARGET example APPEND PROPERTY COMPILE_OPTIONS + "$<$<CONFIG:Release>:/Os>" "$<$<CONFIG:Release>:/GL>" + "$<$<CONFIG:MinSizeRel>:/Os>" "$<$<CONFIG:MinSizeRel>:/GL>" + "$<$<CONFIG:RelWithDebInfo>:/Os>" "$<$<CONFIG:RelWithDebInfo>:/GL>" + ) + set_property(TARGET example APPEND_STRING PROPERTY LINK_FLAGS_RELEASE "/LTCG ") + set_property(TARGET example APPEND_STRING PROPERTY LINK_FLAGS_MINSIZEREL "/LTCG ") + set_property(TARGET example APPEND_STRING PROPERTY LINK_FLAGS_RELWITHDEBINFO "/LTCG ") endif() # .PYD file extension on Windows diff --git a/stormpy/resources/pybind11/LICENSE b/stormpy/resources/pybind11/LICENSE index d134ff5bc..ccf4e9787 100644 --- a/stormpy/resources/pybind11/LICENSE +++ b/stormpy/resources/pybind11/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>, All rights reserved. +Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/stormpy/resources/pybind11/README.md b/stormpy/resources/pybind11/README.md index baefb2baf..376f56295 100644 --- a/stormpy/resources/pybind11/README.md +++ b/stormpy/resources/pybind11/README.md @@ -32,6 +32,8 @@ simpler binding code in many common situations. Tutorial and reference documentation is provided at [http://pybind11.readthedocs.org/en/latest](http://pybind11.readthedocs.org/en/latest). +A PDF version of the manual is available +[here](https://media.readthedocs.org/pdf/pybind11/latest/pybind11.pdf). ## Core features pybind11 can map the following core C++ features to Python @@ -97,6 +99,7 @@ Jonas Adler, Sylvain Corlay, Axel Huebl, @hulucc, +Sergey Lyskov Johan Mabille, Tomasz Miąsko, and Ben Pritchard. diff --git a/stormpy/resources/pybind11/conda.recipe/bld.bat b/stormpy/resources/pybind11/conda.recipe/bld.bat deleted file mode 100644 index b9cd616ce..000000000 --- a/stormpy/resources/pybind11/conda.recipe/bld.bat +++ /dev/null @@ -1,2 +0,0 @@ -"%PYTHON%" setup.py install --single-version-externally-managed --record=record.txt -if errorlevel 1 exit 1 diff --git a/stormpy/resources/pybind11/conda.recipe/build.sh b/stormpy/resources/pybind11/conda.recipe/build.sh deleted file mode 100644 index 175d6f16e..000000000 --- a/stormpy/resources/pybind11/conda.recipe/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -${PYTHON} setup.py install --single-version-externally-managed --record=record.txt; - diff --git a/stormpy/resources/pybind11/conda.recipe/meta.yaml b/stormpy/resources/pybind11/conda.recipe/meta.yaml deleted file mode 100644 index fbbb830b7..000000000 --- a/stormpy/resources/pybind11/conda.recipe/meta.yaml +++ /dev/null @@ -1,26 +0,0 @@ -package: - name: pybind11 - version: {{ environ.get('GIT_DESCRIBE_TAG', '').replace('v', '') }} - -build: - number: {{ environ.get('GIT_DESCRIBE_NUMBER', 0) }} - {% if environ.get('GIT_DESCRIBE_NUMBER', '0') == '0' %}string: py{{ environ.get('PY_VER').replace('.', '') }}_0 - {% else %}string: py{{ environ.get('PY_VER').replace('.', '') }}_{{ environ.get('GIT_BUILD_STR', 'GIT_STUB') }}{% endif %} - -source: - git_url: ../ - -requirements: - build: - - python - - run: - - python - -test: - imports: - - pybind11 - -about: - home: https://github.com/pybind/pybind11/ - summary: Seamless operability between C++11 and Python diff --git a/stormpy/resources/pybind11/docs/_static/theme_overrides.css b/stormpy/resources/pybind11/docs/_static/theme_overrides.css index f678ab548..1071809fa 100644 --- a/stormpy/resources/pybind11/docs/_static/theme_overrides.css +++ b/stormpy/resources/pybind11/docs/_static/theme_overrides.css @@ -5,3 +5,7 @@ .rst-content table.docutils td { vertical-align: top !important; } +div[class^='highlight'] pre { + white-space: pre; + white-space: pre-wrap; +} diff --git a/stormpy/resources/pybind11/docs/advanced.rst b/stormpy/resources/pybind11/docs/advanced.rst index 9df5cb3fe..032cf8593 100644 --- a/stormpy/resources/pybind11/docs/advanced.rst +++ b/stormpy/resources/pybind11/docs/advanced.rst @@ -41,15 +41,18 @@ in C++. public: Vector2(float x, float y) : x(x), y(y) { } - std::string toString() const { return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; } - Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); } Vector2 operator*(float value) const { return Vector2(x * value, y * value); } Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; } Vector2& operator*=(float v) { x *= v; y *= v; return *this; } - friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); } + friend Vector2 operator*(float f, const Vector2 &v) { + return Vector2(f * v.x, f * v.y); + } + std::string toString() const { + return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; + } private: float x, y; }; @@ -265,8 +268,14 @@ helper class that is defined as follows: The macro :func:`PYBIND11_OVERLOAD_PURE` should be used for pure virtual functions, and :func:`PYBIND11_OVERLOAD` should be used for functions which have -a default implementation. The binding code also needs a few minor adaptations -(highlighted): +a default implementation. + +There are also two alternate macros :func:`PYBIND11_OVERLOAD_PURE_NAME` and +:func:`PYBIND11_OVERLOAD_NAME` which take a string-valued name argument +after the *Name of the function* slot. This is useful when the C++ and Python +versions of the function have different names, e.g. ``operator()`` vs ``__call__``. + +The binding code also needs a few minor adaptations (highlighted): .. code-block:: cpp :emphasize-lines: 4,6,7 @@ -310,6 +319,15 @@ a virtual method call. >>> call_go(c) u'meow! meow! meow! ' +.. warning:: + + Both :func:`PYBIND11_OVERLOAD` and :func:`PYBIND11_OVERLOAD_PURE` are + macros, which means that they can get confused by commas in a template + argument such as ``PYBIND11_OVERLOAD(MyReturnValue<T1, T2>, myFunc)``. In + this case, the preprocessor assumes that the comma indicates the beginnning + of the next parameter. Use a ``typedef`` to bind the template to another + name and use it in the macro to avoid this problem. + .. seealso:: The file :file:`example/example12.cpp` contains a complete example that @@ -411,39 +429,52 @@ For this reason, pybind11 provides a several `return value policy` annotations that can be passed to the :func:`module::def` and :func:`class_::def` functions. The default policy is :enum:`return_value_policy::automatic`. - -+--------------------------------------------------+---------------------------------------------------------------------------+ -| Return value policy | Description | -+==================================================+===========================================================================+ -| :enum:`return_value_policy::automatic` | Automatic: copy objects returned as values and take ownership of | -| | objects returned as pointers | -+--------------------------------------------------+---------------------------------------------------------------------------+ -| :enum:`return_value_policy::automatic_reference` | Automatic variant 2 : copy objects returned as values and reference | -| | objects returned as pointers | -+--------------------------------------------------+---------------------------------------------------------------------------+ -| :enum:`return_value_policy::copy` | Create a new copy of the returned object, which will be owned by Python | -+--------------------------------------------------+---------------------------------------------------------------------------+ -| :enum:`return_value_policy::take_ownership` | Reference the existing object and take ownership. Python will call | -| | the destructor and delete operator when the reference count reaches zero | -+--------------------------------------------------+---------------------------------------------------------------------------+ -| :enum:`return_value_policy::reference` | Reference the object, but do not take ownership and defer responsibility | -| | for deleting it to C++ (dangerous when C++ code at some point decides to | -| | delete it while Python still has a nonzero reference count) | -+--------------------------------------------------+---------------------------------------------------------------------------+ -| :enum:`return_value_policy::reference_internal` | Reference the object, but do not take ownership. The object is considered | -| | be owned by the C++ instance whose method or property returned it. The | -| | Python object will increase the reference count of this 'parent' by 1 | -| | to ensure that it won't be deallocated while Python is using the 'child' | -+--------------------------------------------------+---------------------------------------------------------------------------+ - -.. warning:: - - Code with invalid call policies might access unitialized memory and free - data structures multiple times, which can lead to hard-to-debug - non-determinism and segmentation faults, hence it is worth spending the - time to understand all the different options above. - -See below for an example that uses the +.. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}| + ++--------------------------------------------------+----------------------------------------------------------------------------+ +| Return value policy | Description | ++==================================================+============================================================================+ +| :enum:`return_value_policy::automatic` | This is the default return value policy, which falls back to the policy | +| | :enum:`return_value_policy::take_ownership` when the return value is a | +| | pointer. Otherwise, it uses :enum:`return_value::move` or | +| | :enum:`return_value::copy` for rvalue and lvalue references, respectively. | +| | See below for a description of what all of these different policies do. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::automatic_reference` | As above, but use policy :enum:`return_value_policy::reference` when the | +| | return value is a pointer. You probably won't need to use this. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::take_ownership` | Reference an existing object (i.e. do not create a new copy) and take | +| | ownership. Python will call the destructor and delete operator when the | +| | object's reference count reaches zero. Undefined behavior ensues when the | +| | C++ side does the same.. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::copy` | Create a new copy of the returned object, which will be owned by Python. | +| | This policy is comparably safe because the lifetimes of the two instances | +| | are decoupled. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::move` | Use ``std::move`` to move the return value contents into a new instance | +| | that will be owned by Python. This policy is comparably safe because the | +| | lifetimes of the two instances (move source and destination) are decoupled.| ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::reference` | Reference an existing object, but do not take ownership. The C++ side is | +| | responsible for managing the object's lifetime and deallocating it when | +| | it is no longer used. Warning: undefined behavior will ensue when the C++ | +| | side deletes an object that is still referenced and used by Python. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::reference_internal` | This policy only applies to methods and properties. It references the | +| | object without taking ownership similar to the above | +| | :enum:`return_value_policy::reference` policy. In contrast to that policy, | +| | the function or property's implicit ``this`` argument (called the *parent*)| +| | is considered to be the the owner of the return value (the *child*). | +| | pybind11 then couples the lifetime of the parent to the child via a | +| | reference relationship that ensures that the parent cannot be garbage | +| | collected while Python is still using the child. More advanced variations | +| | of this scheme are also possible using combinations of | +| | :enum:`return_value_policy::reference` and the :class:`keep_alive` call | +| | policy described next. | ++--------------------------------------------------+----------------------------------------------------------------------------+ + +The following example snippet shows a use case of the :enum:`return_value_policy::reference_internal` policy. .. code-block:: cpp @@ -460,11 +491,36 @@ See below for an example that uses the py::class_<Example>(m, "Example") .def(py::init<>()) - .def("get_internal", &Example::get_internal, "Return the internal data", py::return_value_policy::reference_internal); + .def("get_internal", &Example::get_internal, "Return the internal data", + py::return_value_policy::reference_internal); return m.ptr(); } +.. warning:: + + Code with invalid call policies might access unitialized memory or free + data structures multiple times, which can lead to hard-to-debug + non-determinism and segmentation faults, hence it is worth spending the + time to understand all the different options in the table above. + +.. note:: + + The next section on :ref:`call_policies` discusses *call policies* that can be + specified *in addition* to a return value policy from the list above. Call + policies indicate reference relationships that can involve both return values + and parameters of functions. + +.. note:: + + As an alternative to elaborate call policies and lifetime management logic, + consider using smart pointers (see the section on :ref:`smart_pointers` for + details). Smart pointers can tell whether an object is still referenced from + C++ or Python, which generally eliminates the kinds of inconsistencies that + can lead to crashes or undefined behavior. For functions returning smart + pointers, it is not necessary to specify a return value policy. + +.. _call_policies: Additional call policies ======================== @@ -474,12 +530,13 @@ specified to indicate dependencies between parameters. There is currently just one policy named ``keep_alive<Nurse, Patient>``, which indicates that the argument with index ``Patient`` should be kept alive at least until the argument with index ``Nurse`` is freed by the garbage collector; argument -indices start at one, while zero refers to the return value. Arbitrarily many -call policies can be specified. +indices start at one, while zero refers to the return value. For methods, index +one refers to the implicit ``this`` pointer, while regular arguments begin at +index two. Arbitrarily many call policies can be specified. -For instance, binding code for a a list append operation that ties the lifetime -of the newly added element to the underlying container might be declared as -follows: +Consider the following example: the binding code for a list append operation +that ties the lifetime of the newly added element to the underlying container +might be declared as follows: .. code-block:: cpp @@ -501,7 +558,7 @@ Implicit type conversions ========================= Suppose that instances of two types ``A`` and ``B`` are used in a project, and -that an ``A`` can easily be converted into a an instance of type ``B`` (examples of this +that an ``A`` can easily be converted into an instance of type ``B`` (examples of this could be a fixed and an arbitrary precision number type). .. code-block:: cpp @@ -557,14 +614,16 @@ The above signature would imply that Python needs to give up ownership of an object that is passed to this function, which is generally not possible (for instance, the object might be referenced elsewhere). +.. _smart_pointers: + Smart pointers ============== This section explains how to pass values that are wrapped in "smart" pointer -types with internal reference counting. For simpler C++11 unique pointers, -please refer to the previous section. +types with internal reference counting. For the simpler C++11 unique pointers, +refer to the previous section. -The binding generator for classes (:class:`class_`) takes an optional second +The binding generator for classes, :class:`class_`, takes an optional second template type, which denotes a special *holder* type that is used to manage references to the object. When wrapping a type named ``Type``, the default value of this template parameter is ``std::unique_ptr<Type>``, which means that @@ -708,6 +767,8 @@ automatically converted into a Python ``Exception``. pybind11 defines multiple special exception classes that will map to different types of Python exceptions: +.. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}| + +--------------------------------------+------------------------------+ | C++ exception type | Python exception type | +======================================+==============================+ @@ -733,6 +794,10 @@ exceptions: | | accesses in ``__getitem__``, | | | ``__setitem__``, etc.) | +--------------------------------------+------------------------------+ +| :class:`pybind11::value_error` | ``ValueError`` (used to | +| | indicate wrong value passed | +| | in ``container.remove(...)`` | ++--------------------------------------+------------------------------+ | :class:`pybind11::error_already_set` | Indicates that the Python | | | exception flag has already | | | been initialized | @@ -746,13 +811,157 @@ There is also a special exception :class:`cast_error` that is thrown by :func:`handle::call` when the input arguments cannot be converted to Python objects. +.. _opaque: + +Treating STL data structures as opaque objects +============================================== + +pybind11 heavily relies on a template matching mechanism to convert parameters +and return values that are constructed from STL data types such as vectors, +linked lists, hash tables, etc. This even works in a recursive manner, for +instance to deal with lists of hash maps of pairs of elementary and custom +types, etc. + +However, a fundamental limitation of this approach is that internal conversions +between Python and C++ types involve a copy operation that prevents +pass-by-reference semantics. What does this mean? + +Suppose we bind the following function + +.. code-block:: cpp + + void append_1(std::vector<int> &v) { + v.push_back(1); + } + +and call it from Python, the following happens: + +.. code-block:: python + + >>> v = [5, 6] + >>> append_1(v) + >>> print(v) + [5, 6] + +As you can see, when passing STL data structures by reference, modifications +are not propagated back the Python side. A similar situation arises when +exposing STL data structures using the ``def_readwrite`` or ``def_readonly`` +functions: + +.. code-block:: cpp + + /* ... definition ... */ + + class MyClass { + std::vector<int> contents; + }; + + /* ... binding code ... */ + + py::class_<MyClass>(m, "MyClass") + .def(py::init<>) + .def_readwrite("contents", &MyClass::contents); + +In this case, properties can be read and written in their entirety. However, an +``append`` operaton involving such a list type has no effect: + +.. code-block:: python + + >>> m = MyClass() + >>> m.contents = [5, 6] + >>> print(m.contents) + [5, 6] + >>> m.contents.append(7) + >>> print(m.contents) + [5, 6] + +To deal with both of the above situations, pybind11 provides a macro named +``PYBIND11_MAKE_OPAQUE(T)`` that disables the template-based conversion +machinery of types, thus rendering them *opaque*. The contents of opaque +objects are never inspected or extracted, hence they can be passed by +reference. For instance, to turn ``std::vector<int>`` into an opaque type, add +the declaration + +.. code-block:: cpp + + PYBIND11_MAKE_OPAQUE(std::vector<int>); + +before any binding code (e.g. invocations to ``class_::def()``, etc.). This +macro must be specified at the top level, since instantiates a partial template +overload. If your binding code consists of multiple compilation units, it must +be present in every file preceding any usage of ``std::vector<int>``. Opaque +types must also have a corresponding ``class_`` declaration to associate them +with a name in Python, and to define a set of available operations: + +.. code-block:: cpp + + py::class_<std::vector<int>>(m, "IntVector") + .def(py::init<>()) + .def("clear", &std::vector<int>::clear) + .def("pop_back", &std::vector<int>::pop_back) + .def("__len__", [](const std::vector<int> &v) { return v.size(); }) + .def("__iter__", [](std::vector<int> &v) { + return py::make_iterator(v.begin(), v.end()); + }, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */ + // .... + + +.. seealso:: + + The file :file:`example/example14.cpp` contains a complete example that + demonstrates how to create and expose opaque types using pybind11 in more + detail. + +.. _eigen: + +Transparent conversion of dense and sparse Eigen data types +=========================================================== + +Eigen [#f1]_ is C++ header-based library for dense and sparse linear algebra. Due to +its popularity and widespread adoption, pybind11 provides transparent +conversion support between Eigen and Scientific Python linear algebra data types. + +Specifically, when including the optional header file :file:`pybind11/eigen.h`, +pybind11 will automatically and transparently convert + +1. Static and dynamic Eigen dense vectors and matrices to instances of + ``numpy.ndarray`` (and vice versa). + +1. Eigen sparse vectors and matrices to instances of + ``scipy.sparse.csr_matrix``/``scipy.sparse.csc_matrix`` (and vice versa). + +This makes it possible to bind most kinds of functions that rely on these types. +One major caveat are functions that take Eigen matrices *by reference* and modify +them somehow, in which case the information won't be propagated to the caller. + +.. code-block:: cpp + + /* The Python bindings of this function won't replicate + the intended effect of modifying the function argument */ + void scale_by_2(Eigen::Vector3f &v) { + v *= 2; + } + +To see why this is, refer to the section on :ref:`opaque` (although that +section specifically covers STL data types, the underlying issue is the same). +The next two sections discuss an efficient alternative for exposing the +underlying native Eigen types as opaque objects in a way that still integrates +with NumPy and SciPy. + +.. [#f1] http://eigen.tuxfamily.org + +.. seealso:: + + The file :file:`example/eigen.cpp` contains a complete example that + shows how to pass Eigen sparse and dense data types in more detail. + Buffer protocol =============== Python supports an extremely general and convenient approach for exchanging -data between plugin libraries. Types can expose a buffer view [#f1]_, -which provides fast direct access to the raw internal representation. Suppose -we want to bind the following simplistic Matrix class: +data between plugin libraries. Types can expose a buffer view [#f2]_, which +provides fast direct access to the raw internal data representation. Suppose we +want to bind the following simplistic Matrix class: .. code-block:: cpp @@ -770,7 +979,7 @@ we want to bind the following simplistic Matrix class: }; The following binding code exposes the ``Matrix`` contents as a buffer object, -making it possible to cast Matrixes into NumPy arrays. It is even possible to +making it possible to cast Matrices into NumPy arrays. It is even possible to completely avoid copy operations with Python expressions like ``np.array(matrix_instance, copy = False)``. @@ -779,12 +988,12 @@ completely avoid copy operations with Python expressions like py::class_<Matrix>(m, "Matrix") .def_buffer([](Matrix &m) -> py::buffer_info { return py::buffer_info( - m.data(), /* Pointer to buffer */ - sizeof(float), /* Size of one scalar */ - py::format_descriptor<float>::value(), /* Python struct-style format descriptor */ - 2, /* Number of dimensions */ - { m.rows(), m.cols() }, /* Buffer dimensions */ - { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ + m.data(), /* Pointer to buffer */ + sizeof(float), /* Size of one scalar */ + py::format_descriptor<float>::value, /* Python struct-style format descriptor */ + 2, /* Number of dimensions */ + { m.rows(), m.cols() }, /* Buffer dimensions */ + { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ sizeof(float) } ); }); @@ -810,41 +1019,71 @@ in a great variety of configurations, hence some safety checks are usually necessary in the function body. Below, you can see an basic example on how to define a custom constructor for the Eigen double precision matrix (``Eigen::MatrixXd``) type, which supports initialization from compatible -buffer -objects (e.g. a NumPy matrix). +buffer objects (e.g. a NumPy matrix). .. code-block:: cpp - py::class_<Eigen::MatrixXd>(m, "MatrixXd") - .def("__init__", [](Eigen::MatrixXd &m, py::buffer b) { + /* Bind MatrixXd (or some other Eigen type) to Python */ + typedef Eigen::MatrixXd Matrix; + + typedef Matrix::Scalar Scalar; + constexpr bool rowMajor = Matrix::Flags & Eigen::RowMajorBit; + + py::class_<Matrix>(m, "Matrix") + .def("__init__", [](Matrix &m, py::buffer b) { + typedef Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> Strides; + /* Request a buffer descriptor from Python */ py::buffer_info info = b.request(); /* Some sanity checks ... */ - if (info.format != py::format_descriptor<double>::value()) + if (info.format != py::format_descriptor<Scalar>::value) throw std::runtime_error("Incompatible format: expected a double array!"); if (info.ndim != 2) throw std::runtime_error("Incompatible buffer dimension!"); - if (info.strides[0] == sizeof(double)) { - /* Buffer has the right layout -- directly copy. */ - new (&m) Eigen::MatrixXd(info.shape[0], info.shape[1]); - memcpy(m.data(), info.ptr, sizeof(double) * m.size()); - } else { - /* Oops -- the buffer is transposed */ - new (&m) Eigen::MatrixXd(info.shape[1], info.shape[0]); - memcpy(m.data(), info.ptr, sizeof(double) * m.size()); - m.transposeInPlace(); - } + auto strides = Strides( + info.strides[rowMajor ? 0 : 1] / sizeof(Scalar), + info.strides[rowMajor ? 1 : 0] / sizeof(Scalar)); + + auto map = Eigen::Map<Matrix, 0, Strides>( + static_cat<Scalar *>(info.ptr), info.shape[0], info.shape[1], strides); + + new (&m) Matrix(map); }); +For reference, the ``def_buffer()`` call for this Eigen data type should look +as follows: + +.. code-block:: cpp + + .def_buffer([](Matrix &m) -> py::buffer_info { + return py::buffer_info( + m.data(), /* Pointer to buffer */ + sizeof(Scalar), /* Size of one scalar */ + /* Python struct-style format descriptor */ + py::format_descriptor<Scalar>::value, + /* Number of dimensions */ + 2, + /* Buffer dimensions */ + { (size_t) m.rows(), + (size_t) m.cols() }, + /* Strides (in bytes) for each index */ + { sizeof(Scalar) * (rowMajor ? m.cols() : 1), + sizeof(Scalar) * (rowMajor ? 1 : m.rows()) } + ); + }) + +For a much easier approach of binding Eigen types (although with some +limitations), refer to the section on :ref:`eigen`. + .. seealso:: The file :file:`example/example7.cpp` contains a complete example that demonstrates using the buffer protocol with pybind11 in more detail. -.. [#f1] http://docs.python.org/3/c-api/buffer.html +.. [#f2] http://docs.python.org/3/c-api/buffer.html NumPy support ============= @@ -856,16 +1095,32 @@ type of Python object satisfying the buffer protocol). In many situations, we want to define a function which only accepts a NumPy array of a certain data type. This is possible via the ``py::array_t<T>`` template. For instance, the following function requires the argument to be a -dense array of doubles in C-style ordering. +NumPy array containing double precision values. .. code-block:: cpp void f(py::array_t<double> array); -When it is invoked with a different type (e.g. an integer), the binding code -will attempt to cast the input into a NumPy array of the requested type. Note -that this feature requires the :file:``pybind11/numpy.h`` header to be -included. +When it is invoked with a different type (e.g. an integer or a list of +integers), the binding code will attempt to cast the input into a NumPy array +of the requested type. Note that this feature requires the +:file:``pybind11/numpy.h`` header to be included. + +Data in NumPy arrays is not guaranteed to packed in a dense manner; +furthermore, entries can be separated by arbitrary column and row strides. +Sometimes, it can be useful to require a function to only accept dense arrays +using either the C (row-major) or Fortran (column-major) ordering. This can be +accomplished via a second template argument with values ``py::array::c_style`` +or ``py::array::f_style``. + +.. code-block:: cpp + + void f(py::array_t<double, py::array::c_style | py::array::forcecast> array); + +The ``py::array::forcecast`` argument is the default value of the second +template paramenter, and it ensures that non-conforming arguments are converted +into an array satisfying the specified requirements instead of trying the next +function overload. Vectorizing functions ===================== @@ -885,7 +1140,7 @@ After including the ``pybind11/numpy.h`` header, this is extremely simple: m.def("vectorized_func", py::vectorize(my_func)); Invoking the function like below causes 4 calls to be made to ``my_func`` with -each of the the array elements. The significant advantage of this compared to +each of the array elements. The significant advantage of this compared to solutions like ``numpy.vectorize()`` is that the loop over the elements runs entirely on the C++ side and can be crunched down into a tight, optimized loop by the compiler. The result is returned as a NumPy array of type @@ -903,7 +1158,7 @@ arrays ``x`` and ``y`` are automatically converted into the right types (they are of type ``numpy.dtype.int64`` but need to be ``numpy.dtype.int32`` and ``numpy.dtype.float32``, respectively) -Sometimes we might want to explitly exclude an argument from the vectorization +Sometimes we might want to explicitly exclude an argument from the vectorization because it makes little sense to wrap it in a NumPy array. For instance, suppose the function signature was @@ -996,8 +1251,9 @@ For instance, the following statement iterates over a Python ``dict``: Available types include :class:`handle`, :class:`object`, :class:`bool_`, :class:`int_`, :class:`float_`, :class:`str`, :class:`bytes`, :class:`tuple`, -:class:`list`, :class:`dict`, :class:`slice`, :class:`capsule`, -:class:`function`, :class:`buffer`, :class:`array`, and :class:`array_t`. +:class:`list`, :class:`dict`, :class:`slice`, :class:`none`, :class:`capsule`, +:class:`iterable`, :class:`iterator`, :class:`function`, :class:`buffer`, +:class:`array`, and :class:`array_t`. In this kind of mixed code, it is often necessary to convert arbitrary C++ types to Python, which can be done using :func:`cast`: @@ -1015,11 +1271,31 @@ The reverse direction uses the following syntax: MyClass *cls = obj.cast<MyClass *>(); When conversion fails, both directions throw the exception :class:`cast_error`. +It is also possible to call python functions via ``operator()``. + +.. code-block:: cpp + + py::function f = <...>; + py::object result_py = f(1234, "hello", some_instance); + MyClass &result = result_py.cast<MyClass>(); + +The special ``f(*args)`` and ``f(*args, **kwargs)`` syntax is also supported to +supply arbitrary argument and keyword lists, although these cannot be mixed +with other parameters. + +.. code-block:: cpp + + py::function f = <...>; + py::tuple args = py::make_tuple(1234); + py::dict kwargs; + kwargs["y"] = py::cast(5678); + py::object result = f(*args, **kwargs); .. seealso:: The file :file:`example/example2.cpp` contains a complete example that - demonstrates passing native Python types in more detail. + demonstrates passing native Python types in more detail. The file + :file:`example/example11.cpp` discusses usage of ``args`` and ``kwargs``. Default arguments revisited =========================== @@ -1068,6 +1344,36 @@ like so: py::class_<MyClass>("MyClass") .def("myFunction", py::arg("arg") = (SomeType *) nullptr); +Binding functions that accept arbitrary numbers of arguments and keywords arguments +=================================================================================== + +Python provides a useful mechanism to define functions that accept arbitrary +numbers of arguments and keyword arguments: + +.. code-block:: cpp + + def generic(*args, **kwargs): + # .. do something with args and kwargs + +Such functions can also be created using pybind11: + +.. code-block:: cpp + + void generic(py::args args, py::kwargs kwargs) { + /// .. do something with args + if (kwargs) + /// .. do something with kwargs + } + + /// Binding code + m.def("generic", &generic); + +(See ``example/example11.cpp``). The class ``py::args`` derives from +``py::list`` and ``py::kwargs`` derives from ``py::dict`` Note that the +``kwargs`` argument is invalid if no keyword arguments were actually provided. +Please refer to the other examples for details on how to iterate over these, +and on how to cast their entries into C++ objects. + Partitioning code over multiple extension modules ================================================= @@ -1136,58 +1442,6 @@ accessed by multiple extension modules: }; -Treating STL data structures as opaque objects -============================================== - -pybind11 heavily relies on a template matching mechanism to convert parameters -and return values that are constructed from STL data types such as vectors, -linked lists, hash tables, etc. This even works in a recursive manner, for -instance to deal with lists of hash maps of pairs of elementary and custom -types, etc. - -A fundamental limitation of this approach is that the internal conversion -between Python and C++ types involves a copy operation that prevents -pass-by-reference semantics. What does this mean? - -Suppose we bind the following function - -.. code-block:: cpp - - void append_1(std::vector<int> &v) { - v.push_back(1); - } - -and call it as follows from Python: - -.. code-block:: python - - >>> v = [5, 6] - >>> append_1(v) - >>> print(v) - [5, 6] - -As you can see, when passing STL data structures by reference, modifications -are not propagated back the Python side. To deal with situations where this -desirable, pybind11 contains a simple template wrapper class named ``opaque<T>``. - -``opaque<T>`` disables the underlying template machinery for -``T`` and can be used to treat STL types as opaque objects, whose contents are -never inspected or extracted (thus, they can be passed by reference). -The downside of this approach is that it the binding code becomes a bit more -wordy. The above function can be bound using the following wrapper code: - -.. code-block:: cpp - - m.def("append_1", [](py::opaque<std::vector<int>> &v) { append_1(v); }); - -Opaque types must also have a dedicated ``class_`` declaration to define a -set of admissible operations. - -.. seealso:: - - The file :file:`example/example14.cpp` contains a complete example that - demonstrates how to create opaque types using pybind11 in more detail. - Pickling support ================ @@ -1210,7 +1464,7 @@ Suppose the class in question has the following signature: int m_extra = 0; }; -The binding code including the requisite ``__setstate__`` and ``__getstate__`` methods [#f2]_ +The binding code including the requisite ``__setstate__`` and ``__getstate__`` methods [#f3]_ looks as follows: .. code-block:: cpp @@ -1247,27 +1501,29 @@ An instance can now be pickled as follows: p = Pickleable("test_value") p.setExtra(15) - data = pickle.dumps(p, -1) + data = pickle.dumps(p, 2) -Note that only the cPickle module is supported on Python 2.7. It is also -important to request usage of the highest protocol version using the ``-1`` -argument to ``dumps``. Failure to follow these two steps will lead to important -pybind11 memory allocation routines to be skipped during unpickling, which will -likely cause memory corruption and/or segmentation faults. +Note that only the cPickle module is supported on Python 2.7. The second +argument to ``dumps`` is also crucial: it selects the pickle protocol version +2, since the older version 1 is not supported. Newer versions are also fine—for +instance, specify ``-1`` to always use the latest available version. Beware: +failure to follow these instructions will cause important pybind11 memory +allocation routines to be skipped during unpickling, which will likely lead to +memory corruption and/or segmentation faults. .. seealso:: The file :file:`example/example15.cpp` contains a complete example that demonstrates how to pickle and unpickle types using pybind11 in more detail. -.. [#f2] http://docs.python.org/3/library/pickle.html#pickling-class-instances +.. [#f3] http://docs.python.org/3/library/pickle.html#pickling-class-instances Generating documentation using Sphinx ===================================== -Sphinx [#f3]_ has the ability to inspect the signatures and documentation +Sphinx [#f4]_ has the ability to inspect the signatures and documentation strings in pybind11-based extension modules to automatically generate beautiful -documentation in a variety formats. The pbtest repository [#f4]_ contains a +documentation in a variety formats. The pbtest repository [#f5]_ contains a simple example repository which uses this approach. There are two potential gotchas when using this approach: first, make sure that @@ -1294,6 +1550,5 @@ work, it is important that all lines are indented consistently, i.e.: ---------- )mydelimiter"); -.. [#f3] http://www.sphinx-doc.org -.. [#f4] http://github.com/pybind/pbtest - +.. [#f4] http://www.sphinx-doc.org +.. [#f5] http://github.com/pybind/pbtest diff --git a/stormpy/resources/pybind11/docs/basics.rst b/stormpy/resources/pybind11/docs/basics.rst index 42ff6e42e..b1765c5c9 100644 --- a/stormpy/resources/pybind11/docs/basics.rst +++ b/stormpy/resources/pybind11/docs/basics.rst @@ -117,7 +117,7 @@ example can be compiled using the following command .. code-block:: bash - $ c++ -O3 -shared -std=c++11 -I <path-to-pybind11>/include `python-config --cflags --ldflags --libs` example.cpp -o example.so + $ c++ -O3 -shared -std=c++11 -I <path-to-pybind11>/include `python-config --cflags --ldflags` example.cpp -o example.so In general, it is advisable to include several additional build parameters that can considerably reduce the size of the created binary. Refer to section @@ -222,57 +222,63 @@ The following basic data types are supported out of the box (some may require an additional extension header to be included). To pass other data structures as arguments and return values, refer to the section on binding :ref:`classes`. -+----------------------------+--------------------------+-----------------------+ -| Data type | Description | Header file | -+============================+==========================+=======================+ -| int8_t, uint8_t | 8-bit integers | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| int16_t, uint16_t | 16-bit integers | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| int32_t, uint32_t | 32-bit integers | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| int64_t, uint64_t | 64-bit integers | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| ssize_t, size_t | Platform-dependent size | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| float, double | Floating point types | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| bool | Two-state Boolean type | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| char | Character literal | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| wchar_t | Wide character literal | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| const char * | UTF-8 string literal | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| const wchar_t * | Wide string literal | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| std::string | STL dynamic UTF-8 string | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| std::wstring | STL dynamic wide string | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| std::pair<T1, T2> | Pair of two custom types | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| std::tuple<....> | Arbitrary tuple of types | pybind11/pybind11.h | -+----------------------------+--------------------------+-----------------------+ -| std::complex<T> | Complex numbers | pybind11/complex.h | -+----------------------------+--------------------------+-----------------------+ -| std::array<T, Size> | STL static array | pybind11/stl.h | -+----------------------------+--------------------------+-----------------------+ -| std::vector<T> | STL dynamic array | pybind11/stl.h | -+----------------------------+--------------------------+-----------------------+ -| std::list<T> | STL linked list | pybind11/stl.h | -+----------------------------+--------------------------+-----------------------+ -| std::map<T1, T2> | STL ordered map | pybind11/stl.h | -+----------------------------+--------------------------+-----------------------+ -| std::unordered_map<T1, T2> | STL unordered map | pybind11/stl.h | -+----------------------------+--------------------------+-----------------------+ -| std::set<T> | STL ordered set | pybind11/stl.h | -+----------------------------+--------------------------+-----------------------+ -| std::unordered_set<T> | STL unordered set | pybind11/stl.h | -+----------------------------+--------------------------+-----------------------+ -| std::function<...> | STL polymorphic function | pybind11/functional.h | -+----------------------------+--------------------------+-----------------------+ ++---------------------------------+--------------------------+-------------------------------+ +| Data type | Description | Header file | ++=================================+==========================+===============================+ +| ``int8_t``, ``uint8_t`` | 8-bit integers | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``int16_t``, ``uint16_t`` | 16-bit integers | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``int32_t``, ``uint32_t`` | 32-bit integers | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``int64_t``, ``uint64_t`` | 64-bit integers | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``ssize_t``, ``size_t`` | Platform-dependent size | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``float``, ``double`` | Floating point types | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``bool`` | Two-state Boolean type | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``char`` | Character literal | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``wchar_t`` | Wide character literal | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``const char *`` | UTF-8 string literal | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``const wchar_t *`` | Wide string literal | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::string`` | STL dynamic UTF-8 string | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::wstring`` | STL dynamic wide string | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::pair<T1, T2>`` | Pair of two custom types | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::tuple<...>`` | Arbitrary tuple of types | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::reference_wrapper<...>`` | Reference type wrapper | :file:`pybind11/pybind11.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::complex<T>`` | Complex numbers | :file:`pybind11/complex.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::array<T, Size>`` | STL static array | :file:`pybind11/stl.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::vector<T>`` | STL dynamic array | :file:`pybind11/stl.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::list<T>`` | STL linked list | :file:`pybind11/stl.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::map<T1, T2>`` | STL ordered map | :file:`pybind11/stl.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::unordered_map<T1, T2>`` | STL unordered map | :file:`pybind11/stl.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::set<T>`` | STL ordered set | :file:`pybind11/stl.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::unordered_set<T>`` | STL unordered set | :file:`pybind11/stl.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``Eigen::Matrix<...>`` | Dense Eigen matrices | :file:`pybind11/eigen.h` | ++---------------------------------+--------------------------+-------------------------------+ +| ``Eigen::SparseMatrix<...>`` | Sparse Eigen matrices | :file:`pybind11/eigen.h` | ++---------------------------------+--------------------------+-------------------------------+ .. [#f1] In practice, implementation and binding code will generally be located diff --git a/stormpy/resources/pybind11/docs/benchmark.rst b/stormpy/resources/pybind11/docs/benchmark.rst index c31e2902d..365919756 100644 --- a/stormpy/resources/pybind11/docs/benchmark.rst +++ b/stormpy/resources/pybind11/docs/benchmark.rst @@ -65,7 +65,13 @@ the largest largest file with 2048 classes and a total of 8192 methods -- a modest **1.2x** speedup relative to Boost.Python, which required 116.35 seconds). -.. image:: pybind11_vs_boost_python1.svg +.. only:: not latex + + .. image:: pybind11_vs_boost_python1.svg + +.. only:: latex + + .. image:: pybind11_vs_boost_python1.png Module size ----------- @@ -79,5 +85,12 @@ that it stores many definitions in an external library, whose size was not included here, hence the comparison is slightly shifted in Boost.Python's favor. -.. image:: pybind11_vs_boost_python2.svg +.. only:: not latex + + .. image:: pybind11_vs_boost_python2.svg + +.. only:: latex + + .. image:: pybind11_vs_boost_python2.png + diff --git a/stormpy/resources/pybind11/docs/changelog.rst b/stormpy/resources/pybind11/docs/changelog.rst index 92b23670b..632f2be84 100644 --- a/stormpy/resources/pybind11/docs/changelog.rst +++ b/stormpy/resources/pybind11/docs/changelog.rst @@ -3,9 +3,50 @@ Changelog ######### -1.5 (not yet released) +1.8 (Not yet released) ---------------------- -* For polymorphic types, use RTTI to try to return the closest type registered with pybind11. +* Prevent implicit conversion of floating point values to integral types in + function arguments +* Transparent conversion of sparse and dense Eigen data types +* Fixed incorrect default return value policy for functions returning a shared + pointer +* Don't allow casting a ``None`` value into a C++ lvalue reference +* Fixed a crash in ``enum_::operator==`` that was triggered by the ``help()`` command +* Improved detection of whether or not custom C++ types can be copy/move-constructed +* Extended ``str`` type to also work with ``bytes`` instances +* Added ``[[noreturn]]`` attribute to ``pybind11_fail()`` to quench some + compiler warnings +* Various minor ``iterator`` and ``make_iterator()`` improvements +* Minor CMake build system improvements on Windows +* Many ``mkdoc.py`` improvements (enumerations, template arguments, ``DOC()`` + macro accepts more arguments) +* Documentation improvements (pickling support, ``keep_alive``) + +1.7 (April 30, 2016) +---------------------- +* Added a new ``move`` return value policy that triggers C++11 move semantics. + The automatic return value policy falls back to this case whenever a rvalue + reference is encountered +* Significantly more general GIL state routines that are used instead of + Python's troublesome ``PyGILState_Ensure`` and ``PyGILState_Release`` API +* Redesign of opaque types that drastically simplifies their usage +* Extended ability to pass values of type ``[const] void *`` +* ``keep_alive`` fix: don't fail when there is no patient +* ``functional.h``: acquire the GIL before calling a Python function +* Added Python RAII type wrappers ``none`` and ``iterable`` +* Added ``*args`` and ``*kwargs`` pass-through parameters to + ``pybind11.get_include()`` function +* Iterator improvements and fixes +* Documentation on return value policies and opaque types improved + +1.6 (April 30, 2016) +---------------------- +* Skipped due to upload to PyPI gone wrong and inability to recover + (https://github.com/pypa/packaging-problems/issues/74) + +1.5 (April 21, 2016) +---------------------- +* For polymorphic types, use RTTI to try to return the closest type registered with pybind11 * Pickling support for serializing and unserializing C++ instances to a byte stream in Python * Added a convenience routine ``make_iterator()`` which turns a range indicated by a pair of C++ iterators into a iterable Python object @@ -16,6 +57,7 @@ Changelog * Added a ``get_include()`` function to the Python module that returns the path of the directory containing the installed pybind11 header files * Documentation improvements: import issues, symbol visibility, pickling, limitations +* Added casting support for ``std::reference_wrapper<>`` 1.4 (April 7, 2016) -------------------------- diff --git a/stormpy/resources/pybind11/docs/cmake.rst b/stormpy/resources/pybind11/docs/compiling.rst similarity index 71% rename from stormpy/resources/pybind11/docs/cmake.rst rename to stormpy/resources/pybind11/docs/compiling.rst index ace216758..5f4d09836 100644 --- a/stormpy/resources/pybind11/docs/cmake.rst +++ b/stormpy/resources/pybind11/docs/compiling.rst @@ -11,6 +11,16 @@ the [pbtest]_ repository. .. [pbtest] https://github.com/pybind/pbtest +Building with cppimport +======================== + + cppimport is a small Python import hook that determines whether there is a C++ + source file whose name matches the requested module. If there is, the file is + compiled as a Python extension using pybind11 and placed in the same folder as + the C++ source file. Python is then able to find the module and load it. + +.. [cppimport] https://github.com/tbenthompson/cppimport + .. _cmake: Building with CMake @@ -29,11 +39,13 @@ subdirectory named :file:`pybind11`. project(example) # Add a CMake parameter for choosing a desired Python version - set(EXAMPLE_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling the example library") - + set(EXAMPLE_PYTHON_VERSION "" CACHE STRING + "Python version to use for compiling the example library") + include(CheckCXXCompilerFlag) - # Set a default build configuration if none is specified. 'MinSizeRel' produces the smallest binaries + # Set a default build configuration if none is specified. + # 'MinSizeRel' produces the smallest binaries if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'MinSizeRel' as none was specified.") set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE) @@ -46,14 +58,15 @@ subdirectory named :file:`pybind11`. set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7) if (NOT ${EXAMPLE_PYTHON_VERSION} STREQUAL "") find_package(PythonLibs ${EXAMPLE_PYTHON_VERSION} EXACT) - if (NOT PythonLibs_FOUND) + if (NOT PYTHONLIBS_FOUND) find_package(PythonLibs ${EXAMPLE_PYTHON_VERSION} REQUIRED) endif() else() find_package(PythonLibs REQUIRED) endif() - # The above sometimes returns version numbers like "3.4.3+"; the "+" must be removed for the next lines to work + # The above sometimes returns version numbers like "3.4.3+"; + # the "+" must be removed for the next lines to work string(REPLACE "+" "" PYTHONLIBS_VERSION_STRING "+${PYTHONLIBS_VERSION_STRING}") # Uncomment the following line if you will also require a matching Python interpreter @@ -88,7 +101,8 @@ subdirectory named :file:`pybind11`. # Include path for Python header files include_directories(${PYTHON_INCLUDE_DIR}) - # Include path for pybind11 header files -- this may need to be changed depending on your setup + # Include path for pybind11 header files -- this may need to be + # changed depending on your setup include_directories(${PROJECT_SOURCE_DIR}/pybind11/include) # Create the binding library @@ -102,17 +116,19 @@ subdirectory named :file:`pybind11`. if (WIN32) if (MSVC) - # /bigobj is needed for bigger binding projects due to the limit to 64k - # addressable sections. /MP enables multithreaded builds (relevant when - # there are many files). - set_target_properties(example PROPERTIES COMPILE_FLAGS "/MP /bigobj ") - - if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) - # Enforce size-based optimization and link time code generation on MSVC - # (~30% smaller binaries in experiments). - set_target_properties(example APPEND_STRING PROPERTY COMPILE_FLAGS "/Os /GL ") - set_target_properties(example APPEND_STRING PROPERTY LINK_FLAGS "/LTCG ") - endif() + # /MP enables multithreaded builds (relevant when there are many files), /bigobj is + # needed for bigger binding projects due to the limit to 64k addressable sections + set_property(TARGET example APPEND PROPERTY COMPILE_OPTIONS /MP /bigobj) + # Enforce size-based optimization and link time code generation on MSVC + # (~30% smaller binaries in experiments); do nothing in debug mode. + set_property(TARGET example APPEND PROPERTY COMPILE_OPTIONS + "$<$<CONFIG:Release>:/Os>" "$<$<CONFIG:Release>:/GL>" + "$<$<CONFIG:MinSizeRel>:/Os>" "$<$<CONFIG:MinSizeRel>:/GL>" + "$<$<CONFIG:RelWithDebInfo>:/Os>" "$<$<CONFIG:RelWithDebInfo>:/GL>" + ) + set_property(TARGET example APPEND_STRING PROPERTY LINK_FLAGS_RELEASE "/LTCG ") + set_property(TARGET example APPEND_STRING PROPERTY LINK_FLAGS_MINSIZEREL "/LTCG ") + set_property(TARGET example APPEND_STRING PROPERTY LINK_FLAGS_RELWITHDEBINFO "/LTCG ") endif() # .PYD file extension on Windows @@ -143,11 +159,13 @@ subdirectory named :file:`pybind11`. set_target_properties(example PROPERTIES MACOSX_RPATH ".") set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup ") if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) - add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_BINARY_DIR}/example.so) + add_custom_command(TARGET example POST_BUILD + COMMAND strip -u -r ${PROJECT_BINARY_DIR}/example.so) endif() else() if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) - add_custom_command(TARGET example POST_BUILD COMMAND strip ${PROJECT_BINARY_DIR}/example.so) + add_custom_command(TARGET example POST_BUILD + COMMAND strip ${PROJECT_BINARY_DIR}/example.so) endif() endif() endif() diff --git a/stormpy/resources/pybind11/docs/conf.py b/stormpy/resources/pybind11/docs/conf.py index a05acc33e..9d25838d2 100644 --- a/stormpy/resources/pybind11/docs/conf.py +++ b/stormpy/resources/pybind11/docs/conf.py @@ -158,7 +158,7 @@ else: # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['.static'] +html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -233,7 +233,7 @@ latex_elements = { #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. -#'preamble': '', +'preamble': '\DeclareUnicodeCharacter{00A0}{}', # Latex figure (float) alignment #'figure_align': 'htbp', @@ -249,7 +249,7 @@ latex_documents = [ # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = 'pybind11-logo.png' # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. diff --git a/stormpy/resources/pybind11/docs/faq.rst b/stormpy/resources/pybind11/docs/faq.rst index 12d28375e..b6c91a8bd 100644 --- a/stormpy/resources/pybind11/docs/faq.rst +++ b/stormpy/resources/pybind11/docs/faq.rst @@ -1,10 +1,8 @@ Frequently asked questions ########################## -(under construction) - -ImportError: dynamic module does not define init function -========================================================= +"ImportError: dynamic module does not define init function" +=========================================================== 1. Make sure that the name specified in ``pybind::module`` and ``PYBIND11_PLUGIN`` is consistent and identical to the filename of the @@ -14,7 +12,36 @@ ImportError: dynamic module does not define init function 2. If the above did not fix your issue, then you are likely using an incompatible version of Python (for instance, the extension library was compiled against Python 2, while the interpreter is running on top of some - version of Python 3) + version of Python 3, or vice versa) + +"Symbol not found: ``__Py_ZeroStruct`` / ``_PyInstanceMethod_Type``" +======================================================================== + +See item 2 of the first answer. + +The Python interpreter immediately crashes when importing my module +=================================================================== + +See item 2 of the first answer. + +CMake doesn't detect the right Python version, or it finds mismatched interpreter and library versions +====================================================================================================== + +The Python detection logic of CMake is flawed and can sometimes fail to find +the desired Python version, or it chooses mismatched interpreter and library +versions. A longer discussion is available on the pybind11 issue tracker +[#f1]_, though this is ultimately not a pybind11 issue. + +To force the build system to choose a particular version, delete CMakeCache.txt +and then invoke CMake as follows: + +.. code-block:: bash + + cmake -DPYTHON_EXECUTABLE:FILEPATH=<...> \ + -DPYTHON_LIBRARY:FILEPATH=<...> \ + -DPYTHON_INCLUDE_DIR:PATH=<...> . + +.. [#f1] http://github.com/pybind/pybind11/issues/99 Limitations involving reference arguments ========================================= @@ -64,24 +91,114 @@ and the binding code m.def("foo", [](int i) { int rv = foo(i); return std::make_tuple(rv, i); }); -CMake doesn't detect the right Python version, or it finds mismatched interpreter and library versions -====================================================================================================== -The Python detection logic of CMake is flawed and can sometimes fail to find -the desired Python version, or it chooses mismatched interpreter and library -versions. A longer discussion is available on the pybind11 issue tracker -[#f1]_, though this is ultimately not a pybind11 issue. +How can I reduce the build time? +================================ -To force the build system to choose a particular version, delete CMakeCache.txt -and then invoke CMake as follows: +It's good practice to split binding code over multiple files, as is done in +the included file :file:`example/example.cpp`. -.. code-block:: bash +.. code-block:: cpp - cmake -DPYTHON_EXECUTABLE:FILEPATH=<...> \ - -DPYTHON_LIBRARY:FILEPATH=<...> \ - -DPYTHON_INCLUDE_DIR:PATH=<...> . + void init_ex1(py::module &); + void init_ex2(py::module &); + /* ... */ -.. [#f1] http://github.com/pybind/pybind11/issues/99 + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind example plugin"); + + init_ex1(m); + init_ex2(m); + + /* ... */ + + return m.ptr(); + } + +The various ``init_ex`` functions should be contained in separate files that +can be compiled independently from another. Following this approach will + +1. reduce memory requirements per compilation unit. + +2. enable parallel builds (if desired). + +3. allow for faster incremental builds. For instance, when a single class + definiton is changed, only a subset of the binding code will generally need + to be recompiled. + +How can I create smaller binaries? +================================== + +To do its job, pybind11 extensively relies on a programming technique known as +*template metaprogramming*, which is a way of performing computation at compile +time using type information. Template metaprogamming usually instantiates code +involving significant numbers of deeply nested types that are either completely +removed or reduced to just a few instrutions during the compiler's optimization +phase. However, due to the nested nature of these types, the resulting symbol +names in the compiled extension library can be extremely long. For instance, +the included test suite contains the following symbol: + +.. only:: html + + .. code-block:: none + + __ZN8pybind1112cpp_functionC1Iv8Example2JRNSt3__16vectorINS3_12basic_stringIwNS3_11char_traitsIwEENS3_9allocatorIwEEEENS8_ISA_EEEEEJNS_4nameENS_7siblingENS_9is_methodEA28_cEEEMT0_FT_DpT1_EDpRKT2_ + +.. only:: not html + + .. code-block:: cpp + + __ZN8pybind1112cpp_functionC1Iv8Example2JRNSt3__16vectorINS3_12basic_stringIwNS3_11char_traitsIwEENS3_9allocatorIwEEEENS8_ISA_EEEEEJNS_4nameENS_7siblingENS_9is_methodEA28_cEEEMT0_FT_DpT1_EDpRKT2_ + +which is the mangled form of the following function type: + +.. code-block:: cpp + + pybind11::cpp_function::cpp_function<void, Example2, std::__1::vector<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, std::__1::allocator<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > > >&, pybind11::name, pybind11::sibling, pybind11::is_method, char [28]>(void (Example2::*)(std::__1::vector<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, std::__1::allocator<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > > >&), pybind11::name const&, pybind11::sibling const&, pybind11::is_method const&, char const (&) [28]) + +The memory needed to store just the mangled name of this function (196 bytes) +is larger than the actual piece of code (111 bytes) it represents! On the other +hand, it's silly to even give this function a name -- after all, it's just a +tiny cog in a bigger piece of machinery that is not exposed to the outside +world. So we'll generally only want to export symbols for those functions which +are actually called from the outside. + +This can be achieved by specifying the parameter ``-fvisibility=hidden`` to GCC +and Clang, which sets the default symbol visibility to *hidden*. It's best to +do this only for release builds, since the symbol names can be helpful in +debugging sessions. On Visual Studio, symbols are already hidden by default, so +nothing needs to be done there. Needless to say, this has a tremendous impact +on the final binary size of the resulting extension library. + +Another aspect that can require a fair bit of code are function signature +descriptions. pybind11 automatically generates human-readable function +signatures for docstrings, e.g.: + +.. code-block:: none + + | __init__(...) + | __init__(*args, **kwargs) + | Overloaded function. + | + | 1. __init__(example.Example1) -> NoneType + | + | Docstring for overload #1 goes here + | + | 2. __init__(example.Example1, int) -> NoneType + | + | Docstring for overload #2 goes here + | + | 3. __init__(example.Example1, example.Example1) -> NoneType + | + | Docstring for overload #3 goes here + + +In C++11 mode, these are generated at run time using string concatenation, +which can amount to 10-20% of the size of the resulting binary. If you can, +enable C++14 language features (using ``-std=c++14`` for GCC/Clang), in which +case signatures are efficiently pre-generated at compile time. Unfortunately, +Visual Studio's C++14 support (``constexpr``) is not good enough as of April +2016, so it always uses the more expensive run-time approach. Working with ancient Visual Studio 2009 builds on Windows ========================================================= @@ -96,4 +213,3 @@ Common gotchas to watch out for involve not ``free()``-ing memory region that that were ``malloc()``-ed in another shared library, using data structures with incompatible ABIs, and so on. pybind11 is very careful not to make these types of mistakes. - diff --git a/stormpy/resources/pybind11/docs/index.rst b/stormpy/resources/pybind11/docs/index.rst index 56a9c0cfa..ab9a1fc82 100644 --- a/stormpy/resources/pybind11/docs/index.rst +++ b/stormpy/resources/pybind11/docs/index.rst @@ -1,9 +1,13 @@ -.. image:: pybind11-logo.png +.. only: not latex + + .. image:: pybind11-logo.png pybind11 --- Seamless operability between C++11 and Python ========================================================== -Contents: +.. only: not latex + + Contents: .. toctree:: :maxdepth: 2 @@ -12,7 +16,7 @@ Contents: basics classes advanced - cmake + compiling benchmark limitations faq diff --git a/stormpy/resources/pybind11/docs/pybind11_vs_boost_python1.png b/stormpy/resources/pybind11/docs/pybind11_vs_boost_python1.png new file mode 100644 index 0000000000000000000000000000000000000000..833231f240809884fb6eb4079db528b9b3c0a9ac GIT binary patch literal 44653 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 literal 0 HcmV?d00001 diff --git a/stormpy/resources/pybind11/docs/pybind11_vs_boost_python2.png b/stormpy/resources/pybind11/docs/pybind11_vs_boost_python2.png new file mode 100644 index 0000000000000000000000000000000000000000..9f17272c50663957d6ae6d8e23fdd5a15757e71f GIT binary patch literal 41121 zcmcG$2{_bm-#7dlYuP7j)*2;A*6eFFmdcVCl08D%$sVSK#-6`~tdTIu8nP>8iAb_9 zL)2s)`(O;uIlBJW^<4LJy~lk&@A1CVag-dh{C?;8T|UeAoXD#NI?N2b3=jk{U(!Wh zgCOc22%>@=q65G27mTd{|IppMqJxC?DSxsX@)IHG7<37F-XtJ>VLbSrrEiAD-XO_G z<Wic5zVVCj2UoL`5XH$JoMYj|IX`G;fAoxt-iSJxp(Ojpv><t-oIyCi{4V#^6CFya z&pZn)%j-lH62d>x!q19+z#eMQJgxu2;<uW<2tJ)ih)*rGYi~&1K9M@Ow$h&4r<B#B zR3fXd9N2^RQKvtK_`i5OFZk#OArLu@rp1=#>=9Gah;QabMrGu=*Ck6;8Ic$aM$}OS zg7;p(a^lFo7y=)c-B}%i^PqzUeLd((3kW_d0lVX^DPi=bI3k(7O?~C}yW)A6q6IQ^ zCUD|s)fzwcuCiN|2QD;_jV6m)N(+_n#W9S2GNY<O0Go8iOb|}<z6E;n#gV(JvT{-V zDS2aCuxWru_K3Np3+{rKBiae^{4VmPU~@YBZsFqER_Q&QSr&T&cGrj0c4BfUklMRu z&XxWs<7kzeg$Tmt^Zv#yNX2ABL0&dC$yJ_Dww0e1iknWkIBt_gSULK*R+93rf?Pew zbE#_XF_)P8+j-XR5$xgHhNy9tNkc7tc{=1w6KW$HtM0DSd7UjG{+G}M{iHaK80`A% zIC$|~^e0)kz9Z?zjT-~;FI$k$_Z9*t`m1DPPNFhSBiIs1sy+5odPpR4ngLvUj`Ux8 zBKXI40W@ee<9vgVptp=xHN_SJTD_|9LNEUO+`PP>HD&tB?|ybB_pm1jdtvY}D2u${ zg!|gpCu@j|!K&j)dz<%1qA)PDXjCoB&wydqO=O$brm2aEt7uo_%}-I&xuVY(6}v0+ z_4OrLDw_gS)knS3r(2{<?7OsaM1Pk4QyB(rRc@nxs^}IIUt^KPz}s)}KBA^2)@qd% z6>Iu-JO(8N1w#X4WA($@EFcy-9=vvA?|nI4yL1EMh6274$;6nK9*Bf@SCC*S<{Jq% zsbNcMh}A1ITuiUeE=<?D^EYe2QbzH!WJu;bn`OP<;z&q~lAo%eMhDND6%<CFP4F$V zfOeaSWD#ft|85?-XNhbi1WugXE@H*Bk47jz!>BF=PLN3I$$BEmuje#iip7(v19az? zW2Z88_AI%0?Iq|vwQ)X1{Tr<*CBd2gVOeYM4mUr3QrE3Ym(8xJfHuGp;{|{76weDr zj;-%FwMePTaz&GMQ5uo^B-?<;7)ub3`W+6dZrJDVUATpUuc0)?M@DvPPwy0(%rzKs zgm5?85CfH|mf6rHTaEjpdom}FL?$6teIcEVO{4yOXjuRr$Payxy4Uht&c(VTt3?4; zWZJKC!@@$N&oIs(X>?Zu-A*L8?4$=1h+A@vgs|dCUnM<c<7?~{$b>k&9)qz2p>mdd z>l9ey_X4XqCy~g+OQBw+ry;S3z6sxP5$H`jXLmf+GHfiyG9lPVoGaL~AB*aHJYooz za)f8?3?xKdYK|O%&QWijMcc!66;t*0jL%mO-r`K)MmqR}*<fp7njw2GhVKJ+6>Tg9 z%{&F+=$^KlWsfZf1qMDiL?VB<+IN+}>V=v&cWbsF`Kb2O*dPy?)O#B@?xMyIP5N&& z(GFKpZCQDgDY4ndbYyk9ws|cX_ZvpH+e7a3%SX`W*dTkER8>Qi5Y@5>L@b;Oqxub7 zHig%;_>K?mTAVr(d29Q@MhQ&y4B`zmKs7`+sRjw&wW@xRwYFyluc2!;!tPv|*(2{= zLGD>2_w3PqDOB0k$X6TH(o8Kpdjy=TZftC<52TudJq(E<{G)W)(ff4EBB+L8-|;IE z6_f-HI%_a0lG9NnAs8>oTXf#dZPDJ$I`HTF-UZbJU2)n{D$PTa_i)6pZ*_0V%DfE3 zx$5YfN9*e9N~pdn4mI+(nHOSZQ5#FSamshRlr!Rjs%wf#z7Wo+Kg`wHc`GzHIM^?n zyw%wBwh7-i`*!yCZ)bW>2K1L<SNUPQ>N99d9DNn}EHKmGKFeO{@T4H*LA`tt>ZDVN z-#we^PIvV*VjlbYHG4ye2Y7QgTq8LcyK@rNpqzA>Tm|xdWnf^y<5&C!4%#zCrCC^5 zgeeYrG4O|vMNJcksstExz46|*UYl1ay=^ge;uwNeDQ+!tqHqKRuLo)aHlr@CNZs79 z&BXYGB=r&6f}<rjtiu}a^kcD0OG}P3+V@Ig+ot1h$)q~LjwM~r;L_^7Gs7^j7J>`g zkkb=M#24Hl9qM-aezR=I7y5Nv0TC954@^5)18Jz5>fH%&nf_O<bV^=H0OjAge6pQV z?>uB%RTYQK%*+O*bH{5i>v1$Tz15y{=t`GCzk<2dU7O@zIyCezv1_ZOU3=VzqtGk; zG{2K*CUltkLTSs6zzhD*n~S3*(6Sd)q8R5hP&sH#Y9gn%p+Xp)pyiOTU=FQ@@cq9) z@tQn$2WrRV2J)iylai7;Nug2+2Km%IYkNjWK`OTBoZn}1m6G=g=1`3Ujjtr4oXbEx z0-><6H_lU0M3C#w#H$^e?17FULI~qztr_*}p?AB}m0pvIw=$YSl~V}{U%b*8gR8ZS z?jH9}zA$dG#T%4KltrE0`Qc7!Wso{_EGFl7Un9X|u5O%2&O#_qYvzdVwB5vm>i^vJ zx+;6G!vO7M&HKinpddQ_PXaOXwWlCOID~Yt3UdS1KuF6S>(S+vP9zS#O2()rg>3~6 z`ZlG4Hb8W*Tm5{7b*C|FIb^@?%a<>8+6fy7R0Er)A%_+-_`f01J-ThW4W@V)ijgK~ z>WCz63wRqB+P9{h@1bs{U&B|pqr+P{YFMeD$%nIdgY+gIBWJk7d$f$!FYHZq?{Re= zNf3atvBo4-^7~yMw{W4GkY;0wduR2w)DymbdQZpDto;cabrkthSWo;(`!4hC$6;L# zGKMTqrt`NS6D%t4pipJ9a5!9FB)v)>nK-<YAi*PVi4FP-v##Fw&3D`r{i+YrME+te z71&-JESQsl+MstPC`n%{e`<6VuYIWBN4SpaHyde%r$~gCJUXmHXxb-L?^n}~yFWkv zME@ACgB_3cRIR&Ib8!&&WxjP)DE-O)TIBhWb@$hV-@j81+qQESJ^rC+pflyunsO}6 zU9!HBJ{t>zboYeHU%Ys6q-IbkZkp-T{tD#K`RuGmK|w)E0uJv(_60u;@kdaHM90Lc z;}Ughi%D73=jN?6i?DTdBxfj%&RGX^Wm>R-@K^)fr;2VKJJR6o+qZ|OYL_lRHuRo? z=$3>tCQbZWy~!%d%F0I~KXQZQ^bmA!c97XNKs6ji=VEc2AvhuNWK2ErY7ez0;fFJI zahF@n@Sufm>&>!4>Po)D@L7I`HBF&I^{qwb6?cMzyer;5JjNr{gjwk1{>jPA%*+X* zS~f@nE!DanY=Qmt>z5ViSu|22cop<SSekjeK2Fd*n1WL1K#@c6(!!OVgbj@YG|=gl zp87BZwl#8<v>p<cPaxS0f$U3wCYUEJprCwQH$1^N5_$8w@GJ;qMN|WOO#)#P)Hp1T z^I5LwoLYR5wBx2!w|&9<Q`Q-xh3wUb#}2(B2JWtUb~}j<yP7_Bms7OYBizBUCBW8n zjMnGqX%-h3%~2t~VhvbR;@~L_t)S1x9uxe1{ZRr%hA#|`DclMz2-9iva$FjzbSdri z1y?QBoB&Xd5hlmkXUX7F0TzpWK0Y?K+qO3%CokVUT<wADes9{|oe1!b5P+Lk+}zx( z+Q)O|s-bV7zJ0;&_{_ZGkkneLx=4M4QU>k2dSG32%RJ~?)cV_g{7ya`TF}*_H1FZm zR%cYk*4Pqav9)Z?Hn4YYXveUmeV=3k>0vBS^7no-oAJfkB}OQYE1`*Md46vsvfW~h zwHk&dkR<Dh>-d^uM589CY%khn6&DxV2j@Q~=3&PXRH#LwpJQu^u(l^d+A2x)cDBoO z@>vV{yz=t$2_kt>ct{dt$9>@*Br?}~y;o-+u1OCejo!X&lJ88G)R5<jR<p3N36o0D z-6d<1F6Z~P`i^r8v;`LD<ow7DA64ri$)ZV+Z8ix;yiw&k{Peo`rtu7yZ14cjTJL*? z@6Vn+(>QKJ!)xC?UlKcC+qSM0Z^-1gyQ}u}IN}NeA#1FYr$QX}Yw7*wtxJT;4_W8k zHx>q+ot-_OkRWR8NSY05!w+IhSR;)VV(t|+;bW!iR!2!^|I(W2nxa!^U3Ux%MkFZK zG|7V)<c9tBv?7Mp*z&;Pz3rs|AlAa~DhoumH~re*IXURdx8rV8<9#c3T2X<jfTpzJ z)hoy53(^{5V;1~j_y>#<iuHs|6ER;7bOoe|65>7a%*52R3Ok2@R0P_#bwLA(J8qzr zU~`qJc@E@H$A>k@^WvVW_1xTCtxIXfr<-LWGq2p6E}_y$Twk|Y4@(&J6Oa3QEVx9p zn|d2@SkY$FH`@R-LD;ZjRs{fdZhpSxg8R&_EkH#Zyx#U*ob6T?Wa&X)jZy!s;`vO5 z$*iyOqESI+<~CQi)Sl{|cvdi%O{6DuuGQNdt4>LUCs+WAv)%fDOxDlhS70gSRR%lB zjP9$7#Awg93&+=Eb93$C=y=#Wxl}!M4z1o?XzszWEtMHA@*Gv^TLL+b#IDt=5F;%_ z=Xq00>r<<POyFazAEYQ2mD5Chm3p%G`Sa&4^dmZmga8fi=vbI0Tg24a;`srV@9I%G z6|$*a#y-EgwvF~w)r+wTb;TqllvS2S{HOM_n*ApcS3KTLMNm^OvO?fpszeeyeqw_j zV#Mh^Bj#&0=)d;$_O67^F!UU1PFCv)b|?)Qe$wHPsdwTCcVv6K*320J0fA_%!3INA zUT*GmOZ(X$1G(6a#_HWwRYD{Zu_6cGR!0lrH6Crf!3su?5!-y)t=24ui2-%~gwX89 z#=XM;!+2gnBwRm@uz>2Rn=N2(@g$WNObOIYyL<&YMSp(T1P}nwW0{+&P-NXujd*}6 zJ>vFIl$<x@4+PPZ2cl<jq;g)!WTO+ZHtE+wtcKs~4NyeWYdItkNUThiC3+%jMHul5 z?liTgsAOnM25m@<#+<uVG0e(h`iRedhs#mtnAsBnjjzemib)~e)9g?qjjam0kCfgf z4iD5t?GLQglOC_t24wn2OaEe;DL$$$*z5$ed}KMbdk7uB)fo2EbMw|k7Z;aAY$!*w z5LAD(8L#EQi4H`p+8|al0rKM8nI%eMcWy&zDBlEZ=wVH2G)~)S{rGytoIe15JT&jk zu{*NRbDNc2*>=uZ4N$^vL|GcCiZ>GWPjW>!TtRtIT|JJ-y4EjQI5*rL@?>oq6gi^2 zoZO<&O*7D8OeTE?eLzYT=&B0ZK$E&q@PlJR-v<V&g3qbksJzp^o|&0x|3OOi0@At= zi`_9koIlhUB#1Zy2%YNq_wVaJoc#xeh7{X)d>%+^KRh->VN-+S@qwxqpdOaBrqsku z(?Ie}_PnaRyu9f<J3HG5Zxc2eiviGYycFA_+NLW6+LWZDa*i>z?3>s5EuyPCdE@e~ zBpakD`_5V9h&~rVNG?n?kZSD2Eh#PW|NjSj_z;U!Z%uJ994!PXUR|({#1vrT2FZe- zL$yc!Pms004$L%Nfb92z3~e8H?FMno<6Azgw66LJZZvB9gbFXpc5PBM!`OZ{9m?Ae z6*|qgy(JjvOs4$BvO;<};Fa!wPC-FK>D3F2bJr(V`jp?unWHH3MK&5d2kAN|C#MJN zgGttD-=@dqS-qPAmzt)kI1^G^Q~V3&N^(T!1aH6U5RJ;21x4{O?fKGSzi0Qs736+z z1L^@g&3l-AS0{Mkb#ZyQs2uxT(Vb4`o%mn7+9OVii?Pxugm;jkVUG~Y1}Gbs$z=6w z@~bOqt6z6k)V$Y`FK?i5hbCux*W*9k44a*u4ZIa&4~NHUfL^CJ=qn`gsq9+e_tVpX z|GcuBm1pSzu1QPKJu%^+(q?;^>|t6o{b_n-TH@X0gBDg_jpBLJ{A-2PF;)A{-5xJP zB1SVc;!6}JY}o&~DoR0Dk|i>p>7FnUbPF5w^;ZC$_h_dc(uBX&58_ovo&9{O-o6rd zak$5s6!+4m%(}_jHs&y@vdu5<{nH&>HKuJ|y7kfH+C(6rgxjSExb63*<8(>OPTuRS zBo`-PA)GMl8(hGCCT|am%0g*7kL=vOM<nL6_Gz8W!n<3A%Dr3fvvhJ+!Zi}@qd}`= zr`O4hWcWC}qGiN!mJ*+CPRGUk3r+5ra%e^W)iHw`>Arx}6iZS*8<nGV#;jQNgC7?n z=bHVBo{1)s3%Y&`;agR~mZXAuLtT1oUkmvx+%5otrX6;znmBmk^qo;8ZH)9h%$23Z zGk;MW`Lmm+LN+QVEm!o%<x%7`8msOYGkgt&s%-h^8#k}jpK^6NmXl5aV9-)^#zTy^ zOezyWOAmP~n$i;v9udtyQvdwqd<XzylVgJMSv1)rJQck}vRc&|TaxUc?>xvT`fS<6 z4%J&KtVT5!Wj8-Xs;Q~Too92s<Ki;vrosw0I_))+T7br+yT_OpVe3(x3AYe3pp_4K zrE7sZgR{}RzulVhsqFfK?x;Bib2(PH$6gcp>eaPEW2l*@qM@+x_UlExb3v^sZgxC= z)W6?mgcpoO>N@d6q{T{Gx}`buOSRs8WXHo}&ob04lW;PzV;gae6|&>;mWsxFz6j`g zpYQl%H#|id%!zFC9UrGqY*+lToEPB2C^zW*l=oY;sexR-mywd${Y1!wDnOe?<2AOZ zeq?_x)lwte`LD@yaPV?~?VR;+fx9M!duk@dMz(Nt3#3QCY=E*H=+7W`ZYNKy3_i0z z(#tc|E^BoE<dtW7S?VFR0O^HN6g2#CF((keigCsj{)7q7@mk+tH}E@ua5<GIKs_>4 z`~{soJbFgD?fbTI<ah-dHE$vGG~I1Kn(t#3>*XrAkQRlWUjoz^5yd!FcFuz0;ynkR z2yX10tw#jXgbE>}z|_L%a_3HWWkxs#YV+d#AXQ&lT)adxYF^Z7Y8CaK5pUgh@-LSt zfybDr_)oG%FnC8)`+4}`gOF@Zxr$`bHZmCywnR>cOGgkAAl~A4zG5_;+FyUh+?rM4 z;yA+!Pom3rW9I}EPI>ewMl`>sCQugL2^Kepzh}+;ZHAp{N^RKOD9j}OrJ<-dFS?22 z6dayJ1yX>r(At{0*U7php7$6MTkqC~KjGy}6LZ*x_qGtNwYWAHLQDY2laz;W>B;At zG{+?4v!g%!rq*IaB2T_|0hx5-NTd&}%d~$KV2TP#6jqps$$=a9G4TbIv8KaMFvlBT z>;4c67=cO%4(Ff}f3`_43ohQU-YpdQxjLfH+QhwPi7&dEQ-vGO$qg>ey2KPYr}grK zA6t%hK9&=4ji6}o24oUV!JRjl?>a^%w^gFuWF1pFVSx@j`dRUlme<!cktTP=!R27u z-OjUZfspSR?Y>~LR9jb9O?Q6MsbYB4)#*4w6Y0+SpqceS_JWh66?wa&_Ts0<u%iq6 z`M3+YS_&^U-sU>I#}qg#x}_BWXs+T$$;qm!DhWuS%7@K}1t)CdVzpD$0I7#g<oQd; zB&0LGw}2GUt~Bda^OEZGewc#AbmTdC3atYVfd_n&>ZIckYlC~s$-JHm$WJY|NB_~_ zE&?UP=zf4|W4l-SQ9GXE9tRoW#&}_PYzA1qD=0(S(zdmF`h$1`lHfU1#;js@E)Z4g zJ*44DoRn~5OQ6NpUPaD<`x5iV-pI!?!o*8KprNIh3{CpO|5cE{2Z62;gnAR3gNe>z zGY948Xv9>A5yxURB`#4RddN)B{C~{#B2E0jrE@N;5)S_zP26ak;qLQDB|w`mf!|?V zr{20zG7se5aSBX7c<@qDf)LX-eF|0}-|7koVf>;h@@JRtc&%vEFW7Gis~_&ZXtHEl zblvNwp`oEZ8%^5C$cW!)_eG@1WdPX3jv?~-?73dgxq_PWIRn!r(<%-KRsv<$Y0i5- zmv;0L=TiChr^5cZp(-h+I@n!MtxcAYFJ+lpzO<$!gTz5J^Yp<Z>}+F{Y*iTHMulYo zB4U$)6XR8~Y(@rv2*^W&qm&!U#E;vnP{R|>QnZDG$2ppRggO#=QFQ+HXz_d~y!r8C z=S@~iubO&s^Kyrs_1V4*DJCMR5oZs|tCEjZ^#`x?=MBNci1~pxqb`(^>*DHK^ahKK zS{$oc(*zi9z)ujg53%_l<|tO~glW<+2el^?I;8BnxVV>ic~NccPNE%;U>;Tjwj4uQ zG(F_62)lPLU%h%ojrO3tp$~ulai$h~Kvmpf&7*B_BlFYqKWZu~H(o=HH@5D{r0(9w zh8iJx)1E)yw7_U{Me3R&S*RxIPa&Tjwf`U*1!~AgxI~UuGfyI|=T+pE;3ed({Gw?5 z9?0DIf;n!O<znDO6WE?SAnyAfER&DVnj@6__cA#jER&^FQ9SCkDJrs^6;^*}^5$qD zrGkKBeQ&beM+o=;2xtwp@nB%URN{#Cp9O^!S9h_L*A&i$Lsgh|<$u0rH|2?N4-f{N z?Yo)^=T5$P^QP%Hg=3y7m`jFslK>!7Ur_AkJbU)6%8m=JzrPZRjH6jrn#e4u2SWJ& zWxb)aJpFeGc;N61@YuW4dSay=9mCvytZX5mePKkW)<;ac34Hr9hgLkmGBwl-JC=|d zz-bEHr<L{jD-qWu5u8;I4_ZE3LQtF69ZHmGqFl6I0xEU+phvo0h*hmC4%TC%siso& z&6cNtrkgP}v=l9k(CHx41VbYcW!I3Q{1Go$Cm)88imsRCs57+?sooKvyA%i3VDdHD z(U>tVn)A0fv`U8lE?vC#_fS7$j^%iP!i5h$0Z)2;*hn?MZ}z&5PMa8nqq)jB84pc- zvl)$wit>T+pGG8aa&<#rL2Av^E<M(A@B(6b1wJrrX`Bmm^=+fpV4XxmBo?Si9mcQp zhJ!Zx%?OJj>PeTsFtjXt!UI16RiU9r(yI3E$kWrtzqF0MH#mNI9vebT0{D#%&CDmS zO767TllfgyQUjctY3ZmiCgAEAM669p2gG!E#(?W!4~p+4Zb$kFs?x<vo5%H%1XC~P z{SrA6c{o^bdVz-u@tjTM<J-l>(P|<3Nd`zIR+_+>U_p2141&<PA84kLMxX-bQuiF` zrSvbWZH=%#!>r?lb5jU!BcS)1gJSq}LK41RfH{Y0SJ|n`l6M=KLVUB0*|wc(TwUaw z*lJZU-3XzqZItds@CrW0+WOQsaCuCE5C8s$hu9YIg%F9|@q*XrqE3CZ<$~)!NpJ#2 z7C_vtK%t%gHhcGpo=6YR%k5EEGce_*=-|USShfTOZdc{wVd=dR_j*qw;+5kn8bQbP zAtbH@sNUtzzknicx}|?{tN_s?0QqesmQh2swY52oJ$&}obXP$Mf8W?cf4;QGE1l(E zS3_C4YXa1Lahiq;rRFKh^TPQ29;MaE_3p=`P0NuF*%wtW-;3D`HH-n$ugO#+NV(@v z`j7ytDwu4@z_;Jx153<9`hCaUpg5YVsCRe#0D3(cm4l0F&&b4|U8-negt~y1KcCy~ z{R;ak1gGKlH2>nX9$<tsirq0%OoL7`smTX$2*BWH*h~i7czhu12&G_4Z2cf=aO$f} zMbGJNhXpJW66m4rvfjeks`aB*Rjc~Q;`t?(2a{i128$Od&4*6mxOS#a0atV5p1VRG zwjt|?DKTVXt={DdJVt~LZk~<RiEQtKK$kIpiS@<SN@?V@{77xjS^MU{r;m1y#mH7> zed&Y9mrrC6-0F9ooQlbxl}MKbpI{2wMLx>)2y?&+<~$x^4LbIRt-c}8z2LDQpnfMA zm6LH%UL+?+rgZ_ig!gKo!0rX(SrrypgoZ%2=hFQ5W!rF@zpet%B7amTlL#vSrF(=( z?r!8mzO+WcY(1LPBB6jx;-f_-<kLQ2J~B3!07xq4&-vrt;jb-^`%JYo0<CxAgvL^= zcS$$#yoT2GdvE&6hpF3Wfj;a%xYkyDZ_js7i@o=w{LyH<J`@+1<1B(6<mfTtXgH5N zhOlT`MI&V7fCoYawWchBR&HM#M(Lhu93xT>!o86ncd60kqL~UMN-Id6md@IWjA&Tu z4`&(^(+G<jh5?$fma6{StvU>(6aPfi2Cb>t$i#0B;+bKrlWMIg)v$mUgouez=7PBt zgMH)vhnaY<3oz#Wzh?n19|x#JUzvH<;tZ{#`-u>m^6cw@t%-P<H4QP|38w5<wu#gU zte77$c$rg{=M)-e+d>qAGOJ$@%jRq080QNqcRy8N_tG%HYD|Kb=(3@&LqpdYC+|VQ z(3p!fB9`L6pMd&XQ(_wlgtCms1?j+E<_7jMlmYO=X;A(@8<7**Tn3{hPiuQ7bA=o1 zJXqfDI_zQe`;F*zOch%AiICe0Uc<krZmRp*E#aIWDR=vjz{Ut;o@9Y5ok`W3cyc*! z;z)cO4tUHVP#k9hq3l@BdrbQ*U@TbWQ9rI6?^B4180lz%Hgg9RMx&b5M8X1Wc|msv zGuNjTCF?HQ^^>RGbLpg1P~HSX{!l8W;GKxoN_sU%a}Ub*5{K5leM}${Iq?FU9GpoE z8J%*zC)?^8o#R}A^<x=-j)}U2R9@4Fr+`T@k5vz0=OXwzE}H8W|4^gf#1uNzna1ju zS`+b+KlfQSc+$s5=~d(7<K*c=<NQ4&(r>+5O{4stsj6Vu>uE&~+EPQLpv&#sQ<664 zPV}sS35WX_@6~+|8xIwFqni2NWgD@NmXPg$)N`Ebu-V9xX-KrD_PM{rpMY(Cr<;H& zpb>Fc83S4lU-Qz75n!>Mf~lJC9<<)XLH*fJDm_<l+xtfo>Yy&3m$M!>jUPA^dJo^c zQ20He2UjF^fde7-;;^}DyaM2Wl(_Iyc-6DFQQo<vcrvOh3F`jf!o}7{zPj6PJ95jV z$y+=5O-$Yq#crRt2;qgi5^IHS3lv;mPdu{?@<7Se{7><bY|q5zkMCG)-f(KZA)zpR z#ZS}eP&&7=3z1w)X3SD_R<SAMZ`z&B&+6<7)<!EZS9IPth#bd}xF@ht&NpuY9-jR_ z22C@0^zJq4iQB1*s`5vZ-bU>?D7tB_N6~g>O_(hJ4Z<>A<N~1e<p}SqNNr`IXiRI0 zv<OGSLnDq`f1qRwvAy2@2%r0r_i`=HL4-Kl)>~SvNTgO<f>RC^m_2X;*ytyadpzho zYZm#DPp1PXV!`;usWx%kR?XSeZ9YhUdV{ghmwKmVpV{f&bVdhmMMf&;5*o~HfJd*W z03U9-g;}AyuBx0*Nc)jObOE(oTE+RhgY}$gI}LBd4p#Vptg*b`U6Ws;^?VIJ$HcP! z*8x=q`0EgVpdfX9&)Upix+l76r7Tb$fJ^kS4By8@iGaq=+_KD%8c*nOa4!c5IaX6V znvL~A&VUI8h2d^lqZM@^iLgiGrJG5rhRT)O3U3)k&jSRGHO1&QNWXGj61s9Ov+$q1 zs}tEuQe~&?`ah_a36LwJDCM@et}ghsbgLPv*yPGN7EJr%z4#M3-k*K|so_5|smOx# z6<)?a{NX=QiD>?|RCvVH4p3?TqTph2a4*;TjbRHbs)X~DN@4}NoIc7)Id09_*tjnm zP)~T$5sJ2hX{SP2iT+cjG42nCxB#L;YVt&!!p?ngmACLXU<L;=h_qt^b^st`EhCJ$ zZ0iD3%W|V=)F$ALNFdaRAbLztsDs8<@cpA7I#ME4FZ1xEH~bO|E$tW#KGw9e>;MF( zUlvJR(|RcgMl$LpnObN;Km3_Ni)mGgQ;mnA)P4s}1dS>kJaczV)#D<;e$ZDq%^c&r z74YRC5I`ufDX!}Mf1~OAk+l9hQHP>Zjed|?p!<58QYhIIx}}&D08Xi*kV1Ps9iE8$ z(!bDPYms@alwHIJ`j2*NB9#CrAB8MIje`FK%6B|yn8+&65qU~DQ|{s)+!weR_knW7 z@INgJ|Cu)3Tv4S%I@|#}O$$uuQ9yC3M!J!?W>!|@4k@PiYyDYJKr2OI5JC8~NLgM3 zI|6I2ro_2YTpw^eq<wvTtD(uoY3<XgdfnU!LC~R=C$i@wMGkQRQ47Tin%jgQ3ojqy zFV2LA(1io;DJ=plcUulE{wc&6b#jBs{F(A{Jz9eCCs+8wwcjn$#$Jn+xUH+hA=lkw zI;a#y5%=O%X)^I{ze5&k-5q2Z;mlbSff?vtvM9Ml(%x-~s0QyHQj!cIw#EFu0d0_7 zm#+1ejC-yOn<Xi8>r4Ds4ApiUL8;=jtKn-+x%-sy1<dCpyiL%c*_G623}(S@g)-9h zy{&xRO*ZB?FB6`4;*)=O-FjR#rv|9x!>vG<0kO7owXhy)?y{3t(EeEgjUlvo&HOBV zy!D+>n*?Nzu~r`4SC-~oyz~k)z<Sz9lY^xG@8ujZR<Qt~yC>9ULOy+#nb=(j&bO(o z{t=dJrs<OXS6C_yI&^xws~&gg?kwMQn*50VB_Q<zj=diAADPq(nVb~44}v-zC)*U) z?#<V8dT8u^>M=_xebuzcP_Ob}_ZRK{mO_#;A0Tm_2fF2dBuR^98R4HXw#0VrOzByi zWYyN1f$95rsr8H-6KuRb6|YtdE<LQaMdVxxr^sx8vW!qdnd0|C0VFQ5)8XpkPgvu! zTP|wF$g1<)qixx5SP`&@%iM?Cwpe|N0Y=K5KRUtp$2?ZllarpKe8@N8xz_g_PQ=Fk z#*DDT^=Uv+q%8ZpJs@Tk{vLchc*A1!TXdNDcg<&R4I94;Ar`(%LMVRYmx@T_07#kt zqW?%zB$93*!Hc8RIGY7~)<W#Zvhs)JfPi$p#k&4jkR&I_|Os>m5A)GH=&|-2L4P z#5J9sd6?8f_&L<wFt{)rZvOs9AQPtjJ1|2TARhZF1vxpl%8W>DLnK$hoDpL690WuT zuEIMRSP6~<7Dzm^@MUq+7I>@FD}<Vha_^-4Rm3uw+a-(w70(&<#d2q<ZI}4c9lMRR z7-$#D-YK^8k6NxnXg^;D^y419kRGT_O6*UaAJ~FSHQC6<2hO|Uv&-ya%uBG9MjT#K zQi#qNX_XdG6{8SwHxoDqt#+q0V4iOHQhk$A4j%WFG0ul$*S>4Ar{e?pf`sadJ5e16 z>4~IO?Fs(iM~C=)+uePFcG3(ea7lF`eXnKYNadXovOD4rI^*Iz?!Dls0U~u|AM&8O zUOg4|!_b`hCSG%ebe>PFILLmwm5?OL1vk0`gdosua*lt|SFcoyqRl_O-icNpcQS_B z$yc{0%OYc6Yh@2yI0EN{{}08i#-=^tw$1f*RW_RQztY0U*;ECxNxgB?5&^}Xe)5Q% zn}0k51MY-elZ{gcoae*=HeGw|RuLdlE`I1iUyO9y$D3sq2D<K{4EM55<j4RKwgB`N z3!aE^NclhqMtlQmog=V)D0Rd(X7*5vlvFD}g=`gk|A$)VexTOn<=x^#gXKTaewWGs znr!Ei;Q5CZ^S_H*lW*N}sIEK{PgM`uxqFJKh1^IW4pCyya`25Of4(DOqG77mcYgDL z0rK+kxxB_=Z>sn&seYZ9$gIqGj460Z=~e%LVb%rMw&4R6&cPk1-vi&jr@Mgu3X7XQ z_sA~5&dO^1Fy+dVcn^B>fjD*O;Ko{0q@r>F)be^1P4NsIVEi2LMx7%@!=S#Ifa%Qn zzb%n3ki>x{qS{l}3jzXR0rXkQZd1U|pPU0fMl|0Z{SQ6`rI4Oe|2GrjzXmICxBi8j zDECas!7(YO9;1E%KwCs8U?XF`mKm$8gIogIX5ykMd(uCmm2bG~0<xv;N9ym5J8M~V zW<xAMjx?#ffSik!rvE>6qSynGzvk?r2cJcwtU=8x81wb__mFGd!j9Ne77gL8f)kD` zusl#LNqYtd8w=zyM$N|*c-cbKMTj|BW}^@8{=eQnl9r-rfeDyLcJI^^JL(-M8s(L| zYZWFNCQvX)r>~S&nS43Vz_>p(Zd!E&7`!<ETOsp4Qs6A2Toc6|rJF%Pa|Wn+6W`-# z+5<x<Vk#0a^|UVo6j)?(ha%V7{+-}P9REu295UtU+1U8Vc3EJcs8AGlF*#6g{?Al? znr4_sP%QeO=)sXvghZu{d~>=x+>M;R2nK?`9qjQR905(r&emxZ<Rn7@3MR3LN0;&U zdtMUmm?4ubv#fXP7eQr4RxLkw0-60`8&`YgO%4&-;;Y{zKD;e<oz5#XEOZB-ZxIEY zWd{LD`~lw&_(^>B@;i-9ZIspcRqJlWp|u9xb(BfXcg3d`sjt1Mlejwh*L#auzGFKT zjE&^zY8z54tJ_(98D3z2{$C5&iT&S%c5gnXN@lIt?vi3^M19ws9*Q1p@_oL@R7Lw= zv~5bs045vo9=~8m{>EjyJ=5}|<|1#X)r6=#x0Y3$Td+doR;ahC(_I6VYZDbGWeH9e zGHaW@PAWu?j;{HUa>og>#SJ|9q1Z>i#%r>zcfnB5Fpp33ANib;{XqS8qfnQ(Z{NC7 zdp0ccC#GWReIKdau@0m?1#S5lQN^-9j~Mn|uMdkv6iE!3(0(Ev3&1^-TMHeT@|8$U zTo6rTwNUG+Yx|Rss{oOhbaMy`YH>X>j)LD(9o}hW|Mp;zv%BPYb6e2O{=p<M;E4<a zK7hd#q#w@Yvx_fa-~?v+3)hCtt!?aTrJbDVZi~;Gwk*_)F34Gyg9iCO^6XM$_)q!y z^U%Q}wpH#!tR<JiwvrHS<zft9XnEcfbm<KEHO(zo`+!zqfkJVP*7)G>Z*FcD{VVeO z`}?y1^1pym>;9u405Dl!`s&p$OR(&(U7A*2yup_HrF`L(N(`%X>-Uc>sQF#^DN1HS z@c?Cp1C)7+!Z1wk9PlDajf>KCrl4xs)<+0$DbV^nIs4Ax8KD8zem$+eL95jS(v>Ie z5(%@y3)0^<*`HDDJ)}w1Ka3~K-Eil0XVCUyrf?5av}YqE!+xXF8mD6<q|Kn~aSw2; zGy#VZ`vK%nLT96sdN_ac467A<#+%*&+xkbX2do^8(bLbnmJj{SR7NR;QTv0T<Py!3 z8-F#DMy1&^^5Ajdy7JcobAosFY~F@Vv4ff=&YAnpj8=%xk6w<*CC#FLp~Jzu5%ZlI z(5Ljnm(QIq4G^Tp27O(tKb~I)5Pz)y{5Pit2%zqkSD&$S^K}*UjfdM4TAVY(h0QqC zIP}H-4I2w-%u+bt+%#q_OEvq!NhqRmz}mOJEVjp0B2)~4C<k^kk`@TmHIU=$xkXTa z%_;TQTrBB1U&NFWwpKW?V+<6wr1+Xn1-0dSj(e#L4T8;O<a2>q$6x;vk>7jyec098 zs`@+%k7>^Ule2*Kf`$dkNrSc9p7P6or?<t`c`MT?TM_gMyUr7loc*grx}DJQZn_yx zO~JVIOpCa>$r@lCJ$sHFh|&$=&`SE#%AzUd(%XWKCJCr}Hz^xEzqB-QCuW5*x4<Q4 zxTeum#@B4PYIDo*AHw|^N*TO|!`(i}y2?sl*zZz`%}=poe#S6H9Iz(}Y5F4!P?!`Y z7&QMUA}wfFx3S87Ug<i3AX&ftXM+aw3I%f);Dr^GK63#1Xi6zHfC>!!7@@cwD~5v( z+>3)H2O|rpO8F>+MAQX`RB1<G=M%Mz-r^`vH`$Pe2fo5$?>zqB*`VPN1wvB>hoRli zek_R39l+(Iz-k9Z0HFTd&wscbjl-Ii(vG<V(%%OBfR@oYR!t{R_&-w$ay2+a!X6wH zbmt#~N}~t<*$;~62Uh|kU)NDi2hJ|i;hD5!*|cIbrOO;UfKt)+WkU)7!WsbmhT9D> zXZQWd=?ps_clp+OS4x|0O^K6YqPFjX{keZiSN>ao14n79VDA7cM0^HHgW!MTd0sDf z=m4f*zKR{s5;5eTEhT(fQ7)Lc#60-MqI!^WSA+lWiVx-xz+=GuW1OFxGx!7fD9GzT zv0~HwyTTZ82*l)IC}RR>X%WWBY|OISUzpD<lpy_ol&IL?!yo=-M%x}RN(xk>q0IT_ zl>6>g6BHR<+~aS)bhYrRFkiZ8eZ$#?Ey=113dskf0!lr;;|%cB66`n_>Iy1uXvko+ zds+y_tR>LH*q~sro51+Y@qPxZp9s5vIP6lpgN#CKe<+`OLx1Y(_qUyFKNuk_IKze! zLrCK+o;S|7N|=OIsfD!el_`t#I!ylC$iTtW$_TJ-ea)zcUSPwhO3NA>LoI;!`E=3J zK_5&7MC*nx9;4uvGsu?{Ug;y!V}&OBHNUiBjS&+cwku-}b!UlX5EU%F=D$m;Nc5h_ z#sWGjq-B(M5YncbpM1cZQK8R3yBClXClNwWDGKEQ9PMcFHep8OOx3YNyI@ofe*j#8 zq-*i;*mA}2f}4G158!5_sNShDg`KB`q*oyxMR8Zo9R>Oq7(+PE=IO`<Ps%9ItZD#Z zy(7gWN$p8USMpKMFvu5%z{D#7a`oarb$Igl>*Iwp|6U$=z@an-i3XC3@b82hnT_~w za<i;WGLA=EYxE~pd=0v`(MD<_4>mEsh2jdwcQN;<>eC|+%w4zdpDN~SeYag6Wu+DD zCjfy?8tTXHj86b10enOzz<-<xYFyJ`BY7-#-qaaHw3iA0zLu0UNrpzElWx}sbXi>Y zN*PY%darf$jVU;0XtKOJ5tvrB<=tDh6rtjVKLP6Wt@a;E83t)_adADc>yxCt%aE=} zqL5ktJj$0B?Ftstsb@{%wBJzKD=dNP$vE)Hg(=fiIr;f`J$NBk!efwVg4G%E7)<Lk zY9(dfT636>9y}-JOjzy4%xB=KFVT4Zg7gj0y`x#3>C4+SEBYD|x8wnXTe;c(qXtZt zsz8klw)E&EirJcjeFMFMy<=@wMKvfU=&JUQj0E|3O~;*uD_Ns#ic3l~G!8v@t>wS~ z6<}+NgDVLnZrIgM>B5iy4PsutO3c^9>yi%L{Z{hMs;-1or|da3c7?{f-^b+_*?nm> zHvZ`eo>-NCo6(R2Bm#^zJe1(63fh<}gw$Cl!ARc(GX!S(2=r3y%>s>ttfSGN_86ME z;O0i_Z$sV{TMT~vDm8OC9?aw?&EBoWu^!G5#lobhn>i8Q$I&fXGY;???q+;q#|*wz zUQVCpKY?}ovL@{5Btxh@?qxhiU7o8=uq3m=ZwZdQF4y%dPLzT?&lQ7lwH&NOmt)1o zL8TnY{<PK@LYkn<=54MfjS)8O!I6z>NE0Y&q3{~UW{c>fZ%YDH_uL`Lo^+)(0{xvt zK$m>2h=v;*8}#60LM`akC3M%-g2m9Csy*Of4{kPaA`297UTC)jYkj@QCwm1<mkBn5 zffN09m+eRqcKa@anNY#O_)mMgC7Crk$29oPC-2uRr3sPA*ZG6%|B~|KLMM#*{f+^F zzUx`0S2$-6EddTXVt1h1GAp}*Gle%$THusUpEphOFjS8C=HL575Hd)RY1EcUO)tUj zOAoDp3%g7?<K+Vt(|{pa;Pq-GT@EP)hn|wbiJV}Hue;Vr9xS%1lLQm;H;~=t4M7{< z&y>`!+Lm=cZWZcT%Pgf>GSAb}{9#-D*O&Twf4@GzRQ2d$Y&xx2IRhe*v?}oF@Dun3 z=BQU3_44B%G&w8cVDygC;}gz4j8lC*X9@=3x1q_}rPELx<k>_ZHJmYu#!66KT@U^N z=BfcRgF`wj-zh@<kpv-V$Tdc(pGXb^EYp`m%Zchxj_4gQx8Hy#C*R)`uCaOc0NBZy z(rSl60^V`kS@?n|=V`XBxKc}_xE~SSvqQM{vs{bjJs9Z{#qoi;)&(Zz)q0>sGlR|I zL(W(f&l}J_fgn@^bAT_$mJ76(h1o5=ew+_*eEYKNY1mNy8d3-lTXM;jz&8N;j%k0G z+wI$dzL$-_@gFdtF%NwNrzS#`!5H<7HOfjLV(KOow%}GriF0}uenrmaX>b%svB~5+ z5E5An=JwaEZ0~%E;%uWo?^%zj2X(?`N7Y7%=KTfGe0$ccD}G-_By2$tWd!&=0Oe*S zo#4<Bqt?sJzrA|Jb$d(y6?4`sVn*=9od>^NzS^Gtn3~{GYxcswz)K>n{3ovS$Npv< zIi8SdT*23pCpI4MuQ$56U*V5m@k06TH*4U0PF+eqkta@j;|9aoryy+3pA{_-wfLmt zcK-8o5r2_mn~&Aqv)MH7(Quobm>tu*a-HGwJtP|&2Q6GdQwVNe2U%S!IBVscD3Ti7 z)TGhPlxmQ8N#x6nqf8btI`Eb^L5X<J=`We>iHci-e1}UOx|PP>bfYHUbu=mwv(10D zd8^Np_8JlaVZGDC7~A(9=h!aot8z9sYdpE|WK9Unhrec>Tq|XKM5bv5Sn5_+iZnPG zg0-ffL_mgMfZv6Y)4|+)I27up@l-+kN4DFL#Lgfpj1B!~&$1<GKxk|x4dl_d{mTQU zdKQs9*x#Q4gNo<lMjJzd`J4B!I}c$I?;c~)Pa;l%gAVq6tdI~_!nD@RWY-6*@_A$& z7)Ks&_!v-+;n#5NN+~az*2(K$%<z44+tuEAwBXGfwfd^6&6MxfzqCloLv*7&C*AIu zAb**fnl{=OjJ}(WG9DQB>%VQov$pe4Lo9gOA9rT{y1#DQ)F`o@jFs(fm`=-YG<ihm z&mMWVpLB8XSiFYmK&6=^=~Gm$-&~*|Wx<#X`9OqLT<e(h`n0Qj;f{TN6Z^wsTkkOG z;dak=6h9+j^{LZS)LX1*dRRK^jFQqV2X-inAKAc)AO;UGr)ielA2*u4IrP#`^ys=^ zu$x#!)p2)^_Ki9e5NetV-@M8Aso32ChG56)1J^Dd_3sNkJn28(7T@&d$=U;yZv%#3 zFupArrg@I{3u^ZeBq}M1yG43*?2t7#ykJhed4eDF=_VMm4~Ff2_8nKS#W!m~mdR}c z7HOyrC+yBbj#jh`LDc<f|3ka5!#ELyg~`TY`>suE>v?vl)V?ilsc5=~>Uu6#g;|y( z0ad8%YL6Mw4QbXl>Q_m4?qVKu5Hh`A>CoJ$jobv?88S3s{mw<#<}pFTZnwHL@Kej{ z8%=$4+%IF{yK7s9IzM?ec_Fghrd$PWRNTHr6OO3;W8RjprH@kl++tF}uul`L-m<7f z_@%txwu*GBo`m7aujk(G4@`jU|MR^7Oy~w!`tzVJdMWzAr79^Z0fua)jg3Ys%O;tP z6spPG(%d)=Slz9aCFLWURL$z5dJ8Q%qJ$5~++L4@xk`k$fvRBBnYHx!+7jxa;MJLq zpP+M{AE*KHOC45y2%NIoEF}P@tsJ~mgV%xh^RS@l?fb3#_|!?y)7gO?0W*0EdsmF5 zG1|HL+l@^MXdF0SBS$tpmh&L;(@kR_FYClg^MUgv#})##D^Sr+dq~dY8PRepxfF#4 z_n!}2xHw`Jd!5%gaKuwb?FH9VOD5;XpHdC_Dx6B}5Pl|ZF7qRJT>FV6q-%IoO{lrH zXzeHDNTtZ#OuE+ANI%)xa>Q!t9&PgmWUUh?m%X!md_AVCfww`jwMJ*ImeE#+pSrn3 z>RslND>GC~RZ6w#lsJ22$f#SOU5#JkE_qWmzkgt$(FXY|s(lJF4bJ3_)y~agd0^`T zX6J-~vu2Y7Royz(ecA#XP;7M+)MGZ>cbhwZ5*!j<W4)LIzuB9k<pLYy^5f659eMCG z%O)vh<q;J#y6dyzPwD_RI-4}>iq-8WA9CRc!FUZ0Kc;i5@0go-2gBP>$X2;b|5cK? zJs_p9e+oK7QXHg7lM012ndI-!yFE27+~!{Ry3lw6+7)aj*#$4e(=3lkeU$sLk*2C} z?i_O9jm2OQmfMj(lnyf4kOlh)1X_JC47ME>a-yi^4ZEhCYsrqmXf%&K_Te!!W?6_C z4mWysyYfsZ!({$zc3DTNltQV+S6zWiXh!QX9zR#)xeo=Ow+DBF1kvFt*=?}<hy9SA zd;P4cjLtrftJ*C1eub;))$+;T--BG~N2j1n7P*`sUt!>w;5Q5QFebfB7?Z7U6PU7{ zH`%y=3Snxl|853q+62`kExhI~n93Hu)!6C?C0vngxSQNRW8&NMz3=QW9*7z3&u`S- z-2Oho$*TX_YEzNj3GrE;Nbeu7MtDwd0VAKz7HaNR`ecOO4Je8U+w~b7uk*Mr?bvR~ zR#xJ+xk<b1Hbhg#?$<wyg1A~XYk!rWTJW3+qZ)##+;C!ExX?!EF!Ep>%3OA`#owea z^@%1>FW+8JZSdn-I5a#GBj1<nh{GA)dzhs3&AI9Opo_6v)w(fp!K5Y&rl`EJTmQYL z<98(4s$qcc7gYei-&0NQg{uTU+rd|Jo!5t^cEb$%jfaS9f{+j)x7*9S1aA+8GLux; zq3g`YSSFkAhNr9bBwGjF_H}Z?Ux30=WNv-#04a89(6{Fj{RGIb_6M|#ao`;5_OU|} zFi*4MdFI4qh<|KiLj7>_K#@-(I0%=_eCr`XM!vFE9<X~L<eRbn+_)X^B}=0Tz=)BR zkgzm-;8^EVQ82~zOexN|#&_N{Z1!8;@V?=x96M8EV`G$&5q!ARu4S`pF-24ZWE&ei z^$^rZ;2t+c*;mIIYA&aSMhTcbiy2d?o?2oJAEPEGd>{0MtbhO9y#y^qSlKd_UNSq< zYy!za640_1q_LE@<W<^X{%dzyVu-f7JKU;ZL2T%yY~NmKhuyC+oIq*x?Jt+qo_!EW zXRxJmy_sy9xf1fCiZS!~ifRb;O<J_aOEBwn)Pn4|jaaZ;OS4;R?HX!xyw~Jpss@`p zUa96C@z4(cI*hBi43c-q&^T0;yo-skw<;yz^RLC9EWJpS-LJx_aCVk|-zaJ8RyfN7 zO;T+!q1mB&(2D2d1XL!Nvo9c@?~D)vK&|q?&Z!|(zQi-cVs?)L2U@6IJs&%()v)(h zh`WEmoi<STGcDgb_a^G4N8{dkO?R(`guTEDa`=fO^9+!$NR3UU<>jjjrS@Pf*(<%K zksz5aW%nVb)c&;NO29qy9S<G&(ZhX$^b5NYBn`UvO4Q<^W7mymxz1%b>Qi~1L|-w+ zg)!F^SB0EF2iqkU3_`oyXz9|9SubesP+ihcJle{7?K~ui)_*hz+v0b<c^x)64hcr+ ze=LSw%|a1_hCT*zx~`fgU{yHP8nV}VE3OX8LXI!zV19hXM+@742qR24TXD3fZ<MC` zgS!*$(BNp=#oh|t(Km&)vR{4H>^OsN_DqBZFuDHN4Terp4Kex^kbivNehA%@eQm(G z5FA3|8oze3RDn<In%mfOF*EAPx{!|m+xXk!@P;2mzQ`K?l;dpkM~6nZ@!5YiHuPcf zk#AKj)mZ)tESW4S-KcgmiTdRaYTw!b3}St36-!9!NIb<ommH%FgU=pGV1ciYB=wQu z4lyfQFNF_LZF<6Ep;n$y?PrScL>rl+8^33^rH2H2*Qb4l#(pvnq4KI*Sp1jVRyqjH zA~t+>!CYaHnKYzJ(5V&)T{=jkxqG|2zw}bS{1B3mU)s=y7WfdN?0PNP-6=k%*2%$g z+W)9q@qMdVWwj>73|0RR5>cCubHN%L<jc@vLw)hM7qq~(*^}QG#<eLzWsB>~%FoP- zp77~lyk?U{zs#|)JDUW_=f(Nwp4yzKQV!+uOW6>zwIM{89^S|@#v68sHL*1xFKsF6 zq4|o*>}@*(vrJK@8?qbMu{E=Yb_F&gI!d6TaI)1716oC9L{90k8|Y@q0&VxPnJn3Z z{hX4GTR%R76Rd|JNqp^qr+IzAiZ?jWPe1AM^XJcaFoG<*Ky}lGPRan)^wmsK84hL| z{ayC+FwTnS<mBEUdouhG4CbJ7=k8xS_x$uZoKlrezh#&Q3T8HyIT8lvXG#0*SUgqA zjqbbF)5NIKBxi97y&oY^Su5#!Vb^EqM36hS%kXQk;0*OUCV6;q#A1iOLz0qUmD9O3 zN0TRaoah&r(HGvqntz(NiNW+*x)lypy%)(!%@uZsc^Y9CR!UoX`e@YD)*q6CcSeV{ z$&f37Kn<xMN*i;!+>_VHy{V1#Xk;0Uym6Q>*u&!4_@fCTEKIatTM3N?^)Q-SGW2Yv z=FlfliK0O<R5>}yZF6tsyMxRy1L@b<FTQVHyu=DX@*Dl^Q{W4Kpkj2!lg2}v+z#LX zW^GN)_TI!C7{vhnEbQE1j()>szm)p<nJEUSx2Wv`v`;<iV#z#trSy{Zudx}{oP7Mb zLHWEetsef-b&jvZ51Xb`@`dxAjHPNRvzy<(W&Fhr+tL`C`bp60xi>m^_1(v#r7fxP z9YI|e41W}rsx=enm*b0S!yZ}LGn8KJl+B>ARd!ts#vijM1q-$Hk+S12_S9M>+CGk? zt_fqY=uMmnD~*>KE|ER!6Y7g<vOq=Zo<*NB*&u--g+YYxsb=4CC&2#g!1p7qwymzN zX07|bdGR9<tj|3S9r%VSVH7NgLXk~V=ze#1_abGfWOV{5T03GcxgIw9P~mE*j&EBS z11Ix>=WOF<Af4+2f0YH#aYDA!^_9@0w@e+(K9^JZS>LTSa2&UE%b)N5*d0mYw!>=) z(M=Y7pT09>H%k1#A{55tH&uS&9d(_==1-7oHq2?d#f1F5%F+gc4SMkfeNfPSp@@*P z+jH7DlBd(AcD_fDLt{Rf%#=*LcB=1}dYsc96M`(#lZk%=1TZyh&>KuwctbEXL_lX4 ze;peh-d+q)ofsyfJ|ysFexa>DusS0i{4hGSYA&@@^2R28aCB^7s+_~m>vf+U`>g1~ zliw>xZ~3iXlQdTDxr8^UGv+Q;`d(-E7@5U5+A`nFa;fpeMu4DSCpKAXeF?T4JzjvL zs{1m493pOTm#Tf3<s70{aZtgf(N4=`5|g7hH+|aAW&85)=x4&f$vj`^4!%2sZ``G% z;T3QVbpRF9E*5w5dX4SP1Bba>Arf{j1bmlGQt9+@v0G)=U26#>C+yq~5+Qx0>f#Bp z+r{(UsQwOwcN0F4ys>^&C@S!^nEmp!rqRPtF2T^W&#a7my=c|LX){Wt7oTOdbTc9d z_cK4e3rd{0c6yvI&2YS-eD2jEI>WkF)R&xSm-w^KE^$rRHt}0->00`9f-UpH?vMDE zZm&Jsg_~BWQpShl3VL1+`~2Rs^Y|yp=^bmglC9+ZNSliq90|{Wl#>k3Xb3gG9{y=L zXhmcD03R4~)?6K1ct;1!rOGTQI=7qTsek?af#p%b_rg1=7`=0?kA_{&BTr**oJ0Ut zCQ4{Jw{a4D+07LVe=Gl&C$*I-EdzHd@HYR8wzm$8vTfJJA3{KpQt47ckPwiTREClg zVL(7il#p&|6e%SHq@<K)kPxJ6041bBngMj^8l`jC_wau2TJN{kKK5_@_Hpd_Ltz+( zdG6=FuQ;#sIxoLd_rNEP^j~-fGG;vHZBE~Ww6qULcb~kf%4xK`x#=!)IK62jz2<B7 z!HV0(1JxMfplqhRYB{38Do5fGV2->#Bc~?Q)^hW%9zlvc>-oB0J1Rr?Dbg7iCJByB z3((1hQM40<rEh%WTd_?3X<2J^I;O<JsmJz`7&@S9)4&wSNO&j1N1`uHYV<{eg3Htf z;a!mjVI4A^PX<AC#)KN@l#9#DUEOabZ-e+}<Gd88ZNTOlpWIsJj8l#3<}t4__Bw=T zx{$f-g-tuW{Ihrm7Rp;Jt1jR7eayCBIA_adyW6!vQ2FFwY5BgYz`Y&mH4mke;S)E+ zNp~$*bMLAjJyOc2U<j`+)7^04cyqh|S4@AiD}|lFmc$smOD^X2^yu65ZOr%kZPQWd z{GWOiXP8@+v$(u^D@q?WdDwga+iA5esSiZIw*f+>ub4H^XO*ZCKTho7i)HoTqRfnG z*{UZyNo33X**`c~Mj*p$cS*ZrpI#M$s2ZrNS6XaY_PsuM-w2F@k_l5Hu$|Vk6(ZeU zd{bAo$!A+j-@MY$WUix^QGLX<hHXl0y>8M(^j1b@iF>Rl4yrRAZhFv1jf^()+)gIA zN+flBdq^D;&rO#jo(=!8m1pi_*@gFrSZYf0=sL`M<G085+QG%`wPk54k0h4`HhrIF z4{Lm+aDno*^}zKT(aptnCS-M7TQi5;8Bu<h>>T|~NrUEBmB#!kqXSR8e9!ML##PeV z2}nZ6#K_YPO^Z5?zDCRp51VNyb9uU$F+6Xvx>v2>HjcjmdMOQyrB4hXhYs^&g1YM& zX!E!s^=N4S&d6t5^H7#1S`YKjTCKb49xYJ_ck@u~rttLm>>-C&>&`M%@|W#?c~jWM z?z4<#mtF8k+LxpkYCM<nHh>sOU$E~Ov`($Xg<L+#Ya*!Yd0^=MHS~o>lqunFg|V-v zX4~6`CXp>%eSsSHEK0>M49@IvG9S^6nJ;yjna*U@(YN|R2}p9+ri;6al~+986twF6 zStqWeGaz&6)5472?A(gwRGYX7Ty`hIaAbHG4oK^T2ya!6OXE*J(oiis*x5}b_@$m1 zIBPofrNv|3($4j0v&DAH3B1`XNE+ILe8qM;wz<aAm-Wk|xXk0GGLYmbS$6Q;o-T^E zJZc7-)H$MtFfGMKzdf3F7fce}j|YB;M&k+c@9gus^zHCxH#J{xSyt?ESzkY<T-$vJ ztSrWlaxK%ME=8I^o_USCLZEd6o!XGN#an9h?!?)XamD@7^V`>CcYf$h=4qxe5d6mR zYjaWd5&3jLIUs#jqL&4z9VM%9T&TGtL$$+B^G4&rFdDK82SQJw%oN%MZ@xV)hr4UF zJEuRhv-6c%d!GN~gaKL0v`8?<(nbv(8ns&T29}%qeAEhES9CXvn>TGGFW*oj4m<}H zhiar!oVy=`I5OJqZtuy3iXqBS=1M=hHNmw=$RrT8T2pmHEe(q5%iq#dV&pZen#1=% zwbB=?_NvKXY^`_9j;Y1Guw*WdRQ1f2`ujSim?4^Nj&h2;$6Xc1KhR6zaz1K>5K`Pc zv^U_AM@+@Dv5b?92csB!f2`cC;_*@0zSCart&G${d#$wF?ibgj1A~Cr2hbbI#fsqx zsIonN_Ust~GCSV?V=Rtx8w#7;dQYSYBi9+e!M1q`y50x7_F(ut!aE}DOS8YzCG9ZZ znG8<0Az*G2S~uWoK~CdO6C+V&PrCvuBXUgm75eTCE6hu-NjFKb3RsL@`$_Qm0#d_k zM72+}clY|*y-~jdiog-+$rUY0J2r~31N4cFGNxguODFn~iJFXy0jbn?vkxO5Pxqeq zSth5RTC>N5WvE{-RGcdWif=%oOc}nTM|EJ@w>9B9%rEq`Er|g70C?K$9<HZ?7ZQaQ zRN+MzUIv1u(BN*m^5(r0<(F4yuUyNdl80x|#3b_a@a$LhIy_%3s@lEPmOV-vdq3zJ zL%pjRE#yOu4Eh;zOZxDn-FrDFQP0iY-R}{+FKFFTAc#5BsR`i?3d2pUy}a+^-&u=z zmm$QSr;AIiJ;d$x{OaoBI?zzc^7%>Ur42s$Z?kq|*TzDdZ>o#YAoa}`ouj=^$Z1u{ z?qI0{P5B>|n)Ru0Y>r<g0sP$>wp*j_s9}V+700EYr4DD&P3Ax$4Y-kC0toh<RX$&= zt6wnWGpXO#7#m)y2Y)&Y;eP@7GQu3yq&=LHr=GlNrl6outTA-PsRy6s_#E<cX;ut| z*y;S5^jfT7e((hvzK4Q3@Wqc-6(UH@O<5C|rj4zwPbH{0I)Ia)ra;X--~=#5878EJ zMYl`eR^=<O>u<Okd)}oa6vq1ka4g!EsL=c$!=s~pD;pcdK<A7XRJ#rh(-OjzN*wX4 zFLB<sAHDcxR*}~DOY~}OMzm5^fHRX7eV}9W&H2U-I#)o3Ea&0j$<1Gxho*lXVFef& z7>IoRGGp$-qQu*}wTJy$qk{AA_a1GuqFbZPufm?h3Ry;>CAeNOgX%UQY*Y$aY63GO z2UeV0gfm%!;A9&I|0Ds8re5K;Zv9~`h+AhELOQ~-bAaq(I?(#5s#|ufUCu3nu%IVj z2l55Tuf6HqbWo)ASE05~JAO@<JtX}ywaqtBo>FKNx`4)sntK=ppR%>%Le{a1-yE;( zZ>*E$El#xG5@8$M00lvd?zXeUmu_g`$bXQoTn2ahLyUUoY5<|_9&F<Q9C~<@t?G7^ ztF48FMKM_^UW(fnjdbY)xw91p=7jU}583!ASL`A-Jcf2IfLh|l>JJvm?#r{~i^hJZ z@l~eoZSEfllUhL<K7wD(za|mZ0Tdl5f|&`Zv>y_c^=<Lrp_~G35$Q;%Zb{sJ!p#z7 znWJxE4+&w}E$*mRs1CfOYN{oL2qwbT-Eic<wfXW`z(XTdnEnOeB7^JlJ%Z=WNI&`< zyk1im%~vupVNlp#jwi_^FBzCf?NWj{67LBso_kLW)1|Das34}Z;L(|J$*{^~ixKw1 znRlWO*Js`&JouG5XsoS0Km>utz%+AW1=za;21FXKvww<wldDN<Yf+WB?_<A@=nIp! zYUDC>Mp77^*^W<5Ml-zqdrC~MorQ0#{Jjrf&Ig?5Rbpdk02(i1pn6mU^^cDmlx-=8 zzt)&8v>ye4<PaSiv4RKbg{!<-^g891w^LMr2mSDMWH`6bmtksbY`hMX1bepXH$bpD z!F-{Bale-3fsOj6UBrhI2IEnF&}{4iTA8tfIclMEr{%T|GIjz@QU@e~K`vJ&wXRS! zO!#&j<&E;Ad1hcYL`6m6;DTa6Td18tb8qZ5S9GMf2ebr%I=w<vNEi`fbWV~X(q9)| zg7@12vW3kN1JpxXgh56J9zcGTZF4v6P%U#{DG~i=pCaUjW#&r;afc~`MvN8!#_{Tz zJfvYkxjfYi&3g-QPNZ}21uH?=6A)c*@$&LcLeCYPd!Bf1GIXX%<iX!8^+2+>uB=~* zB#J_J@Aw5wygGl`pD0i~AuK<8tt?&_{80m(O5`1gJdhrNYmZITtvD}F8@LLaV}j%e zXA4(wMY8e`QI|}7s+gNp%al~O)8o-T#c0$Had#EQ-f=h2q-U~-5MX1zLwQk^VsxdB zf{qs%?4>KY9KZiDluU6Fmi0m?Bm*$H$~>06KwqR0+a)}wKR|u39^5kL7?rOCzm1_x zM24+{1J(wyZw!cItBP}zjhH?Hr**+LO<hXB;9~H&2vhjD^JeRIZ`0um4d^;~b?jsN zpKRYvf%UlujZzHn99Ok5@gu8!S5!EX$Y#HNeElLn3COZYwM4xL<K~mvkp@}uH=q}4 z0-gSrE-9#}7&Zk&6(b<@qE^a_aC4ZhKcG!^e|fc9cxOBR=Xt;kBU1k}S^v5an|uFb z1j!x2-;C#N5C@|`WiV6QDsQf)u+TQ+$7j*x_C(OoL5?JcPCHGQ9#2&}m*k~yMw7B- zQYo$He>4mHX8I`d&mQ%y^wRTlk@c(j_0s`2fR$!gFIxnSFc7?FI`1K#9e!z-n7Yq; zg}x_3bDG!lGL^PDYTD^==t6@Fq*$dem)g#td5=aqpHjm}YKI<T+{(|)osu@pe~$AW z&$r+Iey!pdAWimV@nwEK;O?c7nVG^HKoPh864)|ztGk80)f>3e%h!*A9*nES&|Y)t zwbxJI4QOR~BnPA>-DdXsbcc69(pHRWNEeY#@Z}fUYKMwhRJ?+Z?N-hSMCW_W!pvQa zJ&O^VG%-gqeMVH^onfsuiNlrQByhG{+OSQdoFr?)x)a2ZqaJ_CwU@ycj4#aMLC)}# zZXRaOA1dmpc=GTr*pp1O1YE(rr`Y2W#jL<d{ADwEnbboGUEEInJE5WgiAd(pk<t6B zSy=;1`oa|X&!_{1#@i<+CI~q-VQoOo&jM7d%Zq`2sQZ}Ez-%}!sVS2tc_|LufHgO2 z`giya<j>^6bg;Cx_Q*csk8Xueez8{vZGz{`I*WxH)XamKnWw`>^yjb%+d*E!tNO*P z2#;_j0;-zmjF>tBhDa7Rw##_PJwFdiD(djGOEaK@yfsp&k7D62;_x9TX{ah(*88Kf z{sx6B+u*Ev=JBUzvfHoZUzVSHP7D#hozL{{`!O-U7cSo#6&<D|_n&o`K^l;Fy_?jO z>5EZ$0(f6R6Iw%b<u2BDar=U0XvGA}9w@irlIgGy-j*#h#y)S(3sgr|@qGES&*BAe z)0H?J1Qg%pfI1{0Xwn91C!H|1n7#B;n1~y=og8o(awIOZeLnVwGQJjQBN@T>+?W;% z+S-&hUTDHNgGsMYKBbCj)!m_^N~SymXW>9<KnNly#pQq?M$198gAhjJ;@O>OOSj78 zYfIvSSMZR$Br|WntGf~*#OON{z(MlT9(;>y4dZ7M(AU*<;`C<YkyK9)F9XD4E8OY( z1R_NZD4j%#oUIHH5SqYq+=TeEAAW4@K${I8rN}(KVw509GV@0#l9YjQ&pf-J?}-Ew z7vvcO-MuR3AqfT~BQ!E+P-X2j_E%4p_Dmc8!x-;W*|5VtyyxfSd+rm7LII(X2bp*Y zO&5?u&@<wJ5n3Jh)0wL)G-MzGJ$vM=mqU%WI%+c@r*+D<TaTT`#IzG|cNH%}xQ%a5 z+VQHwqp*DWN26&#??)Y42WKG|2Vl74j37`=;RRUJYY-Lmn71qFayXn5BtkZ|l4nya z5~!Ft)%?uEo5K6>ScRS8W0Le`u(W8!C$ACH;V*h9uHnq5YFm;d+aOV3r?7ShsN?~e z-!CAB6NW(d98~Jj8Bw6h8prXrM`x5jK#_s+74s0u)<G%3QY#DO0Noc4tBo&h=pi*< ze3eKDuE!uk$kuNLL)g!9cIRLdelw;v5#w~=J3=~(3Evql28+s2X42r*<$a;2M=-JW z4`qV%W<-Sdi66QnBisvV*axCIJSmKR4?5k9;)HeyOV86)&iV1#MQ`R_tG7IKw<9iP zkM^F2+RSIgD|+#NUxs}08XaG*D^7bt?u$?u!5Bb**MS<V*@Ao!zn*$}Xkb`G<hRG| z_<&q%Y+-?3DYeLK2E+x55D<D8yrJPYB%Q4+MPFs({i}MHbqDw#80<Pe=!I0QA{r=@ zveZk&jBTprr+!&A7&oP!VIn;(FPU-~vmrL#{#AI6<ma=o;5r8aC-Fc`OYb-{!3R>L z4%A36i~Zz%evJBK27%L^sMUaTNNGp_FKMRhAR1J#SW*uCg#%3?YpCCd<u`ZWAE=RH z){4HJHB{qyAHfHxSgoP>^^d(%;@QyBP8&z2F~trVd<njt6UNf;^(xnTS!n-?-LLu! z$Q)>c;CHA0N_HAiibM&)Z%)Y5e2!d|^#Sh65guT#bG1eV;bM8EMj&CscQWOU%4GcY zs8In!=&hFO=~DeCZm;Sa7ps)ygxHU)gIod$BIFwg%ZSt+gE@%WU6N!(mO#FwNO9p6 z83HrBz&&I!-^nw9QL)m_IXuXJy6eEz{PLq0sLJoi>mNlSS%SLfBQs?y^|T&ITmA;^ z(M0#p&03UpVyk~RYZ#x(l!}v(hcuYKEx<<(>ZU;b=j*=xzyj8f6TZu$cL|bww2^E# zL_u~0+Q(n(35$|mrK!lQ8&W(wC_f)oJYV3#qhIpSQ1*~Q-{d!w*uqnPfnu@Y2}GO4 zDGRt`86hlh*71We4jm{J)h;Rr7KONAbG$cDqgE@B`By!Ko!0hk=rZ)B<@(oyeOWuq z&H=RhlKJI{5LA-WYZ_&I8B@}Fz4yW_!`R2^p$GFc1QIu>wM=h@YWQzyq~c8~_+P%q z=S(!VrT*p3!PX+sHP)8`#AQ&@mRfrrb}xCg_GuJa*8x>KY+CEKJaTqS{~3EZ+S@aC zv!Zn8bhoApt7(us!C{>9&mg()`;E+?EF2@vIlL=V;Of}2s}extk-zQfT{G>aK3(wb zZ!SPVNz)ySLTMGA1ii=U+?Sb_>%##-8oxk+I;q{31oGuxecu#>$~f37?c5F>5T5hV zf=o4KPKE3QyeHapk1m^;a*<uz1%`nBulP+scQ~j8Bq%?^JAkXD1yqsUVFh_uE6_Un zM-A*_f4xB8rm+53ir!&@TB%BC-$bCD+Jo8#k|0D%3HMfHH?rVK+1(y`K30PaM42GO z)k<AsQ+6q!Wp~%jlWy<QXj?3md@Z}x<F-FKW}(lCmyX(CyMm4k_&AFkrji)u78b^e zGa9{g=r=0Ll!R+P*%<I5gpMP!eM31c)RT2-*(k^6%1RD?1So0!l9WR4x0bpFy)dRF zNFkLH_aa@xH*7etk9v-MdwA$DHvQ|xp+0MS95l$AVAY6O9xcD<QT^NzOIG)sj_exw z<n`~ryi80z8N#iT!0jo5nTH-xX|n)^A+veAy!nuryyd+1$2z~1PXhM^d0kUi2}|)j z$hWcd;2k#tjkS-MAX9?3jr8wW%1(5))7~|Wv^zr&Qw|M@q&#a%zKR(Y+o*Q_(C0!w z^p+|RJ$bZ8ebH|92E$db@VKJJKwwx0`vDxuN^#J#*^3`MG$Y%woL$Ygy8n3WBPtFr zHR-n4IS&(|{=K*M*(*DoTkZ>SR`Yeg4#$3sKIwhHS^Yu(qY#kJ1dmKSs>{bDGOZtv zp6WIkA)Q=$a>Pm-nvlgZNCAR<+m!=JdQ;}HhP2aIbgj>#M52S1IV~6OyKSena7i`1 zV1}EfWxy@`^`X=otmki0`P!T1R6KpQ{yOvmU9YxeZ_iyVignk9R7X`mnadtLwgIHU zIX&IZ8!`nYUH8XKW)dHmM#E-Y3)xFCcx2aly{><Mps(*K7U&1xX#^6Y_i&EB3^;lq ziY*Lx_XBF6yttzR+O%BZ?qy+97%vmYLIR!hNtI>?6edQ}S&Tg55Z#bkj69*Zrm@V9 zZG!-t%#&#fGa_%txt1TJ8W0O+{#eVrDsF;Q%vqM)W8W=c>##2b#VTn;z4p=q`n~F3 z{JC!91<KM^8i>qJO{*nqwcPYqQV8o59w<h@p0IhOu_`Do9NV(^R`JNPA!YGV_}?<f zTXeKUL`3GKs;qUN-}YA@m$h6C=aJC-5P#n$C@Y%jVfpbvsm1CWL_&B6%;MsrJt%Mf zD=h4=;xuOnCVy1=E0_9D5XL<s{B?8q{WW5<%dpcY5!Z7~zHAzpd3|gZgdBoUwaY~j zXjbA<!JT8`CBLKty)h0qS-VT?A21DR!hToeWdd^}EapqM^7me(h5G5p3OuGX2{9%+ zj>EYK40KDbE018`{DlR#>e<oxJHEWz3;&3Zu&F+sb+DjO*nz1s>p+xdoYQ-2!DJM* z{A772qV1eYX`}BcB<ag?&LbnXeekufLMCe6^#V?@13@>vcXlWh*5H7{@XR724?&P_ zstgNeXWRQD96M+U(=Wz%QVhH1MzDW1(8@g2sD$`8-q^G`vB$<HncqmILe(OH#MPY> zd5=d1q#vk|HW15;^^-J;I>#^g`vKfeo<83>p=r{(rE#6oBP}_Kx)OJ?wYNJv&~-8e zKF%Nze9-i5iM?VbAe;6Yoep?@>utMYMaemts0%PwDa^`IAC8~K!ZI>@w~R*!Z5KTK zBCV>XV_OxiJl&A%wLnafZ!|qqN!yA5ot4DiyJ(Kgx8QRtCCRmtcQ!I1<LTS|#$fx8 zA!EsvQ*sZfydX25%mB$iF#*VlIZ*gP^cRiN22=yt$D6N20eZagvf;(=g9z72C^hAE zXy+E?W6(5})fP?`t)$+Mb?s@mbRE(qnJexSJznXrV_1k-kt5XqX4QLtmS!8IxEec( z7{cEl%}GE9xHUJo-JmbyTK&AA*`B#SNzGnh@268HyUkQv$3;zuD=+<&8fiE7@mG5b z`M5s|@U?auS=i-LuhA}p_P$pqzP+;PHV%l$={97^y>Bkkc5DseYdwKJX8Lpf=a4KX zkK~3HAzd>knML=~hTk>2%{RTlwy^$@WI3@|@GA_DCWG#U0m*DiaKsI}mD$22KcPgE zj`Jm)<k+Pb6}$oZ{U1PR5HjKd%`n0m{QBdrw7b6BG7q)3^1ix57dB19M-Zs&ndOkn z^&r|#i{gVruH1rwtWNQIgA#~e6)e<&s<Jo);_(I?LP##e_ZVO+ToO^`p_n5rAS5Mz zSaOFwnDCaeBC&~yAaRzo7m*-W)2~~^9(0polyAOWFIaJgDnXR;;u!A^?A(<%-#{x- zI%s$t22!@aMpU_JK#)sZxIzfD{xgi)Ll!|zw@3@xSMK<HpUP}gTI4q19*RTiDPlbo zQgjnCY%WO%O{$p0{_^uO)Ogfs=~nSU7pU4*{(R>jYDc#F9}LG*?WE_g5W;1YU=xC+ zbr_hgJjm%U#n=GEr3+8cizORiB=us>zhDFq+k;ps`BzJ~#twQgA!(P%AUSdYCZ6jc zv<mS~Z;v-q2GqeggdsIybACFh6hlD=`GB-{`U~xblY#9&B_1Ucw}+HZx6*_o^Y^~~ z4cd<3axB99l_9oG7oY}xh$EN)kWF^&zFBoKql*aVqA#Ru<r^Rum=St~l$stFRRg~y z4E$2im8GVu5<<}or#!mc>@T{5PM_UPzq}+x{76}8#Aoowk1yvN`p|5dlz`AnwR1|s zW1!XS@NL^S;GEB&tAR3jgr%xm;xQ8gvH5bT7I$D-Ar{@t9cThUy2f>myI1D680z5N zTBI}=fP?DaKOg7?F%W6*U4V#NG*O4Q0+|(PX(Bz&HkWnH=8rt61~`g&0V(nse=BqL z3mG~npl3--q-W?TUAi#;!fyQzt{mhdVVA-U)Y{j7LT&UG2|npnoNLdy<(T1<EA0-9 zRTR3KUD|6IcfR`Ox=+_@Hz8+!c-h|817}H_m;x_pTwfAzBem9Yg*s?*;<M8~QlQ6y z;&@^C_W|H<1=@1;0mO!rpz~X|QG<!_d|piEeiO#z7?GTXI0|7VoiD*bG`GoZPqQzq z;PFi!eENdtGEYZlIph58#_HYkf`mhvUHXKYn|^`QklAAJ?<;+X*{K53gbZG?XwKH~ zQb)F1opi$O&Z(C{tP~db<d)<loiG58*Ki>VtTj^R-%}qEi2{~+MTo|DyC^h|=*}KT z*tqX1aAxN_E!dZ|=RUkKL0z0J^cKHqT6Zu@->3qo{4>hpHc;qMn0)SM+bAuS&7NOC zj*z9r*k@cHxy_cJ9LS<@ITcLz2|(dGi&wEX0E7x2`TGE&uK^nCE@RG=+NWT(anFM1 zS;3w9>&wGtN$~OhJE+L>^xwH;My+Q^_>UjDa9v%PnB7=u131h$XB`%D*$0Ga5scy+ zV4x9DO}%rLX`dl{qyXUqa=sup2P!bDN7$D0m#=q|{AY5`Hpt1w3@M$kAYtrjLTy0M z^FO#jNkFWVt)&n2NuTBAIR49+5M|6T*vOZVJLc_oU_gJViG7VOEUcx){BJqV6Ej=~ zEAH`w;_nn1b~2j^fB=BeSrLrs!!cm!RLL3A59(V(Kt)XlJ__zu-5JzhQ!J$q=X%p| z0$2?sQb6(X=hwMpYkhzeQOO&Oy`YT04d=fc6At>$aNvnNyb$)}F(u(V4onc4`YVO@ ziS2v>=2AI=t)*SC`Ztb)tC^61K~A8^3(I-^pDvBc04I(JeF<hJrZPB=;K+Q?cCPiW zTN8HJoW6MNDw_pphx-hHPHoV9R(*Rd3HMX$C$E*VLbFHoUto^by4iRx{aZ#Cq6E&= z`6%=nC^^IdL?H5SN<%Dyh1g6D@B^fAQI;_uO-d2M2Pp68g4}o2yj|xLFeYW&uA}Zj zf)>{@Us!Cazf=52QA|;tQ8VIGdhN;*R7P<%B@MxRntI!jOyB+{8(^Trqp4!V05lMO zci{-jN0kgJr4>w2oE00-4e(?cokhCtFybmnHTS(3@A-sf3w6qa6&~ZQbNS;s588u@ zEGG2%)4kq=!-{XuzN8foVc;MO6S54#97Pk}Ddop4-~Hh{#kqMPO$cuP-|G#k3w>vi z0WK9!VSY}6B=(k+(WFk?M|J9$8o4ZW5|7l^yHumIjsbJZ9{)EC9EBJlgNUUD@GQ*y zC;mB@2;v<EX}=`n-0LRza&~%gL$=IU;_+Dk{i_{F87oB&t6BQfA(ILCuu+Jr+GiK& zDR4n?Bnwle#u=LB1fe5@x@7t$0dOhebmv0`LH6lOnfX32%*=^uU;_Y<|L2mD7^t^W z4LCjS1ECI;<TRbIGJKCrDxtZ$^yh#O-~;6xIv$1jUU)Oh9DLzbNJyCat+sAwro~sd zO?VY3;)u0%14aHL0G@z%vB15HMYrM1o)q4fQ06XqW2f~XVSH9ossSw`>lsJRY1-6) z9fH2sOU&!>>*7`Z&L%c?eH_2!w-7(Ca9?6z`&ZfLqP{X0F3YlS#BfClO#+BA%(@z6 z7T<wx8|y`>5Z_eKo)atE4^?4i>TTu(v&M+c;?IteB{j1X#EVmhJwtl0sL`d`pP=8( zc!{(Idevsu+<b;#toZ{cTL9|t2>^Zf!I7p4&e09^xD<I|(c}c#ndw4Ys`D##-HGgF z=uNw7tLUGvdHHy}wPfed9d_OQb{BWFvq<AWWoEuD<EC)G(naf~&)wVF*qxWe)MW(v zCDpXZI0D|H)!V$k<6aWsUJlD53bnudG+8ddAJ~8j^buC9Z>zR7Do-G7btHo@CYgX= zfQ?ks?)moXGram%v7jo!OX@#n4#^hSeB>7<#VSOH6}hD6!H79&6wx<#)U9@Bo+<~_ z3J}<QCnu2k78s@fky(t58?e|a{NSUZaMT=p-f}L9%D9H70Q(v8C)zIaO`6?%;TV<D zXm(&4A|vrVB}^R{dh@4G=f`o|JrFJ73IH<+^Ojfie{Fw&Gl0`s3(F=51fHgb5D)QW z)`)=sx{`lWU4*@>*}bG5Z+1<zNBDG-SW}n%NWtCWYHtR)$?rim^LAwdtB5~ASC>d$ z2Fg5wu?Gs}0%?k{h$UcfGw%W;`tI9SJ+S$pB-x+f$jt9LLc^92vl3W4ZwpOPc`%7Q z2f~Md^~mbM1bgxg?TnR+54%SLmYMp7>3o%!p4V;^ucm?iTeCA$rX&e$vEnnER+~Q3 z--Ry{Xi0o9XFnhc2bPd(i(T^yas~VShTC$He!BOf;H$ISCc@(kgv}B_&Al9Ntq`#X z6l3*UqPP;JiY1<+jzfs$mQ<W*ueR?!$Tp%DFK*lCy;`>VeF(<>2$(fcw@gOV%EqWn zQ3Jp~r`H`-gSc$~+W>&6BFH(Z$hg2KszY3g35Nhf>dDmvvD8W;<aydhC#%ssFD3Dr zKD{QV^SXYCP|kSJsqK5I1qTD){}0QrChO3!@?!>X-xydMvK&C<8*Zc1g4f~B5JXi| zLMO)_9u|TRwlN>*MJ16UVk-lMWe@1Uu}cXS+>G;jPag?JoUPHndu!n741fZ>mJ^c| z#mrs?7}nwVw=av+-I0KdfCWe6u-+8_sN2C&pqo4oFvd+O{&HqGL>w0ev#_(_q7}dl z!$rG9Nb|EThB*R_Y)N2rP556s>|W#IK?|t>)8%kj)Eau55ex$ADJ6n^1Y^4j5OB~H zt9>Q&Exm;p7;UFQNeE8$nGCfd%%nI!|KVTJPtjc5B2G*eOi%Pn#mWYrvh+UZ_67Qq z$)y%_pDOo1`glq<>z?nYe#fcL1fm>J`U<!9{NI}D8wYceBriR~0gz=3^Oz{_-}CdA zzpstM{o1Lk5k^6Kq-JIiTDh_*A!*?K_6~x6Ail6ADh9WT`APA<pg1aN2(Q9brbEC3 z^rM7r?ig-$6Tu&ymoL+dB%W&tV|O(%^8K9$vh~;o&$C?^q`TQ!j$k31#i*y=C<2v> zf7<#QP&}Dqqi#TCJodTM(_ov}E#ZBy=k;*wCAtAh=l`MA=UJXRTV(<>nm{WMz<I)V zU=Uyt3tb97*0Qi*zZ`jqgRT8d#}zPr2^pr5ZrZe-hW2!;FwH=rrb1=v;KfAubwH{X zl62-5{&vC%>esCpEpipvVlwb>Q4wcOb`=7VpZ^?idtbTg?yy7Hb4PdX1D?t0M(xci zr5ktJk}B>{e$pM@Ew$);s%+KHML1^lVO~+lb3EEg@5-&~nIEsStrrAD+n#M>3w5BI z!22JLf!e;$6||smDb8i2FYeS(J^-gM8xeZYSaOH**tIj3)A1<~;%u65PHie&L4oq< zTiK1;jdPG8B!a)M^3jAKQXTAyX0R(rUNj2#@x;%^C*jQ=-2JMcOY+}=c;LBjd{18l zwt<1FMjvLm=K)3?0!~T5CBkMy_(_n^!XHqms9mi!?d3~U;qYe#Qllw=J^|G4s$O@P z;-yxbHNTW0-G2~9)OQtQ@}y$u(%E6-)>2Fa3eZP4sBFH&m0%7;PUizd;qFlge;OnM zBo2}=W)&&Kp)>^Ct<SngKP>pe=CgEBe6IYCDso&*K=m;!#NO0n{Hev{<YZF;!c;LT zTMpFaJ|ajV>CZMpxx!%lmmdU38GbEvTNeWzjlpZHP|wkk%zzBd2eGcKt<`5HQnT+7 z&n6}&x&};L5)Qx~1J&?n?RzKo>5J~6%vz>w*Pjd0t6U<$dVUIcZ+JA7a+1i-Ao=Lu z>i$(BI1X1~K|uky>0uyXH}?Uo3H>wcmzSxM4x-9zAl@uTX2uh!4Am1(me-TQWrzc* zVluKXTR|$ovQ!uQkOr1iR8?hMn5Df#sZJg9rtAB6?D-Fp#(+hGHJjPf!v9^D;!s=Q z3SHZvk5n?Y=w`<`h9P3`r=mfGLI=mG23PHk6%`aDKho3l2thb(N|%Uk-5s$0aV}7N z#&>HM%+HC6K)XU~ePS18+Wysj0jf~o{j``0O3*7!D_i<ZdrOz{YnL))Yc1P`To)Uy z)>M3$?Sky*o+-c@83>!5K^I^E39{$g;aP7Zzr941@aW!&jnCTW_Csrt_k1IxLa`Gh zFF$Z&S-3LURMX+^_>d_abwekY&jk4LdBlYNpS`>lX;hbcIt}O+bcXytBC6hW=)>lG zidPX~$9PC8(D`;1jx8j(=$wjZ6i8Ng0JS5ZJc`#HF@Wnp6C;`&+yx#%SChbaxcXDX zZF;CJg1%e_<4sBE6W%cgGDESg=Ny*`09VWYqB-MP_EXyA%6{ms`!4e2v6cSO02I~J z=#aZOGqpz%;E>Yj-klUhb%491j)68=sBOP7gKu-RS!}E=-@27<=p4wGUOs~}>zuU+ zM)e#^X~So-5ba?dkY^f4W+}De<|7l6Mg*V+^@Eut4p5kqtEN#pIgY<_+9~@}qPOiT z31mj}+rx2N8IKRIKQ-oU6E|B1m>iG+uCf6w0fg08L0fTE4#mjmsDLYzRVGjYB@+dV z0W_lzreV)s%42QpsY)qYq6!ZQ+HO3au<ZGrii7vJfIabBaHjHVb54cZSu9O}_Z-=- z0i%VePHyi?otjQg{)*FD@o2+BZ_kbG%xp7Ko_zN!soy%^PG57@NXcXmS~!6$__kq8 z6M1E`n35tRun^?4>nvlLe$3_-F(;mEfiwG!aso$&Fp*o-^J&G_B8Oz~20d6WNDDll zrUNP$LEy8#Egop?hm5h2(UGP_w=mnL6BvBTxixjh+CobR!{&Ox+9Ym;%|C(L1DeHX zd{cp7uWj`yGg}gIlBfJ^7*UsQn(6e2)5_(OQI@n3kv?f;XnO8jf^Q$xbTeXBdPDPi zjfMsSa03-C1g+MlfSM~6&}Fm1Ri(cdaeJq4i4e(4m0hxe?ho(&7%E$Ht(tP_3V_xI zjWpQ1g2|$z&iDIYCKQD(ekeF4d^@YQXnKMysS}krEe?@nY>9HOX1-tLO9l!2mDYn+ z%gjl{GiU-&w+E1<J7u-OkTfnRpGV)0|1Ou9G{gC9bRy-COw0^Qr|YY<zj>>S&qXV{ zzk;gT$hP!FGH5qh#Ac8M60=MPb22l-fD%bnP9~cm{5B2#VL09unMXOGQRo@*5U#Co z9NL8sAAu@3Z%_>p6<OrJ;q`^53@}}le{kb@K_U(MR3h8v4!odHPft%RB|V($y;{LN zR<1Dq;jfBo?!-e}I_u3{q9w1O5M*%v1oI+6fA-}T154xaZiv<=Ow;yF931aWKdl98 zRXd|#2!*)rg)2euA`rLTp?nw0tS0mZmj+`;Ks`3gnS*;EUt}fLipmQHmm`=(cifAG z&umoq`f^X|4o87>WA465oX0ND^qwYkG_TG1nBzbj^4in=Pa4Knks3^)5OB*YgxYk5 zjrA%yGk<d7P;Qq!K+Ac$yjZ+SWZrfcMj*ZtyQso3H~~bV?IBYjqaY4OgpxwQgqP#S zfCWUgqwCi2G}w)<mIVmdBIk<<lBJU>rTchmzO{uZAwWT%8LGzTA0YWF*2}u-1^T{I z#6ikz%*UpNciicYGR4b(Fgyg=oquU|f6MH~6CTGqn`-HJPUaH0%#@Ac(zn~~zr3I# zwlYLj9AIh6!H1)v=NFNo5Ys0Fe_N6TxM8HNbX;UH<Pis4fy@U#oMESiADqtoT>jT9 zPy1Y@Sx(Odn$Gb6q4Z;7D1a_KEWh87QFForw0&YP_LCAloOk5cPnXRP{`p^G&Wj5S zFcFb|a5iMKSK*Y}*#BM7sryN$PxmF;gr8)f`!c4mTaQWi^F`tI`mpd`&DDf8$^kW^ z$*3@<T%6f@g(67|3kgJM-XFGrn9k5paKP2z(aS3<?{Q24SZfitPr5RL16))(K_qqD z!@speOS1IwK`U#azgZIjub%uZ8Y-U#pIiP-J73lX+?jU96AF9xkIW{8{s&PjUANxb zcP&MTu-9>~nB_l%-NjY-EC{eTTcdKW)Ym>=@YM!ZaugeT;hQM&2)`p;TPbcmaY<nh zU}c2?oiisZyiBSn&)R(JPnt~Lc5>mu5DB4v!+VLj)Ss^b=no!Ba@YHGMXogObfif% zX?z%!W0uSPgv5!ugPx{vfL8HbC~2dZF&#MhDUDz%^?b7R2V&`|D*7kyL#=Tq+#1Y9 zm%2vsG8vkv8NRB$|6c&l6oA=*lL!FM*Doc~l&{W69=>KL9!}`^185zHT8!Ds<$?ac zNFGt>R2-j%5NOhmgC7Eh&nXUDU~pLT%FVp`m}wZ>wf;z%2y`(;7_1)oa|P};|KQ5} z$j-Ljh$#_iv%?W?@c#=`;9Rkex&nMSkyAt1SI7Yl=Pu!w+%_X@e(k%$Jr}WD(Z#~8 zdxq8p#Z<tD*&8veZGe`gB)cn3fd^j)qCHw6%<a}5W<6cJ`ka=sS;#t~hfiH=nq)8s zy*OhQOaq$zb293R8DG%@xn8D4X`O+7`9?f5`JgIlZ`7PMW2o_8)yubLeZtg{1gNKb zO(W7<3?#)Xc}sodkIH`$2iaR;j}HL(Y&Z&YG%4M;%ChDjX1xdW?iVC9=RueC2^ezc zKqkeK`9S}ljkF+WDF&z-8-pfpg<Q-~n?%9g#HG23Ln+jU^ES2#8SG?q+m!jv=(e=^ zBP@`lv;G}(Y2ZF(%rfX6{q*UR^cf-u(zs&G5h<7Y{^>d@AoY>EALh^AqK~C#+}pQ& zA-~yQtK9#ApuRjX@~dL^@txNRD~9jb%!Pd{FGapHY49$rGOl>cPgB@&-PHr1l!P0J z_xs0xZ~^4*Db~P^R-^9~d}Y0I-=FXxhEOn;ld}_><SM%totCqDJ>`k`xJ;c?$s#(Y zUA^}p6;p2&=cp;`+M8PLWH4<2nIW9#=!JX3za2UJ?j1#K_q(!4qOub^6r7f^3vQ!L zOi?-&J$A_MU6p$j3Xh=BtFPW#8dP$1-HLL;8<Hn6mmg#i2D7Xox{L<}Zc0q;GksFT z5CmDKOGNpA=r|gD8%TiuVh^5!0G)Gz9`}DB!K_qY=!@hY{=}|4)dwWzMqu~{yO$L{ z1R=L|dE(O@EsJ8`<=!AJ52Sy&a3JWkClh~fez)Fr_V?1#l7!Zv(1yQjg`uAyMp~Yo zH?fN=*XGdDGa%EjXgbN0<-@=?=c$E__LOn`I1aC?7-?a6&Vw4qeJ`f=%Z&;ofdz_N z7uW3XoD9w8)(1h6y{MG#Pol3%xiEYXho`BTWsyOG=wjMAD3_r}SnzeSUyWX&sFlI) zlWBuMrO}z0Qx%eH&U?-E<<Q&iHOpNv>5IB&>*Aj`E1h}o*F^Ly<t-=6_)Zp7nJHw` zJ&VV=Rb$t^tRTVcyu3WE!I64bh^|HUl018sSNZ~rrlxmJXg{Y-@Z7EBxd%_Q51n@A zY>9@}`V!*B<l;Rwaf_AIQ(ZeFvipXtt9O&Kk=^E-te*1C3fj!yK}GSjeCaE8xEJ-S zNNh@L$hh>7CRhfIFLL%s$}hhmVsBC!9M_>Nyavi@Ls{I0?{b&dho8mkpkFY>cg=Hd zV0l!v;5_k|xin&Hw|SQX(G7oHFjiq;czEaGv=?N?<2>i}{`<4#(*(D<X7~|fKn&l} zx+>WZ`R=vgjmD{NnuWA;)@~b({isAWZ*#DlRBYa-|JvvxCL%K2>cxk2fLh&9{A3OK z2F0~h-sPF=H#8K^Uz^(4AT8rVXL8H;-X)nF5;?I<c&Y^!JaBG9PNdw&$j~soLy8nq z7k$5Iv((s^I>oj;jvjBD@5{)RAOll>jyW(Fp^#5TRSu!qnE5mU<lAQzheP$kki3a? zIt77niqXwPt+;H;mP&wfD3d>}kIV4&IQ(6&Y#bYDQT{@~O9L#JdgOzGZC_#A_-ql4 z0|rh(g??#PqK!uI_EY}VZRNd=qbw6nn+==JzU_VPdq2JXaK8iOxLjs_Z-MHjbU7sP zTm)R)s*)<JY{!avjKlkGiOB4Se2prD^^`3qs<BQK_E(jinFPAa)}E-=6%Mb+crD^F zpjL(pwdk3cQcVkoS(d<H#~vvPNS#yja&j)w!V-o<#?5JX`ebVNNOIFRDQO(@in7;v z&jN5nL~aWkUAim5^*VD1EUi3Z_*u#MYpFWiSE9Q9UaXaa0GHF=+2s_DnaZZyi4M$T z_Ox2?VkOGEW3f-iEj?$_JZU}*B#&<#`cB1q(m>$g*(N+qQ6Q-U?+<R)P-WidMK|gF zp-}PEvX+Kjq0Zho5v#8&MYoK1r_Sw}nk(jbJxz_|iT^&j*$bI<9PX@Esnm*Ln4l1F zXpOddA;{|^*w&g4ceaXRZ+fpyBsSCqn2mM?eUXoG^x9QO!IWt_zc`QEuu1qLeZpTq zV~&?^s{YGnKq74Kt<2tS^~s%rsk+j)?hS1(bEpz+^%97bNkpZ9X^Bm)i@n>2t0gnZ zxKj>tRsm}pn;UjBjeetTk&MKfy#$a>IB5u8R(FaxCVEJuVGNa#_}4Xu+q^fC21)i7 zxK#Pqnfd%0LvLtrKC0#er(SSaV)J6eV@m?dO66a7?c}HLlGr3X^#Oa7gjSI36(teJ zx{xsLppyfGa4(i)bS@1K`PO}P#6Dp=9Cx4}6zIw(dJ;h$q&-{aW|qKjj66EEuXRQ% z$wr<7Hci&u!-Hm{cJ*eX?D=j%5n%f2ssKv9^ey&@WwhEvf-47Zcj-jS9xk~8KH`^B ztkHXGvycy7veJiu-x(ln5LD%k?K-Y8-%F7mDpZ%9d1@529cg>J58L~s;X3%`>&n0! zI^j&5LAn9NBn^(v#>;5m9qBDpM$D?Uu<EU3jzrn*UWyqPqlJNU8LQG;*i?&N9x(oQ zQT28k%8{kUl|XRk`}`(YsK#+rM!sI5_yW!>I5Sn%9R0D}9p+GF>G*rEw%t7bJ*t;7 zNfsN$k~KHnTsAp9?$t$_drP0-AuynpBkw#ZKMd6P#3ffKX@9x;Ps_?$%>Y@_g3q_o z5<PXuc=I%ZV=^E|PA#|3)5Bxa$_s4zMB56(TM`ocPXA$Xi}ciph=>|f!KRH(Mm;JV zjx{W5OEv&^B+p(;XJh%u{da(Do~$)*Z>(Dvhte}T)mXbeDT2UjV7Q=PY~=zl5|p?b zNUzMBS5n@l?|}Y<^HLBKANU~o>zgSH_Y9?bdo+_G_;61{nv>}X{uYa<la%%Npjh(5 zm++f1GT|`{_dY+AmI1RyZQf6t6zQ?{Nm2B7fHk}184#bH#}j`6kYHT&ZYG+dH<T5% zw^;$BAbLKH7|I2+F7iGCgt$A$86`gP)KgtAUCF{yz-@2dvQiMkC!giI2Mp??K~mh& z2K)Ysr>U%<VE=n?y-7gBIX$<#UfH2Ux?{7kdnXuYfbWu2)g8U$>#F9y@V1<?WmiO_ zDfubA)hIL+Sa;gry@3+~V>{d0*6Dc#GUFR7Oj3_?REZrv^vHUjm^S_yxDhr?2~M)s z*+~Wp;vOo8CexD8#R9!TxgIG3Xf7C-gM!F3N5<cGw=LuBCrs07PEi%7d!M4U;5TuL zWDNrbaBNZb`GVM1O^MLfp6cO27+kcoDPGmFI(LiWW=!&8JQePh40zx+xyqz9O>!;A z#mds3?ugUu?(Fbie18h_le~WC^F!a5Y_Dstj)1@B!TIzz=;!7MPr1}4jEnRzonV!h z^h!+pzR%9i9vc?z%7dwdj%WU9K)Ua0CvorddzX5qIE2e*gvxU^{Dbzr2x@MXb6$Jp z+HF_J@!smHRfXZY=(SguF9f&HatuflSaajf;C~B0TD}HTR%Y8w2-tYycAk}G-H-^1 z>Fz!p=h?2kDzbS$au;VSZ^gym%UMh@DCEeo`98{xCld01ihbhF7VF<*A0+o;MgTTO znZ@e~@X14}u@`Y??TIs!I1pG304?mxJENve!eA+~Y#kj<K?CuFF`)cc9LXq74xIJb zhI*mB(37&)4(!_6Mj!A2{Y%|zUqv(o(&YlMUS3vsR~5B?B;+oCBL!wI;a?kxNJ*$1 zPk563Mi1`w|MzAt&z=BxU!5S4KHUEh6VxMo_60H06VP9P)L?I%TSVQ=BXCH%|8+?I zzYPnp{*I&^{9@&Q$7LM+U@(^!ZuK`B<p+Q9b-n*9s#u_>`_|oPXPLLNw<iaT!iNFe z7lVU?n?WyLyg0>051ri(#Ta%;VN&_lpHh8D5QW)^m#^c@0azLaW3YoVlI@!gR|*4? z!P=~`<B5p9w>rB75Ttq$g`@X#hP<W}=&dp*qpa#W4-Z6N?gAa6LcJnyhiS=OE5xZU z*DB6l4h|RUSFx-}0Kv@E@@K<{IIh|g*!0ZvDsxTEDYw({`Iu<GxsUeZs8dZ1tHehx zol_D~iMXg`4n%-=?vl9XZB>Wf>V;J?_jwQ-8S&9*^_8t{KmPo@8+NNl$sj@T+N*?m z*R{SUJ<$dJ4TeP{Q=_Av9iv%5a+(~#u&&qt_2(p$4qa;MIl9V*)N%%G+f%H>QdXKU z=y+w>-I&lyRP#te*Zk-c1CPV^qP9_KD!Jp<KxLpA#dVC~4@_>|Bo`b4n_8IDPvVu+ z!jmRFlAqKD3HI-c(JbF3E~7l8Cz<W+i}ZY~!1J-iB-fl6$yIT2AFbA6M*H6%ZFj1< zx!D-_Xp}!U8m28G-c@!Pb&?)#Cl|9PK5b8)E8A7}G<Kx+C_0n7)>7Kbvb+F$Bx~X| zXTj=ajr#-da~D&_c~K3#uQPqxQ*6Xs_PjRy?~?qqx;!qcF=V>Ev(vCYVOxT7sV>Kp zsIQ*b{pb^3SE4es{khZsBVSiH%C9!cha0W#Hu=ZSv$Vp}GInlbF~{civ`YDe8`evG z<Tz<%l=NCYkQaFyFk<umd$-6y*k!K(G|Dp7b#vY3z5nC?`l%wbJob^KM;%n%Yxl7z zhi5i6l7^T5wb{?M%m4Tv!OI5Ic!BlboR1w;DXy!!bUhRWA@>))E)#y67s)3})##|B zJm4cHe&i5ZCIX8B!s0wPPtO4FPw!o7d>_BhwMrWQyn!VZu9H-a&1>VX0(!19aoaA! zq?R5=IS&qsIWpdfL*4h!_9%(@4zQM{d)wRF8->@S&|VwZ>%vBsmQuDA6QkmGV@{_J zEok0+qXlkCZtBF^^Ry<}PgFG)b%e0DwS5zHdnI4I_Q)}5JTMyrVmnrr+$v%y?)3sa zSrJfkl@_iWKnY+rHn65yqrh#`RN7CDpf?ty4J%X!Svge8?4QNrmn#?OdN<ac)@6qR zvwlD)YKuC#rOMAvb2^Bc1X0bY`;+yF3ft&44CYi>wS-x;dz7=m{nP1Jf=Em71Aae0 zzpD4+tAipk&aEM26p_U@Xx?-wkeJ47uTj0xQ4NUU=*-DlMN43lviH<pEAjcO41#r; zk}RuiXgJxw`|-ECssLln6slx>ecc`iK3UxU;|Z=oV2&B;P-}2*v<wiPth7IR-rzh< zr#Mgs42PcZQFgYzO0Dy~m-yu>Ozi^hdycBlm<w~kCG&Zne#!3H@SmVkW)jjGJYcxJ zh3=v?b{iOAUp+cHDjB+uKCX(561Z}qJ$YOswl{XWK-EVWdGW#N+vPWwyS1O60S|^^ zxLd6_sJ(&Z0uD*VQw~0O5-Y366OXli;>Xmks2Xr{d6%+9jg#5j5;Jfg?YG65_~@1= ztcLnRaKPK`2f{}<sn=hWEnD4d89i%hpk#J9Ywq6#IgL?ol0)hh5>d1%<2f7C*9sgz z)&6A-JXLG0+M}2qS^tFZAKl9tbl&jy2kzFd!tiAA#(DB?GvIS-ju=!ESCFhz9`_Kc zxAW@ij$Ry=G2Y90@TSfb&>q}AXH%$x5Z6#!u3@_nB;pON1YasD8nVD#+nQLtBEyQ6 zL4eg0Feu{QI3VEkwyHpXzrSN|<I13jG5a!|D%dF-jg5`_?cW~%2?(LwaNW~XHH{7F z?VbREM<|C3wc@}yZYZyINfTQXS}|6(3<z?Qauy|KgCy;`r|Hj))i{m=Si`P9PL{Y1 z9A6e;pBZ4tZemteyuB~^6GBc8o#yBxm)dvQ4&H3|4?I-dz!Ista-t*-b<6m=yg53% zC$0-~3mR4X40mHS2ZJ`SMi#^0oPAT1)2=Vi#Bz9<&DDBsE%=!zoc;-z40E30P&G&} z7B8!mwJM3bqNwe*@zaM3**!Qg@F#(?rHX^u%96JF2rK*BuRL4ibta?I%};uT(f1BR zvJ=~!kMF8Z0NsFs*mPS<Q|18)wb%>6ccVFKjyh@%EmdD<F1fPX`gnUEa`>4H9*b!7 zrOr+g2Hv={6%k@#d1_;6#ihEbrz+Kk=qg+L;(cO#M29XuL>I)-TuD;AOCrV5PzOlP z2cYfu)b&%XH@d#hYp+1d?^$#<F=raklxsA5(vaP-qCn!Q`rzb?&IfI<pgM)aCJ#ZD zBCa<8&YTg)Np7}%R*Jc*%U)g1=`@C{uYs>?_q`7;U{#s8VKX<ySUh8krReiq;0aug z8mb&{0<mJVf0<t@$5Vsd!U0^5d^$L}iP?)xZPv(7@B&?|+rAgzj$?Oa+ErugFrt_h zf6mUkBz*~P(RHj`s=!zI439pm;8GyDCA@HhLC@23Pb1dh_I(tvQ;$`97~Wg>2$gfK zYH8)mv2dwgd-Zu?B`#Le4un5W!*Kl*{f5Q_j?P}8XPmnQP%fC&Mqpv|Fknj7`x~|X zqX7Y%#B48}_asRtZK<B_t*4zV={}^K%ZW|L^Kr!5q-Gbvf$KONI_Z`1%rFX&&OfAV z`F$+)Kq2zLq$*l%=v~bPGo=q+L~Ul4!H4LFRlO?T)~5qozoSAOJ<I#N#HCrYxEa!Y zVzTW_cK{4uahTMtGYj1%X+5f+XdJ2YDQcWviEg!eyXMGRu&`h`)Zch(us;~uyQDbq z+XXD4O(Y0ef|A!`IXvZ_ZP$WqmV^K8_7B}fd`n@^8F)bLXnkQxKmy0`vx@1%OjK+O z5F??9Ebb|@b3VDTbwvUU*=?Iz96p)wWtdie7E!~qY!LeeoDmZ;X8UR3`ZakA0;C&& zwIZ5PRrg|(*WKkNDDM`A$X;VzbrXdyn^_vIYPHu=xD|4Uii@A#JH&WRjE+|6`xWUi znzTuuBfqLK)Gp#i(=MCxlj^8teK4R;W<8*I17WIR6kB=keYwm0cR$qiH-E2^M;=G= zxN4Su^-<a3kjB}vZ@lC1oUxrA77+2s%qCWTM7FO9HoA3*x3EPzKJg9USz=k<e)-}* zzdn!vw#R8cR$}2%B>MU1Y(>l6?kVANDNazuwi#bKq_Pm!$5Xcz=|j?i8M^N|Jog$l zs8%-|3*`JQz6arzKaAy&i`x!NZt$P~9^d4_vzx$g)Z5=b%Bj>_XS5O>AmaUrvc+gc zt4WgH;Dx~wjjAiCM@~z)n4gR|Ille!6j(z~wL!4y_C(yI5UwkxPra4=nryOmW2#gD zBC;(zJarPyL6$V$#4_SZ0EN<nq(9`ZWdEsZ6Jz@yQ;^LQsq)0%b4=W3QQh0w-Srph zi$L1VZ6vB0f>3?)+s`A(#IE_oBm?*$7*3Z+F$zLQf1N=s4r&maAr2qELGSmWPAE7~ zxY`oBz@GxC4$^@5*u!o+V=yhci_@m(z33KcaEnH)A?l<IME$w3KZb^etSt4PEselO z$ytkT(!9w_8Gjn<Atoy7P8Q9qI6%uGv$DYoMlUX^JOKQIEA4-%8ERR#D?sF%@_mmK zLgQdh<%FlU94P+fAb_6viA14~P$xvHS~W*Ct*7CT)Bg7Et{#WqG|JSJ`%2|kXJ4y? zr*g4hzIML`*7@kbX&s;}I-YW-gC3qGZO-+QQRq-kKlQ<eYp+OMy%~`a<>sv+M<~CF zY^&sP3baIHxn7}tj9YHqOtstcAg|I$AAn`DVjDS^>#<m@y))Ac_1%4aRsIcZB~HmZ z*+<^f-CZW_>9`aJS?y7eGt+537`{=M?WuaWclV=H=Z^**C@E<P$%$Osd97d1MtaQ- zSjfo~F?(;P?L&<ev32itTT`DMBoaA7c~@hQMz{`4{f-A7>n9T%f$;RI$=+?5lkFiN z;65=R+-iurFyps}@^5GM^mPWp*K!_v?~_jw>jHYZ@2ST6+Pa+pH30vE6@8E=@O62p z-0N90@x-t&G4a6*;l<OW5v5>Iz#ZW_3owOxrr~6F@<_R4=8MfxbfSPMmYU4CQ&zZ~ zwfaaI1Uqurb;p3C(TxG$N&Bi{&D+b_tBc*qu8t(;_Z9X$ur43(SLZ({Slc<72bUq^ zyHb#6Vr3~M>gHUQQF}zKmU#1IsOx6kCr3A#|8cze|N4bV-U*%n+u8>Kt%0f)YkqIH z?EM1WM!|D2<c2;zNB^s)YmaK;O5?*)AE#7hPZhL_U}Yj;u(72ef(aI(FhD^l26=|+ z5*BFXVIYP`aIN5WD_BM#faN7qk8G3_qP!yE_$UE^#Rdfe36a-g5Q9J@ZbHa@^ql>7 z&YYQh?tJ(AJ-)f$y$GADudN#l`Fyw|2U`XN@3*NlLy#*@K*5lMJPq#(@gb?7A3ic5 zOnSR;zAc7!@3`Ztb8pk3!l=xP`QzK*@pr?!JrN{+Qjv240HdEX>wYq_w8LMvSjWFE zZ`0V$Sc0ASqUPxlb0j08KAcwuHXL%nSj*XXVWXvVaiKz<ppkrx;hA+q#@h0nZY3oI zpU&4eg#=`u2n_6%8;wT060I8+h<=x)6J&F_CgxOEfx0^#q+Jrci6K+tg~i$nga8na z#s#p^vRSOvJH%O1Pv1D0=i{fC3$dL%V+$;8zQXtq6yxQFH@jgAMR#MuP&EyU2-FAR z==YB@e+g56#x}i%y0B=DGluTAPZALV_Wa1=4@I0Gf16zP-fV|!xp<X*l9+&TGX}fO zkqbHHbXA@?5(LfrrZv6F9O2hDNe8lYGan_pT|RK_?y30r7bdLzsEkcgqUw__VjyO3 zg<ozx4g;%5kh5J`e-@<%>TeTfShda0ovn1dTt0<Y-AY{|#Hqo9tO%-#OzOy<E_=%~ z?87J-x&jTaglNNQPU;k3h6U$x9k8fzl`1!dx}Z}SE#B(1jo@wuUQVI3zr0a*Y_r!- z+O3$1t?N}7qj9jR7qVEa`>Qp)TL@B93zQ6DHZM=Q(=r)kg|Q20Aa~n0^M^IG#I&?G z#R8#3&&R`^tr%9`BWOLUHu=k*l#s344B42GxuT!2Z-Iu2p(!b^4k?V^&17(t;5eH= z%=nRF83QYejd88v`zt3jx%<>r!1oP*uou||>zK61ing<<#jHX?hqbdFGY{bZ$+L`W z<r(!3s8it-KVTGfD%F}{agN)^Yin<|+hh3Lo33;lhGV_7k3OujgTQkEPZ)72EANO6 zo0ahLEQ1d}TT~jCCb}Z=e?6ZIAyLtKSCCcsGa$&#L?RaDwNyO2o~fBDUtrZ=4YJ~Y zro<MbF5HE*DQ9drmaS}X?)5;oB-?FiD37Hn+ylda4Fu@(2;Y>U+lOz&xwJ_1zf@LM z4$N<Y5(v%C`<yQXsG+NT2ZDT#0N;TkoHa9ROhRupT-}<P#_mkje&#YZsc}e%Y(6SG z;}RXpkPN?qkhJsHKX@;WowrUWI>w{H89q`t)sF{*fRcs_o=g31kCTPO0X(?jd9npc zt-PsL`Gsn8Ngauh=5u#S7l-@jnV2dHqWWV~AI!zP&+__Qh)pPlrv?qZ3*Bx^wi8BP zBY^7&C{fNBv-$NwiFPk024(qXT0$TC%e${DDk`k7?3<i_H+?I-k0;~s<{%t4m89i1 zo?Pv)e8>pM?jUe6UvDs&$c0lB;FW8kTMk3o0(a@?_erDDrqW}(o+=F_r`{%Cut*%a zX#Z}S>v=mNhh<Ec`fL=^1uY~jqcp!^4^Ki+l3tq6SkyV{pFG|R3rBv%egJv8Gb<1< z{Q+&LGR@Kax_sbO2)`gMVt)yEW{eD7$_o4Mzvi_1$z-6yQFUPv`IEM3ybVst@xa0s z8l|@4ocrrbbII~yJ^TaJ>IS+SRqj#epAgV@gJ`MLtj)Qm4B3o9!EEH56f%#<+ONv2 z#>^*FdkN@%J)R%ZLbs7xkSf`Zr^N;@|0n1UO6!Y@_Fvv12Y8S!{pySNeOt5UZbBZd z<xq8-po_?jB68O2(aawR`@VTHgoFIta=zs$Ot~)h9u@VnHH!Zh=hOb`Poh%C)6L-9 zbQL8+7Xhg)cfN8R)cs|tkZ(7zO<|iS{>EkqYMJQ|0e}_?rrr(WpOnMVklR28I*6RP zF~@Z0d3-_)A0QP%(T-Lj-d{M?hD&}zdpZ|Rj|k9?LFGU!v`jt(2NUj1Y7tkH)!x`u zv7tHy6_#hV88$G7l)wMp=zQtTF>G1U5i9G#8#HrsH#jg8o%!qYk9c@`ra&6?l?|Zx z%H;)`wIs}|<nG*Ysn^=ODHT~wL8${u;isbL{&^+t7T{3_Wl~`r`#KTr%Br3T?3=%m zQ@}@i;_uKs2bG7)<S7c{Mz-mngjbRFYM%E*35Ex~{8IuzyaRKEj)jzi{9Oxq+o;;3 zegcZ#^}}7(2-0`P2H;@Vt(F$uDkLupF2K{atn115vM&?Xkj?Lp^p$RZKhGd;Z?}c+ zVLw_?;?6&-qH<S07`A#p&qC3mE<0VwN!Gf9i0Fr{JbCa3$PrNkPp|chXo%s+;gF!X z(uByfAkL`~ahw@ptg&4r675sp1`YoCSA+IYyRa=KU_7%e&CR3Tqk@L^xlVKk9A{!k z1e=5Mspue-JC=)dm9|AXZ#Lx&RJ3MkOI2gw`?|wCRrf>#vJT1RoXOKysaf7#?` z*49q88u!3@`3Up*B7DtLDAu&cZZa&t_kZNKU(M~6-=Pf)Klpk566PE1)8HL{@qbes BtT6xp literal 0 HcmV?d00001 diff --git a/stormpy/resources/pybind11/docs/release.rst b/stormpy/resources/pybind11/docs/release.rst index 591158e95..d8f9db854 100644 --- a/stormpy/resources/pybind11/docs/release.rst +++ b/stormpy/resources/pybind11/docs/release.rst @@ -2,20 +2,18 @@ To release a new version of pybind11: - Update the version number and push to pypi - Update ``pybind11/_version.py`` (set release version, remove 'dev') + - Tag release date in ``doc/changelog.rst``. - ``git add`` and ``git commit``. + - ``git tag -a vX.Y -m 'vX.Y release'``. + - ``git push`` + - ``git push --tags``. - ``python setup.py sdist upload``. - ``python setup.py bdist_wheel upload``. - - Tag release date in ``doc/changelog.rst``. -- Tag the commit and push to anaconda.org - - ``git tag -a X.X -m '[Release comment]'``. - - ``conda-build conda.recipe --output`` - This should ouput the path of the generated tar.bz2 for the package - - ``conda-convert --platform all [path/to/tar.bz2] -o .`` - - ``for i in *-32/* *-64/*; do anaconda upload -u pybind $i; done`` +- Update conda-forge (https://github.com/conda-forge/pybind11-feedstock) + - change version number in ``meta.yml`` + - update checksum to match the one computed by pypi - Get back to work - Update ``_version.py`` (add 'dev' and increment minor). - Update version macros in ``include/pybind11/common.h`` - - ``git add`` and ``git commit``. ``git push``. ``git push --tags``. - -The remote for the last ``git push --tags`` should be the main repository for -pybind11. + - ``git add`` and ``git commit``. + ``git push`` diff --git a/stormpy/resources/pybind11/example/eigen.cpp b/stormpy/resources/pybind11/example/eigen.cpp new file mode 100644 index 000000000..b6fa24a42 --- /dev/null +++ b/stormpy/resources/pybind11/example/eigen.cpp @@ -0,0 +1,73 @@ +/* + example/eigen.cpp -- automatic conversion of Eigen types + + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" +#include <pybind11/eigen.h> + +void init_eigen(py::module &m) { + typedef Eigen::Matrix<float, 5, 6, Eigen::RowMajor> FixedMatrixR; + typedef Eigen::Matrix<float, 5, 6> FixedMatrixC; + typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> DenseMatrixR; + typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> DenseMatrixC; + typedef Eigen::SparseMatrix<float, Eigen::RowMajor> SparseMatrixR; + typedef Eigen::SparseMatrix<float> SparseMatrixC; + + // Non-symmetric matrix with zero elements + Eigen::MatrixXf mat(5, 6); + mat << 0, 3, 0, 0, 0, 11, 22, 0, 0, 0, 17, 11, 7, 5, 0, 1, 0, 11, 0, + 0, 0, 0, 0, 11, 0, 0, 14, 0, 8, 11; + + m.def("fixed_r", [mat]() -> FixedMatrixR { + return FixedMatrixR(mat); + }); + + m.def("fixed_c", [mat]() -> FixedMatrixC { + return FixedMatrixC(mat); + }); + + m.def("fixed_passthrough_r", [](const FixedMatrixR &m) -> FixedMatrixR { + return m; + }); + + m.def("fixed_passthrough_c", [](const FixedMatrixC &m) -> FixedMatrixC { + return m; + }); + + m.def("dense_r", [mat]() -> DenseMatrixR { + return DenseMatrixR(mat); + }); + + m.def("dense_c", [mat]() -> DenseMatrixC { + return DenseMatrixC(mat); + }); + + m.def("dense_passthrough_r", [](const DenseMatrixR &m) -> DenseMatrixR { + return m; + }); + + m.def("dense_passthrough_c", [](const DenseMatrixC &m) -> DenseMatrixC { + return m; + }); + + m.def("sparse_r", [mat]() -> SparseMatrixR { + return Eigen::SparseView<Eigen::MatrixXf>(mat); + }); + + m.def("sparse_c", [mat]() -> SparseMatrixC { + return Eigen::SparseView<Eigen::MatrixXf>(mat); + }); + + m.def("sparse_passthrough_r", [](const SparseMatrixR &m) -> SparseMatrixR { + return m; + }); + + m.def("sparse_passthrough_c", [](const SparseMatrixC &m) -> SparseMatrixC { + return m; + }); +} diff --git a/stormpy/resources/pybind11/example/eigen.py b/stormpy/resources/pybind11/example/eigen.py new file mode 100644 index 000000000..accaf236a --- /dev/null +++ b/stormpy/resources/pybind11/example/eigen.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys +sys.path.append('.') + +from example import fixed_r, fixed_c +from example import fixed_passthrough_r, fixed_passthrough_c +from example import dense_r, dense_c +from example import dense_passthrough_r, dense_passthrough_c +from example import sparse_r, sparse_c +from example import sparse_passthrough_r, sparse_passthrough_c +import numpy as np + +ref = np.array( + [[0, 3, 0, 0, 0, 11], + [22, 0, 0, 0, 17, 11], + [7, 5, 0, 1, 0, 11], + [0, 0, 0, 0, 0, 11], + [0, 0, 14, 0, 8, 11]]) + + +def check(mat): + return 'OK' if np.sum(mat - ref) == 0 else 'NOT OK' + +print("fixed_r = %s" % check(fixed_r())) +print("fixed_c = %s" % check(fixed_c())) +print("pt_r(fixed_r) = %s" % check(fixed_passthrough_r(fixed_r()))) +print("pt_c(fixed_c) = %s" % check(fixed_passthrough_c(fixed_c()))) +print("pt_r(fixed_c) = %s" % check(fixed_passthrough_r(fixed_c()))) +print("pt_c(fixed_r) = %s" % check(fixed_passthrough_c(fixed_r()))) + +print("dense_r = %s" % check(dense_r())) +print("dense_c = %s" % check(dense_c())) +print("pt_r(dense_r) = %s" % check(dense_passthrough_r(dense_r()))) +print("pt_c(dense_c) = %s" % check(dense_passthrough_c(dense_c()))) +print("pt_r(dense_c) = %s" % check(dense_passthrough_r(dense_c()))) +print("pt_c(dense_r) = %s" % check(dense_passthrough_c(dense_r()))) + +print("sparse_r = %s" % check(sparse_r())) +print("sparse_c = %s" % check(sparse_c())) +print("pt_r(sparse_r) = %s" % check(sparse_passthrough_r(sparse_r()))) +print("pt_c(sparse_c) = %s" % check(sparse_passthrough_c(sparse_c()))) +print("pt_r(sparse_c) = %s" % check(sparse_passthrough_r(sparse_c()))) +print("pt_c(sparse_r) = %s" % check(sparse_passthrough_c(sparse_r()))) diff --git a/stormpy/resources/pybind11/example/eigen.ref b/stormpy/resources/pybind11/example/eigen.ref new file mode 100644 index 000000000..b87f8ede3 --- /dev/null +++ b/stormpy/resources/pybind11/example/eigen.ref @@ -0,0 +1,18 @@ +fixed_r = OK +fixed_c = OK +pt_r(fixed_r) = OK +pt_c(fixed_c) = OK +pt_r(fixed_c) = OK +pt_c(fixed_r) = OK +dense_r = OK +dense_c = OK +pt_r(dense_r) = OK +pt_c(dense_c) = OK +pt_r(dense_c) = OK +pt_c(dense_r) = OK +sparse_r = OK +sparse_c = OK +pt_r(sparse_r) = OK +pt_c(sparse_c) = OK +pt_r(sparse_c) = OK +pt_c(sparse_r) = OK diff --git a/stormpy/resources/pybind11/example/example.cpp b/stormpy/resources/pybind11/example/example.cpp index ba0ff2812..470684a3b 100644 --- a/stormpy/resources/pybind11/example/example.cpp +++ b/stormpy/resources/pybind11/example/example.cpp @@ -1,7 +1,7 @@ /* example/example.cpp -- pybind example plugin - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -25,8 +25,13 @@ void init_ex13(py::module &); void init_ex14(py::module &); void init_ex15(py::module &); void init_ex16(py::module &); +void init_ex17(py::module &); void init_issues(py::module &); +#if defined(PYBIND11_TEST_EIGEN) + void init_eigen(py::module &); +#endif + PYBIND11_PLUGIN(example) { py::module m("example", "pybind example plugin"); @@ -46,7 +51,12 @@ PYBIND11_PLUGIN(example) { init_ex14(m); init_ex15(m); init_ex16(m); + init_ex17(m); init_issues(m); + #if defined(PYBIND11_TEST_EIGEN) + init_eigen(m); + #endif + return m.ptr(); } diff --git a/stormpy/resources/pybind11/example/example1.cpp b/stormpy/resources/pybind11/example/example1.cpp index 2a0038d82..dd651fbaf 100644 --- a/stormpy/resources/pybind11/example/example1.cpp +++ b/stormpy/resources/pybind11/example/example1.cpp @@ -2,7 +2,7 @@ example/example1.cpp -- constructors, deconstructors, attribute access, __str__, argument and return value conventions - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/example/example1.ref b/stormpy/resources/pybind11/example/example1.ref index 37c7fef9a..2c242f9c4 100644 --- a/stormpy/resources/pybind11/example/example1.ref +++ b/stormpy/resources/pybind11/example/example1.ref @@ -7,8 +7,8 @@ Called Example1 destructor (32) Instance 1: Example1[value=320] Instance 2: Example1[value=32] Called Example1 copy constructor with value 320.. -Called Example1 copy constructor with value 320.. -Called Example1 destructor (320) +Called Example1 move constructor with value 320.. +Called Example1 destructor (0) Example1[value=320] Called Example1 destructor (320) Example1[value=320] diff --git a/stormpy/resources/pybind11/example/example10.cpp b/stormpy/resources/pybind11/example/example10.cpp index 1a377e569..cbe737e72 100644 --- a/stormpy/resources/pybind11/example/example10.cpp +++ b/stormpy/resources/pybind11/example/example10.cpp @@ -2,7 +2,7 @@ example/example10.cpp -- auto-vectorize functions over NumPy array arguments - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -33,4 +33,9 @@ void init_ex10(py::module &m) { // Vectorize a complex-valued function m.def("vectorized_func3", py::vectorize(my_func3)); + + /// Numpy function which only accepts specific data types + m.def("selective_func", [](py::array_t<int, py::array::c_style>) { std::cout << "Int branch taken. "<< std::endl; }); + m.def("selective_func", [](py::array_t<float, py::array::c_style>) { std::cout << "Float branch taken. "<< std::endl; }); + m.def("selective_func", [](py::array_t<std::complex<float>, py::array::c_style>) { std::cout << "Complex float branch taken. "<< std::endl; }); } diff --git a/stormpy/resources/pybind11/example/example10.py b/stormpy/resources/pybind11/example/example10.py index 0d49fcaa7..b18e729a6 100755 --- a/stormpy/resources/pybind11/example/example10.py +++ b/stormpy/resources/pybind11/example/example10.py @@ -27,3 +27,8 @@ for f in [vectorized_func, vectorized_func2]: print(f(np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2)) print(np.array([[1, 2, 3], [4, 5, 6]])* np.array([[2], [3]])* 2) +from example import selective_func + +selective_func(np.array([1], dtype=np.int32)) +selective_func(np.array([1.0], dtype=np.float32)) +selective_func(np.array([1.0j], dtype=np.complex64)) diff --git a/stormpy/resources/pybind11/example/example10.ref b/stormpy/resources/pybind11/example/example10.ref index 9d48d7cfd..4885fc1ca 100644 --- a/stormpy/resources/pybind11/example/example10.ref +++ b/stormpy/resources/pybind11/example/example10.ref @@ -73,3 +73,6 @@ my_func(x:int=6, y:float=3, z:float=2) [ 24. 30. 36.]] [[ 4 8 12] [24 30 36]] +Int branch taken. +Float branch taken. +Complex float branch taken. diff --git a/stormpy/resources/pybind11/example/example11.cpp b/stormpy/resources/pybind11/example/example11.cpp index e7069def2..799fa6226 100644 --- a/stormpy/resources/pybind11/example/example11.cpp +++ b/stormpy/resources/pybind11/example/example11.cpp @@ -1,7 +1,7 @@ /* example/example11.cpp -- keyword arguments and default values - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -19,6 +19,27 @@ void kw_func4(const std::vector<int> &entries) { std::cout << endl; } +py::object call_kw_func(py::function f) { + py::tuple args = py::make_tuple(1234); + py::dict kwargs; + kwargs["y"] = py::cast(5678); + return f(*args, **kwargs); +} + +void args_function(py::args args) { + for (size_t it=0; it<args.size(); ++it) + std::cout << "got argument: " << py::object(args[it]) << std::endl; +} + +void args_kwargs_function(py::args args, py::kwargs kwargs) { + for (auto item : args) + std::cout << "got argument: " << item << std::endl; + if (kwargs) { + for (auto item : kwargs) + std::cout << "got keyword argument: " << item.first << " -> " << item.second << std::endl; + } +} + void init_ex11(py::module &m) { m.def("kw_func", &kw_func, py::arg("x"), py::arg("y")); m.def("kw_func2", &kw_func, py::arg("x") = 100, py::arg("y") = 200); @@ -30,4 +51,8 @@ void init_ex11(py::module &m) { list.push_back(17); m.def("kw_func4", &kw_func4, py::arg("myList") = list); + m.def("call_kw_func", &call_kw_func); + + m.def("args_function", &args_function); + m.def("args_kwargs_function", &args_kwargs_function); } diff --git a/stormpy/resources/pybind11/example/example11.py b/stormpy/resources/pybind11/example/example11.py index 04baa7bc9..ff35be2e4 100755 --- a/stormpy/resources/pybind11/example/example11.py +++ b/stormpy/resources/pybind11/example/example11.py @@ -5,7 +5,8 @@ import pydoc sys.path.append('.') -from example import kw_func, kw_func2, kw_func3, kw_func4 +from example import kw_func, kw_func2, kw_func3, kw_func4, call_kw_func +from example import args_function, args_kwargs_function print(pydoc.render_doc(kw_func, "Help on %s")) print(pydoc.render_doc(kw_func2, "Help on %s")) @@ -32,4 +33,9 @@ except Exception as e: print("Caught expected exception: " + str(e)) kw_func4() -kw_func4(myList = [1, 2, 3]) +kw_func4(myList=[1, 2, 3]) + +call_kw_func(kw_func2) + +args_function('arg1_value', 'arg2_value', 3) +args_kwargs_function('arg1_value', 'arg2_value', arg3='arg3_value', arg4=4) diff --git a/stormpy/resources/pybind11/example/example11.ref b/stormpy/resources/pybind11/example/example11.ref index 54e4fef31..f4c23aecd 100644 --- a/stormpy/resources/pybind11/example/example11.ref +++ b/stormpy/resources/pybind11/example/example11.ref @@ -29,6 +29,14 @@ kw_func(x=5, y=10) kw_func(x=5, y=10) Caught expected exception: Incompatible function arguments. The following argument types are supported: 1. (x : int = 100L, y : int = 200L) -> NoneType - + Invoked with: kw_func4: 13 17 kw_func4: 1 2 3 +kw_func(x=1234, y=5678) +got argument: arg1_value +got argument: arg2_value +got argument: 3 +got argument: arg1_value +got argument: arg2_value +got keyword argument: arg3 -> arg3_value +got keyword argument: arg4 -> 4 diff --git a/stormpy/resources/pybind11/example/example12.cpp b/stormpy/resources/pybind11/example/example12.cpp index ab1b48294..5cc8dc87c 100644 --- a/stormpy/resources/pybind11/example/example12.cpp +++ b/stormpy/resources/pybind11/example/example12.cpp @@ -1,7 +1,7 @@ /* example/example12.cpp -- overriding virtual functions from Python - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -50,19 +50,21 @@ public: virtual bool run_bool() { PYBIND11_OVERLOAD_PURE( - bool, - Example12, - run_bool + bool, /* Return type */ + Example12, /* Parent class */ + run_bool, /* Name of function */ + /* This function has no arguments. The trailing comma + in the previous line is needed for some compilers */ ); - throw std::runtime_error("this will never be reached"); } virtual void pure_virtual() { PYBIND11_OVERLOAD_PURE( void, /* Return type */ Example12, /* Parent class */ - pure_virtual /* Name of function */ - /* This function has no arguments */ + pure_virtual, /* Name of function */ + /* This function has no arguments. The trailing comma + in the previous line is needed for some compilers */ ); } }; @@ -87,6 +89,8 @@ void init_ex12(py::module &m) { /* Declare that 'PyExample12' is really an alias for the original type 'Example12' */ .alias<Example12>() .def(py::init<int>()) + /* Copy constructor (not needed in this case, but should generally be declared in this way) */ + .def(py::init<const PyExample12 &>()) /* Reference original class in function definitions */ .def("run", &Example12::run) .def("run_bool", &Example12::run_bool) diff --git a/stormpy/resources/pybind11/example/example12.ref b/stormpy/resources/pybind11/example/example12.ref index 2274cddd2..a25023fae 100644 --- a/stormpy/resources/pybind11/example/example12.ref +++ b/stormpy/resources/pybind11/example/example12.ref @@ -1,7 +1,7 @@ Constructing Example12.. Original implementation of Example12::run(state=10, value=20) 30 -Caught expected exception: Tried to call pure virtual function "pure_virtual" +Caught expected exception: Tried to call pure virtual function "Example12::pure_virtual" Constructing Example12.. ExtendedExample12::run(20), calling parent.. Original implementation of Example12::run(state=11, value=21) diff --git a/stormpy/resources/pybind11/example/example13.cpp b/stormpy/resources/pybind11/example/example13.cpp index 782db3109..6c1b8765d 100644 --- a/stormpy/resources/pybind11/example/example13.cpp +++ b/stormpy/resources/pybind11/example/example13.cpp @@ -2,7 +2,7 @@ example/example13.cpp -- keep_alive modifier (pybind11's version of Boost.Python's with_custodian_and_ward / with_custodian_and_ward_postcall) - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/example/example14.cpp b/stormpy/resources/pybind11/example/example14.cpp index abae02140..ad67fe419 100644 --- a/stormpy/resources/pybind11/example/example14.cpp +++ b/stormpy/resources/pybind11/example/example14.cpp @@ -1,7 +1,7 @@ /* example/example14.cpp -- opaque types, passing void pointers - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -13,24 +13,46 @@ typedef std::vector<std::string> StringList; +class ClassWithSTLVecProperty { +public: + StringList stringList; +}; + +/* IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures */ +PYBIND11_MAKE_OPAQUE(StringList); + void init_ex14(py::module &m) { - py::class_<py::opaque<StringList>>(m, "StringList") + py::class_<StringList>(m, "StringList") + .def(py::init<>()) + .def("pop_back", &StringList::pop_back) + /* There are multiple versions of push_back(), etc. Select the right ones. */ + .def("push_back", (void (StringList::*)(const std::string &)) &StringList::push_back) + .def("back", (std::string &(StringList::*)()) &StringList::back) + .def("__len__", [](const StringList &v) { return v.size(); }) + .def("__iter__", [](StringList &v) { + return py::make_iterator(v.begin(), v.end()); + }, py::keep_alive<0, 1>()); + + py::class_<ClassWithSTLVecProperty>(m, "ClassWithSTLVecProperty") .def(py::init<>()) - .def("push_back", [](py::opaque<StringList> &l, const std::string &str) { l->push_back(str); }) - .def("pop_back", [](py::opaque<StringList> &l) { l->pop_back(); }) - .def("back", [](py::opaque<StringList> &l) { return l->back(); }); - - m.def("print_opaque_list", [](py::opaque<StringList> &_l) { - StringList &l = _l; - std::cout << "Opaque list: " << std::endl; - for (auto entry : l) - std::cout << " " << entry << std::endl; + .def_readwrite("stringList", &ClassWithSTLVecProperty::stringList); + + m.def("print_opaque_list", [](const StringList &l) { + std::cout << "Opaque list: ["; + bool first = true; + for (auto entry : l) { + if (!first) + std::cout << ", "; + std::cout << entry; + first = false; + } + std::cout << "]" << std::endl; }); - m.def("return_void_ptr", []() { return (void *) 1234; }); - m.def("print_void_ptr", [](void *ptr) { std::cout << "Got void ptr : " << (uint64_t) ptr << std::endl; }); + m.def("return_void_ptr", []() { return (void *) 0x1234; }); + m.def("print_void_ptr", [](void *ptr) { std::cout << "Got void ptr : 0x" << std::hex << (uint64_t) ptr << std::endl; }); m.def("return_null_str", []() { return (char *) nullptr; }); - m.def("print_null_str", [](char *ptr) { std::cout << "Got null str : " << (uint64_t) ptr << std::endl; }); + m.def("print_null_str", [](char *ptr) { std::cout << "Got null str : 0x" << std::hex << (uint64_t) ptr << std::endl; }); m.def("return_unique_ptr", []() -> std::unique_ptr<StringList> { StringList *result = new StringList(); diff --git a/stormpy/resources/pybind11/example/example14.py b/stormpy/resources/pybind11/example/example14.py index 82d14de84..c653e0cea 100644 --- a/stormpy/resources/pybind11/example/example14.py +++ b/stormpy/resources/pybind11/example/example14.py @@ -4,21 +4,47 @@ import sys sys.path.append('.') from example import StringList, print_opaque_list +from example import ClassWithSTLVecProperty from example import return_void_ptr, print_void_ptr from example import return_null_str, print_null_str from example import return_unique_ptr +from example import Example1 + +##### l = StringList() l.push_back("Element 1") l.push_back("Element 2") print_opaque_list(l) print("Back element is %s" % l.back()) +for i, k in enumerate(l): + print("%i/%i : %s" % (i + 1, len(l), k)) l.pop_back() print_opaque_list(l) +##### +cvp = ClassWithSTLVecProperty() +print_opaque_list(cvp.stringList) + +cvp.stringList = l +cvp.stringList.push_back("Element 3") +print_opaque_list(cvp.stringList) + +##### + print_void_ptr(return_void_ptr()) +print_void_ptr(Example1()) # Should also work for other C++ types + +try: + print_void_ptr([1, 2, 3]) # This should not work +except Exception as e: + print("Caught expected exception: " + str(e)) print(return_null_str()) print_null_str(return_null_str()) -print(return_unique_ptr()) +##### + +ptr = return_unique_ptr() +print(ptr) +print_opaque_list(ptr) diff --git a/stormpy/resources/pybind11/example/example14.ref b/stormpy/resources/pybind11/example/example14.ref index b4768efe9..44e682098 100644 --- a/stormpy/resources/pybind11/example/example14.ref +++ b/stormpy/resources/pybind11/example/example14.ref @@ -1,10 +1,18 @@ -Opaque list: - Element 1 - Element 2 +Opaque list: [Element 1, Element 2] Back element is Element 2 -Opaque list: - Element 1 -Got void ptr : 1234 +1/2 : Element 1 +2/2 : Element 2 +Opaque list: [Element 1] +Opaque list: [] +Opaque list: [Element 1, Element 3] +Got void ptr : 0x1234 +Called Example1 default constructor.. +Got void ptr : 0x7f9ba0f3c430 +Called Example1 destructor (0) +Caught expected exception: Incompatible function arguments. The following argument types are supported: + 1. (capsule) -> NoneType + Invoked with: [1, 2, 3] None -Got null str : 0 -[u'some value'] +Got null str : 0x0 +<example.StringList object at 0x10d3277a0> +Opaque list: [some value] diff --git a/stormpy/resources/pybind11/example/example15.cpp b/stormpy/resources/pybind11/example/example15.cpp index bfc75268a..acdd36823 100644 --- a/stormpy/resources/pybind11/example/example15.cpp +++ b/stormpy/resources/pybind11/example/example15.cpp @@ -1,7 +1,7 @@ /* example/example15.cpp -- pickle support - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/example/example15.py b/stormpy/resources/pybind11/example/example15.py index 9868b62c2..1810d3e2e 100644 --- a/stormpy/resources/pybind11/example/example15.py +++ b/stormpy/resources/pybind11/example/example15.py @@ -14,7 +14,7 @@ p = Pickleable("test_value") p.setExtra1(15) p.setExtra2(48) -data = pickle.dumps(p, -1) # -1 is important (use highest protocol version) +data = pickle.dumps(p, 2) # Must use pickle protocol >= 2 print("%s %i %i" % (p.value(), p.extra1(), p.extra2())) p2 = pickle.loads(data) diff --git a/stormpy/resources/pybind11/example/example16.cpp b/stormpy/resources/pybind11/example/example16.cpp index 350435f57..7b676a9dc 100644 --- a/stormpy/resources/pybind11/example/example16.cpp +++ b/stormpy/resources/pybind11/example/example16.cpp @@ -1,7 +1,7 @@ /* example/example16.cpp -- automatic upcasting for polymorphic types - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/example/example17.cpp b/stormpy/resources/pybind11/example/example17.cpp new file mode 100644 index 000000000..8ae4cad08 --- /dev/null +++ b/stormpy/resources/pybind11/example/example17.cpp @@ -0,0 +1,36 @@ +/* + example/example17.cpp -- Usage of stl_binders functions + + Copyright (c) 2016 Sergey Lyskov + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" + +#include <pybind11/stl_bind.h> + +class El { +public: + El() = delete; + El(int v) : a(v) { } + + int a; +}; + +std::ostream & operator<<(std::ostream &s, El const&v) { + s << "El{" << v.a << '}'; + return s; +} + +void init_ex17(py::module &m) { + pybind11::class_<El>(m, "El") + .def(pybind11::init<int>()); + + pybind11::bind_vector<unsigned int>(m, "VectorInt"); + + pybind11::bind_vector<El>(m, "VectorEl"); + + pybind11::bind_vector<std::vector<El>>(m, "VectorVectorEl"); +} diff --git a/stormpy/resources/pybind11/example/example17.py b/stormpy/resources/pybind11/example/example17.py new file mode 100644 index 000000000..65e586bcb --- /dev/null +++ b/stormpy/resources/pybind11/example/example17.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +from __future__ import print_function + +from example import VectorInt, El, VectorEl, VectorVectorEl + +v_int = VectorInt([0, 0]) +print(len(v_int)) + +print(bool(v_int)) + +v_int2 = VectorInt([0, 0]) +print(v_int == v_int2) + +v_int2[1] = 1 +print(v_int != v_int2) + +v_int2.append(2) +v_int2.append(3) +v_int2.insert(0, 1) +v_int2.insert(0, 2) +v_int2.insert(0, 3) +print(v_int2) + +v_int.append(99) +v_int2[2:-2] = v_int +print(v_int2) +del v_int2[1:3] +print(v_int2) +del v_int2[0] +print(v_int2) + +v_a = VectorEl() +v_a.append(El(1)) +v_a.append(El(2)) +print(v_a) + +vv_a = VectorVectorEl() +vv_a.append(v_a) +vv_b = vv_a[0] +print(vv_b) diff --git a/stormpy/resources/pybind11/example/example17.ref b/stormpy/resources/pybind11/example/example17.ref new file mode 100644 index 000000000..55e47a68d --- /dev/null +++ b/stormpy/resources/pybind11/example/example17.ref @@ -0,0 +1,10 @@ +2 +True +True +True +VectorInt[3, 2, 1, 0, 1, 2, 3] +VectorInt[3, 2, 0, 0, 99, 2, 3] +VectorInt[3, 0, 99, 2, 3] +VectorInt[0, 99, 2, 3] +VectorEl[El{1}, El{2}] +VectorEl[El{1}, El{2}] diff --git a/stormpy/resources/pybind11/example/example2.cpp b/stormpy/resources/pybind11/example/example2.cpp index 2d49286b1..9b91baaad 100644 --- a/stormpy/resources/pybind11/example/example2.cpp +++ b/stormpy/resources/pybind11/example/example2.cpp @@ -2,7 +2,7 @@ example/example2.cpp2 -- singleton design pattern, static functions and variables, passing and interacting with Python types - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/example/example3.cpp b/stormpy/resources/pybind11/example/example3.cpp index 3b3a6253e..af956b13e 100644 --- a/stormpy/resources/pybind11/example/example3.cpp +++ b/stormpy/resources/pybind11/example/example3.cpp @@ -1,7 +1,7 @@ /* example/example3.cpp -- operator overloading - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/example/example3.ref b/stormpy/resources/pybind11/example/example3.ref index 698b5ad6e..8f2c29886 100644 --- a/stormpy/resources/pybind11/example/example3.ref +++ b/stormpy/resources/pybind11/example/example3.ref @@ -3,52 +3,52 @@ Value constructor v1 = [1.000000, 2.000000] v2 = [3.000000, -1.000000] Value constructor -Copy constructor +Move constructor Destructor. Destructor. v1+v2 = [4.000000, 1.000000] Value constructor -Copy constructor +Move constructor Destructor. Destructor. v1-v2 = [-2.000000, 3.000000] Value constructor -Copy constructor +Move constructor Destructor. Destructor. v1-8 = [-7.000000, -6.000000] Value constructor -Copy constructor +Move constructor Destructor. Destructor. v1+8 = [9.000000, 10.000000] Value constructor -Copy constructor +Move constructor Destructor. Destructor. v1*8 = [8.000000, 16.000000] Value constructor -Copy constructor +Move constructor Destructor. Destructor. v1/8 = [0.125000, 0.250000] Value constructor -Copy constructor +Move constructor Destructor. Destructor. 8-v1 = [7.000000, 6.000000] Value constructor -Copy constructor +Move constructor Destructor. Destructor. 8+v1 = [9.000000, 10.000000] Value constructor -Copy constructor +Move constructor Destructor. Destructor. 8*v1 = [8.000000, 16.000000] Value constructor -Copy constructor +Move constructor Destructor. Destructor. 8/v1 = [8.000000, 4.000000] diff --git a/stormpy/resources/pybind11/example/example4.cpp b/stormpy/resources/pybind11/example/example4.cpp index e673c4a81..281eafed5 100644 --- a/stormpy/resources/pybind11/example/example4.cpp +++ b/stormpy/resources/pybind11/example/example4.cpp @@ -1,7 +1,7 @@ /* example/example4.cpp -- global constants and functions, enumerations, raw byte strings - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/example/example5.cpp b/stormpy/resources/pybind11/example/example5.cpp index ad24ef069..11d37d0ef 100644 --- a/stormpy/resources/pybind11/example/example5.cpp +++ b/stormpy/resources/pybind11/example/example5.cpp @@ -2,7 +2,7 @@ example/example5.cpp -- inheritance, callbacks, acquiring and releasing the global interpreter lock - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -43,12 +43,12 @@ void dog_bark(const Dog &dog) { } bool test_callback1(py::object func) { - func.call(); + func(); return false; } int test_callback2(py::object func) { - py::object result = func.call("Hello", 'x', true, 5); + py::object result = func("Hello", 'x', true, 5); return result.cast<int>(); } diff --git a/stormpy/resources/pybind11/example/example5.ref b/stormpy/resources/pybind11/example/example5.ref index bfc3cb26e..a9c7d465f 100644 --- a/stormpy/resources/pybind11/example/example5.ref +++ b/stormpy/resources/pybind11/example/example5.ref @@ -14,7 +14,7 @@ Polly is a parrot Molly is a dog The following error is expected: Incompatible function arguments. The following argument types are supported: 1. (example.Dog) -> NoneType - + Invoked with: <Pet object at 0> Callback function 1 called! False Callback function 2 called : Hello, x, True, 5 diff --git a/stormpy/resources/pybind11/example/example6.cpp b/stormpy/resources/pybind11/example/example6.cpp index 89db2fbab..26552b7e3 100644 --- a/stormpy/resources/pybind11/example/example6.cpp +++ b/stormpy/resources/pybind11/example/example6.cpp @@ -2,7 +2,7 @@ example/example6.cpp -- supporting Pythons' sequence protocol, iterators, etc. - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/example/example6.ref b/stormpy/resources/pybind11/example/example6.ref index bc369023f..c02dc76af 100644 --- a/stormpy/resources/pybind11/example/example6.ref +++ b/stormpy/resources/pybind11/example/example6.ref @@ -1,13 +1,13 @@ Value constructor: Creating a sequence with 5 entries -s = <example.Sequence object at 0x1033bd8d0> +s = <example.Sequence object at 0x10c786c70> len(s) = 5 s[0], s[3] = 0.000000 0.000000 12.34 in s: False 12.34 in s: True s[0], s[3] = 12.340000 56.779999 Value constructor: Creating a sequence with 5 entries -Copy constructor: Creating a sequence with 5 entries -Freeing a sequence with 5 entries +Move constructor: Creating a sequence with 5 entries +Freeing a sequence with 0 entries Value constructor: Creating a sequence with 5 entries rev[0], rev[1], rev[2], rev[3], rev[4] = 0.000000 56.779999 0.000000 0.000000 12.340000 0.0 56.7799987793 0.0 0.0 12.3400001526 diff --git a/stormpy/resources/pybind11/example/example7.cpp b/stormpy/resources/pybind11/example/example7.cpp index b68b55396..6aabf1c1c 100644 --- a/stormpy/resources/pybind11/example/example7.cpp +++ b/stormpy/resources/pybind11/example/example7.cpp @@ -1,7 +1,7 @@ /* example/example7.cpp -- supporting Pythons' buffer protocol - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -80,7 +80,7 @@ void init_ex7(py::module &m) { /// Construct from a buffer .def("__init__", [](Matrix &v, py::buffer b) { py::buffer_info info = b.request(); - if (info.format != py::format_descriptor<float>::value() || info.ndim != 2) + if (info.format != py::format_descriptor<float>::value || info.ndim != 2) throw std::runtime_error("Incompatible buffer format!"); new (&v) Matrix(info.shape[0], info.shape[1]); memcpy(v.data(), info.ptr, sizeof(float) * v.rows() * v.cols()); @@ -103,12 +103,12 @@ void init_ex7(py::module &m) { /// Provide buffer access .def_buffer([](Matrix &m) -> py::buffer_info { return py::buffer_info( - m.data(), /* Pointer to buffer */ - sizeof(float), /* Size of one scalar */ - py::format_descriptor<float>::value(), /* Python struct-style format descriptor */ - 2, /* Number of dimensions */ - { m.rows(), m.cols() }, /* Buffer dimensions */ - { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ + m.data(), /* Pointer to buffer */ + sizeof(float), /* Size of one scalar */ + py::format_descriptor<float>::value, /* Python struct-style format descriptor */ + 2, /* Number of dimensions */ + { m.rows(), m.cols() }, /* Buffer dimensions */ + { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ sizeof(float) } ); }); diff --git a/stormpy/resources/pybind11/example/example8.cpp b/stormpy/resources/pybind11/example/example8.cpp index f492588bd..dbdd4218d 100644 --- a/stormpy/resources/pybind11/example/example8.cpp +++ b/stormpy/resources/pybind11/example/example8.cpp @@ -2,7 +2,7 @@ example/example8.cpp -- binding classes with custom reference counting, implicit conversions between types - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/example/example9.cpp b/stormpy/resources/pybind11/example/example9.cpp index f64b539a2..ca75ecc79 100644 --- a/stormpy/resources/pybind11/example/example9.cpp +++ b/stormpy/resources/pybind11/example/example9.cpp @@ -2,7 +2,7 @@ example/example9.cpp -- nested modules, importing modules, and internal references - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/example/issues.cpp b/stormpy/resources/pybind11/example/issues.cpp index c9f9e8b07..d1a1941b7 100644 --- a/stormpy/resources/pybind11/example/issues.cpp +++ b/stormpy/resources/pybind11/example/issues.cpp @@ -1,36 +1,30 @@ /* example/issues.cpp -- collection of testcases for miscellaneous issues - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include "example.h" +#include <pybind11/stl.h> -struct Base { - virtual void dispatch(void) const = 0; -}; +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>); -struct DispatchIssue : Base { - virtual void dispatch(void) const { - PYBIND11_OVERLOAD_PURE(void, Base, dispatch); - } -}; - -void dispatch_issue_go(const Base * b) { b->dispatch(); } - -PYBIND11_PLUGIN(mytest) -{ - pybind11::module m("mytest", "A test"); - - - return m.ptr(); -} void init_issues(py::module &m) { py::module m2 = m.def_submodule("issues"); +#if !defined(_MSC_VER) + // Visual Studio 2015 currently cannot compile this test + // (see the comment in type_caster_base::make_copy_constructor) + // #70 compilation issue if operator new is not public + class NonConstructible { private: void *operator new(size_t bytes) throw(); }; + py::class_<NonConstructible>(m, "Foo"); + m2.def("getstmt", []() -> NonConstructible * { return nullptr; }, + py::return_value_policy::reference); +#endif + // #137: const char* isn't handled properly m2.def("print_cchar", [](const char *string) { std::cout << string << std::endl; }); @@ -38,10 +32,80 @@ void init_issues(py::module &m) { m2.def("print_char", [](char c) { std::cout << c << std::endl; }); // #159: virtual function dispatch has problems with similar-named functions - pybind11::class_<DispatchIssue> base(m2, "DispatchIssue"); + struct Base { virtual void dispatch(void) const { + /* for some reason MSVC2015 can't compile this if the function is pure virtual */ + }; }; + + struct DispatchIssue : Base { + virtual void dispatch(void) const { + PYBIND11_OVERLOAD_PURE(void, Base, dispatch, /* no arguments */); + } + }; + + py::class_<DispatchIssue> base(m2, "DispatchIssue"); base.alias<Base>() - .def(pybind11::init<>()) + .def(py::init<>()) .def("dispatch", &Base::dispatch); - m2.def("dispatch_issue_go", &dispatch_issue_go); + m2.def("dispatch_issue_go", [](const Base * b) { b->dispatch(); }); + + struct Placeholder { int i; Placeholder(int i) : i(i) { } }; + + py::class_<Placeholder>(m2, "Placeholder") + .def(py::init<int>()) + .def("__repr__", [](const Placeholder &p) { return "Placeholder[" + std::to_string(p.i) + "]"; }); + + // #171: Can't return reference wrappers (or STL datastructures containing them) + m2.def("return_vec_of_reference_wrapper", [](std::reference_wrapper<Placeholder> p4){ + Placeholder *p1 = new Placeholder{1}; + Placeholder *p2 = new Placeholder{2}; + Placeholder *p3 = new Placeholder{3}; + std::vector<std::reference_wrapper<Placeholder>> v; + v.push_back(std::ref(*p1)); + v.push_back(std::ref(*p2)); + v.push_back(std::ref(*p3)); + v.push_back(p4); + return v; + }); + + // #181: iterator passthrough did not compile + m2.def("iterator_passthrough", [](py::iterator s) -> py::iterator { + return py::make_iterator(std::begin(s), std::end(s)); + }); + + // #187: issue involving std::shared_ptr<> return value policy & garbage collection + struct ElementBase { virtual void foo() { } /* Force creation of virtual table */ }; + struct ElementA : ElementBase { + ElementA(int v) : v(v) { } + int value() { return v; } + int v; + }; + + struct ElementList { + void add(std::shared_ptr<ElementBase> e) { l.push_back(e); } + std::vector<std::shared_ptr<ElementBase>> l; + }; + + py::class_<ElementBase, std::shared_ptr<ElementBase>> (m2, "ElementBase"); + + py::class_<ElementA, std::shared_ptr<ElementA>>(m2, "ElementA", py::base<ElementBase>()) + .def(py::init<int>()) + .def("value", &ElementA::value); + + py::class_<ElementList, std::shared_ptr<ElementList>>(m2, "ElementList") + .def(py::init<>()) + .def("add", &ElementList::add) + .def("get", [](ElementList &el){ + py::list list; + for (auto &e : el.l) + list.append(py::cast(e)); + return list; + }); + + // (no id): should not be able to pass 'None' to a reference argument + m2.def("print_element", [](ElementA &el) { std::cout << el.value() << std::endl; }); + + // (no id): don't cast doubles to ints + m2.def("expect_float", [](float f) { return f; }); + m2.def("expect_int", [](int i) { return i; }); } diff --git a/stormpy/resources/pybind11/example/issues.py b/stormpy/resources/pybind11/example/issues.py index 84752b0d3..d075e8340 100644 --- a/stormpy/resources/pybind11/example/issues.py +++ b/stormpy/resources/pybind11/example/issues.py @@ -5,6 +5,11 @@ sys.path.append('.') from example.issues import print_cchar, print_char from example.issues import DispatchIssue, dispatch_issue_go +from example.issues import Placeholder, return_vec_of_reference_wrapper +from example.issues import iterator_passthrough +from example.issues import ElementList, ElementA, print_element +from example.issues import expect_float, expect_int +import gc print_cchar("const char *") print_char('c') @@ -26,3 +31,27 @@ class PyClass2(DispatchIssue): b = PyClass2() dispatch_issue_go(b) + +print(return_vec_of_reference_wrapper(Placeholder(4))) + +print(list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15])))) + +el = ElementList() +for i in range(10): + el.add(ElementA(i)) +gc.collect() +for i, v in enumerate(el.get()): + print("%i==%i, " % (i, v.value()), end='') +print() + +try: + print_element(None) +except Exception as e: + print("Failed as expected: " + str(e)) + +try: + print(expect_int(5.2)) +except Exception as e: + print("Failed as expected: " + str(e)) + +print(expect_float(12)) diff --git a/stormpy/resources/pybind11/example/issues.ref b/stormpy/resources/pybind11/example/issues.ref index 55cbdda1d..4888ea55b 100644 --- a/stormpy/resources/pybind11/example/issues.ref +++ b/stormpy/resources/pybind11/example/issues.ref @@ -1,4 +1,14 @@ const char * c -Failed as expected: Tried to call pure virtual function "dispatch" +Failed as expected: Tried to call pure virtual function "Base::dispatch" Yay.. +[Placeholder[1], Placeholder[2], Placeholder[3], Placeholder[4]] +[3, 5, 7, 9, 11, 13, 15] +0==0, 1==1, 2==2, 3==3, 4==4, 5==5, 6==6, 7==7, 8==8, 9==9, +Failed as expected: Incompatible function arguments. The following argument types are supported: + 1. (example.issues.ElementA) -> NoneType + Invoked with: None +Failed as expected: Incompatible function arguments. The following argument types are supported: + 1. (int) -> int + Invoked with: 5.2 +12.0 diff --git a/stormpy/resources/pybind11/include/pybind11/attr.h b/stormpy/resources/pybind11/include/pybind11/attr.h index 759feed7e..d63a44e9f 100644 --- a/stormpy/resources/pybind11/include/pybind11/attr.h +++ b/stormpy/resources/pybind11/include/pybind11/attr.h @@ -2,7 +2,7 @@ pybind11/pybind11.h: Infrastructure for processing custom type and function attributes - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -92,19 +92,28 @@ struct function_record { std::vector<argument_record> args; /// Pointer to lambda function which converts arguments and performs the actual call - handle (*impl) (function_record *, handle, handle) = nullptr; + handle (*impl) (function_record *, handle, handle, handle) = nullptr; /// Storage for the wrapped function pointer and captured data, if any - void *data = nullptr; + void *data[3] = { }; /// Pointer to custom destructor for 'data' (if needed) - void (*free_data) (void *ptr) = nullptr; + void (*free_data) (function_record *ptr) = nullptr; /// Return value policy associated with this function return_value_policy policy = return_value_policy::automatic; /// True if name == '__init__' - bool is_constructor = false; + bool is_constructor : 1; + + /// True if the function has a '*args' argument + bool has_args : 1; + + /// True if the function has a '**kwargs' argument + bool has_kwargs : 1; + + /// Number of arguments + uint16_t nargs; /// Python method object PyMethodDef *def = nullptr; diff --git a/stormpy/resources/pybind11/include/pybind11/cast.h b/stormpy/resources/pybind11/include/pybind11/cast.h index 0fe35274d..31f5cb5a6 100644 --- a/stormpy/resources/pybind11/include/pybind11/cast.h +++ b/stormpy/resources/pybind11/include/pybind11/cast.h @@ -2,7 +2,7 @@ pybind11/cast.h: Partial template specializations to cast between C++ and Python types - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -15,23 +15,9 @@ #include "descr.h" #include <array> #include <limits> +#include <iostream> NAMESPACE_BEGIN(pybind11) - -/// Thin wrapper type used to treat certain data types as opaque (e.g. STL vectors, etc.) -template <typename Type> class opaque { -public: - template <typename... Args> opaque(Args&&... args) : value(std::forward<Args>(args)...) { } - operator Type&() { return value; } - operator const Type&() const { return value; } - operator Type*() { return &value; } - operator const Type*() const { return &value; } - Type* operator->() { return &value; } - const Type* operator->() const { return &value; } -private: - Type value; -}; - NAMESPACE_BEGIN(detail) /// Additional type information which does not fit into the PyTypeObject @@ -55,20 +41,30 @@ PYBIND11_NOINLINE inline internals &get_internals() { internals_ptr = caps; } else { internals_ptr = new internals(); + #if defined(WITH_THREAD) + PyEval_InitThreads(); + PyThreadState *tstate = PyThreadState_Get(); + internals_ptr->tstate = PyThread_create_key(); + PyThread_set_key_value(internals_ptr->tstate, tstate); + internals_ptr->istate = tstate->interp; + #endif builtins[id] = capsule(internals_ptr); } return *internals_ptr; } -PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) { +PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type, bool throw_if_missing = true) { auto const &type_dict = get_internals().registered_types_py; do { auto it = type_dict.find(type); if (it != type_dict.end()) return (detail::type_info *) it->second; type = type->tp_base; - if (!type) - pybind11_fail("pybind11::detail::get_type_info: unable to find type object!"); + if (!type) { + if (throw_if_missing) + pybind11_fail("pybind11::detail::get_type_info: unable to find type object!"); + return nullptr; + } } while (true); } @@ -110,6 +106,18 @@ PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr) { return handle((PyObject *) it->second); } +inline PyThreadState *get_thread_state_unchecked() { +#if PY_VERSION_HEX < 0x03000000 + return _PyThreadState_Current; +#elif PY_VERSION_HEX < 0x03050000 + return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current); +#elif PY_VERSION_HEX < 0x03050200 + return (PyThreadState*) _PyThreadState_Current.value; +#else + return _PyThreadState_UncheckedGet(); +#endif +} + class type_caster_generic { public: PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info) @@ -139,6 +147,7 @@ public: const std::type_info *type_info, const std::type_info *type_info_backup, void *(*copy_constructor)(const void *), + void *(*move_constructor)(const void *), const void *existing_holder = nullptr) { void *src = const_cast<void *>(_src); if (src == nullptr) @@ -185,6 +194,12 @@ public: wrapper->value = copy_constructor(wrapper->value); if (wrapper->value == nullptr) throw cast_error("return_value_policy = copy, but the object is non-copyable!"); + } else if (policy == return_value_policy::move) { + wrapper->value = move_constructor(wrapper->value); + if (wrapper->value == nullptr) + wrapper->value = copy_constructor(wrapper->value); + if (wrapper->value == nullptr) + throw cast_error("return_value_policy = move, but the object is neither movable nor copyable!"); } else if (policy == return_value_policy::reference) { wrapper->owned = false; } else if (policy == return_value_policy::reference_internal) { @@ -207,16 +222,16 @@ protected: /* Determine suitable casting operator */ template <typename T> -using cast_op_type = typename std::conditional<std::is_pointer<T>::value, +using cast_op_type = typename std::conditional<std::is_pointer<typename std::remove_reference<T>::type>::value, typename std::add_pointer<typename intrinsic_type<T>::type>::type, typename std::add_lvalue_reference<typename intrinsic_type<T>::type>::type>::type; /// Generic type caster for objects stored on the heap -template <typename type, typename Enable = void> class type_caster : public type_caster_generic { +template <typename type> class type_caster_base : public type_caster_generic { public: static PYBIND11_DESCR name() { return type_descr(_<type>()); } - type_caster() : type_caster_generic(typeid(type)) { } + type_caster_base() : type_caster_generic(typeid(type)) { } static handle cast(const type &src, return_value_policy policy, handle parent) { if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) @@ -224,21 +239,55 @@ public: return cast(&src, policy, parent); } + static handle cast(type &&src, return_value_policy policy, handle parent) { + if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) + policy = return_value_policy::move; + return cast(&src, policy, parent); + } + static handle cast(const type *src, return_value_policy policy, handle parent) { - return type_caster_generic::cast(src, policy, parent, src ? &typeid(*src) : nullptr, &typeid(type), ©_constructor); + return type_caster_generic::cast( + src, policy, parent, src ? &typeid(*src) : nullptr, &typeid(type), + make_copy_constructor(src), make_move_constructor(src)); } template <typename T> using cast_op_type = pybind11::detail::cast_op_type<T>; operator type*() { return (type *) value; } - operator type&() { return *((type *) value); } + operator type&() { if (!value) throw cast_error(); return *((type *) value); } + protected: - template <typename T = type, typename std::enable_if<detail::is_copy_constructible<T>::value, int>::type = 0> - static void *copy_constructor(const void *arg) { - return (void *) new type(*((const type *) arg)); + typedef void *(*Constructor)(const void *stream); +#if !defined(_MSC_VER) + /* Only enabled when the types are {copy,move}-constructible *and* when the type + does not have a private operator new implementaton. */ + template <typename T = type> static auto make_copy_constructor(const T *value) -> decltype(new T(*value), Constructor(nullptr)) { + return [](const void *arg) -> void * { return new T(*((const T *) arg)); }; } + template <typename T = type> static auto make_move_constructor(const T *value) -> decltype(new T(std::move(*((T *) value))), Constructor(nullptr)) { + return [](const void *arg) -> void * { return (void *) new T(std::move(*((T *) arg))); }; } +#else + /* Visual Studio 2015's SFINAE implementation doesn't yet handle the above robustly in all situations. + Use a workaround that only tests for constructibility for now. */ + template <typename T = type, typename = typename std::enable_if<std::is_copy_constructible<T>::value>::type> + static Constructor make_copy_constructor(const T *value) { + return [](const void *arg) -> void * { return new T(*((const T *)arg)); }; } + template <typename T = type, typename = typename std::enable_if<std::is_move_constructible<T>::value>::type> + static Constructor make_move_constructor(const T *value) { + return [](const void *arg) -> void * { return (void *) new T(std::move(*((T *)arg))); }; } +#endif + static Constructor make_copy_constructor(...) { return nullptr; } + static Constructor make_move_constructor(...) { return nullptr; } +}; + +template <typename type, typename SFINAE = void> class type_caster : public type_caster_base<type> { }; + +template <typename type> class type_caster<std::reference_wrapper<type>> : public type_caster_base<type> { +public: + static handle cast(const std::reference_wrapper<type> &src, return_value_policy policy, handle parent) { + return type_caster_base<type>::cast(&src.get(), policy, parent); } - template <typename T = type, typename std::enable_if<!detail::is_copy_constructible<T>::value, int>::type = 0> - static void *copy_constructor(const void *) { return nullptr; } + template <typename T> using cast_op_type = std::reference_wrapper<type>; + operator std::reference_wrapper<type>() { return std::ref(*((type *) this->value)); } }; #define PYBIND11_TYPE_CASTER(type, py_name) \ @@ -251,7 +300,7 @@ protected: } \ operator type*() { return &value; } \ operator type&() { return value; } \ - template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>; + template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T> #define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type) \ namespace pybind11 { namespace detail { \ @@ -272,14 +321,20 @@ public: bool load(handle src, bool) { py_type py_value; - if (std::is_floating_point<T>::value) { + if (!src) { + return false; + } if (std::is_floating_point<T>::value) { py_value = (py_type) PyFloat_AsDouble(src.ptr()); } else if (sizeof(T) <= sizeof(long)) { + if (PyFloat_Check(src.ptr())) + return false; if (std::is_signed<T>::value) py_value = (py_type) PyLong_AsLong(src.ptr()); else py_value = (py_type) PyLong_AsUnsignedLong(src.ptr()); } else { + if (PyFloat_Check(src.ptr())) + return false; if (std::is_signed<T>::value) py_value = (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr()); else @@ -346,18 +401,31 @@ public: using type_caster<void_type>::cast; bool load(handle h, bool) { - if (h.ptr() == Py_None) { + if (!h) { + return false; + } else if (h.ptr() == Py_None) { value = nullptr; return true; } + + /* Check if this is a capsule */ capsule c(h, true); - if (!c.check()) - return false; - value = (void *) c; - return true; + if (c.check()) { + value = (void *) c; + return true; + } + + /* Check if this is a C++ type */ + if (get_type_info((PyTypeObject *) h.get_type().ptr(), false)) { + value = ((instance<void> *) h.ptr())->value; + return true; + } + + /* Fail */ + return false; } - static handle cast(void *ptr, return_value_policy /* policy */, handle /* parent */) { + static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) { if (ptr) return capsule(ptr).release(); else @@ -366,6 +434,7 @@ public: template <typename T> using cast_op_type = void*&; operator void *&() { return value; } + static PYBIND11_DESCR name() { return _("capsule"); } private: void *value = nullptr; }; @@ -375,7 +444,8 @@ template <> class type_caster<std::nullptr_t> : public type_caster<void_type> { template <> class type_caster<bool> { public: bool load(handle src, bool) { - if (src.ptr() == Py_True) { value = true; return true; } + if (!src) return false; + else if (src.ptr() == Py_True) { value = true; return true; } else if (src.ptr() == Py_False) { value = false; return true; } else return false; } @@ -390,7 +460,9 @@ public: bool load(handle src, bool) { object temp; handle load_src = src; - if (PyUnicode_Check(load_src.ptr())) { + if (!src) { + return false; + } else if (PyUnicode_Check(load_src.ptr())) { temp = object(PyUnicode_AsUTF8String(load_src.ptr()), false); if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError load_src = temp; @@ -416,12 +488,12 @@ protected: template <typename type> class type_caster<std::unique_ptr<type>> { public: static handle cast(std::unique_ptr<type> &&src, return_value_policy policy, handle parent) { - handle result = type_caster<type>::cast(src.get(), policy, parent); + handle result = type_caster_base<type>::cast(src.get(), policy, parent); if (result) src.release(); return result; } - static PYBIND11_DESCR name() { return type_caster<type>::name(); } + static PYBIND11_DESCR name() { return type_caster_base<type>::name(); } }; template <> class type_caster<std::wstring> { @@ -429,7 +501,9 @@ public: bool load(handle src, bool) { object temp; handle load_src = src; - if (!PyUnicode_Check(load_src.ptr())) { + if (!src) { + return false; + } else if (!PyUnicode_Check(load_src.ptr())) { temp = object(PyUnicode_FromObject(load_src.ptr()), false); if (!temp) { PyErr_Clear(); return false; } load_src = temp; @@ -467,7 +541,7 @@ protected: template <> class type_caster<char> : public type_caster<std::string> { public: bool load(handle src, bool convert) { - if (src.ptr() == Py_None) { return true; } + if (src.ptr() == Py_None) return true; return type_caster<std::string>::load(src, convert); } @@ -490,7 +564,7 @@ public: template <> class type_caster<wchar_t> : public type_caster<std::wstring> { public: bool load(handle src, bool convert) { - if (src.ptr() == Py_None) { return true; } + if (src.ptr() == Py_None) return true; return type_caster<std::wstring>::load(src, convert); } @@ -514,7 +588,9 @@ template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> { typedef std::pair<T1, T2> type; public: bool load(handle src, bool convert) { - if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != 2) + if (!src) + return false; + else if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != 2) return false; return first.load(PyTuple_GET_ITEM(src.ptr(), 0), convert) && second.load(PyTuple_GET_ITEM(src.ptr(), 1), convert); @@ -550,13 +626,41 @@ protected: template <typename... Tuple> class type_caster<std::tuple<Tuple...>> { typedef std::tuple<Tuple...> type; + typedef std::tuple<typename intrinsic_type<Tuple>::type...> itype; + typedef std::tuple<args> args_type; + typedef std::tuple<args, kwargs> args_kwargs_type; public: enum { size = sizeof...(Tuple) }; + static constexpr const bool has_kwargs = std::is_same<itype, args_kwargs_type>::value; + static constexpr const bool has_args = has_kwargs || std::is_same<itype, args_type>::value; + bool load(handle src, bool convert) { + if (!src || !PyTuple_Check(src.ptr()) || PyTuple_GET_SIZE(src.ptr()) != size) + return false; return load(src, convert, typename make_index_sequence<sizeof...(Tuple)>::type()); } + template <typename T = itype, typename std::enable_if< + !std::is_same<T, args_type>::value && + !std::is_same<T, args_kwargs_type>::value, int>::type = 0> + bool load_args(handle args, handle, bool convert) { + return load(args, convert, typename make_index_sequence<sizeof...(Tuple)>::type()); + } + + template <typename T = itype, typename std::enable_if<std::is_same<T, args_type>::value, int>::type = 0> + bool load_args(handle args, handle, bool convert) { + std::get<0>(value).load(args, convert); + return true; + } + + template <typename T = itype, typename std::enable_if<std::is_same<T, args_kwargs_type>::value, int>::type = 0> + bool load_args(handle args, handle kwargs, bool convert) { + std::get<0>(value).load(args, convert); + std::get<1>(value).load(kwargs, convert); + return true; + } + static handle cast(const type &src, return_value_policy policy, handle parent) { return cast(src, policy, parent, typename make_index_sequence<size>::type()); } @@ -595,10 +699,8 @@ protected: } template <size_t ... Indices> bool load(handle src, bool convert, index_sequence<Indices...>) { - if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != size) - return false; std::array<bool, size> success {{ - (PyTuple_GET_ITEM(src.ptr(), Indices) != nullptr ? std::get<Indices>(value).load(PyTuple_GET_ITEM(src.ptr(), Indices), convert) : false)... + std::get<Indices>(value).load(PyTuple_GET_ITEM(src.ptr(), Indices), convert)... }}; (void) convert; /* avoid a warning when the tuple is empty */ for (bool r : success) @@ -627,13 +729,12 @@ protected: }; /// Type caster for holder types like std::shared_ptr, etc. -template <typename type, typename holder_type> class type_caster_holder : public type_caster<type> { +template <typename type, typename holder_type> class type_caster_holder : public type_caster_base<type> { public: - using type_caster<type>::cast; - using type_caster<type>::typeinfo; - using type_caster<type>::value; - using type_caster<type>::temp; - using type_caster<type>::copy_constructor; + using type_caster_base<type>::cast; + using type_caster_base<type>::typeinfo; + using type_caster_base<type>::value; + using type_caster_base<type>::temp; bool load(handle src, bool convert) { if (!src || !typeinfo) { @@ -670,11 +771,11 @@ public: explicit operator holder_type&() { return holder; } #endif - static handle cast(const holder_type &src, return_value_policy policy, handle parent) { + static handle cast(const holder_type &src, return_value_policy, handle) { return type_caster_generic::cast( - src.get(), policy, parent, + src.get(), return_value_policy::take_ownership, handle(), src.get() ? &typeid(*src.get()) : nullptr, &typeid(type), - ©_constructor, &src); + nullptr, nullptr, &src); } protected: @@ -683,14 +784,16 @@ protected: template <typename T> struct handle_type_name { static PYBIND11_DESCR name() { return _<T>(); } }; template <> struct handle_type_name<bytes> { static PYBIND11_DESCR name() { return _(PYBIND11_BYTES_NAME); } }; +template <> struct handle_type_name<args> { static PYBIND11_DESCR name() { return _("*args"); } }; +template <> struct handle_type_name<kwargs> { static PYBIND11_DESCR name() { return _("**kwargs"); } }; template <typename type> struct type_caster<type, typename std::enable_if<std::is_base_of<handle, type>::value>::type> { public: - template <typename T = type, typename std::enable_if<std::is_same<T, handle>::value, int>::type = 0> - bool load(handle src, bool /* convert */) { value = src; return value.check(); } + template <typename T = type, typename std::enable_if<!std::is_base_of<object, T>::value, int>::type = 0> + bool load(handle src, bool /* convert */) { value = type(src); return value.check(); } - template <typename T = type, typename std::enable_if<!std::is_same<T, handle>::value, int>::type = 0> + template <typename T = type, typename std::enable_if<std::is_base_of<object, T>::value, int>::type = 0> bool load(handle src, bool /* convert */) { value = type(src, true); return value.check(); } static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) { @@ -701,14 +804,17 @@ public: NAMESPACE_END(detail) -template <typename T> inline T cast(handle handle) { - detail::type_caster<typename detail::intrinsic_type<T>::type> conv; +template <typename T> T cast(handle handle) { + typedef detail::type_caster<typename detail::intrinsic_type<T>::type> type_caster; + type_caster conv; if (!conv.load(handle, true)) throw cast_error("Unable to cast Python object to C++ type"); - return (T) conv; + return conv.operator typename type_caster::template cast_op_type<T>(); } -template <typename T> inline object cast(const T &value, return_value_policy policy = return_value_policy::automatic_reference, handle parent = handle()) { +template <typename T> object cast(const T &value, + return_value_policy policy = return_value_policy::automatic_reference, + handle parent = handle()) { if (policy == return_value_policy::automatic) policy = std::is_pointer<T>::value ? return_value_policy::take_ownership : return_value_policy::copy; else if (policy == return_value_policy::automatic_reference) @@ -716,11 +822,11 @@ template <typename T> inline object cast(const T &value, return_value_policy pol return object(detail::type_caster<typename detail::intrinsic_type<T>::type>::cast(value, policy, parent), false); } -template <typename T> inline T handle::cast() const { return pybind11::cast<T>(*this); } +template <typename T> T handle::cast() const { return pybind11::cast<T>(*this); } template <> inline void handle::cast() const { return; } template <return_value_policy policy = return_value_policy::automatic_reference, - typename... Args> inline tuple make_tuple(Args&&... args_) { + typename... Args> tuple make_tuple(Args&&... args_) { const size_t size = sizeof...(Args); std::array<object, size> args { { object(detail::type_caster<typename detail::intrinsic_type<Args>::type>::cast( @@ -736,7 +842,7 @@ template <return_value_policy policy = return_value_policy::automatic_reference, return result; } -template <typename... Args> inline object handle::call(Args&&... args) const { +template <typename... Args> object handle::operator()(Args&&... args) const { tuple args_tuple = pybind11::make_tuple(std::forward<Args>(args)...); object result(PyObject_CallObject(m_ptr, args_tuple.ptr()), false); if (!result) @@ -744,4 +850,27 @@ template <typename... Args> inline object handle::call(Args&&... args) const { return result; } +template <typename... Args> object handle::call(Args &&... args) const { + return operator()(std::forward<Args>(args)...); +} + +inline object handle::operator()(detail::args_proxy args) const { + object result(PyObject_CallObject(m_ptr, args.ptr()), false); + if (!result) + throw error_already_set(); + return result; +} + +inline object handle::operator()(detail::args_proxy args, detail::kwargs_proxy kwargs) const { + object result(PyObject_Call(m_ptr, args.ptr(), kwargs.ptr()), false); + if (!result) + throw error_already_set(); + return result; +} + +#define PYBIND11_MAKE_OPAQUE(Type) \ + namespace pybind11 { namespace detail { \ + template<> class type_caster<Type> : public type_caster_base<Type> { }; \ + }} + NAMESPACE_END(pybind11) diff --git a/stormpy/resources/pybind11/include/pybind11/common.h b/stormpy/resources/pybind11/include/pybind11/common.h index 15047b859..e60684fc2 100644 --- a/stormpy/resources/pybind11/include/pybind11/common.h +++ b/stormpy/resources/pybind11/include/pybind11/common.h @@ -1,7 +1,7 @@ /* pybind11/common.h -- Basic macros - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -31,7 +31,7 @@ #endif #define PYBIND11_VERSION_MAJOR 1 -#define PYBIND11_VERSION_MINOR 5 +#define PYBIND11_VERSION_MINOR 8 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) @@ -39,13 +39,14 @@ # pragma warning(push) # pragma warning(disable: 4510 4610 4512 4005) # if _DEBUG -# define _DEBUG_MARKER +# define PYBIND11_DEBUG_MARKER # undef _DEBUG # endif #endif #include <Python.h> #include <frameobject.h> +#include <pythread.h> #ifdef isalnum # undef isalnum @@ -58,10 +59,10 @@ #endif #if defined(_MSC_VER) -# if defined(_DEBUG_MARKER) +# if defined(PYBIND11_DEBUG_MARKER) # define _DEBUG -# undef _DEBUG_MARKER -#endif +# undef PYBIND11_DEBUG_MARKER +# endif # pragma warning(pop) #endif @@ -80,6 +81,7 @@ #define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize #define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize #define PYBIND11_BYTES_AS_STRING PyBytes_AsString +#define PYBIND11_BYTES_CHECK PyBytes_Check #define PYBIND11_LONG_CHECK(o) PyLong_Check(o) #define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o) #define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) PyLong_AsUnsignedLongLong(o) @@ -97,6 +99,7 @@ #define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize #define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize #define PYBIND11_BYTES_AS_STRING PyString_AsString +#define PYBIND11_BYTES_CHECK PyString_Check #define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o)) #define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o)) #define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) (PyInt_Check(o) ? (unsigned long long) PyLong_AsUnsignedLong(o) : PyLong_AsUnsignedLongLong(o)) @@ -109,6 +112,13 @@ extern "C" PYBIND11_EXPORT PyObject *init##name() #endif +#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200 +extern "C" { + struct _Py_atomic_address { void *value; }; + PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current; +}; +#endif + #define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code #define PYBIND11_STRINGIFY(x) #x #define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x) @@ -127,39 +137,59 @@ } \ PyObject *pybind11_init() - NAMESPACE_BEGIN(pybind11) typedef Py_ssize_t ssize_t; /// Approach used to cast a previously unknown C++ instance into a Python object -enum class return_value_policy : int { - /** Automatic: copy objects returned as values and take ownership of objects - returned as pointers */ +enum class return_value_policy : uint8_t { + /** This is the default return value policy, which falls back to the policy + return_value_policy::take_ownership when the return value is a pointer. + Otherwise, it uses return_value::move or return_value::copy for rvalue + and lvalue references, respectively. See below for a description of what + all of these different policies do. */ automatic = 0, - /** Automatic variant 2: copy objects returned as values and reference objects - returned as pointers */ + + /** As above, but use policy return_value_policy::reference when the return + value is a pointer. You probably won't need to use this. */ automatic_reference, - /** Reference the object and take ownership. Python will call the - destructor and delete operator when the reference count reaches zero */ + + /** Reference an existing object (i.e. do not create a new copy) and take + ownership. Python will call the destructor and delete operator when the + object’s reference count reaches zero. Undefined behavior ensues when + the C++ side does the same.. */ take_ownership, - /** Reference the object, but do not take ownership (dangerous when C++ code - deletes it and Python still has a nonzero reference count) */ + + /** Create a new copy of the returned object, which will be owned by + Python. This policy is comparably safe because the lifetimes of the two + instances are decoupled. */ + copy, + + /** Use std::move to move the return value contents into a new instance + that will be owned by Python. This policy is comparably safe because the + lifetimes of the two instances (move source and destination) are + decoupled. */ + move, + + /** Reference an existing object, but do not take ownership. The C++ side + is responsible for managing the object’s lifetime and deallocating it + when it is no longer used. Warning: undefined behavior will ensue when + the C++ side deletes an object that is still referenced and used by + Python. */ reference, - /** Reference the object, but do not take ownership. The object is considered - be owned by the C++ instance whose method or property returned it. The - Python object will increase the reference count of this 'parent' by 1 */ - reference_internal, - /// Create a new copy of the returned object, which will be owned by Python - copy -}; -/// Format strings for basic number types -template <typename type> struct format_descriptor { }; -#define PYBIND11_DECL_FMT(t, n) template<> struct format_descriptor<t> { static std::string value() { return n; }; } -PYBIND11_DECL_FMT(int8_t, "b"); PYBIND11_DECL_FMT(uint8_t, "B"); PYBIND11_DECL_FMT(int16_t, "h"); PYBIND11_DECL_FMT(uint16_t, "H"); -PYBIND11_DECL_FMT(int32_t, "i"); PYBIND11_DECL_FMT(uint32_t, "I"); PYBIND11_DECL_FMT(int64_t, "q"); PYBIND11_DECL_FMT(uint64_t, "Q"); -PYBIND11_DECL_FMT(float, "f"); PYBIND11_DECL_FMT(double, "d"); PYBIND11_DECL_FMT(bool, "?"); + /** This policy only applies to methods and properties. It references the + object without taking ownership similar to the above + return_value_policy::reference policy. In contrast to that policy, the + function or property’s implicit this argument (called the parent) is + considered to be the the owner of the return value (the child). + pybind11 then couples the lifetime of the parent to the child via a + reference relationship that ensures that the parent cannot be garbage + collected while Python is still using the child. More advanced + variations of this scheme are also possible using combinations of + return_value_policy::reference and the keep_alive call policy */ + reference_internal +}; /// Information record describing a Python buffer object struct buffer_info { @@ -171,6 +201,7 @@ struct buffer_info { std::vector<size_t> shape; // Shape of the tensor (1 entry per dimension) std::vector<size_t> strides; // Number of entries between adjacent entries (for each per dimension) + buffer_info() : ptr(nullptr), view(nullptr) {} buffer_info(void *ptr, size_t itemsize, const std::string &format, int ndim, const std::vector<size_t> &shape, const std::vector<size_t> &strides) : ptr(ptr), itemsize(itemsize), size(1), format(format), @@ -197,6 +228,8 @@ private: NAMESPACE_BEGIN(detail) +inline static constexpr int log2(size_t n, int k = 0) { return (n <= 1) ? k : log2(n >> 1, k + 1); } + inline std::string error_string(); /// Core part of the 'instance' type which POD (needed to be able to use 'offsetof') @@ -228,6 +261,10 @@ struct internals { std::unordered_map<const void *, void*> registered_types_py; // PyTypeObject* -> type_info std::unordered_map<const void *, void*> registered_instances; // void * -> PyObject* std::unordered_set<std::pair<const PyObject *, const char *>, overload_hash> inactive_overload_cache; +#if defined(WITH_THREAD) + int tstate = 0; + PyInterpreterState *istate = nullptr; +#endif }; /// Return a reference to the current 'internals' information @@ -239,7 +276,7 @@ template<size_t N, size_t ...S> struct make_index_sequence : make_index_sequence template<size_t ...S> struct make_index_sequence <0, S...> { typedef index_sequence<S...> type; }; /// Strip the class from a method type -template <typename T> struct remove_class {}; +template <typename T> struct remove_class { }; template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { typedef R type(A...); }; template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...) const> { typedef R type(A...); }; @@ -252,34 +289,37 @@ template <typename T> struct intrinsic_type<T&&> { typedef type template <typename T, size_t N> struct intrinsic_type<const T[N]> { typedef typename intrinsic_type<T>::type type; }; template <typename T, size_t N> struct intrinsic_type<T[N]> { typedef typename intrinsic_type<T>::type type; }; -/** \brief SFINAE helper class to check if a copy constructor is usable (in contrast to - * std::is_copy_constructible, this class also checks if the 'new' operator is accessible */ -template <typename T> struct is_copy_constructible { - template <typename T2> static std::true_type test(decltype(new T2(std::declval<typename std::add_lvalue_reference<T2>::type>())) *); - template <typename T2> static std::false_type test(...); - static const bool value = std::is_same<std::true_type, decltype(test<T>(nullptr))>::value; -}; - /// Helper type to replace 'void' in some expressions struct void_type { }; -/// to_string variant which also accepts strings -template <typename T> inline typename std::enable_if<!std::is_enum<T>::value, std::string>::type -to_string(const T &value) { return std::to_string(value); } -template <> inline std::string to_string(const std::string &value) { return value; } -template <typename T> inline typename std::enable_if<std::is_enum<T>::value, std::string>::type -to_string(T value) { return std::to_string((int) value); } - NAMESPACE_END(detail) +#define PYBIND11_RUNTIME_EXCEPTION(name) \ + class name : public std::runtime_error { public: \ + name(const std::string &w) : std::runtime_error(w) { }; \ + name(const char *s) : std::runtime_error(s) { }; \ + name() : std::runtime_error("") { } \ + }; + // C++ bindings of core Python exceptions -struct stop_iteration : public std::runtime_error { public: stop_iteration(const std::string &w="") : std::runtime_error(w) {} }; -struct index_error : public std::runtime_error { public: index_error(const std::string &w="") : std::runtime_error(w) {} }; -struct error_already_set : public std::runtime_error { public: error_already_set() : std::runtime_error(detail::error_string()) {} }; -/// Thrown when pybind11::cast or handle::call fail due to a type casting error -struct cast_error : public std::runtime_error { public: cast_error(const std::string &w = "") : std::runtime_error(w) {} }; - -PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); } -PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); } +class error_already_set : public std::runtime_error { public: error_already_set() : std::runtime_error(detail::error_string()) {} }; +PYBIND11_RUNTIME_EXCEPTION(stop_iteration) +PYBIND11_RUNTIME_EXCEPTION(index_error) +PYBIND11_RUNTIME_EXCEPTION(value_error) +PYBIND11_RUNTIME_EXCEPTION(cast_error) /// Thrown when pybind11::cast or handle::call fail due to a type casting error + +[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); } +[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); } + +/// Format strings for basic number types +#define PYBIND11_DECL_FMT(t, v) template<> struct format_descriptor<t> { static constexpr const char *value = v; } +template <typename T, typename SFINAE = void> struct format_descriptor { }; +template <typename T> struct format_descriptor<T, typename std::enable_if<std::is_integral<T>::value>::type> { + static constexpr const char value[2] = + { "bBhHiIqQ"[detail::log2(sizeof(T))*2 + (std::is_unsigned<T>::value ? 1 : 0)], '\0' }; +}; +template <typename T> constexpr const char format_descriptor< + T, typename std::enable_if<std::is_integral<T>::value>::type>::value[2]; +PYBIND11_DECL_FMT(float, "f"); PYBIND11_DECL_FMT(double, "d"); PYBIND11_DECL_FMT(bool, "?"); NAMESPACE_END(pybind11) diff --git a/stormpy/resources/pybind11/include/pybind11/complex.h b/stormpy/resources/pybind11/include/pybind11/complex.h index a140f6feb..f767f354c 100644 --- a/stormpy/resources/pybind11/include/pybind11/complex.h +++ b/stormpy/resources/pybind11/include/pybind11/complex.h @@ -1,7 +1,7 @@ /* pybind11/complex.h: Complex number support - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -26,6 +26,8 @@ NAMESPACE_BEGIN(detail) template <typename T> class type_caster<std::complex<T>> { public: bool load(handle src, bool) { + if (!src) + return false; Py_complex result = PyComplex_AsCComplex(src.ptr()); if (result.real == -1.0 && PyErr_Occurred()) { PyErr_Clear(); diff --git a/stormpy/resources/pybind11/include/pybind11/descr.h b/stormpy/resources/pybind11/include/pybind11/descr.h index b040014dc..1b65f68c8 100644 --- a/stormpy/resources/pybind11/include/pybind11/descr.h +++ b/stormpy/resources/pybind11/include/pybind11/descr.h @@ -2,7 +2,7 @@ pybind11/descr.h: Helper type for concatenating type signatures either at runtime (C++11) or compile time (C++14) - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/include/pybind11/eigen.h b/stormpy/resources/pybind11/include/pybind11/eigen.h new file mode 100644 index 000000000..96daf48dd --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/eigen.h @@ -0,0 +1,281 @@ +/* + pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices + + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "numpy.h" +#include <Eigen/Core> +#include <Eigen/SparseCore> + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +template <typename T> class is_eigen_dense { +private: + template<typename Derived> static std::true_type test(const Eigen::DenseBase<Derived> &); + static std::false_type test(...); +public: + static constexpr bool value = decltype(test(std::declval<T>()))::value; +}; + +template <typename T> class is_eigen_sparse { +private: + template<typename Derived> static std::true_type test(const Eigen::SparseMatrixBase<Derived> &); + static std::false_type test(...); +public: + static constexpr bool value = decltype(test(std::declval<T>()))::value; +}; + +template<typename Type> +struct type_caster<Type, typename std::enable_if<is_eigen_dense<Type>::value>::type> { + typedef typename Type::Scalar Scalar; + static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit; + static constexpr bool isVector = Type::IsVectorAtCompileTime; + + bool load(handle src, bool) { + array_t<Scalar> buffer(src, true); + if (!buffer.check()) + return false; + + buffer_info info = buffer.request(); + if (info.ndim == 1) { + typedef Eigen::Stride<Eigen::Dynamic, 0> Strides; + if (!isVector && + !(Type::RowsAtCompileTime == Eigen::Dynamic && + Type::ColsAtCompileTime == Eigen::Dynamic)) + return false; + + if (Type::SizeAtCompileTime != Eigen::Dynamic && + info.shape[0] != (size_t) Type::SizeAtCompileTime) + return false; + + auto strides = Strides(info.strides[0] / sizeof(Scalar), 0); + + value = Eigen::Map<Type, 0, Strides>( + (Scalar *) info.ptr, info.shape[0], 1, strides); + } else if (info.ndim == 2) { + typedef Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> Strides; + + if ((Type::RowsAtCompileTime != Eigen::Dynamic && info.shape[0] != (size_t) Type::RowsAtCompileTime) || + (Type::ColsAtCompileTime != Eigen::Dynamic && info.shape[1] != (size_t) Type::ColsAtCompileTime)) + return false; + + auto strides = Strides( + info.strides[rowMajor ? 0 : 1] / sizeof(Scalar), + info.strides[rowMajor ? 1 : 0] / sizeof(Scalar)); + + value = Eigen::Map<Type, 0, Strides>( + (Scalar *) info.ptr, info.shape[0], info.shape[1], strides); + } else { + return false; + } + return true; + } + + static handle cast(const Type *src, return_value_policy policy, handle parent) { + return cast(*src, policy, parent); + } + + static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) { + if (isVector) { + return array(buffer_info( + /* Pointer to buffer */ + const_cast<Scalar *>(src.data()), + /* Size of one scalar */ + sizeof(Scalar), + /* Python struct-style format descriptor */ + format_descriptor<Scalar>::value, + /* Number of dimensions */ + 1, + /* Buffer dimensions */ + { (size_t) src.size() }, + /* Strides (in bytes) for each index */ + { sizeof(Scalar) } + )).release(); + } else { + return array(buffer_info( + /* Pointer to buffer */ + const_cast<Scalar *>(src.data()), + /* Size of one scalar */ + sizeof(Scalar), + /* Python struct-style format descriptor */ + format_descriptor<Scalar>::value, + /* Number of dimensions */ + isVector ? 1 : 2, + /* Buffer dimensions */ + { (size_t) src.rows(), + (size_t) src.cols() }, + /* Strides (in bytes) for each index */ + { sizeof(Scalar) * (rowMajor ? src.cols() : 1), + sizeof(Scalar) * (rowMajor ? 1 : src.rows()) } + )).release(); + } + } + + template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>; + + static PYBIND11_DESCR name() { + return _("numpy.ndarray[dtype=") + npy_format_descriptor<Scalar>::name() + + _(", shape=(") + rows() + _(", ") + cols() + _(")]"); + } + + operator Type*() { return &value; } + operator Type&() { return value; } + +protected: + template <typename T = Type, typename std::enable_if<T::RowsAtCompileTime == Eigen::Dynamic, int>::type = 0> + static PYBIND11_DESCR rows() { return _("m"); } + template <typename T = Type, typename std::enable_if<T::RowsAtCompileTime != Eigen::Dynamic, int>::type = 0> + static PYBIND11_DESCR rows() { return _<T::RowsAtCompileTime>(); } + template <typename T = Type, typename std::enable_if<T::ColsAtCompileTime == Eigen::Dynamic, int>::type = 0> + static PYBIND11_DESCR cols() { return _("n"); } + template <typename T = Type, typename std::enable_if<T::ColsAtCompileTime != Eigen::Dynamic, int>::type = 0> + static PYBIND11_DESCR cols() { return _<T::ColsAtCompileTime>(); } + +protected: + Type value; +}; + +template<typename Type> +struct type_caster<Type, typename std::enable_if<is_eigen_sparse<Type>::value>::type> { + typedef typename Type::Scalar Scalar; + typedef typename std::remove_reference<decltype(*std::declval<Type>().outerIndexPtr())>::type StorageIndex; + typedef typename Type::Index Index; + static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit; + + bool load(handle src, bool) { + if (!src) + return false; + + object obj(src, true); + object sparse_module = module::import("scipy.sparse"); + object matrix_type = sparse_module.attr( + rowMajor ? "csr_matrix" : "csc_matrix"); + + if (obj.get_type() != matrix_type.ptr()) { + try { + obj = matrix_type(obj); + } catch (const error_already_set &) { + PyErr_Clear(); + return false; + } + } + + auto valuesArray = array_t<Scalar>((object) obj.attr("data")); + auto innerIndicesArray = array_t<StorageIndex>((object) obj.attr("indices")); + auto outerIndicesArray = array_t<StorageIndex>((object) obj.attr("indptr")); + auto shape = pybind11::tuple((pybind11::object) obj.attr("shape")); + auto nnz = obj.attr("nnz").cast<Index>(); + + if (!valuesArray.check() || !innerIndicesArray.check() || + !outerIndicesArray.check()) + return false; + + buffer_info outerIndices = outerIndicesArray.request(); + buffer_info innerIndices = innerIndicesArray.request(); + buffer_info values = valuesArray.request(); + + value = Eigen::MappedSparseMatrix<Scalar, Type::Flags, StorageIndex>( + shape[0].cast<Index>(), + shape[1].cast<Index>(), + nnz, + static_cast<StorageIndex *>(outerIndices.ptr), + static_cast<StorageIndex *>(innerIndices.ptr), + static_cast<Scalar *>(values.ptr) + ); + + return true; + } + + static handle cast(const Type *src, return_value_policy policy, handle parent) { + return cast(*src, policy, parent); + } + + static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) { + const_cast<Type&>(src).makeCompressed(); + + object matrix_type = module::import("scipy.sparse").attr( + rowMajor ? "csr_matrix" : "csc_matrix"); + + array data(buffer_info( + // Pointer to buffer + const_cast<Scalar *>(src.valuePtr()), + // Size of one scalar + sizeof(Scalar), + // Python struct-style format descriptor + format_descriptor<Scalar>::value, + // Number of dimensions + 1, + // Buffer dimensions + { (size_t) src.nonZeros() }, + // Strides + { sizeof(Scalar) } + )); + + array outerIndices(buffer_info( + // Pointer to buffer + const_cast<StorageIndex *>(src.outerIndexPtr()), + // Size of one scalar + sizeof(StorageIndex), + // Python struct-style format descriptor + format_descriptor<StorageIndex>::value, + // Number of dimensions + 1, + // Buffer dimensions + { (size_t) (rowMajor ? src.rows() : src.cols()) + 1 }, + // Strides + { sizeof(StorageIndex) } + )); + + array innerIndices(buffer_info( + // Pointer to buffer + const_cast<StorageIndex *>(src.innerIndexPtr()), + // Size of one scalar + sizeof(StorageIndex), + // Python struct-style format descriptor + format_descriptor<StorageIndex>::value, + // Number of dimensions + 1, + // Buffer dimensions + { (size_t) src.nonZeros() }, + // Strides + { sizeof(StorageIndex) } + )); + + return matrix_type( + std::make_tuple(data, innerIndices, outerIndices), + std::make_pair(src.rows(), src.cols()) + ).release(); + } + + template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>; + + template <typename T = Type, typename std::enable_if<(T::Flags & Eigen::RowMajorBit) != 0, int>::type = 0> + static PYBIND11_DESCR name() { return _("scipy.sparse.csr_matrix[dtype=") + npy_format_descriptor<Scalar>::name() + _("]"); } + template <typename T = Type, typename std::enable_if<(T::Flags & Eigen::RowMajorBit) == 0, int>::type = 0> + static PYBIND11_DESCR name() { return _("scipy.sparse.csc_matrix[dtype=") + npy_format_descriptor<Scalar>::name() + _("]"); } + + operator Type*() { return &value; } + operator Type&() { return value; } + +protected: + Type value; +}; + +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif diff --git a/stormpy/resources/pybind11/include/pybind11/functional.h b/stormpy/resources/pybind11/include/pybind11/functional.h index f00a60379..f74a9bdf9 100644 --- a/stormpy/resources/pybind11/include/pybind11/functional.h +++ b/stormpy/resources/pybind11/include/pybind11/functional.h @@ -1,7 +1,7 @@ /* pybind11/functional.h: std::function<> support - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -17,6 +17,7 @@ NAMESPACE_BEGIN(detail) template <typename Return, typename... Args> struct type_caster<std::function<Return(Args...)>> { typedef std::function<Return(Args...)> type; + typedef typename std::conditional<std::is_same<Return, void>::value, void_type, Return>::type retval_type; public: bool load(handle src_, bool) { src_ = detail::get_function(src_); @@ -24,7 +25,8 @@ public: return false; object src(src_, true); value = [src](Args... args) -> Return { - object retval(src.call(std::move(args)...)); + gil_scoped_acquire acq; + object retval(src(std::move(args)...)); /* Visual studio 2015 parser issue: need parentheses around this expression */ return (retval.template cast<Return>()); }; @@ -38,7 +40,7 @@ public: PYBIND11_TYPE_CASTER(type, _("function<") + type_caster<std::tuple<Args...>>::name() + _(" -> ") + - type_caster<typename intrinsic_type<Return>::type>::name() + + type_caster<retval_type>::name() + _(">")); }; diff --git a/stormpy/resources/pybind11/include/pybind11/numpy.h b/stormpy/resources/pybind11/include/pybind11/numpy.h index 3386876e5..f97c790ad 100644 --- a/stormpy/resources/pybind11/include/pybind11/numpy.h +++ b/stormpy/resources/pybind11/include/pybind11/numpy.h @@ -1,7 +1,7 @@ /* - pybind11/numpy.h: Basic NumPy support, auto-vectorization support + pybind11/numpy.h: Basic NumPy support, vectorize() wrapper - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -20,8 +20,7 @@ #endif NAMESPACE_BEGIN(pybind11) - -template <typename type> struct npy_format_descriptor { }; +namespace detail { template <typename type, typename SFINAE = void> struct npy_format_descriptor { }; } class array : public buffer { public: @@ -77,9 +76,15 @@ public: PYBIND11_OBJECT_DEFAULT(array, buffer, lookup_api().PyArray_Check_) + enum { + c_style = API::NPY_C_CONTIGUOUS_, + f_style = API::NPY_F_CONTIGUOUS_, + forcecast = API::NPY_ARRAY_FORCECAST_ + }; + template <typename Type> array(size_t size, const Type *ptr) { API& api = lookup_api(); - PyObject *descr = api.PyArray_DescrFromType_(npy_format_descriptor<Type>::value); + PyObject *descr = api.PyArray_DescrFromType_(detail::npy_format_descriptor<Type>::value); if (descr == nullptr) pybind11_fail("NumPy: unsupported buffer format!"); Py_intptr_t shape = (Py_intptr_t) size; @@ -120,34 +125,49 @@ protected: } }; -template <typename T> class array_t : public array { +template <typename T, int ExtraFlags = array::forcecast> class array_t : public array { public: PYBIND11_OBJECT_CVT(array_t, array, is_non_null, m_ptr = ensure(m_ptr)); array_t() : array() { } + array_t(const buffer_info& info) : array(info) {} static bool is_non_null(PyObject *ptr) { return ptr != nullptr; } static PyObject *ensure(PyObject *ptr) { if (ptr == nullptr) return nullptr; API &api = lookup_api(); - PyObject *descr = api.PyArray_DescrFromType_(npy_format_descriptor<T>::value); - PyObject *result = api.PyArray_FromAny_( - ptr, descr, 0, 0, API::NPY_C_CONTIGUOUS_ | API::NPY_ENSURE_ARRAY_ - | API::NPY_ARRAY_FORCECAST_, nullptr); + PyObject *descr = api.PyArray_DescrFromType_(detail::npy_format_descriptor<T>::value); + PyObject *result = api.PyArray_FromAny_(ptr, descr, 0, 0, API::NPY_ENSURE_ARRAY_ | ExtraFlags, nullptr); + if (!result) + PyErr_Clear(); Py_DECREF(ptr); return result; } }; -#define DECL_FMT(t, n) template<> struct npy_format_descriptor<t> { enum { value = array::API::n }; } -DECL_FMT(int8_t, NPY_BYTE_); DECL_FMT(uint8_t, NPY_UBYTE_); DECL_FMT(int16_t, NPY_SHORT_); -DECL_FMT(uint16_t, NPY_USHORT_); DECL_FMT(int32_t, NPY_INT_); DECL_FMT(uint32_t, NPY_UINT_); -DECL_FMT(int64_t, NPY_LONGLONG_); DECL_FMT(uint64_t, NPY_ULONGLONG_); DECL_FMT(float, NPY_FLOAT_); -DECL_FMT(double, NPY_DOUBLE_); DECL_FMT(bool, NPY_BOOL_); DECL_FMT(std::complex<float>, NPY_CFLOAT_); -DECL_FMT(std::complex<double>, NPY_CDOUBLE_); -#undef DECL_FMT - NAMESPACE_BEGIN(detail) +template <typename T> struct npy_format_descriptor<T, typename std::enable_if<std::is_integral<T>::value>::type> { +private: + constexpr static const int values[8] = { + array::API::NPY_BYTE_, array::API::NPY_UBYTE_, array::API::NPY_SHORT_, array::API::NPY_USHORT_, + array::API::NPY_INT_, array::API::NPY_UINT_, array::API::NPY_LONGLONG_, array::API::NPY_ULONGLONG_ }; +public: + enum { value = values[detail::log2(sizeof(T)) * 2 + (std::is_unsigned<T>::value ? 1 : 0)] }; + template <typename T2 = T, typename std::enable_if<std::is_signed<T2>::value, int>::type = 0> + static PYBIND11_DESCR name() { return _("int") + _<sizeof(T)*8>(); } + template <typename T2 = T, typename std::enable_if<!std::is_signed<T2>::value, int>::type = 0> + static PYBIND11_DESCR name() { return _("uint") + _<sizeof(T)*8>(); } +}; +template <typename T> constexpr const int npy_format_descriptor< + T, typename std::enable_if<std::is_integral<T>::value>::type>::values[8]; + +#define DECL_FMT(Type, NumPyName, Name) template<> struct npy_format_descriptor<Type> { \ + enum { value = array::API::NumPyName }; \ + static PYBIND11_DESCR name() { return _(Name); } } +DECL_FMT(float, NPY_FLOAT_, "float32"); DECL_FMT(double, NPY_DOUBLE_, "float64"); DECL_FMT(bool, NPY_BOOL_, "bool"); +DECL_FMT(std::complex<float>, NPY_CFLOAT_, "complex64"); DECL_FMT(std::complex<double>, NPY_CDOUBLE_, "complex128"); +#undef DECL_FMT + template <class T> using array_iterator = typename std::add_pointer<T>::type; @@ -298,11 +318,11 @@ struct vectorize_helper { template <typename T> vectorize_helper(T&&f) : f(std::forward<T>(f)) { } - object operator()(array_t<Args>... args) { + object operator()(array_t<Args, array::c_style | array::forcecast>... args) { return run(args..., typename make_index_sequence<sizeof...(Args)>::type()); } - template <size_t ... Index> object run(array_t<Args>&... args, index_sequence<Index...> index) { + template <size_t ... Index> object run(array_t<Args, array::c_style | array::forcecast>&... args, index_sequence<Index...> index) { /* Request buffers from all parameters */ const size_t N = sizeof...(Args); @@ -312,7 +332,7 @@ struct vectorize_helper { int ndim = 0; std::vector<size_t> shape(0); bool trivial_broadcast = broadcast(buffers, ndim, shape); - + size_t size = 1; std::vector<size_t> strides(ndim); if (ndim > 0) { @@ -328,13 +348,13 @@ struct vectorize_helper { return cast(f(*((Args *) buffers[Index].ptr)...)); array result(buffer_info(nullptr, sizeof(Return), - format_descriptor<Return>::value(), + format_descriptor<Return>::value, ndim, shape, strides)); buffer_info buf = result.request(); Return *output = (Return *) buf.ptr; - if(trivial_broadcast) { + if (trivial_broadcast) { /* Call the function */ for (size_t i=0; i<size; ++i) { output[i] = f((buffers[Index].size == 1 @@ -364,8 +384,8 @@ struct vectorize_helper { } }; -template <typename T> struct handle_type_name<array_t<T>> { - static PYBIND11_DESCR name() { return _("array[") + type_caster<T>::name() + _("]"); } +template <typename T, int Flags> struct handle_type_name<array_t<T, Flags>> { + static PYBIND11_DESCR name() { return _("numpy.ndarray[dtype=") + type_caster<T>::name() + _("]"); } }; NAMESPACE_END(detail) diff --git a/stormpy/resources/pybind11/include/pybind11/operators.h b/stormpy/resources/pybind11/include/pybind11/operators.h index b10bfe30c..305cd2cd5 100644 --- a/stormpy/resources/pybind11/include/pybind11/operators.h +++ b/stormpy/resources/pybind11/include/pybind11/operators.h @@ -1,7 +1,7 @@ /* pybind11/operator.h: Metatemplates for operator overloading - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/include/pybind11/pybind11.h b/stormpy/resources/pybind11/include/pybind11/pybind11.h index 22044feeb..34869ebae 100644 --- a/stormpy/resources/pybind11/include/pybind11/pybind11.h +++ b/stormpy/resources/pybind11/include/pybind11/pybind11.h @@ -2,7 +2,7 @@ pybind11/pybind11.h: Main header file of the C++11 python binding generator library - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -20,11 +20,13 @@ #elif defined(__ICC) || defined(__INTEL_COMPILER) # pragma warning(push) # pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline" -#elif defined(__GNUG__) and !defined(__clang__) +#elif defined(__GNUG__) && !defined(__clang__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-but-set-parameter" # pragma GCC diagnostic ignored "-Wunused-but-set-variable" # pragma GCC diagnostic ignored "-Wmissing-field-initializers" +# pragma GCC diagnostic ignored "-Wstrict-aliasing" +# pragma GCC diagnostic ignored "-Wattributes" #endif #include "attr.h" @@ -33,77 +35,32 @@ NAMESPACE_BEGIN(pybind11) /// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object class cpp_function : public function { -protected: - /// Picks a suitable return value converter from cast.h - template <typename T> using return_value_caster = - detail::type_caster<typename std::conditional< - std::is_void<T>::value, detail::void_type, typename detail::intrinsic_type<T>::type>::type>; - - /// Picks a suitable argument value converter from cast.h - template <typename... T> using arg_value_caster = - detail::type_caster<typename std::tuple<T...>>; public: cpp_function() { } - /// Vanilla function pointers + /// Construct a cpp_function from a vanilla function pointer template <typename Return, typename... Args, typename... Extra> cpp_function(Return (*f)(Args...), const Extra&... extra) { - auto rec = new detail::function_record(); - rec->data = (void *) f; - - typedef arg_value_caster<Args...> cast_in; - typedef return_value_caster<Return> cast_out; - - /* Dispatch code which converts function arguments and performs the actual function call */ - rec->impl = [](detail::function_record *rec, handle pyArgs, handle parent) -> handle { - cast_in args; - - /* Try to cast the function arguments into the C++ domain */ - if (!args.load(pyArgs, true)) - return PYBIND11_TRY_NEXT_OVERLOAD; - - /* Invoke call policy pre-call hook */ - detail::process_attributes<Extra...>::precall(pyArgs); - - /* Do the call and convert the return value back into the Python domain */ - handle result = cast_out::cast( - args.template call<Return>((Return (*) (Args...)) rec->data), - rec->policy, parent); - - /* Invoke call policy post-call hook */ - detail::process_attributes<Extra...>::postcall(pyArgs, result); - - return result; - }; - - /* Process any user-provided function attributes */ - detail::process_attributes<Extra...>::init(extra..., rec); - - /* Generate a readable signature describing the function's arguments and return value types */ - using detail::descr; - PYBIND11_DESCR signature = cast_in::name() + detail::_(" -> ") + cast_out::name(); - - /* Register the function with Python from generic (non-templated) code */ - initialize(rec, signature.text(), signature.types(), sizeof...(Args)); + initialize(f, f, extra...); } - /// Delegating helper constructor to deal with lambda functions + /// Construct a cpp_function from a lambda function (possibly with internal state) template <typename Func, typename... Extra> cpp_function(Func &&f, const Extra&... extra) { initialize(std::forward<Func>(f), (typename detail::remove_class<decltype( &std::remove_reference<Func>::type::operator())>::type *) nullptr, extra...); } - /// Delegating helper constructor to deal with class methods (non-const) - template <typename Return, typename Class, typename... Arg, typename... Extra> cpp_function( - Return (Class::*f)(Arg...), const Extra&... extra) { + /// Construct a cpp_function from a class method (non-const) + template <typename Return, typename Class, typename... Arg, typename... Extra> + cpp_function(Return (Class::*f)(Arg...), const Extra&... extra) { initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); }, (Return (*) (Class *, Arg...)) nullptr, extra...); } - /// Delegating helper constructor to deal with class methods (const) - template <typename Return, typename Class, typename... Arg, typename... Extra> cpp_function( - Return (Class::*f)(Arg...) const, const Extra&... extra) { + /// Construct a cpp_function from a class method (const) + template <typename Return, typename Class, typename... Arg, typename... Extra> + cpp_function(Return (Class::*f)(Arg...) const, const Extra&... extra) { initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); }, (Return (*)(const Class *, Arg ...)) nullptr, extra...); } @@ -119,35 +76,44 @@ protected: /* Store the function including any extra state it might have (e.g. a lambda capture object) */ auto rec = new detail::function_record(); - rec->data = new capture { std::forward<Func>(f) }; - /* Create a cleanup handler, but only if we have to (less generated code) */ - if (!std::is_trivially_destructible<Func>::value) - rec->free_data = [](void *ptr) { delete (capture *) ptr; }; - else - rec->free_data = operator delete; + /* Store the capture object directly in the function record if there is enough space */ + if (sizeof(capture) <= sizeof(rec->data)) { + new ((capture *) &rec->data) capture { std::forward<Func>(f) }; + if (!std::is_trivially_destructible<Func>::value) + rec->free_data = [](detail::function_record *r) { ((capture *) &r->data)->~capture(); }; + } else { + rec->data[0] = new capture { std::forward<Func>(f) }; + rec->free_data = [](detail::function_record *r) { delete ((capture *) r->data[0]); }; + } - typedef arg_value_caster<Args...> cast_in; - typedef return_value_caster<Return> cast_out; + /* Type casters for the function arguments and return value */ + typedef detail::type_caster<typename std::tuple<Args...>> cast_in; + typedef detail::type_caster<typename std::conditional< + std::is_void<Return>::value, detail::void_type, + typename detail::intrinsic_type<Return>::type>::type> cast_out; /* Dispatch code which converts function arguments and performs the actual function call */ - rec->impl = [](detail::function_record *rec, handle pyArgs, handle parent) -> handle { - cast_in args; + rec->impl = [](detail::function_record *rec, handle args, handle kwargs, handle parent) -> handle { + cast_in args_converter; /* Try to cast the function arguments into the C++ domain */ - if (!args.load(pyArgs, true)) + if (!args_converter.load_args(args, kwargs, true)) return PYBIND11_TRY_NEXT_OVERLOAD; /* Invoke call policy pre-call hook */ - detail::process_attributes<Extra...>::precall(pyArgs); + detail::process_attributes<Extra...>::precall(args); - /* Do the call and convert the return value back into the Python domain */ - handle result = cast_out::cast( - args.template call<Return>(((capture *) rec->data)->f), - rec->policy, parent); + /* Get a pointer to the capture object */ + capture *cap = (capture *) (sizeof(capture) <= sizeof(rec->data) + ? &rec->data : rec->data[0]); + + /* Perform the functioncall */ + handle result = cast_out::cast(args_converter.template call<Return>(cap->f), + rec->policy, parent); /* Invoke call policy post-call hook */ - detail::process_attributes<Extra...>::postcall(pyArgs, result); + detail::process_attributes<Extra...>::postcall(args, result); return result; }; @@ -160,12 +126,15 @@ protected: PYBIND11_DESCR signature = cast_in::name() + detail::_(" -> ") + cast_out::name(); /* Register the function with Python from generic (non-templated) code */ - initialize(rec, signature.text(), signature.types(), sizeof...(Args)); + initialize_generic(rec, signature.text(), signature.types(), sizeof...(Args)); + + if (cast_in::has_args) rec->has_args = true; + if (cast_in::has_kwargs) rec->has_kwargs = true; } /// Register a function call with Python (generic non-templated code goes here) - void initialize(detail::function_record *rec, const char *text, - const std::type_info *const *types, int args) { + void initialize_generic(detail::function_record *rec, const char *text, + const std::type_info *const *types, int args) { /* Create copies of all referenced C-style strings */ rec->name = strdup(rec->name ? rec->name : ""); @@ -176,7 +145,7 @@ protected: if (a.descr) a.descr = strdup(a.descr); else if (a.value) - a.descr = strdup(((std::string) ((object) handle(a.value).attr("__repr__")).call().str()).c_str()); + a.descr = strdup(((std::string) ((object) handle(a.value).attr("__repr__"))().str()).c_str()); } auto const ®istered_types = detail::get_internals().registered_types_cpp; @@ -231,6 +200,9 @@ protected: if (strcmp(rec->name, "__next__") == 0) { std::free(rec->name); rec->name = strdup("next"); + } else if (strcmp(rec->name, "__bool__") == 0) { + std::free(rec->name); + rec->name = strdup("__nonzero__"); } #endif @@ -240,9 +212,12 @@ protected: std::to_string(args) + " arguments, but " + std::to_string(rec->args.size()) + " pybind11::arg entries were specified!"); - rec->is_constructor = !strcmp(rec->name, "__init__"); rec->signature = strdup(signature.c_str()); rec->args.shrink_to_fit(); + rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__"); + rec->has_args = false; + rec->has_kwargs = false; + rec->nargs = (uint16_t) args; #if PY_MAJOR_VERSION < 3 if (rec->sibling && PyMethod_Check(rec->sibling.ptr())) @@ -336,7 +311,7 @@ protected: while (rec) { detail::function_record *next = rec->next; if (rec->free_data) - rec->free_data(rec->data); + rec->free_data(rec); std::free((char *) rec->name); std::free((char *) rec->doc); std::free((char *) rec->signature); @@ -361,15 +336,15 @@ protected: *it = overloads; /* Need to know how many arguments + keyword arguments there are to pick the right overload */ - int nargs = (int) PyTuple_Size(args), - nkwargs = kwargs ? (int) PyDict_Size(kwargs) : 0; + size_t nargs = PyTuple_GET_SIZE(args), + nkwargs = kwargs ? PyDict_Size(kwargs) : 0; - handle parent = nargs > 0 ? PyTuple_GetItem(args, 0) : nullptr, + handle parent = nargs > 0 ? PyTuple_GET_ITEM(args, 0) : nullptr, result = PYBIND11_TRY_NEXT_OVERLOAD; try { for (; it != nullptr; it = it->next) { tuple args_(args, true); - int kwargs_consumed = 0; + size_t kwargs_consumed = 0; /* For each overload: 1. If the required list of arguments is longer than the @@ -378,10 +353,11 @@ protected: 2. Ensure that all keyword arguments were "consumed" 3. Call the function call dispatcher (function_record::impl) */ - - if (nargs < (int) it->args.size()) { - args_ = tuple(it->args.size()); - for (int i = 0; i < nargs; ++i) { + size_t nargs_ = nargs; + if (nargs < it->args.size()) { + nargs_ = it->args.size(); + args_ = tuple(nargs_); + for (size_t i = 0; i < nargs; ++i) { handle item = PyTuple_GET_ITEM(args, i); PyTuple_SET_ITEM(args_.ptr(), i, item.inc_ref().ptr()); } @@ -404,20 +380,26 @@ protected: if (value) { PyTuple_SET_ITEM(args_.ptr(), index, value.inc_ref().ptr()); } else { - kwargs_consumed = -1; /* definite failure */ + kwargs_consumed = (size_t) -1; /* definite failure */ break; } } } - if (kwargs_consumed == nkwargs) - result = it->impl(it, args_, parent); + try { + if ((kwargs_consumed == nkwargs || it->has_kwargs) && + (nargs_ == it->nargs || it->has_args)) + result = it->impl(it, args_, kwargs, parent); + } catch (cast_error &) { + result = PYBIND11_TRY_NEXT_OVERLOAD; + } if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) break; } } catch (const error_already_set &) { return nullptr; } catch (const index_error &e) { PyErr_SetString(PyExc_IndexError, e.what()); return nullptr; + } catch (const value_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return nullptr; } catch (const stop_iteration &e) { PyErr_SetString(PyExc_StopIteration, e.what()); return nullptr; } catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return nullptr; } catch (const std::domain_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return nullptr; @@ -440,6 +422,14 @@ protected: msg += it2->signature; msg += "\n"; } + msg += " Invoked with: "; + tuple args_(args, true); + for( std::size_t ti = 0; ti != args_.size(); ++ti) + { + msg += static_cast<std::string>(static_cast<object>(args_[ti]).str()); + if ((ti + 1) != args_.size() ) + msg += ", "; + } PyErr_SetString(PyExc_TypeError, msg.c_str()); return nullptr; } else if (!result) { @@ -450,9 +440,9 @@ protected: return nullptr; } else { if (overloads->is_constructor) { - /* When a construtor ran successfully, the corresponding + /* When a constructor ran successfully, the corresponding holder type (e.g. std::unique_ptr) must still be initialized. */ - PyObject *inst = PyTuple_GetItem(args, 0); + PyObject *inst = PyTuple_GET_ITEM(args, 0); auto tinfo = detail::get_type_info(Py_TYPE(inst)); tinfo->init_holder(inst, nullptr); } @@ -937,10 +927,11 @@ public: ((it == entries->end()) ? std::string("???") : std::string(it->second)); }); - this->def("__init__", [](Type& value, int i) { value = (Type) i; }); + this->def("__init__", [](Type& value, int i) { value = (Type)i; }); + this->def("__init__", [](Type& value, int i) { new (&value) Type((Type) i); }); this->def("__int__", [](Type value) { return (int) value; }); - this->def("__eq__", [](const Type &value, Type value2) { return value == value2; }); - this->def("__ne__", [](const Type &value, Type value2) { return value != value2; }); + this->def("__eq__", [](const Type &value, Type *value2) { return value2 && value == *value2; }); + this->def("__ne__", [](const Type &value, Type *value2) { return !value2 || value != *value2; }); this->def("__hash__", [](const Type &value) { return (int) value; }); m_entries = entries; } @@ -982,6 +973,9 @@ PYBIND11_NOINLINE inline void keep_alive_impl(int Nurse, int Patient, handle arg if (!nurse || !patient) pybind11_fail("Could not activate keep_alive!"); + if (patient.ptr() == Py_None) + return; /* Nothing to keep alive */ + cpp_function disable_lifesupport( [patient](handle weakref) { patient.dec_ref(); weakref.dec_ref(); }); @@ -1003,7 +997,7 @@ template <typename Iterator, typename... Extra> iterator make_iterator(Iterator if (!detail::get_type_info(typeid(state))) { class_<state>(handle(), "") .def("__iter__", [](state &s) -> state& { return s; }) - .def("__next__", [](state &s) -> decltype(*std::declval<Iterator>()) & { + .def("__next__", [](state &s) -> decltype(*std::declval<Iterator>()) { if (s.it == s.end) throw stop_iteration(); return *s.it++; @@ -1013,6 +1007,10 @@ template <typename Iterator, typename... Extra> iterator make_iterator(Iterator return (iterator) cast(state { first, last }); } +template <typename Type, typename... Extra> iterator make_iterator(Type &value, Extra&&... extra) { + return make_iterator(std::begin(value), std::end(value), extra...); +} + template <typename InputType, typename OutputType> void implicitly_convertible() { auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * { if (!detail::type_caster<InputType>().load(obj, false)) @@ -1032,21 +1030,126 @@ template <typename InputType, typename OutputType> void implicitly_convertible() } #if defined(WITH_THREAD) -inline void init_threading() { PyEval_InitThreads(); } + +/* The functions below essentially reproduce the PyGILState_* API using a RAII + * pattern, but there are a few important differences: + * + * 1. When acquiring the GIL from an non-main thread during the finalization + * phase, the GILState API blindly terminates the calling thread, which + * is often not what is wanted. This API does not do this. + * + * 2. The gil_scoped_release function can optionally cut the relationship + * of a PyThreadState and its associated thread, which allows moving it to + * another thread (this is a fairly rare/advanced use case). + * + * 3. The reference count of an acquired thread state can be controlled. This + * can be handy to prevent cases where callbacks issued from an external + * thread would otherwise constantly construct and destroy thread state data + * structures. + */ class gil_scoped_acquire { - PyGILState_STATE state; public: - inline gil_scoped_acquire() { state = PyGILState_Ensure(); } - inline ~gil_scoped_acquire() { PyGILState_Release(state); } + PYBIND11_NOINLINE gil_scoped_acquire() { + auto const &internals = detail::get_internals(); + tstate = (PyThreadState *) PyThread_get_key_value(internals.tstate); + + if (!tstate) { + tstate = PyThreadState_New(internals.istate); + #if !defined(NDEBUG) + if (!tstate) + pybind11_fail("scoped_acquire: could not create thread state!"); + #endif + tstate->gilstate_counter = 0; + #if PY_MAJOR_VERSION < 3 + PyThread_delete_key_value(internals.tstate); + #endif + PyThread_set_key_value(internals.tstate, tstate); + } else { + release = detail::get_thread_state_unchecked() != tstate; + } + + if (release) { + /* Work around an annoying assertion in PyThreadState_Swap */ + #if defined(Py_DEBUG) + PyInterpreterState *interp = tstate->interp; + tstate->interp = nullptr; + #endif + PyEval_AcquireThread(tstate); + #if defined(Py_DEBUG) + tstate->interp = interp; + #endif + } + + inc_ref(); + } + + void inc_ref() { + ++tstate->gilstate_counter; + } + + PYBIND11_NOINLINE void dec_ref() { + --tstate->gilstate_counter; + #if !defined(NDEBUG) + if (detail::get_thread_state_unchecked() != tstate) + pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!"); + if (tstate->gilstate_counter < 0) + pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!"); + #endif + if (tstate->gilstate_counter == 0) { + #if !defined(NDEBUG) + if (!release) + pybind11_fail("scoped_acquire::dec_ref(): internal error!"); + #endif + PyThreadState_Clear(tstate); + PyThreadState_DeleteCurrent(); + PyThread_delete_key_value(detail::get_internals().tstate); + release = false; + } + } + + PYBIND11_NOINLINE ~gil_scoped_acquire() { + dec_ref(); + if (release) + PyEval_SaveThread(); + } +private: + PyThreadState *tstate = nullptr; + bool release = true; }; class gil_scoped_release { - PyThreadState *state; public: - inline gil_scoped_release() { state = PyEval_SaveThread(); } - inline ~gil_scoped_release() { PyEval_RestoreThread(state); } + gil_scoped_release(bool disassoc = false) : disassoc(disassoc) { + tstate = PyEval_SaveThread(); + if (disassoc) { + int key = detail::get_internals().tstate; + #if PY_MAJOR_VERSION < 3 + PyThread_delete_key_value(key); + #else + PyThread_set_key_value(key, nullptr); + #endif + } + } + ~gil_scoped_release() { + if (!tstate) + return; + PyEval_RestoreThread(tstate); + if (disassoc) { + int key = detail::get_internals().tstate; + #if PY_MAJOR_VERSION < 3 + PyThread_delete_key_value(key); + #endif + PyThread_set_key_value(key, tstate); + } + } +private: + PyThreadState *tstate; + bool disassoc; }; +#else +class gil_scoped_acquire { }; +class gil_scoped_release { }; #endif inline function get_overload(const void *this_ptr, const char *name) { @@ -1081,19 +1184,25 @@ inline function get_overload(const void *this_ptr, const char *name) { return overload; } -#define PYBIND11_OVERLOAD_INT(ret_type, class_name, name, ...) { \ +#define PYBIND11_OVERLOAD_INT(ret_type, name, ...) { \ pybind11::gil_scoped_acquire gil; \ - pybind11::function overload = pybind11::get_overload(this, #name); \ + pybind11::function overload = pybind11::get_overload(this, name); \ if (overload) \ - return overload.call(__VA_ARGS__).template cast<ret_type>(); } + return overload(__VA_ARGS__).template cast<ret_type>(); } + +#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \ + PYBIND11_OVERLOAD_INT(ret_type, name, __VA_ARGS__) \ + return cname::fn(__VA_ARGS__) + +#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \ + PYBIND11_OVERLOAD_INT(ret_type, name, __VA_ARGS__) \ + pybind11::pybind11_fail("Tried to call pure virtual function \"" #cname "::" name "\""); -#define PYBIND11_OVERLOAD(ret_type, class_name, name, ...) \ - PYBIND11_OVERLOAD_INT(ret_type, class_name, name, __VA_ARGS__) \ - return class_name::name(__VA_ARGS__) +#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \ + PYBIND11_OVERLOAD_NAME(ret_type, cname, #fn, fn, __VA_ARGS__) -#define PYBIND11_OVERLOAD_PURE(ret_type, class_name, name, ...) \ - PYBIND11_OVERLOAD_INT(ret_type, class_name, name, __VA_ARGS__) \ - pybind11::pybind11_fail("Tried to call pure virtual function \"" #name "\""); +#define PYBIND11_OVERLOAD_PURE(ret_type, cname, fn, ...) \ + PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, #fn, fn, __VA_ARGS__) NAMESPACE_END(pybind11) @@ -1101,6 +1210,6 @@ NAMESPACE_END(pybind11) # pragma warning(pop) #elif defined(__ICC) || defined(__INTEL_COMPILER) # pragma warning(pop) -#elif defined(__GNUG__) and !defined(__clang__) +#elif defined(__GNUG__) && !defined(__clang__) # pragma GCC diagnostic pop #endif diff --git a/stormpy/resources/pybind11/include/pybind11/pytypes.h b/stormpy/resources/pybind11/include/pybind11/pytypes.h index c7f109cdc..4da205b4f 100644 --- a/stormpy/resources/pybind11/include/pybind11/pytypes.h +++ b/stormpy/resources/pybind11/include/pybind11/pytypes.h @@ -1,7 +1,7 @@ /* pybind11/typeid.h: Convenience wrapper classes for basic Python types - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -16,12 +16,8 @@ NAMESPACE_BEGIN(pybind11) /* A few forward declarations */ -class object; -class str; -class object; -class dict; -class iterator; -namespace detail { class accessor; } +class object; class str; class object; class dict; class iterator; +namespace detail { class accessor; class args_proxy; class kwargs_proxy; } /// Holds a reference to a Python object (no reference counting) class handle { @@ -43,11 +39,17 @@ public: inline detail::accessor attr(const char *key) const; inline pybind11::str str() const; template <typename T> T cast() const; - template <typename ... Args> object call(Args&&... args_) const; + template <typename ... Args> + [[deprecated("call(...) was deprecated in favor of operator()(...)")]] + object call(Args&&... args) const; + template <typename ... Args> object operator()(Args&&... args) const; + inline object operator()(detail::args_proxy args) const; + inline object operator()(detail::args_proxy f_args, detail::kwargs_proxy kwargs) const; operator bool() const { return m_ptr != nullptr; } bool operator==(const handle &h) const { return m_ptr == h.m_ptr; } bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; } bool check() const { return m_ptr != nullptr; } + inline detail::args_proxy operator*() const; protected: PyObject *m_ptr; }; @@ -59,7 +61,7 @@ public: object(const object &o) : handle(o) { inc_ref(); } object(const handle &h, bool borrowed) : handle(h) { if (borrowed) inc_ref(); } object(PyObject *ptr, bool borrowed) : handle(ptr) { if (borrowed) inc_ref(); } - object(object &&other) { m_ptr = other.m_ptr; other.m_ptr = nullptr; } + object(object &&other) noexcept { m_ptr = other.m_ptr; other.m_ptr = nullptr; } ~object() { dec_ref(); } handle release() { @@ -68,14 +70,14 @@ public: return handle(tmp); } - object& operator=(object &other) { + object& operator=(const object &other) { other.inc_ref(); dec_ref(); m_ptr = other.m_ptr; return *this; } - object& operator=(object &&other) { + object& operator=(object &&other) noexcept { if (this != &other) { handle temp(m_ptr); m_ptr = other.m_ptr; @@ -126,7 +128,7 @@ public: return result; } - template <typename T> inline T cast() const { return operator object().cast<T>(); } + template <typename T> T cast() const { return operator object().cast<T>(); } operator bool() const { if (attr) { @@ -163,7 +165,7 @@ public: return object(result, true); } - template <typename T> inline T cast() const { return operator object().cast<T>(); } + template <typename T> T cast() const { return operator object().cast<T>(); } private: handle list; size_t index; @@ -188,7 +190,7 @@ public: return object(result, true); } - template <typename T> inline T cast() const { return operator object().cast<T>(); } + template <typename T> T cast() const { return operator object().cast<T>(); } private: handle tuple; size_t index; @@ -212,16 +214,42 @@ private: ssize_t pos = 0; }; -NAMESPACE_END(detail) +inline bool PyIterable_Check(PyObject *obj) { + PyObject *iter = PyObject_GetIter(obj); + if (iter) { + Py_DECREF(iter); + return true; + } else { + PyErr_Clear(); + return false; + } +} + +inline bool PyNone_Check(PyObject *o) { return o == Py_None; } + +inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); } + +class kwargs_proxy : public handle { +public: + kwargs_proxy(handle h) : handle(h) { } +}; + +class args_proxy : public handle { +public: + args_proxy(handle h) : handle(h) { } + kwargs_proxy operator*() const { return kwargs_proxy(*this); } +}; +NAMESPACE_END(detail) #define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, CvtStmt) \ - Name(const handle &h, bool borrowed) : Parent(h, borrowed) { CvtStmt; } \ - Name(const object& o): Parent(o) { CvtStmt; } \ - Name(object&& o): Parent(std::move(o)) { CvtStmt; } \ - Name& operator=(object&& o) { (void) static_cast<Name&>(object::operator=(std::move(o))); CvtStmt; return *this; } \ - Name& operator=(object& o) { return static_cast<Name&>(object::operator=(o)); CvtStmt; } \ - bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } + public: \ + Name(const handle &h, bool borrowed) : Parent(h, borrowed) { CvtStmt; } \ + Name(const object& o): Parent(o) { CvtStmt; } \ + Name(object&& o) noexcept : Parent(std::move(o)) { CvtStmt; } \ + Name& operator=(object&& o) noexcept { (void) object::operator=(std::move(o)); CvtStmt; return *this; } \ + Name& operator=(const object& o) { return static_cast<Name&>(object::operator=(o)); CvtStmt; } \ + bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } #define PYBIND11_OBJECT(Name, Parent, CheckFun) \ PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ) @@ -232,48 +260,99 @@ NAMESPACE_END(detail) class iterator : public object { public: - PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check) - iterator(handle obj, bool borrowed = false) : object(obj, borrowed) { } + PYBIND11_OBJECT_CVT(iterator, object, PyIter_Check, value = object(); ready = false) + iterator() : object(), value(object()), ready(false) { } + iterator(const iterator& it) : object(it), value(it.value), ready(it.ready) { } + iterator(iterator&& it) : object(std::move(it)), value(std::move(it.value)), ready(it.ready) { } + + /** Caveat: this copy constructor does not (and cannot) clone the internal + state of the Python iterable */ + iterator &operator=(const iterator &it) { + (void) object::operator=(it); + value = it.value; + ready = it.ready; + return *this; + } + + iterator &operator=(iterator &&it) noexcept { + (void) object::operator=(std::move(it)); + value = std::move(it.value); + ready = it.ready; + return *this; + } + iterator& operator++() { - if (ptr()) - value = object(PyIter_Next(m_ptr), false); + if (m_ptr) + advance(); return *this; } + + /** Caveat: this postincrement operator does not (and cannot) clone the + internal state of the Python iterable. It should only be used to + retrieve the current iterate using <tt>operator*()</tt> */ + iterator operator++(int) { + iterator rv(*this); + rv.value = value; + if (m_ptr) + advance(); + return rv; + } + bool operator==(const iterator &it) const { return *it == **this; } bool operator!=(const iterator &it) const { return *it != **this; } - const handle &operator*() const { - if (m_ptr && !value) - value = object(PyIter_Next(m_ptr), false); + + handle operator*() const { + if (!ready && m_ptr) { + auto& self = const_cast<iterator &>(*this); + self.advance(); + self.ready = true; + } return value; } + +private: + void advance() { value = object(PyIter_Next(m_ptr), false); } + private: - mutable object value; + object value; + bool ready; +}; + +class iterable : public object { +public: + PYBIND11_OBJECT_DEFAULT(iterable, object, detail::PyIterable_Check) }; inline detail::accessor handle::operator[](handle key) const { return detail::accessor(ptr(), key.ptr(), false); } inline detail::accessor handle::operator[](const char *key) const { return detail::accessor(ptr(), key, false); } inline detail::accessor handle::attr(handle key) const { return detail::accessor(ptr(), key.ptr(), true); } inline detail::accessor handle::attr(const char *key) const { return detail::accessor(ptr(), key, true); } -inline iterator handle::begin() const { return iterator(PyObject_GetIter(ptr())); } -inline iterator handle::end() const { return iterator(nullptr); } +inline iterator handle::begin() const { return iterator(PyObject_GetIter(ptr()), false); } +inline iterator handle::end() const { return iterator(nullptr, false); } +inline detail::args_proxy handle::operator*() const { return detail::args_proxy(*this); } class str : public object { public: - PYBIND11_OBJECT_DEFAULT(str, object, PyUnicode_Check) + PYBIND11_OBJECT_DEFAULT(str, object, detail::PyUnicode_Check_Permissive) + str(const std::string &s) : object(PyUnicode_FromStringAndSize(s.c_str(), s.length()), false) { if (!m_ptr) pybind11_fail("Could not allocate string object!"); } operator std::string() const { -#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 - return PyUnicode_AsUTF8(m_ptr); -#else - object temp(PyUnicode_AsUTF8String(m_ptr), false); - if (temp.ptr() == nullptr) - pybind11_fail("Unable to extract string contents!"); - return PYBIND11_BYTES_AS_STRING(temp.ptr()); -#endif + object temp = *this; + if (PyUnicode_Check(m_ptr)) { + temp = object(PyUnicode_AsUTF8String(m_ptr), false); + if (!temp) + pybind11_fail("Unable to extract string contents! (encoding issue)"); + } + char *buffer; + ssize_t length; + int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length); + if (err == -1) + pybind11_fail("Unable to extract string contents! (invalid type)"); + return std::string(buffer, length); } }; @@ -305,6 +384,12 @@ public: } }; +class none : public object { +public: + PYBIND11_OBJECT(none, object, detail::PyNone_Check) + none() : object(Py_None, true) { } +}; + class bool_ : public object { public: PYBIND11_OBJECT_DEFAULT(bool_, object, PyBool_Check) @@ -388,8 +473,8 @@ class capsule : public object { public: PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact) capsule(PyObject *obj, bool borrowed) : object(obj, borrowed) { } - capsule(void *value, void (*destruct)(PyObject *) = nullptr) - : object(PyCapsule_New(value, nullptr, destruct), false) { + capsule(const void *value, void (*destruct)(PyObject *) = nullptr) + : object(PyCapsule_New(const_cast<void*>(value), nullptr, destruct), false) { if (!m_ptr) pybind11_fail("Could not allocate capsule object!"); } template <typename T> operator T *() const { @@ -406,7 +491,7 @@ public: if (!m_ptr) pybind11_fail("Could not allocate tuple object!"); } size_t size() const { return (size_t) PyTuple_Size(m_ptr); } - detail::tuple_accessor operator[](size_t index) const { return detail::tuple_accessor(ptr(), index); } + detail::tuple_accessor operator[](size_t index) const { return detail::tuple_accessor(*this, index); } }; class dict : public object { @@ -432,6 +517,9 @@ public: void append(const object &object) const { PyList_Append(m_ptr, object.ptr()); } }; +class args : public tuple { PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check) }; +class kwargs : public dict { PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check) }; + class set : public object { public: PYBIND11_OBJECT(set, object, PySet_Check) diff --git a/stormpy/resources/pybind11/include/pybind11/stl.h b/stormpy/resources/pybind11/include/pybind11/stl.h index 97ccdbc84..e0177de40 100644 --- a/stormpy/resources/pybind11/include/pybind11/stl.h +++ b/stormpy/resources/pybind11/include/pybind11/stl.h @@ -1,7 +1,7 @@ /* - pybind11/complex.h: Complex number support + pybind11/stl.h: Transparent conversion for STL data types - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/include/pybind11/stl_bind.h b/stormpy/resources/pybind11/include/pybind11/stl_bind.h new file mode 100644 index 000000000..37839826d --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/stl_bind.h @@ -0,0 +1,349 @@ +/* + pybind11/std_bind.h: Binding generators for STL data types + + Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "common.h" +#include "operators.h" + +#include <type_traits> +#include <utility> +#include <algorithm> +#include <sstream> + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +/* SFINAE helper class used by 'is_comparable */ +template <typename T> struct container_traits { + template <typename T2> static std::true_type test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>())*); + template <typename T2> static std::false_type test_comparable(...); + template <typename T2> static std::true_type test_value(typename T2::value_type *); + template <typename T2> static std::false_type test_value(...); + template <typename T2> static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *); + template <typename T2> static std::false_type test_pair(...); + + static constexpr const bool is_comparable = std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value; + static constexpr const bool is_pair = std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value; + static constexpr const bool is_vector = std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value; + static constexpr const bool is_element = !is_pair && !is_vector; +}; + +/* Default: is_comparable -> std::false_type */ +template <typename T, typename SFINAE = void> +struct is_comparable : std::false_type { }; + +/* For non-map data structures, check whether operator== can be instantiated */ +template <typename T> +struct is_comparable< + T, typename std::enable_if<container_traits<T>::is_element && + container_traits<T>::is_comparable>::type> + : std::true_type { }; + +/* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */ +template <typename T> +struct is_comparable<T, typename std::enable_if<container_traits<T>::is_vector>::type> { + static constexpr const bool value = + is_comparable<typename T::value_type>::value; +}; + +/* For pairs, recursively check the two data types */ +template <typename T> +struct is_comparable<T, typename std::enable_if<container_traits<T>::is_pair>::type> { + static constexpr const bool value = + is_comparable<typename T::first_type>::value && + is_comparable<typename T::second_type>::value; +}; + +/* Fallback functions */ +template <typename, typename, typename... Args> void vector_if_copy_constructible(const Args&...) { } +template <typename, typename, typename... Args> void vector_if_equal_operator(const Args&...) { } +template <typename, typename, typename... Args> void vector_if_insertion_operator(const Args&...) { } + +template<typename Vector, typename Class_, typename std::enable_if<std::is_copy_constructible<typename Vector::value_type>::value, int>::type = 0> +void vector_if_copy_constructible(Class_ &cl) { + cl.def(pybind11::init<const Vector &>(), + "Copy constructor"); +} + +template<typename Vector, typename Class_, typename std::enable_if<is_comparable<Vector>::value, int>::type = 0> +void vector_if_equal_operator(Class_ &cl) { + using T = typename Vector::value_type; + + cl.def(self == self); + cl.def(self != self); + + cl.def("count", + [](const Vector &v, const T &x) { + return std::count(v.begin(), v.end(), x); + }, + arg("x"), + "Return the number of times ``x`` appears in the list" + ); + + cl.def("remove", [](Vector &v, const T &x) { + auto p = std::find(v.begin(), v.end(), x); + if (p != v.end()) + v.erase(p); + else + throw pybind11::value_error(); + }, + arg("x"), + "Remove the first item from the list whose value is x. " + "It is an error if there is no such item." + ); + + cl.def("__contains__", + [](const Vector &v, const T &x) { + return std::find(v.begin(), v.end(), x) != v.end(); + }, + arg("x"), + "Return true the container contains ``x``" + ); +} + +template <typename Vector, typename Class_> auto vector_if_insertion_operator(Class_ &cl, std::string const &name) + -> decltype(std::declval<std::ostream&>() << std::declval<typename Vector::value_type>(), void()) { + using size_type = typename Vector::size_type; + + cl.def("__repr__", + [name](Vector &v) { + std::ostringstream s; + s << name << '['; + for (size_type i=0; i < v.size(); ++i) { + s << v[i]; + if (i != v.size() - 1) + s << ", "; + } + s << ']'; + return s.str(); + }, + "Return the canonical string representation of this list." + ); +} + +NAMESPACE_END(detail) + + +template <typename T, typename Allocator = std::allocator<T>, typename holder_type = std::unique_ptr<std::vector<T, Allocator>>, typename... Args> +pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::module &m, std::string const &name, Args&&... args) { + using Vector = std::vector<T, Allocator>; + using SizeType = typename Vector::size_type; + using Class_ = pybind11::class_<Vector, holder_type>; + + Class_ cl(m, name.c_str(), std::forward<Args>(args)...); + + cl.def(pybind11::init<>()); + + // Register copy constructor (if possible) + detail::vector_if_copy_constructible<Vector, Class_>(cl); + + // Register comparison-related operators and functions (if possible) + detail::vector_if_equal_operator<Vector, Class_>(cl); + + // Register stream insertion operator (if possible) + detail::vector_if_insertion_operator<Vector, Class_>(cl, name); + + cl.def("__init__", [](Vector &v, iterable it) { + new (&v) Vector(); + try { + v.reserve(len(it)); + for (handle h : it) + v.push_back(h.cast<typename Vector::value_type>()); + } catch (...) { + v.~Vector(); + throw; + } + }); + cl.def("append", (void (Vector::*) (const T &)) & Vector::push_back, + arg("x"), + "Add an item to the end of the list"); + + cl.def("extend", + [](Vector &v, Vector &src) { + v.reserve(v.size() + src.size()); + v.insert(v.end(), src.begin(), src.end()); + }, + arg("L"), + "Extend the list by appending all the items in the given list" + ); + + cl.def("insert", + [](Vector &v, SizeType i, const T &x) { + v.insert(v.begin() + i, x); + }, + arg("i") , arg("x"), + "Insert an item at a given position." + ); + + cl.def("pop", + [](Vector &v) { + if (v.empty()) + throw pybind11::index_error(); + T t = v.back(); + v.pop_back(); + return t; + }, + "Remove and return the last item" + ); + + cl.def("pop", + [](Vector &v, SizeType i) { + if (i >= v.size()) + throw pybind11::index_error(); + T t = v[i]; + v.erase(v.begin() + i); + return t; + }, + arg("i"), + "Remove and return the item at index ``i``" + ); + + cl.def("__bool__", + [](const Vector &v) -> bool { + return !v.empty(); + }, + "Check whether the list is nonempty" + ); + + cl.def("__getitem__", + [](const Vector &v, SizeType i) { + if (i >= v.size()) + throw pybind11::index_error(); + return v[i]; + } + ); + + cl.def("__setitem__", + [](Vector &v, SizeType i, const T &t) { + if (i >= v.size()) + throw pybind11::index_error(); + v[i] = t; + } + ); + + cl.def("__delitem__", + [](Vector &v, SizeType i) { + if (i >= v.size()) + throw pybind11::index_error(); + v.erase(v.begin() + i); + }, + "Delete list elements using a slice object" + ); + + cl.def("__len__", &Vector::size); + + cl.def("__iter__", + [](Vector &v) { + return pybind11::make_iterator(v.begin(), v.end()); + }, + pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); + + /// Slicing protocol + cl.def("__getitem__", + [](const Vector &v, slice slice) -> Vector * { + ssize_t start, stop, step, slicelength; + + if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) + throw pybind11::error_already_set(); + + Vector *seq = new Vector(); + seq->reserve((size_t) slicelength); + + for (int i=0; i<slicelength; ++i) { + seq->push_back(v[start]); + start += step; + } + return seq; + }, + arg("s"), + "Retrieve list elements using a slice object" + ); + + cl.def("__setitem__", + [](Vector &v, slice slice, const Vector &value) { + ssize_t start, stop, step, slicelength; + if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) + throw pybind11::error_already_set(); + + if ((size_t) slicelength != value.size()) + throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); + + for (int i=0; i<slicelength; ++i) { + v[start] = value[i]; + start += step; + } + }, + "Assign list elements using a slice object" + ); + + cl.def("__delitem__", + [](Vector &v, slice slice) { + ssize_t start, stop, step, slicelength; + + if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) + throw pybind11::error_already_set(); + + if (step == 1 && false) { + v.erase(v.begin() + start, v.begin() + start + slicelength); + } else { + for (ssize_t i = 0; i < slicelength; ++i) { + v.erase(v.begin() + start); + start += step - 1; + } + } + }, + "Delete list elements using a slice object" + ); + +#if 0 + // C++ style functions deprecated, leaving it here as an example + cl.def(pybind11::init<size_type>()); + + cl.def("resize", + (void (Vector::*) (size_type count)) & Vector::resize, + "changes the number of elements stored"); + + cl.def("erase", + [](Vector &v, SizeType i) { + if (i >= v.size()) + throw pybind11::index_error(); + v.erase(v.begin() + i); + }, "erases element at index ``i``"); + + cl.def("empty", &Vector::empty, "checks whether the container is empty"); + cl.def("size", &Vector::size, "returns the number of elements"); + cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end"); + cl.def("pop_back", &Vector::pop_back, "removes the last element"); + + cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements"); + cl.def("reserve", &Vector::reserve, "reserves storage"); + cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage"); + cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory"); + + cl.def("clear", &Vector::clear, "clears the contents"); + cl.def("swap", &Vector::swap, "swaps the contents"); + + cl.def("front", [](Vector &v) { + if (v.size()) return v.front(); + else throw pybind11::index_error(); + }, "access the first element"); + + cl.def("back", [](Vector &v) { + if (v.size()) return v.back(); + else throw pybind11::index_error(); + }, "access the last element "); + +#endif + + return cl; +} + +NAMESPACE_END(pybind11) diff --git a/stormpy/resources/pybind11/include/pybind11/typeid.h b/stormpy/resources/pybind11/include/pybind11/typeid.h index b395110f6..c903fb14c 100644 --- a/stormpy/resources/pybind11/include/pybind11/typeid.h +++ b/stormpy/resources/pybind11/include/pybind11/typeid.h @@ -1,7 +1,7 @@ /* pybind11/typeid.h: Compiler-independent access to type identifiers - Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch> + Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. diff --git a/stormpy/resources/pybind11/pybind11/__init__.py b/stormpy/resources/pybind11/pybind11/__init__.py index af8f14a8e..dc0ddf6f3 100644 --- a/stormpy/resources/pybind11/pybind11/__init__.py +++ b/stormpy/resources/pybind11/pybind11/__init__.py @@ -1,11 +1,11 @@ from ._version import version_info, __version__ -def get_include(): +def get_include(*args, **kwargs): import os try: from pip import locations return os.path.dirname( - locations.distutils_scheme('pybind11')['headers']) + locations.distutils_scheme('pybind11', *args, **kwargs)['headers']) except ImportError: return 'include' diff --git a/stormpy/resources/pybind11/pybind11/_version.py b/stormpy/resources/pybind11/pybind11/_version.py index 93cf8a709..afa4cc9be 100644 --- a/stormpy/resources/pybind11/pybind11/_version.py +++ b/stormpy/resources/pybind11/pybind11/_version.py @@ -1,2 +1,2 @@ -version_info = (1, 5, 'dev0') +version_info = (1, 8, 'dev0') __version__ = '.'.join(map(str, version_info)) diff --git a/stormpy/resources/pybind11/setup.py b/stormpy/resources/pybind11/setup.py index 362b753b0..07465bb67 100644 --- a/stormpy/resources/pybind11/setup.py +++ b/stormpy/resources/pybind11/setup.py @@ -10,7 +10,7 @@ setup( version=__version__, description='Seamless operability between C++11 and Python', author='Wenzel Jakob', - author_email='wenzel@inf.ethz.ch', + author_email='wenzel.jakob@epfl.ch', url='https://github.com/wjakob/pybind11', download_url='https://github.com/wjakob/pybind11/tarball/v' + __version__, packages=['pybind11'], @@ -20,9 +20,11 @@ setup( 'include/pybind11/cast.h', 'include/pybind11/complex.h', 'include/pybind11/descr.h', + 'include/pybind11/eigen.h', 'include/pybind11/numpy.h', 'include/pybind11/pybind11.h', 'include/pybind11/stl.h', + 'include/pybind11/stl_bind.h', 'include/pybind11/common.h', 'include/pybind11/functional.h', 'include/pybind11/operators.h', diff --git a/stormpy/resources/pybind11/tools/FindEigen3.cmake b/stormpy/resources/pybind11/tools/FindEigen3.cmake new file mode 100644 index 000000000..9c546a05d --- /dev/null +++ b/stormpy/resources/pybind11/tools/FindEigen3.cmake @@ -0,0 +1,81 @@ +# - Try to find Eigen3 lib +# +# This module supports requiring a minimum version, e.g. you can do +# find_package(Eigen3 3.1.2) +# to require version 3.1.2 or newer of Eigen3. +# +# Once done this will define +# +# EIGEN3_FOUND - system has eigen lib with correct version +# EIGEN3_INCLUDE_DIR - the eigen include directory +# EIGEN3_VERSION - eigen version + +# Copyright (c) 2006, 2007 Montel Laurent, <montel@kde.org> +# Copyright (c) 2008, 2009 Gael Guennebaud, <g.gael@free.fr> +# Copyright (c) 2009 Benoit Jacob <jacob.benoit.1@gmail.com> +# Redistribution and use is allowed according to the terms of the 2-clause BSD license. + +if(NOT Eigen3_FIND_VERSION) + if(NOT Eigen3_FIND_VERSION_MAJOR) + set(Eigen3_FIND_VERSION_MAJOR 2) + endif(NOT Eigen3_FIND_VERSION_MAJOR) + if(NOT Eigen3_FIND_VERSION_MINOR) + set(Eigen3_FIND_VERSION_MINOR 91) + endif(NOT Eigen3_FIND_VERSION_MINOR) + if(NOT Eigen3_FIND_VERSION_PATCH) + set(Eigen3_FIND_VERSION_PATCH 0) + endif(NOT Eigen3_FIND_VERSION_PATCH) + + set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") +endif(NOT Eigen3_FIND_VERSION) + +macro(_eigen3_check_version) + file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) + + string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") + set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") + set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") + set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") + + set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) + if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK FALSE) + else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK TRUE) + endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + + if(NOT EIGEN3_VERSION_OK) + + message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " + "but at least version ${Eigen3_FIND_VERSION} is required") + endif(NOT EIGEN3_VERSION_OK) +endmacro(_eigen3_check_version) + +if (EIGEN3_INCLUDE_DIR) + + # in cache already + _eigen3_check_version() + set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) + +else (EIGEN3_INCLUDE_DIR) + + find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library + PATHS + ${CMAKE_INSTALL_PREFIX}/include + ${KDE4_INCLUDE_DIR} + PATH_SUFFIXES eigen3 eigen + ) + + if(EIGEN3_INCLUDE_DIR) + _eigen3_check_version() + endif(EIGEN3_INCLUDE_DIR) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) + + mark_as_advanced(EIGEN3_INCLUDE_DIR) + +endif(EIGEN3_INCLUDE_DIR) + diff --git a/stormpy/resources/pybind11/tools/mkdoc.py b/stormpy/resources/pybind11/tools/mkdoc.py index 09c09cfb0..400fb05da 100644 --- a/stormpy/resources/pybind11/tools/mkdoc.py +++ b/stormpy/resources/pybind11/tools/mkdoc.py @@ -5,64 +5,72 @@ # Extract documentation from C++ header files to use it in Python bindings # -import os, sys, platform, re, textwrap +import os +import sys +import platform +import re +import textwrap + from clang import cindex from clang.cindex import CursorKind from collections import OrderedDict from threading import Thread, Semaphore from multiprocessing import cpu_count -if platform.system() == 'Darwin': - libclang = '/opt/llvm/lib/libclang.dylib' - if os.path.exists(libclang): - cindex.Config.set_library_path(os.path.dirname(libclang)) - RECURSE_LIST = [ CursorKind.TRANSLATION_UNIT, CursorKind.NAMESPACE, CursorKind.CLASS_DECL, CursorKind.STRUCT_DECL, + CursorKind.ENUM_DECL, CursorKind.CLASS_TEMPLATE ] PRINT_LIST = [ CursorKind.CLASS_DECL, CursorKind.STRUCT_DECL, + CursorKind.ENUM_DECL, + CursorKind.ENUM_CONSTANT_DECL, CursorKind.CLASS_TEMPLATE, CursorKind.FUNCTION_DECL, CursorKind.FUNCTION_TEMPLATE, + CursorKind.CONVERSION_FUNCTION, CursorKind.CXX_METHOD, CursorKind.CONSTRUCTOR, CursorKind.FIELD_DECL ] CPP_OPERATORS = { - '<=' : 'le', '>=' : 'ge', '==' : 'eq', '!=' : 'ne', '[]' : 'array', - '+=' : 'iadd', '-=' : 'isub', '*=' : 'imul', '/=' : 'idiv', '%=' : - 'imod', '&=' : 'iand', '|=' : 'ior', '^=' : 'ixor', '<<=' : 'ilshift', - '>>=' : 'irshift', '++' : 'inc', '--' : 'dec', '<<' : 'lshift', '>>' : - 'rshift', '&&' : 'land', '||' : 'lor', '!' : 'lnot', '~' : 'bnot', '&' - : 'band', '|' : 'bor', '+' : 'add', '-' : 'sub', '*' : 'mul', '/' : - 'div', '%' : 'mod', '<' : 'lt', '>' : 'gt', '=' : 'assign' + '<=': 'le', '>=': 'ge', '==': 'eq', '!=': 'ne', '[]': 'array', + '+=': 'iadd', '-=': 'isub', '*=': 'imul', '/=': 'idiv', '%=': + 'imod', '&=': 'iand', '|=': 'ior', '^=': 'ixor', '<<=': 'ilshift', + '>>=': 'irshift', '++': 'inc', '--': 'dec', '<<': 'lshift', '>>': + 'rshift', '&&': 'land', '||': 'lor', '!': 'lnot', '~': 'bnot', + '&': 'band', '|': 'bor', '+': 'add', '-': 'sub', '*': 'mul', '/': + 'div', '%': 'mod', '<': 'lt', '>': 'gt', '=': 'assign', '()': 'call' } -CPP_OPERATORS = OrderedDict(sorted(CPP_OPERATORS.items(), key=lambda t: -len(t[0]))) + +CPP_OPERATORS = OrderedDict( + sorted(CPP_OPERATORS.items(), key=lambda t: -len(t[0]))) job_count = cpu_count() job_semaphore = Semaphore(job_count) registered_names = dict() + def d(s): return s.decode('utf8') + def sanitize_name(name): global registered_names + name = re.sub(r'type-parameter-0-([0-9]+)', r'T\1', name) for k, v in CPP_OPERATORS.items(): name = name.replace('operator%s' % k, 'operator_%s' % v) - name = name.replace('<', '_') - name = name.replace('>', '_') - name = name.replace(' ', '_') - name = name.replace(',', '_') + name = re.sub('<.*>', '', name) + name = ''.join([ch if ch.isalnum() else '_' for ch in name]) + name = re.sub('_$', '', re.sub('_+', '_', name)) if name in registered_names: registered_names[name] += 1 name += '_' + str(registered_names[name]) @@ -70,21 +78,31 @@ def sanitize_name(name): registered_names[name] = 1 return '__doc_' + name + def process_comment(comment): result = '' # Remove C++ comment syntax - for s in comment.splitlines(): + leading_spaces = float('inf') + for s in comment.expandtabs(tabsize=4).splitlines(): s = s.strip() if s.startswith('/*'): - s = s[2:].lstrip('* \t') + s = s[2:].lstrip('*') elif s.endswith('*/'): - s = s[:-2].rstrip('* \t') + s = s[:-2].rstrip('*') elif s.startswith('///'): s = s[3:] if s.startswith('*'): s = s[1:] - result += s.strip() + '\n' + if len(s) > 0: + leading_spaces = min(leading_spaces, len(s) - len(s.lstrip())) + result += s + '\n' + + if leading_spaces != float('inf'): + result2 = "" + for s in result.splitlines(): + result2 += s[leading_spaces:] + '\n' + result = result2 # Doxygen tags cpp_group = '([\w:]+)' @@ -96,20 +114,25 @@ def process_comment(comment): s = re.sub(r'\\e\s+%s' % cpp_group, r'*\1*', s) s = re.sub(r'\\em\s+%s' % cpp_group, r'*\1*', s) s = re.sub(r'\\b\s+%s' % cpp_group, r'**\1**', s) - s = re.sub(r'\\param%s?\s+%s' % (param_group, cpp_group), r'\n\n$Parameter ``\2``:\n\n', s) + s = re.sub(r'\\ingroup\s+%s' % cpp_group, r'', s) + s = re.sub(r'\\param%s?\s+%s' % (param_group, cpp_group), + r'\n\n$Parameter ``\2``:\n\n', s) + s = re.sub(r'\\tparam%s?\s+%s' % (param_group, cpp_group), + r'\n\n$Template parameter ``\2``:\n\n', s) for in_, out_ in { - 'return' : 'Returns', - 'author' : 'Author', - 'authors' : 'Authors', - 'copyright' : 'Copyright', - 'date' : 'Date', - 'remark' : 'Remark', - 'sa' : 'See also', - 'see' : 'See also', - 'extends' : 'Extends', - 'throw' : 'Throws', - 'throws' : 'Throws' }.items(): + 'return': 'Returns', + 'author': 'Author', + 'authors': 'Authors', + 'copyright': 'Copyright', + 'date': 'Date', + 'remark': 'Remark', + 'sa': 'See also', + 'see': 'See also', + 'extends': 'Extends', + 'throw': 'Throws', + 'throws': 'Throws' + }.items(): s = re.sub(r'\\%s\s*' % in_, r'\n\n$%s:\n\n' % out_, s) s = re.sub(r'\\details\s*', r'\n\n', s) @@ -117,11 +140,18 @@ def process_comment(comment): s = re.sub(r'\\short\s*', r'', s) s = re.sub(r'\\ref\s*', r'', s) + s = re.sub(r'\\code\s?(.*?)\s?\\endcode', + r"```\n\1\n```\n", s, flags=re.DOTALL) + # HTML/TeX tags - s = re.sub(r'<tt>([^<]*)</tt>', r'``\1``', s) - s = re.sub(r'<em>([^<]*)</em>', r'*\1*', s) - s = re.sub(r'<b>([^<]*)</b>', r'**\1**', s) - s = re.sub(r'\\f\$([^\$]*)\\f\$', r'$\1$', s) + s = re.sub(r'<tt>(.*?)</tt>', r'``\1``', s, flags=re.DOTALL) + s = re.sub(r'<pre>(.*?)</pre>', r"```\n\1\n```\n", s, flags=re.DOTALL) + s = re.sub(r'<em>(.*?)</em>', r'*\1*', s, flags=re.DOTALL) + s = re.sub(r'<b>(.*?)</b>', r'**\1**', s, flags=re.DOTALL) + s = re.sub(r'\\f\$(.*?)\\f\$', r'$\1$', s, flags=re.DOTALL) + s = re.sub(r'<li>', r'\n\n* ', s) + s = re.sub(r'</?ul>', r'', s) + s = re.sub(r'</li>', r'\n\n', s) s = s.replace('``true``', '``True``') s = s.replace('``false``', '``False``') @@ -130,24 +160,39 @@ def process_comment(comment): wrapper = textwrap.TextWrapper() wrapper.expand_tabs = True wrapper.replace_whitespace = True - wrapper.width = 75 + wrapper.drop_whitespace = True + wrapper.width = 70 wrapper.initial_indent = wrapper.subsequent_indent = '' result = '' - for x in re.split(r'\n{2,}', s): - wrapped = wrapper.fill(x.strip()) - if len(wrapped) > 0 and wrapped[0] == '$': - result += wrapped[1:] + '\n' - wrapper.initial_indent = wrapper.subsequent_indent = ' '*4 + in_code_segment = False + for x in re.split(r'(```)', s): + if x == '```': + if not in_code_segment: + result += '```\n' + else: + result += '\n```\n\n' + in_code_segment = not in_code_segment + elif in_code_segment: + result += x.strip() else: - result += wrapped + '\n\n' - wrapper.initial_indent = wrapper.subsequent_indent = '' - return result.rstrip() + for y in re.split(r'(?: *\n *){2,}', x): + wrapped = wrapper.fill(re.sub(r'\s+', ' ', y).strip()) + if len(wrapped) > 0 and wrapped[0] == '$': + result += wrapped[1:] + '\n' + wrapper.initial_indent = \ + wrapper.subsequent_indent = ' ' * 4 + else: + if len(wrapped) > 0: + result += wrapped + '\n\n' + wrapper.initial_indent = wrapper.subsequent_indent = '' + return result.rstrip().lstrip('\n') def extract(filename, node, prefix, output): num_extracted = 0 - if not (node.location.file is None or os.path.samefile(d(node.location.file.name), filename)): + if not (node.location.file is None or + os.path.samefile(d(node.location.file.name), filename)): return 0 if node.kind in RECURSE_LIST: sub_prefix = prefix @@ -162,13 +207,19 @@ def extract(filename, node, prefix, output): if node.kind in PRINT_LIST: comment = d(node.raw_comment) if node.raw_comment is not None else '' comment = process_comment(comment) - name = sanitize_name(prefix + '_' + d(node.spelling)) - output.append('\nstatic const char *%s = %sR"doc(%s)doc";' % (name, '\n' if '\n' in comment else '', comment)) - num_extracted += 1 + sub_prefix = prefix + if len(sub_prefix) > 0: + sub_prefix += '_' + if len(node.spelling) > 0: + name = sanitize_name(sub_prefix + d(node.spelling)) + output.append('\nstatic const char *%s =%sR"doc(%s)doc";' % + (name, '\n' if '\n' in comment else ' ', comment)) + num_extracted += 1 return num_extracted + class ExtractionThread(Thread): - def __init__ (self, filename, parameters, output): + def __init__(self, filename, parameters, output): Thread.__init__(self) self.filename = filename self.parameters = parameters @@ -176,9 +227,10 @@ class ExtractionThread(Thread): job_semaphore.acquire() def run(self): - print('Processing "%s" ..' % self.filename, file = sys.stderr) + print('Processing "%s" ..' % self.filename, file=sys.stderr) try: - index = cindex.Index(cindex.conf.lib.clang_createIndex(False, True)) + index = cindex.Index( + cindex.conf.lib.clang_createIndex(False, True)) tu = index.parse(self.filename, self.parameters) extract(self.filename, tu.cursor, '', self.output) finally: @@ -188,6 +240,20 @@ if __name__ == '__main__': parameters = ['-x', 'c++', '-std=c++11'] filenames = [] + if platform.system() == 'Darwin': + dev_path = '/Applications/Xcode.app/Contents/Developer/' + lib_dir = dev_path + 'Toolchains/XcodeDefault.xctoolchain/usr/lib/' + sdk_dir = dev_path + 'Platforms/MacOSX.platform/Developer/SDKs' + libclang = lib_dir + 'libclang.dylib' + + if os.path.exists(libclang): + cindex.Config.set_library_path(os.path.dirname(libclang)) + + if os.path.exists(sdk_dir): + sysroot_dir = os.path.join(sdk_dir, next(os.walk(sdk_dir))[1][0]) + parameters.append('-isysroot') + parameters.append(sysroot_dir) + for item in sys.argv[1:]: if item.startswith('-'): parameters.append(item) @@ -203,17 +269,19 @@ if __name__ == '__main__': Do not edit! These were automatically extracted by mkdoc.py */ -#define __EXPAND(x) x -#define __COUNT(_1, _2, _3, _4, _5, COUNT, ...) COUNT -#define __VA_SIZE(...) __EXPAND(__COUNT(__VA_ARGS__, 5, 4, 3, 2, 1)) -#define __CAT1(a, b) a ## b -#define __CAT2(a, b) __CAT1(a, b) -#define __DOC1(n1) __doc_##n1 -#define __DOC2(n1, n2) __doc_##n1##_##n2 -#define __DOC3(n1, n2, n3) __doc_##n1##_##n2##_##n3 -#define __DOC4(n1, n2, n3, n4) __doc_##n1##_##n2##_##n3##_##n4 -#define __DOC5(n1, n2, n3, n4, n5) __doc_##n1##_##n2##_##n3##_##n4_##n5 -#define DOC(...) __EXPAND(__EXPAND(__CAT2(__DOC, __VA_SIZE(__VA_ARGS__)))(__VA_ARGS__)) +#define __EXPAND(x) x +#define __COUNT(_1, _2, _3, _4, _5, _6, _7, COUNT, ...) COUNT +#define __VA_SIZE(...) __EXPAND(__COUNT(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1)) +#define __CAT1(a, b) a ## b +#define __CAT2(a, b) __CAT1(a, b) +#define __DOC1(n1) __doc_##n1 +#define __DOC2(n1, n2) __doc_##n1##_##n2 +#define __DOC3(n1, n2, n3) __doc_##n1##_##n2##_##n3 +#define __DOC4(n1, n2, n3, n4) __doc_##n1##_##n2##_##n3##_##n4 +#define __DOC5(n1, n2, n3, n4, n5) __doc_##n1##_##n2##_##n3##_##n4##_##n5 +#define __DOC6(n1, n2, n3, n4, n5, n6) __doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6 +#define __DOC7(n1, n2, n3, n4, n5, n6, n7) __doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6##_##n7 +#define DOC(...) __EXPAND(__EXPAND(__CAT2(__DOC, __VA_SIZE(__VA_ARGS__)))(__VA_ARGS__)) #if defined(__GNUG__) #pragma GCC diagnostic push @@ -226,7 +294,7 @@ if __name__ == '__main__': thr = ExtractionThread(filename, parameters, output) thr.start() - print('Waiting for jobs to finish ..', file = sys.stderr) + print('Waiting for jobs to finish ..', file=sys.stderr) for i in range(job_count): job_semaphore.acquire()