1
/* Python TNC module */
4
* Copyright (c) 2004-2005, Jean-Sebastien Roy (js@jeannot.org)
6
* Permission is hereby granted, free of charge, to any person obtaining a
7
* copy of this software and associated documentation files (the
8
* "Software"), to deal in the Software without restriction, including
9
* without limitation the rights to use, copy, modify, merge, publish,
10
* distribute, sublicense, and/or sell copies of the Software, and to
11
* permit persons to whom the Software is furnished to do so, subject to
12
* the following conditions:
14
* The above copyright notice and this permission notice shall be included
15
* in all copies or substantial portions of the Software.
17
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
static char const rcsid[] =
27
"@(#) $Jeannot: moduleTNC.c,v 1.12 2005/01/28 18:27:31 js Exp $";
36
typedef struct _pytnc_state
38
PyObject *py_function;
43
static tnc_function function;
44
static PyObject *moduleTNC_minimize(PyObject *self, PyObject *args);
45
static int PyObject_AsDouble(PyObject *py_obj, double *x);
46
static double *PyList_AsDoubleArray(PyObject *py_list, int *size);
47
static PyObject *PyDoubleArray_AsList(int size, double *x);
48
static int PyList_IntoDoubleArray(PyObject *py_list, double *x, int size);
50
int PyObject_AsDouble(PyObject *py_obj, double *x)
54
py_float = PyNumber_Float(py_obj);
56
if (py_float == NULL) return -1;
58
*x = PyFloat_AsDouble(py_float);
64
double *PyList_AsDoubleArray(PyObject *py_list, int *size)
69
if (!PyList_Check(py_list))
75
*size = PyList_Size(py_list);
76
if (*size <= 0) return NULL;
77
x = malloc((*size)*sizeof(*x));
78
if (x == NULL) return NULL;
80
for (i=0; i<(*size); i++)
82
PyObject *py_float = PyList_GetItem(py_list, i);
83
if (py_float == NULL || PyObject_AsDouble(py_float, &(x[i])))
93
int PyList_IntoDoubleArray(PyObject *py_list, double *x, int size)
97
if (py_list == NULL) return 1;
99
if (!PyList_Check(py_list)) return 1;
101
if (size != PyList_Size(py_list)) return 1;
103
for (i=0; i<size; i++)
105
PyObject *py_float = PyList_GetItem(py_list, i);
106
if (py_float == NULL || PyObject_AsDouble(py_float, &(x[i])))
113
PyObject *PyDoubleArray_AsList(int size, double *x)
118
py_list = PyList_New(size);
119
if (py_list == NULL) return NULL;
121
for (i=0; i<size; i++)
124
py_float = PyFloat_FromDouble(x[i]);
125
if (py_float == NULL || PyList_SetItem(py_list, i, py_float))
135
static int function(double x[], double *f, double g[], void *state)
137
PyObject *py_list, *arglist, *py_grad, *result = NULL;
138
pytnc_state *py_state = (pytnc_state *)state;
140
py_list = PyDoubleArray_AsList(py_state->n, x);
143
PyErr_SetString(PyExc_MemoryError, "tnc: memory allocation failed.");
147
arglist = Py_BuildValue("(N)", py_list);
148
result = PyEval_CallObject(py_state->py_function, arglist);
154
if (result == Py_None)
160
if (!PyArg_ParseTuple(result, "dO!", f, &PyList_Type, &py_grad))
162
PyErr_SetString(PyExc_ValueError,
163
"tnc: invalid return value from minimized function.");
167
if (PyList_IntoDoubleArray(py_grad, g, py_state->n))
175
py_state->failed = 1;
180
PyObject *moduleTNC_minimize(PyObject *self, PyObject *args)
182
PyObject *py_x0, *py_low, *py_up, *py_list, *py_scale, *py_offset;
183
PyObject *py_function = NULL;
184
pytnc_state py_state;
185
int n, n1, n2, n3, n4;
187
int rc, msg, maxCGit, maxnfeval, nfeval = 0;
188
double *x, *low, *up, *scale = NULL, *offset = NULL;
189
double f, eta, stepmx, accuracy, fmin, ftol, xtol, pgtol, rescale;
191
if (!PyArg_ParseTuple(args, "OO!O!O!O!O!iiidddddddd",
193
&PyList_Type, &py_x0,
194
&PyList_Type, &py_low,
195
&PyList_Type, &py_up,
196
&PyList_Type, &py_scale,
197
&PyList_Type, &py_offset,
198
&msg, &maxCGit, &maxnfeval, &eta, &stepmx, &accuracy, &fmin, &ftol,
204
if (!PyCallable_Check(py_function))
206
PyErr_SetString(PyExc_TypeError, "tnc: function must be callable");
210
scale = PyList_AsDoubleArray(py_scale, &n3);
211
if (n3 != 0 && scale == NULL)
213
PyErr_SetString(PyExc_ValueError, "tnc: invalid scaling parameters.");
217
offset = PyList_AsDoubleArray(py_offset, &n4);
218
if (n4 != 0 && offset == NULL)
220
PyErr_SetString(PyExc_ValueError, "tnc: invalid offset parameters.");
224
x = PyList_AsDoubleArray(py_x0, &n);
225
if (n != 0 && x == NULL)
227
if (scale) free(scale);
229
PyErr_SetString(PyExc_ValueError, "tnc: invalid initial vector.");
233
low = PyList_AsDoubleArray(py_low, &n1);
234
up = PyList_AsDoubleArray(py_up, &n2);
236
if ((n1 != 0 && low == NULL) || (n2 != 0 && up == NULL))
238
if (scale) free(scale);
243
PyErr_SetString(PyExc_ValueError, "tnc: invalid bounds.");
247
if (n1 != n2 || n != n1 || (scale != NULL && n != n3)
248
|| (offset != NULL && n != n4))
250
if (scale) free(scale);
251
if (offset) free(offset);
256
PyErr_SetString(PyExc_ValueError, "tnc: vector sizes must be equal.");
260
py_state.py_function = py_function;
264
Py_INCREF(py_function);
266
rc = tnc(n, x, &f, NULL, function, &py_state, low, up, scale, offset, msg,
267
maxCGit, maxnfeval, eta, stepmx, accuracy, fmin, ftol, xtol, pgtol, rescale,
270
Py_DECREF(py_function);
274
if (scale) free(scale);
275
if (offset) free(offset);
283
if (rc == TNC_ENOMEM)
285
PyErr_SetString(PyExc_MemoryError, "tnc: memory allocation failed.");
290
py_list = PyDoubleArray_AsList(n, x);
294
PyErr_SetString(PyExc_MemoryError, "tnc: memory allocation failed.");
298
return Py_BuildValue("(iiN)", rc, nfeval, py_list);;
301
static PyMethodDef moduleTNC_methods[] =
303
{"minimize", moduleTNC_minimize, METH_VARARGS},
307
PyMODINIT_FUNC initmoduleTNC(void)
309
(void) Py_InitModule("moduleTNC", moduleTNC_methods);