Binding detailed example: Minuit2#
Let’s try a non-trivial example: Minuit2 (6.26.10 standalone edition)
Expectations#
- Be able to minimize a very simple function and get some parameters 
import sys
Step 1: Get source#
- Download Minuit2 source (already provided in - minuit2)
Step 2: Plan interface#
- You should know what the C++ looks like, and know what you want the Python to look like 
- For now, let’s replicate the C++ experience 
For example: a simple minimizer for \(f(x) = x^2\) (should quickly find 0 as minimum):
- Define FCN 
- Setup parameters 
- Minimize 
- Print result 
Will use print out for illustration (instead of MnPrint::SetLevel)
%%writefile SimpleFCN.h
#pragma once
#include <Minuit2/FCNBase.h>
#include <Minuit2/FunctionMinimum.h>
#include <Minuit2/MnPrint.h>
#include <Minuit2/MnMigrad.h>
#include <iostream>
using namespace ROOT::Minuit2;
class SimpleFCN : public FCNBase {
    // Always 0.5 for these sorts of fits
    
    double Up() const override {return 0.5;}
    
    // This computes whatever you are going to minimize
    double operator()(const std::vector<double> &v) const override {
        std::cout << "val = " << v.at(0) << std::endl;
        return v.at(0)*v.at(0);
    }
};
Writing SimpleFCN.h
%%writefile simpleminuit.cpp
#include "SimpleFCN.h"
int main() {
    SimpleFCN fcn;
    MnUserParameters upar;
    upar.Add("x", 1., 0.1);
    MnMigrad migrad(fcn, upar);
    FunctionMinimum min = migrad();
    std::cout << min << std::endl;
}
Writing simpleminuit.cpp
%%writefile CMakeLists.txt
cmake_minimum_required(VERSION 3.18...3.29)
project(Minuit2SimpleExamle LANGUAGES CXX)
include(FetchContent)
FetchContent_Declare(
  minuit2
  URL           https://github.com/root-project/root/archive/refs/tags/v6-26-10.tar.gz
  URL_HASH      SHA256=a84ed095252614c6e2084987fce9ce4a5a62057bfd5a4a2725123ca9f60f674f
  SOURCE_SUBDIR math/minuit2
  DOWNLOAD_NO_PROGRESS
)
FetchContent_MakeAvailable(minuit2)
add_executable(simpleminuit simpleminuit.cpp SimpleFCN.h)
target_link_libraries(simpleminuit PRIVATE Minuit2::Minuit2)
Writing CMakeLists.txt
Standard CMake configure and build (using Ninja instead of Make for speed)
!cmake -GNinja -S . -B build
!cmake --build build
-- The CXX compiler identification is GNU 13.3.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Deprecation Warning at build/_deps/minuit2-src/math/minuit2/CMakeLists.txt:7 (cmake_minimum_required):
  Compatibility with CMake < 3.10 will be removed from a future version of
  CMake.
  Update the VERSION argument <min> value.  Or, use the <min>...<max> syntax
  to tell CMake that the project requires at least <min> but has been updated
  to work with policies introduced by <max> or earlier.
CMake Deprecation Warning at build/_deps/minuit2-src/math/minuit2/StandAlone.cmake:1 (cmake_minimum_required):
  Compatibility with CMake < 3.10 will be removed from a future version of
  CMake.
  Update the VERSION argument <min> value.  Or, use the <min>...<max> syntax
  to tell CMake that the project requires at least <min> but has been updated
  to work with policies introduced by <max> or earlier.
Call Stack (most recent call first):
  build/_deps/minuit2-src/math/minuit2/CMakeLists.txt:250 (include)
