cisst-saw
Loading...
Searching...
No Matches
vctPythonUtilities.h
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/* ex: set filetype=cpp softtabstop=4 shiftwidth=4 tabstop=4 cindent expandtab: */
3
4/*
5 Author(s): Anton Deguet
6 Created on: 2005-08-21
7
8 (C) Copyright 2005-2025 Johns Hopkins University (JHU), All Rights Reserved.
9
10--- begin cisst license - do not edit ---
11
12This software is provided "as is" under an open source license, with
13no warranty. The complete license can be found in license.txt and
14http://www.cisst.org/cisst/license.txt.
15
16--- end cisst license ---
17*/
18
19
20/* This file is to be used only for the generation of SWIG wrappers.
21 It includes all the regular header files from the libraries as well
22 as some header files created only for the wrapping process
23 (e.g. vctDynamicMatrixRotation3.h).
24
25 For any wrapper using %import "cisstVector.i", the file
26 cisstVector/vctPython.h should be included in the %header %{ ... %}
27 section of the interface file. */
28
29
30#ifndef _vctPythonUtilities_h
31#define _vctPythonUtilities_h
32
33/* Put header files here */
34#include <Python.h>
35#include <numpy/numpyconfig.h>
36// Not using anything deprecated as of Numpy Version 1.9.
37// Newer versions of Numpy not yet tested, but based on numpyconfig.h, no new deprecated
38// items were added between Numpy Versions 1.8 and 1.15.
39#if defined(NPY_1_8_API_VERSION)
40#define NPY_NO_DEPRECATED_API NPY_1_8_API_VERSION
41#else
42#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
43#endif
44#include <numpy/arrayobject.h>
45// Numpy 1.7+ API requires PyArrayObject instead of PyObject for a number of methods.
46// The following macro performs this cast, without checking that the underlying object (A)
47// is an array because the code always either first checks if it is an array (e.g.,
48// by calling vctThrowUnlessIsPyArray, which calls PyArray_Check) or has just created
49// an array (e.g., by calling PyArray_SimpleNew).
50#define cast_array(A) reinterpret_cast<PyArrayObject *>(A)
51
52// PyArray_REFCOUNT is deprecated, and should be replaced by Py_REFCNT
53#ifndef PyArray_REFCOUNT
54#define PyArray_REFCOUNT(obj) Py_REFCNT(obj)
55#endif
56
57#include <typeinfo>
58#include <cisstConfig.h>
67
68
69bool vctThrowUnlessIsPyArray(PyObject * input)
70{
71 if (!PyArray_Check(input)) {
72 PyErr_SetString(PyExc_TypeError, "Object must be a NumPy array");
73 return false;
74 }
75 return true;
76}
77
78
79template <class _elementType>
81{
82 PyErr_Format(PyExc_ValueError, "Unsupported data type: %s", typeid(_elementType).name());
83 return false;
84}
85
86
87template <>
89{
90 if (PyArray_ObjectType(input, 0) != NPY_BOOL) {
91 PyErr_SetString(PyExc_ValueError, "Array must be of type bool");
92 return false;
93 }
94 return true;
95}
96
97
98template <>
100{
101 if (PyArray_ObjectType(input, 0) != NPY_INT8) {
102 PyErr_SetString(PyExc_ValueError, "Array must be of type char (int8)");
103 return false;
104 }
105 return true;
106}
107
108
109template <>
111{
112 if (PyArray_ObjectType(input, 0) != NPY_UINT8) {
113 PyErr_SetString(PyExc_ValueError, "Array must be of type unsigned char (uint8)");
114 return false;
115 }
116 return true;
117}
118
119
120template <>
122{
123 if (PyArray_ObjectType(input, 0) != NPY_INT16) {
124 PyErr_SetString(PyExc_ValueError, "Array must be of type short (int16)");
125 return false;
126 }
127 return true;
128}
129
130
131template <>
133{
134 if (PyArray_ObjectType(input, 0) != NPY_UINT16) {
135 PyErr_SetString(PyExc_ValueError, "Array must be of type unsigned short (uint16)");
136 return false;
137 }
138 return true;
139}
140
141
142template <>
144{
145 // NPY_INT and NPY_LONG are considered different types; NPY_INT32 is an alias for one of these
146#if (CISST_DATA_MODEL == CISST_ILP32) || (CISST_DATA_MODEL == CISST_LLP64)
147 if ((PyArray_ObjectType(input, 0) != NPY_INT) && (PyArray_ObjectType(input, 0) != NPY_LONG))
148#else
149 if (PyArray_ObjectType(input, 0) != NPY_INT)
150#endif
151 {
152 PyErr_SetString(PyExc_ValueError, "Array must be of type int (int32)");
153 return false;
154 }
155 return true;
156}
157
158
159template <>
161{
162 // NPY_UINT and NPY_ULONG are considered different types; NPY_UINT32 is an alias for one of these
163#if (CISST_DATA_MODEL == CISST_ILP32) || (CISST_DATA_MODEL == CISST_LLP64)
164 if ((PyArray_ObjectType(input, 0) != NPY_UINT) && (PyArray_ObjectType(input, 0) != NPY_ULONG))
165#else
166 if (PyArray_ObjectType(input, 0) != NPY_UINT)
167#endif
168 {
169 PyErr_SetString(PyExc_ValueError, "Array must be of type unsigned int (uint32)");
170 return false;
171 }
172 return true;
173}
174
175
176template <>
178{
179#if (CISST_DATA_MODEL == CISST_ILP32) || (CISST_DATA_MODEL == CISST_LLP64)
180 if (PyArray_ObjectType(input, 0) != NPY_INT32) {
181 PyErr_SetString(PyExc_ValueError, "Array must be of type long int (int32 on this platform)");
182 return false;
183 }
184#else
185 if (PyArray_ObjectType(input, 0) != NPY_INT64) {
186 PyErr_SetString(PyExc_ValueError, "Array must be of type long int (int64 on this platform)");
187 return false;
188 }
189#endif
190 return true;
191}
192
193
194template <>
196{
197#if (CISST_DATA_MODEL == CISST_ILP32) || (CISST_DATA_MODEL == CISST_LLP64)
198 if (PyArray_ObjectType(input, 0) != NPY_UINT32) {
199 PyErr_SetString(PyExc_ValueError, "Array must be of type unsigned long int (uint32 on this platform)");
200 return false;
201 }
202#else
203 if (PyArray_ObjectType(input, 0) != NPY_UINT64) {
204 PyErr_SetString(PyExc_ValueError, "Array must be of type unsigned long int (uint64 on this platform)");
205 return false;
206 }
207#endif
208 return true;
209}
210
211
212#if CISST_LONG_LONG_NATIVE
213template <>
215{
216 if (PyArray_ObjectType(input, 0) != NPY_INT64) {
217 PyErr_SetString(PyExc_ValueError, "Array must be of type long long int (int64)");
218 return false;
219 }
220 return true;
221}
222
223template <>
225{
226 if (PyArray_ObjectType(input, 0) != NPY_UINT64) {
227 PyErr_SetString(PyExc_ValueError, "Array must be of type unsigned long long int (uint64)");
228 return false;
229 }
230 return true;
231}
232#endif
233
234#if CISST_SIZE_T_NATIVE
235template <>
236bool vctThrowUnlessIsSameTypeArray<size_t>(PyObject * input)
237{
238 if (PyArray_ObjectType(input, 0) != NPY_UINT64) {
239 PyErr_SetString(PyExc_ValueError, "Array must be of type size_t (uint64)");
240 return false;
241 }
242 return true;
243}
244#endif
245
246template <>
248{
249 if (PyArray_ObjectType(input, 0) != NPY_FLOAT) {
250 PyErr_SetString(PyExc_ValueError, "Array must be of type float");
251 return false;
252 }
253 return true;
254}
255
256
257template <>
259{
260 if (PyArray_ObjectType(input, 0) != NPY_DOUBLE) {
261 PyErr_SetString(PyExc_ValueError, "Array must be of type double");
262 return false;
263 }
264 return true;
265}
266
267
268template <class _elementType>
270{
271 return NPY_NOTYPE; // unsupported type
272}
273
274
275template <>
277{
278 return NPY_BOOL;
279}
280
281
282template <>
284{
285 return NPY_INT8;
286}
287
288
289template <>
291{
292 return NPY_UINT8;
293}
294
295
296template <>
298{
299 return NPY_INT16;
300}
301
302
303template <>
305{
306 return NPY_UINT16;
307}
308
309
310template <>
312{
313 return NPY_INT32;
314}
315
316
317template <>
319{
320 return NPY_UINT32;
321}
322
323
324#if (CISST_DATA_MODEL == CISST_ILP32) || (CISST_DATA_MODEL == CISST_LLP64)
325
326template <>
328{
329 return NPY_INT32;
330}
331
332
333template <>
335{
336 return NPY_UINT32;
337}
338
339#else
340
341template <>
343{
344 return NPY_INT64;
345}
346
347
348template <>
350{
351 return NPY_UINT64;
352}
353
354#endif
355
356#if CISST_LONG_LONG_NATIVE
357template <>
359{
360 return NPY_INT64;
361}
362
363
364template <>
366{
367 return NPY_UINT64;
368}
369#endif
370
371#if CISST_SIZE_T_NATIVE
372
373template <>
374int vctPythonType<size_t>(void)
375{
376 return NPY_UINT64;
377}
378
379#endif
380
381template <>
383{
384 return NPY_DOUBLE;
385}
386
387
388bool vctThrowUnlessDimension1(PyArrayObject * input)
389{
390 if (PyArray_NDIM(input) != 1) {
391 PyErr_SetString(PyExc_ValueError, "Array must be 1D (vector)");
392 return false;
393 }
394 return true;
395}
396
397
398bool vctThrowUnlessDimension2(PyArrayObject * input)
399{
400 if (PyArray_NDIM(input) != 2) {
401 PyErr_SetString(PyExc_ValueError, "Array must be 2D (matrix)");
402 return false;
403 }
404 return true;
405}
406
407
408template <vct::size_type _dimension>
409bool vctThrowUnlessDimensionN(PyArrayObject * input)
410{
411 if (PyArray_NDIM(input) != _dimension) {
412 std::stringstream stream;
413 stream << "Array must have " << _dimension << " dimension(s)";
414 std::string msg = stream.str();
415 PyErr_SetString(PyExc_ValueError, msg.c_str());
416 return false;
417 }
418 return true;
419}
420
421
422bool vctThrowUnlessIsWritable(PyArrayObject * input)
423{
424 const int flags = PyArray_FLAGS(input);
425 if(!(flags & NPY_ARRAY_WRITEABLE)) {
426 PyErr_SetString(PyExc_ValueError, "Array must be writable");
427 return false;
428 }
429 return true;
430}
431
432
433template <vct::size_type _size, vct::stride_type _stride, class _elementType, class _dataPtrType>
434bool vctThrowUnlessCorrectVectorSize(PyArrayObject * input,
436{
437 const vct::size_type inputSize = PyArray_DIM(input, 0);
438 const vct::size_type targetSize = target.size();
439 if (inputSize != targetSize) {
440 std::stringstream stream;
441 stream << "Input vector's size must be " << targetSize;
442 std::string msg = stream.str();
443 PyErr_SetString(PyExc_ValueError, msg.c_str());
444 return false;
445 }
446 return true;
447}
448
449
450template <class _vectorOwnerType, typename _elementType>
451bool vctThrowUnlessCorrectVectorSize(PyArrayObject * CMN_UNUSED(input),
453{
454 return true;
455}
456
457
458template <vct::size_type _rows, vct::size_type _cols,
459 vct::stride_type _rowStride, vct::stride_type _colStride,
460 class _elementType, class _dataPtrType>
461bool vctThrowUnlessCorrectMatrixSize(PyArrayObject * input,
463{
464 const vct::size_type inputRows = PyArray_DIM(input, 0);
465 const vct::size_type inputCols = PyArray_DIM(input, 1);
466 const vct::size_type targetRows = target.rows();
467 const vct::size_type targetCols = target.cols();
468 if ( inputRows != targetRows
469 || inputCols != targetCols) {
470 std::stringstream stream;
471 stream << "Input matrix's size must be " << targetRows << " rows by " << targetCols << " columns";
472 std::string msg = stream.str();
473 PyErr_SetString(PyExc_ValueError, msg.c_str());
474 return false;
475 }
476 return true;
477}
478
479
480template <class _matrixOwnerType, typename _elementType>
481bool vctThrowUnlessCorrectMatrixSize(PyArrayObject * CMN_UNUSED(input),
483{
484 return true;
485}
486
487
488bool vctThrowUnlessOwnsData(PyArrayObject * input)
489{
490 const int flags = PyArray_FLAGS(input);
491 if(!(flags & NPY_ARRAY_OWNDATA)) {
492 PyErr_SetString(PyExc_ValueError, "Array must own its data");
493 return false;
494 }
495 return true;
496}
497
498
499template <vct::size_type _size, vct::stride_type _stride, class _elementType, class _dataPtrType>
500bool vctThrowUnlessOwnsData(PyArrayObject * CMN_UNUSED(input),
502{
503 return true;
504}
505
506
507template <class _vectorOwnerType, typename _elementType>
508bool vctThrowUnlessOwnsData(PyArrayObject * input,
510{
511 const int flags = PyArray_FLAGS(input);
512 if(!(flags & NPY_ARRAY_OWNDATA)) {
513 PyErr_SetString(PyExc_ValueError, "Array must own its data");
514 return false;
515 }
516 return true;
517}
518
519
520template <vct::size_type _rows, vct::size_type _cols,
521 vct::stride_type _rowStride, vct::stride_type _colStride,
522 class _elementType, class _dataPtrType>
528
529
530template <class _matrixOwnerType, typename _elementType>
531bool vctThrowUnlessOwnsData(PyArrayObject * input,
533{
534 const int flags = PyArray_FLAGS(input);
535 if(!(flags & NPY_ARRAY_OWNDATA)) {
536 PyErr_SetString(PyExc_ValueError, "Array must own its data");
537 return false;
538 }
539 return true;
540}
541
542
543bool vctThrowUnlessNotReferenced(PyObject * input)
544{
545 if (PyArray_REFCOUNT(input) > 4) {
546 PyErr_SetString(PyExc_ValueError, "Array must not be referenced by other objects. Try making a deep copy of the array and call the function again.");
547 return false;
548 }
549 return true;
550}
551
552
553template <vct::size_type _size, vct::stride_type _stride, class _elementType, class _dataPtrType>
559
560
561template <class _vectorOwnerType, typename _elementType>
562bool vctThrowUnlessNotReferenced(PyObject * input,
564{
565 if (PyArray_REFCOUNT(input) > 4) {
566 PyErr_SetString(PyExc_ValueError, "Array must not be referenced by other objects. Try making a deep copy of the array and call the function again.");
567 return false;
568 }
569 return true;
570}
571
572
573template <vct::size_type _rows, vct::size_type _cols,
574 vct::stride_type _rowStride, vct::stride_type _colStride,
575 class _elementType, class _dataPtrType>
581
582
583template <class _matrixOwnerType, typename _elementType>
584bool vctThrowUnlessNotReferenced(PyObject * input,
586{
587 if (PyArray_REFCOUNT(input) > 4) {
588 PyErr_SetString(PyExc_ValueError, "Array must not be referenced by other objects. Try making a deep copy of the array and call the function again.");
589 return false;
590 }
591 return true;
592}
593
594
595
596#endif // _vctPythonUtilities_h
Definition vctForwardDeclarations.h:145
Definition vctForwardDeclarations.h:119
A template for a fixed size matrix with fixed spacing in memory.
Definition vctFixedSizeConstMatrixBase.h:104
size_type cols() const
Definition vctFixedSizeConstMatrixBase.h:282
size_type rows() const
Definition vctFixedSizeConstMatrixBase.h:277
A template for a fixed length vector with fixed spacing in memory.
Definition vctFixedSizeConstVectorBase.h:108
size_type size(void) const
Definition vctFixedSizeConstVectorBase.h:205
Assert macros definitions.
Portability across compilers and operating systems tools.
#define CMN_UNUSED(argument)
Definition cmnPortability.h:497
size_t size_type
Definition vctContainerTraits.h:35
ptrdiff_t stride_type
Definition vctContainerTraits.h:37
Declaration of vctDynamicConstMatrixBase.
Declaration of vctDynamicConstNArrayBase.
Declaration of vctDynamicConstVectorBase.
Declaration of vctFixedSizeConstMatrixBase.
Declaration of vctFixedSizeConstVectorBase.
bool vctThrowUnlessDimensionN(PyArrayObject *input)
Definition vctPythonUtilities.h:409
bool vctThrowUnlessNotReferenced(PyObject *input)
Definition vctPythonUtilities.h:543
bool vctThrowUnlessIsPyArray(PyObject *input)
Definition vctPythonUtilities.h:69
bool vctThrowUnlessIsWritable(PyArrayObject *input)
Definition vctPythonUtilities.h:422
int vctPythonType(void)
Definition vctPythonUtilities.h:269
bool vctThrowUnlessCorrectVectorSize(PyArrayObject *input, const vctFixedSizeConstVectorBase< _size, _stride, _elementType, _dataPtrType > &target)
Definition vctPythonUtilities.h:434
bool vctThrowUnlessDimension1(PyArrayObject *input)
Definition vctPythonUtilities.h:388
bool vctThrowUnlessCorrectMatrixSize(PyArrayObject *input, const vctFixedSizeConstMatrixBase< _rows, _cols, _rowStride, _colStride, _elementType, _dataPtrType > &target)
Definition vctPythonUtilities.h:461
bool vctThrowUnlessIsSameTypeArray(PyObject *CMN_UNUSED(input))
Definition vctPythonUtilities.h:80
bool vctThrowUnlessOwnsData(PyArrayObject *input)
Definition vctPythonUtilities.h:488
#define PyArray_REFCOUNT(obj)
Definition vctPythonUtilities.h:54
bool vctThrowUnlessDimension2(PyArrayObject *input)
Definition vctPythonUtilities.h:398
Typedef for different transformations.