3 //////////////////////////////////////////////////////////////////////////////
4 // Converting NLopt/C++ exceptions to Python exceptions
8 #define ExceptionSubclass(EXCNAME, EXCDOC) \
9 static PyTypeObject MyExc_ ## EXCNAME = { \
10 PyVarObject_HEAD_INIT(NULL, 0) \
12 sizeof(PyBaseExceptionObject), \
13 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
17 static void init_ ## EXCNAME(PyObject *m) { \
18 MyExc_ ## EXCNAME .tp_base = (PyTypeObject *) PyExc_Exception; \
19 PyType_Ready(&MyExc_ ## EXCNAME); \
20 Py_INCREF(&MyExc_ ## EXCNAME); \
21 PyModule_AddObject(m, # EXCNAME, (PyObject *) &MyExc_ ## EXCNAME); \
25 ExceptionSubclass(ForcedStop,
26 "Python version of nlopt::forced_stop exception.")
28 ExceptionSubclass(RoundoffLimited,
29 "Python version of nlopt::roundoff_limited exception.")
35 init_RoundoffLimited(m);
38 ForcedStop = _nlopt.ForcedStop
39 RoundoffLimited = _nlopt.RoundoffLimited
40 __version__ = str(_nlopt.version_major())+'.'+str(_nlopt.version_minor())+'.'+str(_nlopt.version_bugfix())
43 %typemap(throws) std::bad_alloc %{
44 PyErr_SetString(PyExc_MemoryError, ($1).what());
48 %typemap(throws) nlopt::forced_stop %{
49 if (!PyErr_Occurred())
50 PyErr_SetString((PyObject*)&MyExc_ForcedStop, "NLopt forced stop");
54 %typemap(throws) nlopt::roundoff_limited %{
55 PyErr_SetString((PyObject*)&MyExc_RoundoffLimited, "NLopt roundoff-limited");
59 //////////////////////////////////////////////////////////////////////////////
62 #define SWIG_FILE_WITH_INIT
63 #define array_stride(a,i) (((PyArrayObject *)a)->strides[i])
69 %numpy_typemaps(double, NPY_DOUBLE, unsigned)
71 //////////////////////////////////////////////////////////////////////////////
72 // numpy.i does not include maps for std::vector<double>, so I add them here,
73 // taking advantage of the conversion functions provided by numpy.i
75 // Typemap for input arguments of type const std::vector<double> &
76 %typecheck(SWIG_TYPECHECK_POINTER, fragment="NumPy_Macros")
77 const std::vector<double> &
79 $1 = is_array($input) || PySequence_Check($input);
81 %typemap(in, fragment="NumPy_Fragments")
82 const std::vector<double> &
83 (PyArrayObject* array=NULL, int is_new_object=0, std::vector<double> arrayv)
85 npy_intp size[1] = { -1 };
86 array = obj_to_array_allow_conversion($input, NPY_DOUBLE, &is_new_object);
87 if (!array || !require_dimensions(array, 1) ||
88 !require_size(array, size, 1)) SWIG_fail;
89 arrayv = std::vector<double>(array_size(array,0));
92 double *arr_data = (double *) array_data(array);
93 int arr_i, arr_s = array_stride(array,0) / sizeof(double);
94 int arr_sz = array_size(array,0);
95 for (arr_i = 0; arr_i < arr_sz; ++arr_i)
96 arrayv[arr_i] = arr_data[arr_i * arr_s];
100 const std::vector<double> &
102 if (is_new_object$argnum && array$argnum)
103 { Py_DECREF(array$argnum); }
106 // Typemap for return values of type std::vector<double>
107 %typemap(out, fragment="NumPy_Fragments") std::vector<double>
109 npy_intp sz = $1.size();
110 $result = PyArray_SimpleNew(1, &sz, NPY_DOUBLE);
111 std::memcpy(array_data($result), $1.empty() ? NULL : &$1[0],
112 sizeof(double) * sz);
115 //////////////////////////////////////////////////////////////////////////////
116 // Wrapper for objective function callbacks
119 static void *free_pyfunc(void *p) { Py_DECREF((PyObject*) p); return p; }
120 static void *dup_pyfunc(void *p) { Py_INCREF((PyObject*) p); return p; }
122 static double func_python(unsigned n, const double *x, double *grad, void *f)
124 npy_intp sz = npy_intp(n), sz0 = 0, stride1 = sizeof(double);
125 PyObject *xpy = PyArray_New(&PyArray_Type, 1, &sz, NPY_DOUBLE, &stride1,
126 const_cast<double*>(x), // not NPY_WRITEABLE
127 0, NPY_ARRAY_IN_ARRAY, NULL);
128 PyObject *gradpy = grad
129 ? PyArray_SimpleNewFromData(1, &sz, NPY_DOUBLE, grad)
130 : PyArray_SimpleNew(1, &sz0, NPY_DOUBLE);
132 PyObject *arglist = Py_BuildValue("OO", xpy, gradpy);
133 PyObject *result = PyEval_CallObject((PyObject *) f, arglist);
139 double val = HUGE_VAL;
140 if (PyErr_Occurred()) {
142 throw nlopt::forced_stop(); // just stop, don't call PyErr_Clear()
144 else if (result && PyFloat_Check(result)) {
145 val = PyFloat_AsDouble(result);
150 throw std::invalid_argument("invalid result passed to nlopt");
155 static void mfunc_python(unsigned m, double *result,
156 unsigned n, const double *x, double *grad, void *f)
158 npy_intp nsz = npy_intp(n), msz = npy_intp(m);
159 npy_intp mnsz[2] = {msz, nsz};
160 npy_intp sz0 = 0, stride1 = sizeof(double);
161 PyObject *xpy = PyArray_New(&PyArray_Type, 1, &nsz, NPY_DOUBLE, &stride1,
162 const_cast<double*>(x), // not NPY_WRITEABLE
163 0, NPY_ARRAY_IN_ARRAY, NULL);
164 PyObject *rpy = PyArray_SimpleNewFromData(1, &msz, NPY_DOUBLE, result);
165 PyObject *gradpy = grad
166 ? PyArray_SimpleNewFromData(2, mnsz, NPY_DOUBLE, grad)
167 : PyArray_SimpleNew(1, &sz0, NPY_DOUBLE);
169 PyObject *arglist = Py_BuildValue("OOO", rpy, xpy, gradpy);
170 PyObject *res = PyEval_CallObject((PyObject *) f, arglist);
178 if (PyErr_Occurred()) {
179 throw nlopt::forced_stop(); // just stop, don't call PyErr_Clear()
184 %typemap(in)(nlopt::func f, void *f_data, nlopt_munge md, nlopt_munge mc) {
186 $2 = dup_pyfunc((void*) $input);
190 %typecheck(SWIG_TYPECHECK_POINTER)(nlopt::func f, void *f_data, nlopt_munge md, nlopt_munge mc) {
191 $1 = PyCallable_Check($input);
194 %typemap(in)(nlopt::mfunc mf, void *f_data, nlopt_munge md, nlopt_munge mc) {
196 $2 = dup_pyfunc((void*) $input);
200 %typecheck(SWIG_TYPECHECK_POINTER)(nlopt::mfunc mf, void *f_data, nlopt_munge md, nlopt_munge mc) {
201 $1 = PyCallable_Check($input);