{"id":17737707,"url":"https://github.com/tdegeus/pybind11_examples","last_synced_at":"2025-04-05T10:08:49.249Z","repository":{"id":44762984,"uuid":"79361502","full_name":"tdegeus/pybind11_examples","owner":"tdegeus","description":"Examples for the usage of \"pybind11\"","archived":false,"fork":false,"pushed_at":"2021-06-11T12:38:16.000Z","size":483,"stargazers_count":603,"open_issues_count":6,"forks_count":85,"subscribers_count":20,"default_branch":"master","last_synced_at":"2024-04-16T06:53:19.246Z","etag":null,"topics":["cpp","eigen","examples","numpy","pybind11","python"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tdegeus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-18T16:48:04.000Z","updated_at":"2024-04-16T02:22:21.000Z","dependencies_parsed_at":"2022-08-29T22:00:41.122Z","dependency_job_id":null,"html_url":"https://github.com/tdegeus/pybind11_examples","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdegeus%2Fpybind11_examples","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdegeus%2Fpybind11_examples/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdegeus%2Fpybind11_examples/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdegeus%2Fpybind11_examples/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tdegeus","download_url":"https://codeload.github.com/tdegeus/pybind11_examples/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247318744,"owners_count":20919484,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","eigen","examples","numpy","pybind11","python"],"created_at":"2024-10-26T01:42:27.251Z","updated_at":"2025-04-05T10:08:49.229Z","avatar_url":"https://github.com/tdegeus.png","language":"C++","readme":"# Contents\n\n\u003c!-- MarkdownTOC --\u003e\n\n- [Introduction](#introduction)\n- [Cloning this repository](#cloning-this-repository)\n- [Dependencies](#dependencies)\n- [Compiling strategies](#compiling-strategies)\n    - [DIY](#diy)\n    - [CMake](#cmake)\n        - [Basic usage](#basic-usage)\n        - [Using Eigen](#using-eigen)\n        - [Using the C++14 standard](#using-the-c14-standard)\n    - [setup.py](#setuppy)\n- [Examples](#examples)\n    - [01_py-list_cpp-vector](#01_py-list_cpp-vector)\n    - [02_py-nested-list_cpp-nested-vector](#02_py-nested-list_cpp-nested-vector)\n    - [03_numpy-1D_cpp-vector](#03_numpy-1d_cpp-vector)\n    - [04_numpy-2D_cpp-vector](#04_numpy-2d_cpp-vector)\n    - [05_numpy-2D_cpp-eigen](#05_numpy-2d_cpp-eigen)\n    - [06_class-numpy-eigen](#06_class-numpy-eigen)\n    - [07_cpp-overload-scalar](#07_cpp-overload-scalar)\n    - [08_cpp-overload-eigen](#08_cpp-overload-eigen)\n    - [09_numpy_cpp-custom-matrix](#09_numpy_cpp-custom-matrix)\n    - [10_enum](#10_enum)\n    - [11_class-parent-child](#11_class-parent-child)\n    - [12_crtp](#12_crtp)\n    - [13_static_cast](#13_static_cast)\n\n\u003c!-- /MarkdownTOC --\u003e\n\n\n# Introduction\n\nThe power of [pybind11](https://github.com/pybind/pybind11) is captured by the following citation from pybind11's readme:\n\n\u003e   pybind11 is a lightweight header-only library that exposes C++ types in Python and vice versa, mainly to create Python bindings of existing C++ code. Its goals and syntax are similar to the excellent Boost.Python library by David Abrahams ...\n\u003e\n\u003e   The main issue with Boost.Python - and the reason for creating such a similar project — is Boost. Boost is an enormously large and complex suite of utility libraries that works with almost every C++ compiler in existence. ... Now that C++11-compatible compilers are widely available, this heavy machinery has become an excessively large and unnecessary dependency.\n\nThis repository contains several examples for the usage of pybind11. Even though the [online documentation](http://pybind11.readthedocs.io) provided by the developers of pybind11 makes the usage of it relatively straightforward, several examples - such as provided here - make pybind11 even easier to use. These examples are meant for you to start quicker with pybind11. They are, however, by no means exhaustive, and do not always provide the optimal choice. Therefore it is highly advisable to **think for yourself**. Furthermore, **contributions with similar simple examples (or by further improving existing examples) are highly welcome**. Please file a pull request or an issue on [GitHub](https://github.com/tdegeus/pybind11_examples), or [contact me](mailto:tom_AT_geus.me).\n\nTo give credit where credit is due:\n\n*   The creators of pybind11 have done a great job! It is really easy to use, and very lightweight. Also the [documentation](http://pybind11.readthedocs.io) is already quite complete.\n\n*   The examples made available by [Cliburn Chan and Janice McCarthy, at Duke University](http://people.duke.edu/~ccc14/sta-663-2016/18G_C++_Python_pybind11.html) have been of enormous help. Please also read their [documentation](http://people.duke.edu/~ccc14/sta-663-2016/18G_C++_Python_pybind11.html).\n\nNote that there are also test cases that double as examples in the [pybind11 repository](https://github.com/pybind/pybind11), but these are not very insightful when you are new to pybind11.\n\nFinally, pybind11 is actively used. So one can look in actively maintained libraries for specific solutions. For example:\n\n*   [cppmat](http://cppmat.geus.me) is a library that provided multidimensional arrays in C++, much like the [Eigen](http://eigen.tuxfamily.org) library does for one- and two-dimensional arrays. It also provides a pybind11 interface, such that creating a Python module that uses cppmat objects as (return) arguments in the back end functions becomes trivial.\n\n# Cloning this repository\n\nThe pybind11 module (which is header only!) is included as a submodule of this repository. This requires some attention when cloning this project. There are two options:\n\n*   The simplest option is:\n\n    ```bash\n    git clone --recursive https://github.com/tdegeus/pybind11_examples.git\n    ```\n\n    This will download the submodule up to the version that is used in this project. To update to the latest commit of the submodule itself:\n\n    ```bash\n    git submodule update --remote\n    ```\n\n*   One could also directly download the submodule from the source:\n\n    ```bash\n    git clone https://github.com/tdegeus/pybind11_examples.git\n    cd pybind11_examples\n    git submodule init\n    git submodule update\n    ```\n\n# Dependencies\n\nThe [Eigen](http://eigen.tuxfamily.org) library is used in some of the NumPy examples. From these examples it can be observed that through pybind11, Eigen and NumPy are really handshake modules. Almost no code is needed to create the C++/Python interface. Note that most of the simplicity depends on copies being passed, some attention is needed if one wants to pass purely by reference.\n\nEigen does not need installation because it is also header only. One just needs to download the files and include the headers at compile time.\n\nIn general one can download and install Eigen by:\n\n```bash\nmkdir /path/to/temp/build\ncmake /path/to/eigen/download\nmake install\n```\n\n\u003e For macOS one could simply use\n\u003e \n\u003e ```bash\n\u003e brew install eigen\n\u003e ```\n\nThereafter compile with \n\n```bash\nclang++ -I/path/to/eigen/instalation ...\n```\n\nNote that, when properly configured (which is normally the case), pkg-config can be used to keep track of the paths:\n\n```bash\nclang++ `pkg-config --cflags eigen3` ...\n```\n\nOr one can use CMake (see below).\n\n# Compiling strategies\n\n## DIY\n\nIf you have a simple library you might want to do everything yourself. In this case you compile your C++ source to a shared object which is linked to Python. This boils down to \n\n```bash\nc++ -O3 -shared -std=gnu++11 -I ./pybind11/include `python3-config --cflags --ldflags --libs` example.cpp -o example.so -fPIC\n```\n\n## CMake\n\n### Basic usage\n\npybind11 applications can be compiled very easy using CMake. For simplicity pybind11 is included as a sub-folder of the examples below (in fact using a symbolic link to over many copies), so that we can use a `CMakeLists.txt` like:\n\n```cmake\ncmake_minimum_required(VERSION 2.8.12)\nproject(example)\n\nadd_subdirectory(pybind11)\npybind11_add_module(example example.cpp)\n```\n\n(whereby this example module consists of a single source file `example.cpp`). To compile it, use:\n\n```bash\ncd /path/to/build\ncmake /path/to/example/src\nmake\n```\n\n### Using Eigen\n\nWhen Eigen is 'installed' it can be easily included by adding the following in `CMakeLists.txt`:\n\n```cmake\nfind_package( PkgConfig )\npkg_check_modules( EIGEN3 REQUIRED eigen3 )\ninclude_directories( ${EIGEN3_INCLUDE_DIRS} )\n```\n\n### Using the C++14 standard\n\nThe C++14 standard can be used by including the following in `CMakeLists.txt`:\n\n```cmake\nset(CMAKE_CXX_STANDARD 14)\n```\n\n## setup.py\n\nA file `setup.py` can be added to your library. You can then compile and install using\n\n```bash\npython3 setup.py build\npython3 setup.py install\n```\n\nAlthough writing the `setup.py` is not hard it is not covered here. One can use some tools included in [cppmat](http://cppmat.geus.me), that can be installed with pip (e.g. `pip3 install cppmat`). Furthermore on can look at the `setup.py` of for example [GooseTensor](https://github.com/tdegeus/GooseTensor) or several other of [my repositories](https://github.com/tdegeus).\n\n# Examples\n\n## [01_py-list_cpp-vector](01_py-list_cpp-vector)\n\nThis example features one function `modify` that takes a list (read-only), multiplies all entries by two, and returns it as a list of doubles (see [`example.cpp`](01_py-list_cpp-vector/example.cpp)). From Python this function is contained in a simple module `example` (see [`test.py`](01_py-list_cpp-vector/test.py)).\n\nThe purpose of this example is to show how to make a function accept a list, how to convert this to the standard C++ `std::vector`, and how to return a new `std::vector` (or list). Note that the actual operation is not very important, it is the interface that is illustrated.\n\nTo compile, either employ CMake, whereby the compilation instructions are read from [`CMakeLists.txt`](01_py-list_cpp-vector/CMakeLists.txt) by subsequently:\n\n```bash\ncmake .\nmake\n```\n\nOr, compile directly using:\n\n```bash\nc++ -O3 -shared -std=gnu++11 -I ./pybind11/include `python3-config --cflags --ldflags --libs` example.cpp -o example.so -fPIC\n```\n\nRun the example by:\n\n```bash\npython3 test.py\n```\n\n\u003e   To run with Python 2, simply replace the two occurrences of \"python3\" above with \"python\". To modify the CMake instructions find more [online](http://pybind11.readthedocs.io/en/master/compiling.html?highlight=cmake).\n\n## [02_py-nested-list_cpp-nested-vector](02_py-nested-list_cpp-nested-vector)\n\nSame as the [previous example](#01py-listcpp-vector), but with a nested list.\n\n## [03_numpy-1D_cpp-vector](03_numpy-1D_cpp-vector)\n\nA function `modify` that converts the entries from a one-dimensional array to integers, and then multiplies these entries by 10.\n\nThe purpose of this example is to show how to make a function accept a one-dimensional NumPy array, how to convert this to the standard C++ `std::vector`, and how to return a one-dimensional NumPy array. Note that the interface generated using pybind11 is so flexible that it even accepts list inputs on the Python side.\n\n## [04_numpy-2D_cpp-vector](04_numpy-2D_cpp-vector)\n\nOne function `length`. This function accepts a 'matrix' in which comprises a list of 2-D position vectors, as rows. The result is again a 'matrix' with for each row the \"x\" and \"y\" position, and the length of the 2-D position vector.\n\n## [05_numpy-2D_cpp-eigen](05_numpy-2D_cpp-eigen)\n\nTwo functions `det` and `inv` that use the Eigen library. \n\nThe purpose of this example is to show how trivial the interaction between C++/Eigen and Python/NumPy is.\n\nTo compile using CMake and to run, follow the instructions [above](#01py-listcpp-vector) (whereby the Eigen headers are included in [`CMakeLists.txt`](05_numpy-2D_cpp-eigen/CMakeLists.txt). To compile directly, additionally the Eigen headers have to be included:\n\n```bash\nc++ -O3 -shared -std=gnu++11 -I /path/to/eigen -I ./pybind11/include `python3-config --cflags --ldflags --libs` example.cpp -o example.so -fPIC\n```\n\nFor example on macOS with homebrew:\n\n```bash\nc++ -O3 -shared -std=gnu++11 -I /usr/local/Cellar/eigen/3.3.1/include/eigen3 -I ./pybind11/include `python3-config --cflags --ldflags --libs` example.cpp -o example.so -fPIC\n```\n\n## [06_class-numpy-eigen](06_class-numpy-eigen)\n\nA custom `CustomVectorXd` class with one function `mul`. This class uses the Eigen library. It also includes a default argument.\n\nFurthermore, this example has a function `trans` (totally unrelated to the custom `CustomVectorXd` class). It's purpose is to show how to return a new `Eigen::VectorXi` (or NumPy-array).\n\n## [07_cpp-overload-scalar](07_cpp-overload-scalar)\n\nOne overloaded function `mul`. This function acts 'differently' if it is called with `int` arguments or `double` arguments. Notice that the default behavior of pybind11 is quite robust. When calling the function with one `int` and one `double` argument, the module will choose the `double` version of `mul` (and will cast the `int` argument to a `double`).\n\nTo compile, make sure that the C++14 standard is used, for example by including `-std=c++14` as compiler argument.\n\n## [08_cpp-overload-eigen](08_cpp-overload-eigen)\n\nSimilar to the [previous example](#08cpp-overload-eigen), but with Eigen arguments (i.e. NumPy arguments from the Python side).\n\nTo compile, make sure that the C++14 standard is used.\n\n## [09_numpy_cpp-custom-matrix](09_numpy_cpp-custom-matrix)\n\nThis example includes a custom matrix class in C++ (in `matrix.h`). This class is coupled to a NumPy-array using a simple interface (in `pybind_matrix.h`). Consequently the functions (in `example.cpp`) do not necessitate any special wrapper code.\n\nSee also [this](http://stackoverflow.com/questions/42645228/cast-numpy-array-to-from-custom-c-matrix-class-using-pybind11) discussion of Stack Overflow.\n\n## [10_enum](10_enum)\n\nThis example features a way to interface with an enumerator in C++. In principle the interface is straightforward but warrants a 'trick'. Here a submodule is used to be able to interact with the enumerator in the same way as in C++.\n\n## [11_class-parent-child](11_class-parent-child)\n\nThis example contains a classical example where one or more classes are derived from a certain parent or template. This particular example contains two animals, a `Dog` and a `Cat`, that are both derived from a generic `Animal` class. There is a function `talk` that accepts the generic `Animal` and thus any of the derived classes. \n\nThis particular case requires more involved interface, as is described in [the documentation](http://pybind11.readthedocs.io/en/stable/advanced/classes.html).\n\n## [12_crtp](12_crtp)\n\nThis example features a simple CRTP with as 'base' and and a 'derived' class, \nand its registration to the *pybind11* API.\n\n## [13_static_cast](13_static_cast)\n\nSometimes `py::overload_cast` is not able to resolve your function, \nfor example when the return type cannot be inferred.\nIn that case you can be explicit by `static_cast`ing a pointer to your function\nMore information can be found in [the documentation](https://pybind11.readthedocs.io/en/stable/classes.html?highlight=static_cast#overloaded-methods).\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftdegeus%2Fpybind11_examples","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftdegeus%2Fpybind11_examples","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftdegeus%2Fpybind11_examples/lists"}