Commit 9fbfa1943320350726995817fbf3050e2a51e833

Authored by Jürgen Knödlseder
1 parent 8a8379e6

Add GPythonOptimizerFunction class (#2733)

ChangeLog
1   -2018-11-27
  1 +2018-12-12
2 2  
3 3 * Version 1.6.0 released
4 4 ========================
5 5  
6 6 Add support for Fermi/LAT P8V3 response functions
7 7 CTA background rates are now per ontime (#2758)
  8 + Add GPythonOptimizerFunction class (#2733)
8 9 Remove diffuse response cube caching (#2722)
9 10 Revise GCTAEdispCube::operator() interface and disable stacked response
10 11 cutting in true energy (#2721)
... ...
1 1 New Features and Important Changes in GammaLib 1.6.0
2 2  
3   -23 November 2018
  3 +12 December 2018
4 4  
5 5  
6 6 1. Introduction
... ... @@ -14,6 +14,7 @@ made since the last release of GammaLib.
14 14 The following classes have been added:
15 15 - GModelSpectralExponential
16 16 - GWcsARC
  17 +- GPythonOptimizerFunction
17 18 - GCTAResponseCache
18 19 - GCTAModelBackground
19 20 - GCTAModelSpatial
... ...
doc/source/admin/release_history/1.6.rst
... ... @@ -50,6 +50,8 @@ Improvements
50 50 ------------
51 51  
52 52 * Add support for Fermi/LAT P8V3 response functions
  53 +* [`2733 <https://cta-redmine.irap.omp.eu/issues/2733>`_] -
  54 + Add ``GPythonOptimizerFunction`` class
53 55 * [`2721 <https://cta-redmine.irap.omp.eu/issues/2721>`_] -
54 56 Revise ``GCTAEdispCube::operator()`` interface and disable stacked response
55 57 cutting in true energy
... ...
pyext/GPythonOptimizerFunction.i 0 → 100644
  1 +/***************************************************************************
  2 + * GPythonOptimizerFunction.i - Python optimizer function class *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2018 by Juergen Knoedlseder *
  5 + * ----------------------------------------------------------------------- *
  6 + * *
  7 + * This program is free software: you can redistribute it and/or modify *
  8 + * it under the terms of the GNU General Public License as published by *
  9 + * the Free Software Foundation, either version 3 of the License, or *
  10 + * (at your option) any later version. *
  11 + * *
  12 + * This program is distributed in the hope that it will be useful, *
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  15 + * GNU General Public License for more details. *
  16 + * *
  17 + * You should have received a copy of the GNU General Public License *
  18 + * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  19 + * *
  20 + ***************************************************************************/
  21 +/**
  22 + * @file GPythonOptimizerFunction.i
  23 + * @brief Python optimizer function class
  24 + * @author Juergen Knoedlseder
  25 + */
  26 +%{
  27 +/* Put headers and other declarations here that are needed for compilation */
  28 +#include "GOptimizerFunction.hpp"
  29 +#include "GTools.hpp"
  30 +#include "GVector.hpp"
  31 +#include "GMatrixSparse.hpp"
  32 +#include "GException.hpp"
  33 +
  34 +
  35 +/***********************************************************************//**
  36 + * @class GPythonException
  37 + *
  38 + * @brief Python exception
  39 + *
  40 + * This class implements a Python exception. It allows to catch any error
  41 + * message that occurs during function evaluation.
  42 + ***************************************************************************/
  43 +class GPythonException : public GExceptionHandler {
  44 +public:
  45 + class eval_error : public GExceptionHandler {
  46 + public:
  47 + eval_error(const std::string& origin) {
  48 +
  49 + // Set origin and default message
  50 + m_origin = origin;
  51 + m_message = "";
  52 +
  53 + // Set message
  54 + if (PyErr_Occurred()) {
  55 +
  56 + // Fetch error type, value and traceback
  57 + PyObject *type = 0;
  58 + PyObject *value = 0;
  59 + PyObject *traceback = 0;
  60 + PyErr_Fetch(&type, &value, &traceback);
  61 +
  62 + // Clear error message
  63 + PyErr_Clear();
  64 +
  65 + // Extract message strings
  66 + PyObject *py_type = PyObject_Str(type);
  67 + PyObject *py_value = PyObject_Str(value);
  68 + char *c_type = NULL;
  69 + char *c_value = NULL;
  70 + if (PyUnicode_Check(py_type)) {
  71 + PyObject* temp_bytes = PyUnicode_AsEncodedString(py_type,
  72 + "utf-8",
  73 + "Error ~");
  74 + if (temp_bytes != NULL) {
  75 + c_type = PyString_AsString(temp_bytes);
  76 + }
  77 + }
  78 + else if (py_type != NULL) {
  79 + c_type = PyString_AsString(py_type);
  80 + }
  81 + if (c_type != NULL) {
  82 + m_message += std::string(c_type);
  83 + m_message += "\n";
  84 + }
  85 + if (PyUnicode_Check(py_value)) {
  86 + PyObject* temp_bytes = PyUnicode_AsEncodedString(py_value,
  87 + "utf-8",
  88 + "Error ~");
  89 + if (temp_bytes != NULL) {
  90 + c_value = PyString_AsString(temp_bytes);
  91 + }
  92 + }
  93 + else if (py_value != NULL) {
  94 + c_value = PyString_AsString(py_value);
  95 + }
  96 + if (c_value != NULL) {
  97 + m_message += std::string(c_value);
  98 + }
  99 + Py_DECREF(py_type);
  100 + Py_DECREF(py_value);
  101 + }
  102 + }
  103 + };
  104 +};
  105 +
  106 +
  107 +/***********************************************************************//**
  108 + * @class GPythonOptimizerFunction
  109 + *
  110 + * @brief Python interface for optimizer function
  111 + *
  112 + * This class implements the call back for a Python optimizer function,
  113 + * allowing to use the GammaLib optimizer classes from within Python.
  114 + ***************************************************************************/
  115 +class GPythonOptimizerFunction : public GOptimizerFunction {
  116 +public:
  117 + // Constructor
  118 + GPythonOptimizerFunction(void) {
  119 + m_py_object = NULL;
  120 + m_value = 0.0;
  121 + m_gradient.clear();
  122 + m_curvature.clear();
  123 + m_pars.clear();
  124 + }
  125 +
  126 + // Destructor
  127 + virtual ~GPythonOptimizerFunction(void) {
  128 + if (m_py_object != NULL) {
  129 + Py_DECREF(m_py_object);
  130 + }
  131 + }
  132 +
  133 + // Evaluate Python function
  134 + void eval(const GOptimizerPars& pars) {
  135 +
  136 + // Store parameters
  137 + m_pars = pars;
  138 +
  139 + // Initialise value, gradient and curvature
  140 + int npars = pars.size();
  141 + if (npars < 1) {
  142 + npars = 1;
  143 + }
  144 +
  145 + // Initialise value, gradient vector and curvature matrix
  146 + m_value = 0.0;
  147 + m_gradient = GVector(npars);
  148 + m_curvature = GMatrixSparse(npars,npars);
  149 +
  150 + // Execute evaluation
  151 + PyObject* args = Py_BuildValue("()");
  152 + PyObject* func = static_cast<PyObject*>(m_py_object);
  153 + PyObject* res = PyEval_CallObject(func, args);
  154 + Py_DECREF(args);
  155 +
  156 + // Release result
  157 + if (res != NULL) {
  158 + Py_DECREF(res);
  159 + }
  160 + else {
  161 + throw GPythonException::eval_error("GPythonOptimizerFunction::eval");
  162 + }
  163 + }
  164 +
  165 + // Return value
  166 + double value(void) const {
  167 + return m_value;
  168 + }
  169 +
  170 + // Return gradient
  171 + GVector* gradient(void) {
  172 + return &m_gradient;
  173 + }
  174 +
  175 + // Return curvature
  176 + GMatrixSparse* curvature(void) {
  177 + return &m_curvature;
  178 + }
  179 +
  180 + // Return parameters
  181 + const GOptimizerPars& _pars(void) const {
  182 + return m_pars;
  183 + }
  184 +
  185 + // Set Python callback function
  186 + void _set_eval(PyObject* function) {
  187 + m_py_object = function;
  188 + Py_INCREF(function);
  189 + }
  190 +
  191 + // Set value
  192 + void _set_value(const double& value) {
  193 + m_value = value;
  194 + }
  195 +
  196 + // Callback information
  197 + PyObject* m_py_object; //!< Python callback function
  198 + double m_value; //!< Function value
  199 + GVector m_gradient; //!< Function gradient
  200 + GMatrixSparse m_curvature; //!< Function curvature
  201 + GOptimizerPars m_pars; //!< Current parameters
  202 +};
  203 +%}
  204 +
  205 +
  206 +/***********************************************************************//**
  207 + * @class GPythonOptimizerFunction
  208 + *
  209 + * @brief Optimizer class Python interface definition
  210 + ***************************************************************************/
  211 +class GPythonOptimizerFunction : public GOptimizerFunction {
  212 +public:
  213 + // Constructors and destructors
  214 + GPythonOptimizerFunction(void);
  215 + virtual ~GPythonOptimizerFunction(void);
  216 +
  217 + // Methods
  218 + void eval(const GOptimizerPars& pars);
  219 + double value(void) const;
  220 + GVector* gradient(void);
  221 + GMatrixSparse* curvature(void);
  222 +
  223 + // Protected methods
  224 + const GOptimizerPars& _pars(void) const;
  225 + void _set_eval(PyObject* function);
  226 + void _set_value(const double& value);
  227 +};
... ...
pyext/gammalib/opt.i
1 1 /***************************************************************************
2 2 * opt.i - Optimization module *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2011-2017 by Juergen Knoedlseder *
  4 + * copyright (C) 2011-2018 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -90,3 +90,4 @@
90 90 %include "GOptimizerPar.i"
91 91 %include "GOptimizerPars.i"
92 92 %include "GOptimizerFunction.i"
  93 +%include "GPythonOptimizerFunction.i"
... ...