[go: up one dir, main page]

File: minimumstate.cpp

package info (click to toggle)
iminuit 2.30.1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 8,660 kB
  • sloc: cpp: 14,591; python: 11,177; makefile: 11; sh: 5
file content (115 lines) | stat: -rw-r--r-- 3,715 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "lasymmatrix.hpp"
#include "lavector.hpp"
#include <Minuit2/MinimumState.h>
#include <cmath>
#include <type_traits>

namespace py = pybind11;
using namespace ROOT::Minuit2;

py::tuple par2py(const MinimumParameters& pars) {
  return py::make_tuple(lavector2py(pars.Vec()), lavector2py(pars.Dirin()), pars.Fval(),
                        pars.IsValid(), pars.HasStepSize());
}

MinimumParameters py2par(py::tuple tp) {
  static_assert(std::is_standard_layout<MinimumParameters>(), "");

  struct Layout {
    MnAlgebraicVector fParameters;
    MnAlgebraicVector fStepSize;
    double fFVal;
    bool fValid;
    bool fHasStep;
  };

  MinimumParameters pars(py2lavector(tp[0]), py2lavector(tp[1]), tp[2].cast<double>());

  // evil workaround, will segfault or cause UB if source layout changes
  auto& ptr = reinterpret_cast<std::shared_ptr<Layout>&>(pars);
  auto d = ptr.get();
  d->fValid = tp[3].cast<bool>();
  d->fHasStep = tp[4].cast<bool>();

  return pars;
}

py::tuple err2py(const MinimumError& err) {
  return py::make_tuple(lasymmatrix2py(err.InvHessian()), err.Dcovar(),
                        static_cast<int>(err.GetStatus()));
}

MinimumError py2err(py::tuple tp) {
  auto status = static_cast<MinimumError::Status>(tp[2].cast<int>());
  if (status == MinimumError::MnPosDef)
    return MinimumError(py2lasymmatrix(tp[0]), tp[1].cast<double>());
  return MinimumError(py2lasymmatrix(tp[0]), status);
}

py::tuple grad2py(const FunctionGradient& g) {
  return py::make_tuple(lavector2py(g.Grad()), lavector2py(g.G2()),
                        lavector2py(g.Gstep()), g.IsValid(), g.IsAnalytical());
}

FunctionGradient py2grad(py::tuple tp) {
  const auto& gr = py2lavector(tp[0]);
  const auto& g2 = py2lavector(tp[1]);
  const auto& st = py2lavector(tp[2]);
  const auto& valid = tp[3].cast<bool>();
  const auto& analytical = tp[4].cast<bool>();

  if (valid) {
    if (analytical)
      return FunctionGradient{gr};
    else
      return FunctionGradient{gr, g2, st};
  }
  return FunctionGradient{gr.size()};
}

void bind_minimumstate(py::module m) {
  py::class_<MinimumState>(m, "MinimumState")

      .def(py::init<unsigned>())

      .def_property_readonly(
          "vec", [](const MinimumState& self) { return lavector2py(self.Vec()); })
      .def_property_readonly("fval", &MinimumState::Fval)
      .def_property_readonly("edm", &MinimumState::Edm)
      .def_property_readonly("nfcn", &MinimumState::NFcn)
      .def_property_readonly("is_valid", &MinimumState::IsValid)
      .def_property_readonly("has_parameters", &MinimumState::HasParameters)
      .def_property_readonly("has_covariance", &MinimumState::HasCovariance)

      .def(py::pickle(
          [](const MinimumState& self) {
            return py::make_tuple(par2py(self.Parameters()), err2py(self.Error()),
                                  grad2py(self.Gradient()), self.Edm(), self.NFcn());
          },
          [](py::tuple tp) {
            static_assert(std::is_standard_layout<MinimumState>(), "");

            struct Layout {
              MinimumParameters fParameters;
              MinimumError fError;
              FunctionGradient fGradient;
              double fEDM;
              int fNFcn;
            };

            MinimumState st{0};

            // evil workaround, will segfault or cause UB if source layout changes
            auto& ptr = reinterpret_cast<std::shared_ptr<Layout>&>(st);
            auto d = ptr.get();
            d->fParameters = py2par(tp[0]);
            d->fError = py2err(tp[1]);
            d->fGradient = py2grad(tp[2]);
            d->fEDM = tp[3].cast<double>();
            d->fNFcn = tp[4].cast<int>();

            return st;
          }))

      ;
}