18 #include <structmember.h>
26 #include "Fields/Interpolation/LeastSquaresSolveFactory.h"
28 #include "PyOpal/Globals.h"
29 #include "PyOpal/PySquarePolynomialMap.h"
30 #include "PyOpal/PyPolynomialCoefficient.h"
32 namespace PySquarePolynomialMap {
37 std::string(
"Return the coefficients of the matrix. Takes no arguments\n\n")+
38 std::string(
"Return value is a list of lists, with polynomial coefficients\n")+
39 std::string(
"for y_i = sum_j a_{ij}*prod_n(x_n^j_n) forming the i, j term\n")+
40 std::string(
"in the matrix.\n");
45 if (py_map ==
nullptr) {
46 PyErr_SetString(PyExc_TypeError,
47 "Failed to resolve self as PolynomialMap");
50 if (py_map->
map ==
nullptr) {
51 PyErr_SetString(PyExc_TypeError,
52 "PolynomialMap not properly initialised");
56 PyObject* py_coefficients = PyList_New(coefficients.
num_row());
58 for (
size_t i = 0; i < coefficients.
num_row(); ++i) {
59 PyObject* py_row = PyList_New(coefficients.
num_col());
60 for (
size_t j = 0; j < coefficients.
num_col(); ++j) {
61 PyObject* py_value = PyFloat_FromDouble(coefficients(i+1, j+1));
63 PyList_SetItem(py_row, j, py_value);
65 PyList_SetItem(py_coefficients, i, py_row);
68 Py_INCREF(py_coefficients);
69 return py_coefficients;
73 std::string(
"Maps from the matrix index to the polynomial term.\n\n")+
74 std::string(
" - col: index of the matrix column.\n")+
75 std::string(
" - dim: dimension of the problem.\n")+
76 std::string(
"Return value is a list of ints of length dim. Terms in the\n")+
77 std::string(
"transfer matrix in the column given by col correspond to the\n")+
78 std::string(
"coefficient of the x_j1^k1 ... x_jn^kn term where kn are the\n")+
79 std::string(
"integers returned by this method.\n")+
80 std::string(
"For example, PolynomialMap.index_by_power(5, 2) returns\n")+
81 std::string(
"[2, 1] meaning the 7th column in a two-dimensional problem\n")+
82 std::string(
"represents the coefficients of x_0^2 x_1^1\n");
85 PyObject*
index_by_power(PyObject *py_class, PyObject *args, PyObject *kwds) {
86 PyTypeObject* py_map_type =
reinterpret_cast<PyTypeObject*
>(py_class);
88 if (py_map_type ==
nullptr) {
89 PyErr_SetString(PyExc_TypeError,
90 "Failed to resolve self as PolynomialMapType");
96 static char *kwlist[] = {
97 const_cast<char*
>(
"col"),
98 const_cast<char*>(
"dim"),
101 if (!PyArg_ParseTupleAndKeywords(args, kwds,
"ii", kwlist, &col, &dim)) {
105 PyErr_SetString(PyExc_ValueError,
"col should be >= 0");
109 PyErr_SetString(PyExc_ValueError,
"dim should be > 0");
112 std::vector<int> powers =
114 PyObject* py_powers = PyList_New(powers.size());
115 Py_INCREF(py_powers);
116 for (
size_t i = 0; i < powers.size(); ++i) {
117 PyObject* py_one_power = PyLong_FromSize_t(powers[i]);
118 Py_INCREF(py_one_power);
119 PyList_SetItem(py_powers, i, py_one_power);
125 std::string(
"Apply the mapping to a point.\n\n")+
126 std::string(
" - point: list of floats with length equal to the point\n")+
127 std::string(
" dimension of the mapping, corresponding to the abscissa.\n")+
128 std::string(
"Return value is a list of floats, with length equal to the\n")+
129 std::string(
"value dimension of the mapping; corresponding to the ordinates\n");
131 PyObject*
evaluate(PyObject *
self, PyObject *args, PyObject *kwds) {
134 if (py_map ==
nullptr) {
135 PyErr_SetString(PyExc_TypeError,
136 "Failed to resolve self as PolynomialMap");
139 if (py_map->
map ==
nullptr) {
140 PyErr_SetString(PyExc_TypeError,
141 "PolynomialMap not properly initialised");
145 static char *kwlist[] = {
const_cast<char*
>(
"point"),
nullptr};
146 if (!PyArg_ParseTupleAndKeywords(args, kwds,
"O", kwlist, &py_point)) {
150 if (!PyList_Check(py_point)) {
151 PyErr_SetString(PyExc_TypeError,
"point was not a list");
155 PyErr_SetString(PyExc_TypeError,
"point had wrong size");
159 for (
size_t i = 0; i < point.size(); ++i) {
160 PyObject* point_i = PyList_GetItem(py_point, i);
161 point[i] = PyFloat_AsDouble(point_i);
163 if (PyErr_Occurred())
166 py_map->
map->
F(&point[0], &value[0]);
167 PyObject* py_value = PyList_New(value.size());
168 for (
size_t i = 0; i < value.size(); ++i) {
169 PyObject* value_i = PyFloat_FromDouble(value[i]);
170 PyList_SetItem(py_value, i, value_i);
178 std::string(
"Find a mapping by solving for the matrix.\n\n")+
179 std::string(
" - points: list, each entry containing a list of floats\n")+
180 std::string(
" corresponding to abscissa, each with length PointDimension.\n")+
181 std::string(
" The list should be as long as the number of coefficients in\n")+
182 std::string(
" the polynomial.\n")+
183 std::string(
" - values: list, each entry containing a list of floats\n")+
184 std::string(
" corresponding to ordinates, each with length ValueDimension.\n")+
185 std::string(
" The list should be as long as points.\n")+
186 std::string(
" - polynomial_order: integer, >= 0, corresponding to the\n")+
187 std::string(
" order of the fitted polynomial; 0 is constant, 1 is linear...\n")+
188 std::string(
"Returns a polynomial map.\n");
190 std::vector<std::vector<double> >
get_vectors(PyObject* py_floats) {
193 std::vector< std::vector<double> > data;
194 if (!PyList_Check(py_floats)) {
195 return std::vector<std::vector<double> >();
197 size_t num_rows = PyList_Size(py_floats);
199 return std::vector<std::vector<double> >();
203 for (
size_t i = 0; i < num_rows; ++i) {
204 PyObject* row = PyList_GetItem(py_floats, i);
205 if (!PyList_Check(row)) {
206 return std::vector<std::vector<double> >();
210 num_cols = PyList_Size(row);
212 return std::vector<std::vector<double> >();
214 data = std::vector< std::vector<double> >(num_rows, std::vector<double>(num_cols));
217 if (PyList_Size(row) != static_cast<int>(num_cols)) {
218 return std::vector<std::vector<double> >();
220 for (
size_t j = 0; j < num_cols; ++j) {
221 PyObject* py_value = PyList_GetItem(row, j);
222 data.at(i).at(j) = PyFloat_AsDouble(py_value);
223 if (PyErr_Occurred() !=
nullptr)
224 return std::vector<std::vector<double> >();
230 PyObject*
exact_solve(PyObject *py_class, PyObject *args, PyObject *kwds) {
231 PyTypeObject* py_map_type =
reinterpret_cast<PyTypeObject*
>(py_class);
233 if (py_map_type ==
nullptr) {
234 PyErr_SetString(PyExc_TypeError,
235 "Failed to resolve self as PolynomialMapType");
239 PyObject* py_points =
nullptr;
240 PyObject* py_values =
nullptr;
241 int polynomial_order = 0;
242 PyObject* py_error_matrix = Py_None;
243 static char *kwlist[] = {
244 const_cast<char*
>(
"points"),
245 const_cast<char*>(
"values"),
246 const_cast<char*
>(
"polynomial_order"),
247 const_cast<char*>(
"error_matrix"),
250 if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OOi|O", kwlist, &py_points,
251 &py_values, &polynomial_order, &py_error_matrix)) {
254 if (polynomial_order < 0) {
255 PyErr_SetString(PyExc_ValueError,
"polynomial_order should be >= 0");
258 std::vector<std::vector<double> > points =
get_vectors(py_points);
259 if (points.size() == 0) {
260 PyErr_SetString(PyExc_ValueError,
"Failed to evaluate points");
263 std::vector<std::vector<double> > values =
get_vectors(py_values);
264 if (values.size() == 0) {
265 PyErr_SetString(PyExc_ValueError,
"Failed to evaluate values");
268 if (points.size() != values.size()) {
269 PyErr_SetString(PyExc_ValueError,
"points misaligned with values");
274 std::vector<std::vector<double> > no_derivs;
275 std::vector<std::vector<int> > no_indices;
276 size_t dim = points[0].size();
278 dim, dim, points, no_derivs, no_indices);
281 PyErr_SetString(PyExc_ValueError, exc.
what().c_str());
284 PyObject* py_map_obj =
_alloc(py_map_type, 0);
286 py_map->
map = test_map;
291 std::string(
"Find a mapping by solving for the matrix.\n\n")+
292 std::string(
" - points: list, each entry containing a list of floats\n")+
293 std::string(
" corresponding to abscissa, each with length PointDimension.\n")+
294 std::string(
" The list should be at least as long as the number of \n")+
295 std::string(
" coefficients in the polynomial.\n")+
296 std::string(
" - values: list, each entry containing a list of floats\n")+
297 std::string(
" corresponding to ordinates, each with length ValueDimension.\n")+
298 std::string(
" The list should be as long as points.\n")+
299 std::string(
" - polynomial_order: integer, >= 0, corresponding to the\n")+
300 std::string(
" order of the fitted polynomial; 0 is constant, 1 is linear...\n")+
301 std::string(
" - coefficients: list of PolynomialCoefficients. Fix these\n")+
302 std::string(
" coefficients to some \n")+
303 std::string(
" - weights: list, of length = 0, corresponding to\n")+
304 std::string(
"Returns a polynomial map.\n");
307 PyObject*
least_squares(PyObject *py_class, PyObject *args, PyObject *kwds) {
308 PyTypeObject* py_map_type =
reinterpret_cast<PyTypeObject*
>(py_class);
310 if (py_map_type ==
nullptr) {
311 PyErr_SetString(PyExc_TypeError,
312 "Failed to resolve self as PolynomialMapType");
316 PyObject* py_points =
nullptr;
317 PyObject* py_values =
nullptr;
318 int polynomial_order = 0;
319 PyObject* py_coefficients =
nullptr;
320 PyObject* py_weights =
nullptr;
321 static char *kwlist[] = {
322 const_cast<char*
>(
"points"),
323 const_cast<char*>(
"values"),
324 const_cast<char*
>(
"polynomial_order"),
325 const_cast<char*>(
"polynomial_coefficients"),
326 const_cast<char*
>(
"weights"),
329 if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OOi|OO", kwlist, &py_points,
330 &py_values, &polynomial_order, &py_coefficients, &py_weights)) {
333 if (polynomial_order < 0) {
334 PyErr_SetString(PyExc_ValueError,
"polynomial_order should be >= 0");
337 std::vector<std::vector<double> > points =
get_vectors(py_points);
338 std::vector<std::vector<double> > values =
get_vectors(py_values);
339 std::vector<interpolation::PolynomialCoefficient> coeff;
340 std::vector<double> weights;
342 if (py_weights !=
nullptr) {
343 if (!PyList_Check(py_weights)) {
344 PyErr_SetString(PyExc_TypeError,
345 "Failed to resolve weights as a list");
348 size_t list_size = PyList_Size(py_weights);
349 weights = std::vector<double>(list_size);
350 for (
size_t i = 0; i < list_size; ++i) {
351 PyObject* py_value = PyList_GetItem(py_weights, i);
352 weights[i] = int(PyFloat_AsDouble(py_value));
353 if (PyErr_Occurred() !=
nullptr) {
359 if (py_coefficients !=
nullptr) {
360 if (!PyList_Check(py_coefficients)) {
361 PyErr_SetString(PyExc_TypeError,
362 "Failed to resolve coefficients as a list");
365 size_t list_size = PyList_Size(py_coefficients);
366 for (
size_t i = 0; i < list_size; ++i) {
367 PyObject* py_value = PyList_GetItem(py_coefficients, i);
369 if (py_coeff ==
nullptr) {
370 PyErr_SetString(PyExc_TypeError,
371 "Failed to resolve list item as a PolynomialCoefficient.");
374 coeff.push_back(*(py_coeff->
coeff));
380 interpolation::LeastSquaresSolveFactory solver(polynomial_order, points);
381 solver.setWeights(weights);
382 solver.setCoefficients(coeff);
385 PyErr_SetString(PyExc_ValueError, exc.
what().c_str());
388 PyObject* py_map_obj =
_alloc(py_map_type, 0);
390 py_map->
map = test_map;
396 int _init(PyObject*
self, PyObject *args, PyObject *kwds) {
399 if (py_map ==
nullptr) {
400 PyErr_SetString(PyExc_TypeError,
401 "Failed to resolve self as PolynomialMap in __init__");
406 if (py_map->
map !=
nullptr) {
408 py_map->
map =
nullptr;
412 PyObject* py_coefficients;
413 static char *kwlist[] = {
const_cast<char*
>(
"point_dimension"),
414 const_cast<char*>(
"coefficients"),
nullptr};
415 if (!PyArg_ParseTupleAndKeywords(args, kwds,
"iO", kwlist,
416 &point_dim, &py_coefficients)) {
422 if (!PyList_Check(py_coefficients)) {
423 PyErr_SetString(PyExc_TypeError,
424 "Failed to resolve coefficients as a list");
427 size_t num_rows = PyList_Size(py_coefficients);
429 PyErr_SetString(PyExc_ValueError,
"coefficients was empty");
435 for (
size_t i = 0; i < num_rows; ++i) {
436 PyObject* row = PyList_GetItem(py_coefficients, i);
437 if (!PyList_Check(py_coefficients)) {
438 PyErr_SetString(PyExc_TypeError,
439 "Failed to resolve coefficients row as a list");
444 num_cols = PyList_Size(row);
446 PyErr_SetString(PyExc_ValueError,
"coefficients row was empty");
452 if (PyList_Size(row) !=
static_cast<int>(num_cols)) {
453 PyErr_SetString(PyExc_ValueError,
454 "coefficients row had wrong number of elements");
456 for (
size_t j = 0; j < num_cols; ++j) {
457 PyObject* py_value = PyList_GetItem(row, j);
458 coefficients(i+1, j+1) = PyFloat_AsDouble(py_value);
459 if (PyErr_Occurred() !=
nullptr)
468 PyErr_SetString(PyExc_RuntimeError, (&exc)->what());
480 return reinterpret_cast<PyObject*
>(map);
483 PyObject *
_new(PyTypeObject *
type, Py_ssize_t nitems) {
484 return _alloc(type, nitems);
492 if (
self !=
nullptr) {
493 if (self->map !=
nullptr)
499 static PyMemberDef _members[] = {
503 static PyMethodDef _methods[] = {
509 METH_CLASS|METH_VARARGS|METH_KEYWORDS, exact_solve_docstring.c_str()},
511 METH_CLASS|METH_VARARGS|METH_KEYWORDS, least_squares_docstring.c_str()},
518 std::string(
"PolynomialMap provides routines to calculate multivariate \n")+
519 std::string(
"polynomials.\n\n")+
520 std::string(
"__init__()\n")+
521 std::string(
" Takes two arguments.\n")+
522 std::string(
" - point_dim: integer which defines the dimension of the\n")+
523 std::string(
" points (abscissa)\n")+
524 std::string(
" - coefficients: list of lists of floats which define the\n")+
525 std::string(
" polynomial\n")+
526 std::string(
"The value dimension of the PolynomialMap is the number of rows\n")+
527 std::string(
"coefficients matrix\n");
529 static PyTypeObject PyPolynomialMapType = {
530 PyObject_HEAD_INIT(
nullptr)
531 "polynomial_map.PolynomialMap",
549 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
550 class_docstring.c_str(),
574 "polynomial_map module contains the PolynomialMap class";
576 static struct PyModuleDef polynomial_map_def = {
577 PyModuleDef_HEAD_INIT,
590 PySquarePolynomialMap::PyPolynomialMapType.tp_new = PyType_GenericNew;
591 if (PyType_Ready(&PySquarePolynomialMap::PyPolynomialMapType) < 0)
594 PyObject* module = PyModule_Create(&polynomial_map_def);
595 if (module ==
nullptr)
598 PyTypeObject* polynomial_map_type = &PySquarePolynomialMap::PyPolynomialMapType;
599 Py_INCREF(polynomial_map_type);
600 PyModule_AddObject(module,
"PolynomialMap",
601 reinterpret_cast<PyObject*>(polynomial_map_type));
PyObject * index_by_power(PyObject *py_class, PyObject *args, PyObject *kwds)
void solve(double *Matrix, double *Solution, double *rightHandSide, const int &M, const int &N)
interpolation::SquarePolynomialVector * map
MMatrix< double > GetCoefficientsAsMatrix() const
virtual const std::string & what() const
Return the message string for the exception.
PyObject * exact_solve(PyObject *py_class, PyObject *args, PyObject *kwds)
void _dealloc(PyPolynomialMap *self)
int _init(PyObject *self, PyObject *args, PyObject *kwds)
PyObject * _alloc(PyTypeObject *type, Py_ssize_t nitems)
SolveFactory is a factory class for solving a set of linear equations to generate a polynomial based ...
PyObject * get_coefficients_as_matrix(PyObject *self, PyObject *args, PyObject *kwds)
PyObject * _new(PyTypeObject *type, Py_ssize_t nitems)
PyMODINIT_FUNC PyInit_polynomial_map(void)
const char * module_docstring
interpolation::PolynomialCoefficient * coeff
unsigned int PointDimension() const
std::vector< std::vector< double > > get_vectors(PyObject *py_floats)
SquarePolynomialVector describes a vector of multivariate polynomials.
PyObject * evaluate(PyObject *self, PyObject *args, PyObject *kwds)
std::string get_coefficients_as_matrix_docstring
size_t num_row() const
returns number of rows in the matrix
void F(const double *point, double *value) const
size_t num_col() const
returns number of columns in the matrix
c Accompany it with the information you received as to the offer to distribute corresponding source complete source code means all the source code for all modules it plus any associated interface definition plus the scripts used to control compilation and installation of the executable as a special exception
static std::vector< int > IndexByPower(int index, int nInputVariables)
unsigned int ValueDimension() const
void _free(PyPolynomialMap *self)
std::string exact_solve_docstring
SquarePolynomialVector * PolynomialSolve(const std::vector< std::vector< double > > &values, const std::vector< std::vector< double > > &deriv_values)
std::string least_squares_docstring
std::string index_by_power_docstring
std::string class_docstring
std::string evaluate_docstring
PyObject * least_squares(PyObject *py_class, PyObject *args, PyObject *kwds)