/***************************************************************************
* GPythonOptimizerFunction.i - Python optimizer function class *
* ----------------------------------------------------------------------- *
* copyright (C) 2018 by Juergen Knoedlseder *
* ----------------------------------------------------------------------- *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
* *
***************************************************************************/
/**
* @file GPythonOptimizerFunction.i
* @brief Python optimizer function class
* @author Juergen Knoedlseder
*/
%{
/* Put headers and other declarations here that are needed for compilation */
#include "GOptimizerFunction.hpp"
#include "GTools.hpp"
#include "GVector.hpp"
#include "GMatrixSparse.hpp"
#include "GException.hpp"
/***********************************************************************//**
* @class GPythonException
*
* @brief Python exception
*
* This class implements a Python exception. It allows to catch any error
* message that occurs during function evaluation.
***************************************************************************/
class GPythonException : public GExceptionHandler {
public:
class eval_error : public GExceptionHandler {
public:
eval_error(const std::string& origin) {
// Set origin and default message
m_origin = origin;
m_message = "";
// Set message
if (PyErr_Occurred()) {
// Fetch error type, value and traceback
PyObject *type = 0;
PyObject *value = 0;
PyObject *traceback = 0;
PyErr_Fetch(&type, &value, &traceback);
// Clear error message
PyErr_Clear();
// Extract message strings
PyObject *py_type = PyObject_Str(type);
PyObject *py_value = PyObject_Str(value);
char *c_type = NULL;
char *c_value = NULL;
if (PyUnicode_Check(py_type)) {
PyObject* temp_bytes = PyUnicode_AsEncodedString(py_type,
"utf-8",
"Error ~");
if (temp_bytes != NULL) {
c_type = PyString_AsString(temp_bytes);
}
}
else if (py_type != NULL) {
c_type = PyString_AsString(py_type);
}
if (c_type != NULL) {
m_message += std::string(c_type);
m_message += "\n";
}
if (PyUnicode_Check(py_value)) {
PyObject* temp_bytes = PyUnicode_AsEncodedString(py_value,
"utf-8",
"Error ~");
if (temp_bytes != NULL) {
c_value = PyString_AsString(temp_bytes);
}
}
else if (py_value != NULL) {
c_value = PyString_AsString(py_value);
}
if (c_value != NULL) {
m_message += std::string(c_value);
}
Py_DECREF(py_type);
Py_DECREF(py_value);
}
}
};
};
/***********************************************************************//**
* @class GPythonOptimizerFunction
*
* @brief Python interface for optimizer function
*
* This class implements the call back for a Python optimizer function,
* allowing to use the GammaLib optimizer classes from within Python.
***************************************************************************/
class GPythonOptimizerFunction : public GOptimizerFunction {
public:
// Constructor
GPythonOptimizerFunction(void) {
m_py_object = NULL;
m_value = 0.0;
m_gradient.clear();
m_curvature.clear();
m_pars.clear();
}
// Destructor
virtual ~GPythonOptimizerFunction(void) {
if (m_py_object != NULL) {
Py_DECREF(m_py_object);
}
}
// Evaluate Python function
void eval(const GOptimizerPars& pars) {
// Store parameters
m_pars = pars;
// Initialise value, gradient and curvature
int npars = pars.size();
if (npars < 1) {
npars = 1;
}
// Initialise value, gradient vector and curvature matrix
m_value = 0.0;
m_gradient = GVector(npars);
m_curvature = GMatrixSparse(npars,npars);
// Execute evaluation
PyObject* args = Py_BuildValue("()");
PyObject* func = static_cast(m_py_object);
PyObject* res = PyEval_CallObject(func, args);
Py_DECREF(args);
// Release result
if (res != NULL) {
Py_DECREF(res);
}
else {
throw GPythonException::eval_error("GPythonOptimizerFunction::eval");
}
}
// Return value
double value(void) const {
return m_value;
}
// Return gradient
GVector* gradient(void) {
return &m_gradient;
}
// Return curvature
GMatrixSparse* curvature(void) {
return &m_curvature;
}
// Return parameters
const GOptimizerPars& _pars(void) const {
return m_pars;
}
// Set Python callback function
void _set_eval(PyObject* function) {
m_py_object = function;
Py_INCREF(function);
}
// Set value
void _set_value(const double& value) {
m_value = value;
}
// Callback information
PyObject* m_py_object; //!< Python callback function
double m_value; //!< Function value
GVector m_gradient; //!< Function gradient
GMatrixSparse m_curvature; //!< Function curvature
GOptimizerPars m_pars; //!< Current parameters
};
%}
/***********************************************************************//**
* @class GPythonOptimizerFunction
*
* @brief Optimizer class Python interface definition
***************************************************************************/
class GPythonOptimizerFunction : public GOptimizerFunction {
public:
// Constructors and destructors
GPythonOptimizerFunction(void);
virtual ~GPythonOptimizerFunction(void);
// Methods
void eval(const GOptimizerPars& pars);
double value(void) const;
GVector* gradient(void);
GMatrixSparse* curvature(void);
// Protected methods
const GOptimizerPars& _pars(void) const;
void _set_eval(PyObject* function);
void _set_value(const double& value);
};