-- Configuring done (18.7s)
-- Generating done (0.0s)
-- Build files have been written to: /home/runner/work/se-for-sci.github.io/se-for-sci.github.io/content/week10_binding/03-pybind/build
[0/80] Building CXX object _deps/minui..._/__/mathcore/src/GenAlgoOptions.cxx.o
[0/80] Building CXX object _deps/minui...__/mathcore/src/MinimizerOptions.cxx.o
[0/80] Building CXX object _deps/minui...dir/AnalyticalGradientCalculator.cxx.o
[0/80] Building CXX object _deps/minui...les/Minuit2.dir/BFGSErrorUpdator.cxx.o
[0/80] Building CXX object _deps/minui...nuit2.dir/CombinedMinimumBuilder.cxx.o
[0/80] Building CXX object _deps/minui.../Minuit2.dir/DavidonErrorUpdator.cxx.o
[1/80] Building CXX object _deps/minui...les/Minuit2.dir/BFGSErrorUpdator.cxx.o
[1/80] Building CXX object _deps/minui...ternalInternalGradientCalculator.cxx.o
[2/80] Building CXX object _deps/minui...__/mathcore/src/MinimizerOptions.cxx.o
[2/80] Building CXX object _deps/minui...eFiles/Minuit2.dir/FumiliBuilder.cxx.o
[3/80] Building CXX object _deps/minui.../Minuit2.dir/DavidonErrorUpdator.cxx.o
[3/80] Building CXX object _deps/minui...s/Minuit2.dir/FumiliErrorUpdator.cxx.o
[4/80] Building CXX object _deps/minui...dir/AnalyticalGradientCalculator.cxx.o
[4/80] Building CXX object _deps/minui...it2.dir/FumiliGradientCalculator.cxx.o
[5/80] Building CXX object _deps/minui..._/__/mathcore/src/GenAlgoOptions.cxx.o
[5/80] Building CXX object _deps/minui...iles/Minuit2.dir/FumiliMinimizer.cxx.o
[6/80] Building CXX object _deps/minui...nuit2.dir/CombinedMinimumBuilder.cxx.o
[6/80] Building CXX object _deps/minui...inuit2.dir/FumiliStandardChi2FCN.cxx.o
[7/80] Building CXX object _deps/minui...inuit2.dir/FumiliStandardChi2FCN.cxx.o
[7/80] Building CXX object _deps/minui...miliStandardMaximumLikelihoodFCN.cxx.o
[8/80] Building CXX object _deps/minui...s/Minuit2.dir/FumiliErrorUpdator.cxx.o
[8/80] Building CXX object _deps/minui...t2.dir/HessianGradientCalculator.cxx.o
[9/80] Building CXX object _deps/minui...ternalInternalGradientCalculator.cxx.o
[9/80] Building CXX object _deps/minui...t2.dir/InitialGradientCalculator.cxx.o
[10/80] Building CXX object _deps/minu...it2.dir/FumiliGradientCalculator.cxx.o
[10/80] Building CXX object _deps/minu...eFiles/Minuit2.dir/LaEigenValues.cxx.o
[11/80] Building CXX object _deps/minu...iles/Minuit2.dir/FumiliMinimizer.cxx.o
[11/80] Building CXX object _deps/minu...Files/Minuit2.dir/LaInnerProduct.cxx.o
[12/80] Building CXX object _deps/minu...t2.dir/HessianGradientCalculator.cxx.o
[12/80] Building CXX object _deps/minu...CMakeFiles/Minuit2.dir/LaInverse.cxx.o
[13/80] Building CXX object _deps/minu...eFiles/Minuit2.dir/LaEigenValues.cxx.o
[13/80] Building CXX object _deps/minu...Files/Minuit2.dir/LaOuterProduct.cxx.o
[14/80] Building CXX object _deps/minu...t2.dir/InitialGradientCalculator.cxx.o
[14/80] Building CXX object _deps/minu...iles/Minuit2.dir/LaSumOfElements.cxx.o
[15/80] Building CXX object _deps/minu...eFiles/Minuit2.dir/FumiliBuilder.cxx.o
[15/80] Building CXX object _deps/minu...les/Minuit2.dir/LaVtMVSimilarity.cxx.o
[16/80] Building CXX object _deps/minu...miliStandardMaximumLikelihoodFCN.cxx.o
[16/80] Building CXX object _deps/minu...MakeFiles/Minuit2.dir/MPIProcess.cxx.o
[17/80] Building CXX object _deps/minu...CMakeFiles/Minuit2.dir/LaInverse.cxx.o
[17/80] Building CXX object _deps/minu...Files/Minuit2.dir/MinimumBuilder.cxx.o
[18/80] Building CXX object _deps/minu...iles/Minuit2.dir/LaSumOfElements.cxx.o
[18/80] Building CXX object _deps/minu...les/Minuit2.dir/Minuit2Minimizer.cxx.o
[19/80] Building CXX object _deps/minu...Files/Minuit2.dir/LaInnerProduct.cxx.o
[19/80] Building CXX object _deps/minu...eFiles/Minuit2.dir/MnApplication.cxx.o
[20/80] Building CXX object _deps/minu...Files/Minuit2.dir/LaOuterProduct.cxx.o
[20/80] Building CXX object _deps/minu...MakeFiles/Minuit2.dir/MnContours.cxx.o
[21/80] Building CXX object _deps/minu...les/Minuit2.dir/LaVtMVSimilarity.cxx.o
[21/80] Building CXX object _deps/minu.../Minuit2.dir/MnCovarianceSqueeze.cxx.o
[22/80] Building CXX object _deps/minu...MakeFiles/Minuit2.dir/MPIProcess.cxx.o
[22/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/MnEigen.cxx.o
[23/80] Building CXX object _deps/minu...Files/Minuit2.dir/MinimumBuilder.cxx.o
[23/80] Building CXX object _deps/minu...src/CMakeFiles/Minuit2.dir/MnFcn.cxx.o
[24/80] Building CXX object _deps/minu...src/CMakeFiles/Minuit2.dir/MnFcn.cxx.o
[24/80] Building CXX object _deps/minu...les/Minuit2.dir/MnFumiliMinimize.cxx.o
[25/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/MnEigen.cxx.o
[25/80] Building CXX object _deps/minu...iles/Minuit2.dir/MnFunctionCross.cxx.o
[26/80] Building CXX object _deps/minu.../Minuit2.dir/MnCovarianceSqueeze.cxx.o
[26/80] Building CXX object _deps/minu...it2.dir/MnGlobalCorrelationCoeff.cxx.o
[27/80] Building CXX object _deps/minu...eFiles/Minuit2.dir/MnApplication.cxx.o
[27/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/MnHesse.cxx.o
[28/80] Building CXX object _deps/minu...MakeFiles/Minuit2.dir/MnContours.cxx.o
[28/80] Building CXX object _deps/minu...keFiles/Minuit2.dir/MnLineSearch.cxx.o
[29/80] Building CXX object _deps/minu...it2.dir/MnGlobalCorrelationCoeff.cxx.o
[29/80] Building CXX object _deps/minu...s/Minuit2.dir/MnMachinePrecision.cxx.o
[30/80] Building CXX object _deps/minu...les/Minuit2.dir/MnFumiliMinimize.cxx.o
[30/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/MnMinos.cxx.o
[31/80] Building CXX object _deps/minu...les/Minuit2.dir/Minuit2Minimizer.cxx.o
[31/80] Building CXX object _deps/minu...es/Minuit2.dir/MnParabolaFactory.cxx.o
[32/80] Building CXX object _deps/minu...s/Minuit2.dir/MnMachinePrecision.cxx.o
[32/80] Building CXX object _deps/minu...iles/Minuit2.dir/MnParameterScan.cxx.o
[33/80] Building CXX object _deps/minu...es/Minuit2.dir/MnParabolaFactory.cxx.o
[33/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/MnPlot.cxx.o
[34/80] Building CXX object _deps/minu...iles/Minuit2.dir/MnFunctionCross.cxx.o
[34/80] Building CXX object _deps/minu.../CMakeFiles/Minuit2.dir/MnPosDef.cxx.o
[35/80] Building CXX object _deps/minu...keFiles/Minuit2.dir/MnLineSearch.cxx.o
[35/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/MnPrint.cxx.o
[36/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/MnPlot.cxx.o
[36/80] Building CXX object _deps/minu...akeFiles/Minuit2.dir/MnPrintImpl.cxx.o
[37/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/MnHesse.cxx.o
[37/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/MnScan.cxx.o
[38/80] Building CXX object _deps/minu...akeFiles/Minuit2.dir/MnPrintImpl.cxx.o
[38/80] Building CXX object _deps/minu...iles/Minuit2.dir/MnSeedGenerator.cxx.o
[39/80] Building CXX object _deps/minu...iles/Minuit2.dir/MnParameterScan.cxx.o
[39/80] Building CXX object _deps/minu...MakeFiles/Minuit2.dir/MnStrategy.cxx.o
[40/80] Building CXX object _deps/minu...MakeFiles/Minuit2.dir/MnStrategy.cxx.o
[40/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/MnTiny.cxx.o
[41/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/MnTiny.cxx.o
[41/80] Building CXX object _deps/minu...eFiles/Minuit2.dir/MnTraceObject.cxx.o
[42/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/MnMinos.cxx.o
[42/80] Building CXX object _deps/minu...CMakeFiles/Minuit2.dir/MnUserFcn.cxx.o
[43/80] Building CXX object _deps/minu.../CMakeFiles/Minuit2.dir/MnPosDef.cxx.o
[43/80] Building CXX object _deps/minu...Minuit2.dir/MnUserParameterState.cxx.o
[44/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/MnScan.cxx.o
[44/80] Building CXX object _deps/minu...les/Minuit2.dir/MnUserParameters.cxx.o
[45/80] Building CXX object _deps/minu...CMakeFiles/Minuit2.dir/MnUserFcn.cxx.o
[45/80] Building CXX object _deps/minu...Minuit2.dir/MnUserTransformation.cxx.o
[46/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/MnPrint.cxx.o
[46/80] Building CXX object _deps/minu...it2.dir/ModularFunctionMinimizer.cxx.o
[47/80] Building CXX object _deps/minu...eFiles/Minuit2.dir/MnTraceObject.cxx.o
[47/80] Building CXX object _deps/minu...Minuit2.dir/NegativeG2LineSearch.cxx.o
[48/80] Building CXX object _deps/minu...iles/Minuit2.dir/MnSeedGenerator.cxx.o
[48/80] Building CXX object _deps/minu...ir/Numerical2PGradientCalculator.cxx.o
[49/80] Building CXX object _deps/minu...les/Minuit2.dir/MnUserParameters.cxx.o
[49/80] Building CXX object _deps/minu...s/Minuit2.dir/ParametricFunction.cxx.o
[50/80] Building CXX object _deps/minu...Minuit2.dir/MnUserParameterState.cxx.o
[50/80] Building CXX object _deps/minu...akeFiles/Minuit2.dir/ScanBuilder.cxx.o
[51/80] Building CXX object _deps/minu...it2.dir/ModularFunctionMinimizer.cxx.o
[51/80] Building CXX object _deps/minu...Files/Minuit2.dir/SimplexBuilder.cxx.o
[52/80] Building CXX object _deps/minu...Minuit2.dir/MnUserTransformation.cxx.o
[52/80] Building CXX object _deps/minu...es/Minuit2.dir/SimplexParameters.cxx.o
[53/80] Building CXX object _deps/minu...Minuit2.dir/NegativeG2LineSearch.cxx.o
[53/80] Building CXX object _deps/minu...Minuit2.dir/SimplexSeedGenerator.cxx.o
[54/80] Building CXX object _deps/minu...s/Minuit2.dir/ParametricFunction.cxx.o
[54/80] Building CXX object _deps/minu...2.dir/SinParameterTransformation.cxx.o
[55/80] Building CXX object _deps/minu...ir/Numerical2PGradientCalculator.cxx.o
[55/80] Building CXX object _deps/minu...r/SqrtLowParameterTransformation.cxx.o
[56/80] Building CXX object _deps/minu...2.dir/SinParameterTransformation.cxx.o
[56/80] Building CXX object _deps/minu...ir/SqrtUpParameterTransformation.cxx.o
[57/80] Building CXX object _deps/minu...es/Minuit2.dir/SimplexParameters.cxx.o
[57/80] Building CXX object _deps/minu...inuit2.dir/VariableMetricBuilder.cxx.o
[58/80] Building CXX object _deps/minu...akeFiles/Minuit2.dir/ScanBuilder.cxx.o
[58/80] Building CXX object _deps/minu...2.dir/VariableMetricEDMEstimator.cxx.o
[59/80] Building CXX object _deps/minu...r/SqrtLowParameterTransformation.cxx.o
[59/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/mnbins.cxx.o
[60/80] Building CXX object _deps/minu...ir/SqrtUpParameterTransformation.cxx.o
[60/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/mndasum.cxx.o
[61/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/mnbins.cxx.o
[61/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/mndaxpy.cxx.o
[62/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/mndaxpy.cxx.o
[62/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/mnddot.cxx.o
[63/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/mnddot.cxx.o
[63/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/mndscal.cxx.o
[64/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/mndasum.cxx.o
[64/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/mndspmv.cxx.o
[65/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/mndscal.cxx.o
[65/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/mndspr.cxx.o
[66/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/mndspmv.cxx.o
[66/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/mnlsame.cxx.o
[67/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/mndspr.cxx.o
[67/80] Building CXX object _deps/minu.../CMakeFiles/Minuit2.dir/mnteigen.cxx.o
[68/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/mnlsame.cxx.o
[68/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/mntplot.cxx.o
[69/80] Building CXX object _deps/minu...Files/Minuit2.dir/SimplexBuilder.cxx.o
[69/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/mnvert.cxx.o
[70/80] Building CXX object _deps/minu.../CMakeFiles/Minuit2.dir/mnteigen.cxx.o
[70/80] Building CXX object _deps/minu.../CMakeFiles/Minuit2.dir/mnxerbla.cxx.o
[71/80] Building CXX object _deps/minu...c/CMakeFiles/Minuit2.dir/mntplot.cxx.o
[71/80] Linking CXX static library _deps/minuit2-build/src/math/libMinuit2Math.a
[72/80] Building CXX object _deps/minu...2.dir/VariableMetricEDMEstimator.cxx.o
[72/80] Building CXX object CMakeFiles/simpleminuit.dir/simpleminuit.cpp.o
[73/80] Building CXX object _deps/minu...Minuit2.dir/SimplexSeedGenerator.cxx.o
[74/80] Linking CXX static library _deps/minuit2-build/src/math/libMinuit2Math.a
[75/80] Building CXX object _deps/minu.../CMakeFiles/Minuit2.dir/mnxerbla.cxx.o
[76/80] Building CXX object _deps/minu...rc/CMakeFiles/Minuit2.dir/mnvert.cxx.o
[77/80] Building CXX object CMakeFiles/simpleminuit.dir/simpleminuit.cpp.o
[78/80] Building CXX object _deps/minu...inuit2.dir/VariableMetricBuilder.cxx.o
[78/80] Linking CXX static library _deps/minuit2-build/src/libMinuit2.a
[79/80] Linking CXX static library _deps/minuit2-build/src/libMinuit2.a
[79/80] Linking CXX executable simpleminuit
[80/80] Linking CXX executable simpleminuit
!./build/simpleminuit
val = 1
val = 1.001
val = 0.999
val = 1.0006
val = 0.999402
val = -8.23008e-11
val = 0.000345267
val = -0.000345267
val = -8.23008e-11
val = 0.000345267
val = -0.000345267
val = 6.90533e-05
val = -6.90535e-05
  Valid         : yes
  Function calls: 13
  Minimum value : 6.773427082e-21
  Edm           : 6.773427082e-21
  Internal parameters: 
 -8.230083282e-11
  Internal covariance matrix: 
              1
  External parameters: 
  Pos |    Name    |  type   |      Value       |    Error +/-
    0 |          x |  free   | -8.230083282e-11 | 0.7071067812
Step 3: Bind parts we need#
- subclassable FCNBase 
- MnUserParameters (constructor and - Add(string, double, double))
- MnMigrad (constructor and operator()) 
- FunctionMinimum (cout) 
%mkdir src
Recommended structure of a Pybind11 program#
main.cpp#
- Builds module 
- Avoids imports (fast compile) 
include <pybind11/pybind11.h>
namespace py = pybind11;
void init_part1(py::module &);
void init_part2(py::module &);
PYBIND11_MODULE(mymodule, m) {
    m.doc() = "Real code would never have such poor documentation...";
    init_part1(m);
    init_part2(m);
}
%%writefile src/pyminuit2.cpp
#include <pybind11/pybind11.h>
namespace py = pybind11;
void init_FCNBase(py::module &);
void init_MnUserParameters(py::module &);
void init_MnMigrad(py::module &);
void init_FunctionMinimum(py::module &);
PYBIND11_MODULE(minuit2, m) {
    init_FCNBase(m);
    init_MnUserParameters(m);
    init_MnMigrad(m);
    init_FunctionMinimum(m);
}
Writing src/pyminuit2.cpp
We will put all headers in a collective header (not a good idea unless you are trying to show files one per slide).
%%writefile src/PyHeader.h
#pragma once
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
#include <Minuit2/FCNBase.h>
#include <Minuit2/MnMigrad.h>
#include <Minuit2/MnApplication.h>
#include <Minuit2/MnUserParameters.h>
#include <Minuit2/FunctionMinimum.h>
namespace py = pybind11;
using namespace pybind11::literals;
using namespace ROOT::Minuit2;
Writing src/PyHeader.h
Overloads#
- Pure virtual methods cannot be instantiated in C++ 
- Have to provide “Trampoline class” to provide Python class 
%%writefile src/FCNBase.cpp
#include "PyHeader.h"
class PyFCNBase : public FCNBase {
   public:
     using FCNBase::FCNBase;
     double operator()(const std::vector<double> &v) const override {
         PYBIND11_OVERLOAD_PURE_NAME(
             double, FCNBase, "__call__", operator(), v);}
     double Up() const override {
         PYBIND11_OVERLOAD_PURE(double, FCNBase, Up, );}
 };
void init_FCNBase(py::module &m) {
    py::class_<FCNBase, PyFCNBase>(m, "FCNBase")
         .def(py::init<>())
         .def("__call__", &FCNBase::operator())
         .def("Up", &FCNBase::Up);
}
Writing src/FCNBase.cpp
Overloaded function signatures:#
- C++11 syntax: - (bool (MnUserParameters::*)(const std::string &, double)) &MnUserParameters::Add
- C++14 syntax: - py::overload_cast<const std::string &, double>(&MnUserParameters::Add)
%%writefile src/MnUserParameters.cpp
#include "PyHeader.h"
void init_MnUserParameters(py::module &m) {
    py::class_<MnUserParameters>(m, "MnUserParameters")
        .def(py::init<>())
        .def("Add", (bool (MnUserParameters::*)(const std::string &, double)) &MnUserParameters::Add)
        .def("Add", (bool (MnUserParameters::*)(const std::string &, double, double)) &MnUserParameters::Add)
    ;
}
Writing src/MnUserParameters.cpp
Adding default arguments (and named arguments)#
- Using - ""_aliteral, names and even defaults can be added
%%writefile src/MnMigrad.cpp
#include "PyHeader.h"
        
void init_MnMigrad(py::module &m) {
    py::class_<MnApplication>(m, "MnApplication")
        .def("__call__",
             &MnApplication::operator(),
             "Minimize the function, returns a function minimum",
             py::arg("maxfcn")    = 0,
             "tolerance"_a = 0.1);
    
    py::class_<MnMigrad, MnApplication>(m, "MnMigrad")
        .def(py::init<const FCNBase &, const MnUserParameters &, unsigned int>(),
             "fcn"_a, "par"_a, "stra"_a = 1)
    ;
}    
Writing src/MnMigrad.cpp
Lambda functions#
- Pybind11 accepts lambda functions, as well 
%%writefile src/FunctionMinimum.cpp
#include "PyHeader.h"
#include <sstream>
#include <Minuit2/MnPrint.h>
void init_FunctionMinimum(py::module &m) {
    py::class_<FunctionMinimum>(m, "FunctionMinimum")
        .def("__str__", [](const FunctionMinimum &self) {
            std::stringstream os;
            os << self;
            return os.str();
        })
    ;
}
Writing src/FunctionMinimum.cpp
%%writefile CMakeLists.txt
cmake_minimum_required(VERSION 3.18...3.25)
project(Minuit2SimpleExamle LANGUAGES CXX)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
include(FetchContent)
FetchContent_Declare(
  minuit2
  URL           https://github.com/root-project/root/archive/refs/tags/v6-26-10.tar.gz
  URL_HASH      SHA256=a84ed095252614c6e2084987fce9ce4a5a62057bfd5a4a2725123ca9f60f674f
  SOURCE_SUBDIR math/minuit2
  DOWNLOAD_NO_PROGRESS
  EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(minuit2)
set(PYBIND11_FINDPYTHON ON)
find_package(pybind11)
file(GLOB OUTPUT src/*.cpp)
pybind11_add_module(minuit2 ${OUTPUT})
target_link_libraries(minuit2 PUBLIC Minuit2::Minuit2)
install(TARGETS minuit2 DESTINATION .)
Overwriting CMakeLists.txt
We can use this CMakeLists from scikit-build-core:
%%writefile pyproject.toml
[build-system]
requires = ["scikit-build-core>=0.8", "pybind11>=2.10"]
build-backend = "scikit_build_core.build"
[project]
name = "minuit2"
version = "6.26.10"
Writing pyproject.toml
!{sys.executable} -m pip wheel . -v
Processing /home/runner/work/se-for-sci.github.io/se-for-sci.github.io/content/week10_binding/03-pybind
  Running command pip subprocess to install build dependencies
  Using pip 24.2 from /home/runner/work/se-for-sci.github.io/se-for-sci.github.io/.pixi/envs/default/lib/python3.12/site-packages/pip (python 3.12)
  Collecting scikit-build-core>=0.8
    Obtaining dependency information for scikit-build-core>=0.8 from https://files.pythonhosted.org/packages/43/49/ec16b3db6893db788ae35f98506ff5a9c25dca7eb18cc38ada8a4c1dc944/scikit_build_core-0.11.6-py3-none-any.whl.metadata
    Downloading scikit_build_core-0.11.6-py3-none-any.whl.metadata (18 kB)
  Collecting pybind11>=2.10
    Obtaining dependency information for pybind11>=2.10 from https://files.pythonhosted.org/packages/cd/8a/37362fc2b949d5f733a8b0f2ff51ba423914cabefe69f1d1b6aab710f5fe/pybind11-3.0.1-py3-none-any.whl.metadata
    Downloading pybind11-3.0.1-py3-none-any.whl.metadata (10.0 kB)
  Collecting packaging>=23.2 (from scikit-build-core>=0.8)
    Obtaining dependency information for packaging>=23.2 from https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl.metadata
    Downloading packaging-25.0-py3-none-any.whl.metadata (3.3 kB)
  Collecting pathspec>=0.10.1 (from scikit-build-core>=0.8)
    Obtaining dependency information for pathspec>=0.10.1 from https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl.metadata
    Downloading pathspec-0.12.1-py3-none-any.whl.metadata (21 kB)
  Downloading scikit_build_core-0.11.6-py3-none-any.whl (185 kB)
  Downloading pybind11-3.0.1-py3-none-any.whl (293 kB)
  Downloading packaging-25.0-py3-none-any.whl (66 kB)
  Downloading pathspec-0.12.1-py3-none-any.whl (31 kB)
  Installing collected packages: pybind11, pathspec, packaging, scikit-build-core
    Creating /tmp/pip-build-env-ijogfbb3/overlay/bin
    changing mode of /tmp/pip-build-env-ijogfbb3/overlay/bin/pybind11-config to 755
  Successfully installed packaging-25.0 pathspec-0.12.1 pybind11-3.0.1 scikit-build-core-0.11.6
  Installing build dependencies ... ?25l?25hdone
  Running command Getting requirements to build wheel
  Getting requirements to build wheel ... ?25l?25hdone
  Running command Preparing metadata (pyproject.toml)
  *** scikit-build-core 0.11.6 using CMake 3.31.6 (metadata_wheel)
  Preparing metadata (pyproject.toml) ... ?25l?25hdone
Building wheels for collected packages: minuit2
  Running command Building wheel for minuit2 (pyproject.toml)
  *** scikit-build-core 0.11.6 using CMake 3.31.6 (wheel)
  *** Configuring CMake...
  loading initial cache file /tmp/tmpykk9u13u/build/CMakeInit.txt
  -- The CXX compiler identification is GNU 13.3.0
  -- Detecting CXX compiler ABI info
  -- Detecting CXX compiler ABI info - done
  -- Check for working CXX compiler: /usr/bin/g++ - skipped
  -- Detecting CXX compile features
  -- Detecting CXX compile features - done
  CMake Deprecation Warning at /tmp/tmpykk9u13u/build/_deps/minuit2-src/math/minuit2/CMakeLists.txt:7 (cmake_minimum_required):
    Compatibility with CMake < 3.10 will be removed from a future version of
    CMake.
    Update the VERSION argument <min> value.  Or, use the <min>...<max> syntax
    to tell CMake that the project requires at least <min> but has been updated
    to work with policies introduced by <max> or earlier.
  
  CMake Deprecation Warning at /tmp/tmpykk9u13u/build/_deps/minuit2-src/math/minuit2/StandAlone.cmake:1 (cmake_minimum_required):
    Compatibility with CMake < 3.10 will be removed from a future version of
    CMake.
    Update the VERSION argument <min> value.  Or, use the <min>...<max> syntax
    to tell CMake that the project requires at least <min> but has been updated
    to work with policies introduced by <max> or earlier.
  Call Stack (most recent call first):
    /tmp/tmpykk9u13u/build/_deps/minuit2-src/math/minuit2/CMakeLists.txt:250 (include)
  
  -- Found Python: /home/runner/work/se-for-sci.github.io/se-for-sci.github.io/.pixi/envs/default/bin/python (found suitable version "3.12.7", minimum required is "3.7") found components: Interpreter Development.Module Development.Embed
  -- Performing Test HAS_FLTO
  -- Performing Test HAS_FLTO - Success
  -- Found pybind11: /home/runner/work/se-for-sci.github.io/se-for-sci.github.io/.pixi/envs/default/lib/python3.12/site-packages/pybind11/include (found version "2.13.6")
  -- Configuring done (17.6s)
  -- Generating done (0.0s)
  -- Build files have been written to: /tmp/tmpykk9u13u/build
  *** Building project with Ninja...
  [1/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/DavidonErrorUpdator.cxx.o
  [2/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/AnalyticalGradientCalculator.cxx.o
  [3/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/BFGSErrorUpdator.cxx.o
  [4/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/CombinedMinimumBuilder.cxx.o
  [5/84] Building CXX object _deps/minuit2-build/src/math/CMakeFiles/Minuit2Math.dir/__/__/__/minuit2-src/math/mathcore/src/MinimizerOptions.cxx.o
  [6/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/ExternalInternalGradientCalculator.cxx.o
  [7/84] Building CXX object _deps/minuit2-build/src/math/CMakeFiles/Minuit2Math.dir/__/__/__/minuit2-src/math/mathcore/src/GenAlgoOptions.cxx.o
  [8/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/FumiliErrorUpdator.cxx.o
  [9/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/FumiliGradientCalculator.cxx.o
  [10/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/FumiliStandardChi2FCN.cxx.o
  [11/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/FumiliStandardMaximumLikelihoodFCN.cxx.o
  [12/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/LaEigenValues.cxx.o
  [13/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/FumiliMinimizer.cxx.o
  [14/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/HessianGradientCalculator.cxx.o
  [15/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/LaInverse.cxx.o
  [16/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/LaInnerProduct.cxx.o
  [17/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/LaOuterProduct.cxx.o
  [18/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/InitialGradientCalculator.cxx.o
  [19/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/LaSumOfElements.cxx.o
  [20/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/LaVtMVSimilarity.cxx.o
  [21/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/FumiliBuilder.cxx.o
  [22/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MinimumBuilder.cxx.o
  [23/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MPIProcess.cxx.o
  [24/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnEigen.cxx.o
  [25/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnFcn.cxx.o
  [26/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnCovarianceSqueeze.cxx.o
  [27/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnApplication.cxx.o
  [28/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnFumiliMinimize.cxx.o
  [29/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnGlobalCorrelationCoeff.cxx.o
  [30/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnMachinePrecision.cxx.o
  [31/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnContours.cxx.o
  [32/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnParabolaFactory.cxx.o
  [33/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnLineSearch.cxx.o
  [34/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnPlot.cxx.o
  [35/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/Minuit2Minimizer.cxx.o
  [36/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnParameterScan.cxx.o
  [37/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnFunctionCross.cxx.o
  [38/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnHesse.cxx.o
  [39/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnPrintImpl.cxx.o
  [40/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnStrategy.cxx.o
  [41/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnTiny.cxx.o
  [42/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnScan.cxx.o
  [43/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnPosDef.cxx.o
  [44/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnMinos.cxx.o
  [45/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnPrint.cxx.o
  [46/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnUserFcn.cxx.o
  [47/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnTraceObject.cxx.o
  [48/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnUserParameters.cxx.o
  [49/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnSeedGenerator.cxx.o
  [50/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnUserParameterState.cxx.o
  [51/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/ModularFunctionMinimizer.cxx.o
  [52/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/NegativeG2LineSearch.cxx.o
  [53/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/SimplexParameters.cxx.o
  [54/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/Numerical2PGradientCalculator.cxx.o
  [55/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/ParametricFunction.cxx.o
  [56/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/MnUserTransformation.cxx.o
  [57/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/SinParameterTransformation.cxx.o
  [58/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/SqrtLowParameterTransformation.cxx.o
  [59/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/SqrtUpParameterTransformation.cxx.o
  [60/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/mnbins.cxx.o
  [61/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/ScanBuilder.cxx.o
  [62/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/VariableMetricEDMEstimator.cxx.o
  [63/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/mndaxpy.cxx.o
  [64/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/mndscal.cxx.o
  [65/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/mndasum.cxx.o
  [66/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/mnddot.cxx.o
  [67/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/mnlsame.cxx.o
  [68/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/mndspr.cxx.o
  [69/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/SimplexSeedGenerator.cxx.o
  [70/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/SimplexBuilder.cxx.o
  [71/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/mndspmv.cxx.o
  [72/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/mntplot.cxx.o
  [73/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/mnteigen.cxx.o
  [74/84] Linking CXX static library _deps/minuit2-build/src/math/libMinuit2Math.a
  [75/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/mnvert.cxx.o
  [76/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/mnxerbla.cxx.o
  [77/84] Building CXX object _deps/minuit2-build/src/CMakeFiles/Minuit2.dir/VariableMetricBuilder.cxx.o
  [78/84] Linking CXX static library _deps/minuit2-build/src/libMinuit2.a
  [79/84] Building CXX object CMakeFiles/minuit2.dir/src/pyminuit2.cpp.o
  [80/84] Building CXX object CMakeFiles/minuit2.dir/src/FunctionMinimum.cpp.o
  [81/84] Building CXX object CMakeFiles/minuit2.dir/src/MnMigrad.cpp.o
  [82/84] Building CXX object CMakeFiles/minuit2.dir/src/FCNBase.cpp.o
  [83/84] Building CXX object CMakeFiles/minuit2.dir/src/MnUserParameters.cpp.o
  [84/84] Linking CXX shared module minuit2.cpython-312-x86_64-linux-gnu.so
  lto-wrapper: warning: using serial compilation of 3 LTRANS jobs
  lto-wrapper: note: see the ‘-flto’ option documentation for more information
  *** Installing project into wheel...
  -- Install configuration: "Release"
  -- Installing: /tmp/tmpykk9u13u/wheel/platlib/./minuit2.cpython-312-x86_64-linux-gnu.so
  *** Making wheel...
  *** Created minuit2-6.26.10-cp312-cp312-linux_x86_64.whl
  Building wheel for minuit2 (pyproject.toml) ... ?25l?25hdone
  Created wheel for minuit2: filename=minuit2-6.26.10-cp312-cp312-linux_x86_64.whl size=251184 sha256=d296cc9edf9da6a84e9d4802abeee5d44ba41388efb4320d5464bf667c9c8bb0
  Stored in directory: /home/runner/.cache/pip/wheels/6b/65/d8/dba35df6777745515982ab3c8abb2003221c17f8e6181cd6a1
Successfully built minuit2
Usage#
We can now use our module! We’ll just grab the file we need out of the wheel instead of installing it:
import zipfile
from pathlib import Path
with zipfile.ZipFile(*Path.cwd().glob("minuit2-6.26.10-*.whl")) as f:
    for member in f.filelist:
        print(member.filename)
        if member.filename.startswith("minuit2."):
            f.extract(member, ".")
minuit2.cpython-312-x86_64-linux-gnu.so
minuit2-6.26.10.dist-info/METADATA
minuit2-6.26.10.dist-info/WHEEL
minuit2-6.26.10.dist-info/RECORD
import minuit2
class SimpleFCN(minuit2.FCNBase):
    def Up(self):
        return 0.5
    def __call__(self, v):
        print("val =", v[0])
        return v[0] ** 2
fcn = SimpleFCN()
upar = minuit2.MnUserParameters()
upar.Add("x", 1.0, 0.1)
migrad = minuit2.MnMigrad(fcn, upar)
minimum = migrad()
val = 1.0
val = 1.001
val = 0.999
val = 1.0005980198587356
val = 0.9994019801412644
val = -8.230083281546285e-11
val = 0.00034526688527999595
val = -0.0003452670498816616
val = -8.230083281546285e-11
val = 0.00034526688527999595
val = -0.0003452670498816616
val = 6.905331121533294e-05
val = -6.905347581699857e-05
print(minimum)
  Valid         : yes
  Function calls: 13
  Minimum value : 6.773427082e-21
  Edm           : 6.773427082e-21
  Internal parameters: 
 -8.230083282e-11
  Internal covariance matrix: 
              1
  External parameters: 
  Pos |    Name    |  type   |      Value       |    Error +/-
    0 |          x |  free   | -8.230083282e-11 | 0.7071067812
Done#
- See GooFit’s built in Minuit2 bindings for a more complete example 
- Pybind11 bindings can talk to each other at the C level! 
