From 779d063af9c88152d7b1bc829410a4edb1ff4f88 Mon Sep 17 00:00:00 2001 From: rgommers Date: Sat, 4 Sep 2010 09:52:44 +0000 Subject: DOC: remove built separate swig docs. --- doc/swig/doc/Makefile | 51 -- doc/swig/doc/numpy_swig.html | 1244 ------------------------------------------ doc/swig/doc/numpy_swig.pdf | Bin 168839 -> 0 bytes doc/swig/doc/testing.html | 482 ---------------- doc/swig/doc/testing.pdf | Bin 72439 -> 0 bytes 5 files changed, 1777 deletions(-) delete mode 100644 doc/swig/doc/Makefile delete mode 100644 doc/swig/doc/numpy_swig.html delete mode 100644 doc/swig/doc/numpy_swig.pdf delete mode 100644 doc/swig/doc/testing.html delete mode 100644 doc/swig/doc/testing.pdf (limited to 'doc/swig') diff --git a/doc/swig/doc/Makefile b/doc/swig/doc/Makefile deleted file mode 100644 index 9223f0481..000000000 --- a/doc/swig/doc/Makefile +++ /dev/null @@ -1,51 +0,0 @@ -# ReStructured Text -RST2HTML = rst2html.py -RST2LATEX = rst2latex.py -RFLAGS = --generator --time -HTML_FLAGS = --no-xml-declaration -LATEX_FLAGS = -LATEX = pdflatex - -# Web pages that need to be made -WEB_PAGES = numpy_swig.html testing.html - -# LaTeX files that need to be made -LATEX_FILES = numpy_swig.tex testing.tex - -# PDF files that need to be made -PDF_FILES = numpy_swig.pdf testing.pdf - -# Default target: documentation -.PHONY : doc -doc: html pdf - -# HTML target -.PHONY : html -html: $(WEB_PAGES) - -# Rule: %.txt -> %.html -%.html: %.txt - $(RST2HTML) $(RFLAGS) $(HTML_FLAGS) $< $@ - -# LaTeX target -.PHONY : tex -tex: $(LATEX_FILES) - -# Rule: %.txt -> %.tex -%.tex: %.txt - $(RST2LATEX) $(RFLAGS) $(LATEX_FLAGS) $< $@ - -# PDF target -.PHONY : pdf -pdf: $(PDF_FILES) - -# Rule: %.tex -> %.pdf -%.pdf: %.tex - $(LATEX) $< - $(LATEX) $< - -# Clean target -.PHONY : clean -clean: - $(RM) $(LATEX_FILES) - $(RM) *.pyc *.aux *.dvi *.log *.out *~ diff --git a/doc/swig/doc/numpy_swig.html b/doc/swig/doc/numpy_swig.html deleted file mode 100644 index ed127f330..000000000 --- a/doc/swig/doc/numpy_swig.html +++ /dev/null @@ -1,1244 +0,0 @@ - - - - - -numpy.i: a SWIG Interface File for NumPy - - - - - -
-

numpy.i: a SWIG Interface File for NumPy

- --- - - - - - - - -
Author:Bill Spotz
Institution:Sandia National Laboratories
Date:1 December, 2007
- -
-

Introduction

-

The Simple Wrapper and Interface Generator (or SWIG) is a powerful tool for generating wrapper -code for interfacing to a wide variety of scripting languages. -SWIG can parse header files, and using only the code prototypes, -create an interface to the target language. But SWIG is not -omnipotent. For example, it cannot know from the prototype:

-
-double rms(double* seq, int n);
-
-

what exactly seq is. Is it a single value to be altered in-place? -Is it an array, and if so what is its length? Is it input-only? -Output-only? Input-output? SWIG cannot determine these details, -and does not attempt to do so.

-

If we designed rms, we probably made it a routine that takes an -input-only array of length n of double values called seq -and returns the root mean square. The default behavior of SWIG, -however, will be to create a wrapper function that compiles, but is -nearly impossible to use from the scripting language in the way the C -routine was intended.

-

For python, the preferred way of handling -contiguous (or technically, strided) blocks of homogeneous data is -with the module NumPy, which provides full -object-oriented access to multidimensial arrays of data. Therefore, -the most logical python interface for the rms function would be -(including doc string):

-
-def rms(seq):
-    """
-    rms: return the root mean square of a sequence
-    rms(numpy.ndarray) -> double
-    rms(list) -> double
-    rms(tuple) -> double
-    """
-
-

where seq would be a NumPy array of double values, and its -length n would be extracted from seq internally before being -passed to the C routine. Even better, since NumPy supports -construction of arrays from arbitrary python sequences, seq -itself could be a nearly arbitrary sequence (so long as each element -can be converted to a double) and the wrapper code would -internally convert it to a NumPy array before extracting its data -and length.

-

SWIG allows these types of conversions to be defined via a -mechanism called typemaps. This document provides information on how -to use numpy.i, a SWIG interface file that defines a series of -typemaps intended to make the type of array-related conversions -described above relatively simple to implement. For example, suppose -that the rms function prototype defined above was in a header file -named rms.h. To obtain the python interface discussed above, -your SWIG interface file would need the following:

-
-%{
-#define SWIG_FILE_WITH_INIT
-#include "rms.h"
-%}
-
-%include "numpy.i"
-
-%init %{
-import_array();
-%}
-
-%apply (double* IN_ARRAY1, int DIM1) {(double* seq, int n)};
-%include "rms.h"
-
-

Typemaps are keyed off a list of one or more function arguments, -either by type or by type and name. We will refer to such lists as -signatures. One of the many typemaps defined by numpy.i is used -above and has the signature (double* IN_ARRAY1, int DIM1). The -argument names are intended to suggest that the double* argument -is an input array of one dimension and that the int represents -that dimension. This is precisely the pattern in the rms -prototype.

-

Most likely, no actual prototypes to be wrapped will have the argument -names IN_ARRAY1 and DIM1. We use the %apply directive to -apply the typemap for one-dimensional input arrays of type double -to the actual prototype used by rms. Using numpy.i -effectively, therefore, requires knowing what typemaps are available -and what they do.

-

A SWIG interface file that includes the SWIG directives given -above will produce wrapper code that looks something like:

-
- 1 PyObject *_wrap_rms(PyObject *args) {
- 2   PyObject *resultobj = 0;
- 3   double *arg1 = (double *) 0 ;
- 4   int arg2 ;
- 5   double result;
- 6   PyArrayObject *array1 = NULL ;
- 7   int is_new_object1 = 0 ;
- 8   PyObject * obj0 = 0 ;
- 9
-10   if (!PyArg_ParseTuple(args,(char *)"O:rms",&obj0)) SWIG_fail;
-11   {
-12     array1 = obj_to_array_contiguous_allow_conversion(
-13                  obj0, NPY_DOUBLE, &is_new_object1);
-14     npy_intp size[1] = {
-15       -1
-16     };
-17     if (!array1 || !require_dimensions(array1, 1) ||
-18         !require_size(array1, size, 1)) SWIG_fail;
-19     arg1 = (double*) array1->data;
-20     arg2 = (int) array1->dimensions[0];
-21   }
-22   result = (double)rms(arg1,arg2);
-23   resultobj = SWIG_From_double((double)(result));
-24   {
-25     if (is_new_object1 && array1) Py_DECREF(array1);
-26   }
-27   return resultobj;
-28 fail:
-29   {
-30     if (is_new_object1 && array1) Py_DECREF(array1);
-31   }
-32   return NULL;
-33 }
-
-

The typemaps from numpy.i are responsible for the following lines -of code: 12--20, 25 and 30. Line 10 parses the input to the rms -function. From the format string "O:rms", we can see that the -argument list is expected to be a single python object (specified -by the O before the colon) and whose pointer is stored in -obj0. A number of functions, supplied by numpy.i, are called -to make and check the (possible) conversion from a generic python -object to a NumPy array. These functions are explained in the -section Helper Functions, but hopefully their names are -self-explanatory. At line 12 we use obj0 to construct a NumPy -array. At line 17, we check the validity of the result: that it is -non-null and that it has a single dimension of arbitrary length. Once -these states are verified, we extract the data buffer and length in -lines 19 and 20 so that we can call the underlying C function at line -22. Line 25 performs memory management for the case where we have -created a new array that is no longer needed.

-

This code has a significant amount of error handling. Note the -SWIG_fail is a macro for goto fail, refering to the label at -line 28. If the user provides the wrong number of arguments, this -will be caught at line 10. If construction of the NumPy array -fails or produces an array with the wrong number of dimensions, these -errors are caught at line 17. And finally, if an error is detected, -memory is still managed correctly at line 30.

-

Note that if the C function signature was in a different order:

-
-double rms(int n, double* seq);
-
-

that SWIG would not match the typemap signature given above with -the argument list for rms. Fortunately, numpy.i has a set of -typemaps with the data pointer given last:

-
-%apply (int DIM1, double* IN_ARRAY1) {(int n, double* seq)};
-
-

This simply has the effect of switching the definitions of arg1 -and arg2 in lines 3 and 4 of the generated code above, and their -assignments in lines 19 and 20.

-
-
-

Using numpy.i

-

The numpy.i file is currently located in the numpy/docs/swig -sub-directory under the numpy installation directory. Typically, -you will want to copy it to the directory where you are developing -your wrappers. If it is ever adopted by SWIG developers, then it -will be installed in a standard place where SWIG can find it.

-

A simple module that only uses a single SWIG interface file should -include the following:

-
-%{
-#define SWIG_FILE_WITH_INIT
-%}
-%include "numpy.i"
-%init %{
-import_array();
-%}
-
-

Within a compiled python module, import_array() should only get -called once. This could be in a C/C++ file that you have written and -is linked to the module. If this is the case, then none of your -interface files should #define SWIG_FILE_WITH_INIT or call -import_array(). Or, this initialization call could be in a -wrapper file generated by SWIG from an interface file that has the -%init block as above. If this is the case, and you have more than -one SWIG interface file, then only one interface file should -#define SWIG_FILE_WITH_INIT and call import_array().

-
-
-

Available Typemaps

-

The typemap directives provided by numpy.i for arrays of different -data types, say double and int, and dimensions of different -types, say int or long, are identical to one another except -for the C and NumPy type specifications. The typemaps are -therefore implemented (typically behind the scenes) via a macro:

-
-%numpy_typemaps(DATA_TYPE, DATA_TYPECODE, DIM_TYPE)
-
-

that can be invoked for appropriate (DATA_TYPE, DATA_TYPECODE, -DIM_TYPE) triplets. For example:

-
-%numpy_typemaps(double, NPY_DOUBLE, int)
-%numpy_typemaps(int,    NPY_INT   , int)
-
-

The numpy.i interface file uses the %numpy_typemaps macro to -implement typemaps for the following C data types and int -dimension types:

-
-
    -
  • signed char
  • -
  • unsigned char
  • -
  • short
  • -
  • unsigned short
  • -
  • int
  • -
  • unsigned int
  • -
  • long
  • -
  • unsigned long
  • -
  • long long
  • -
  • unsigned long long
  • -
  • float
  • -
  • double
  • -
-
-

In the following descriptions, we reference a generic DATA_TYPE, which -could be any of the C data types listed above, and DIM_TYPE which -should be one of the many types of integers.

-

The typemap signatures are largely differentiated on the name given to -the buffer pointer. Names with FARRAY are for FORTRAN-ordered -arrays, and names with ARRAY are for C-ordered (or 1D arrays).

-
-

Input Arrays

-

Input arrays are defined as arrays of data that are passed into a -routine but are not altered in-place or returned to the user. The -python input array is therefore allowed to be almost any python -sequence (such as a list) that can be converted to the requested type -of array. The input array signatures are

-

1D:

-
-
    -
  • ( DATA_TYPE IN_ARRAY1[ANY] )
  • -
  • ( DATA_TYPE* IN_ARRAY1, int DIM1 )
  • -
  • ( int DIM1, DATA_TYPE* IN_ARRAY1 )
  • -
-
-

2D:

-
-
    -
  • ( DATA_TYPE IN_ARRAY2[ANY][ANY] )
  • -
  • ( DATA_TYPE* IN_ARRAY2, int DIM1, int DIM2 )
  • -
  • ( int DIM1, int DIM2, DATA_TYPE* IN_ARRAY2 )
  • -
  • ( DATA_TYPE* IN_FARRAY2, int DIM1, int DIM2 )
  • -
  • ( int DIM1, int DIM2, DATA_TYPE* IN_FARRAY2 )
  • -
-
-

3D:

-
-
    -
  • ( DATA_TYPE IN_ARRAY3[ANY][ANY][ANY] )
  • -
  • ( DATA_TYPE* IN_ARRAY3, int DIM1, int DIM2, int DIM3 )
  • -
  • ( int DIM1, int DIM2, int DIM3, DATA_TYPE* IN_ARRAY3 )
  • -
  • ( DATA_TYPE* IN_FARRAY3, int DIM1, int DIM2, int DIM3 )
  • -
  • ( int DIM1, int DIM2, int DIM3, DATA_TYPE* IN_FARRAY3 )
  • -
-
-

The first signature listed, ( DATA_TYPE IN_ARRAY[ANY] ) is for -one-dimensional arrays with hard-coded dimensions. Likewise, -( DATA_TYPE IN_ARRAY2[ANY][ANY] ) is for two-dimensional arrays -with hard-coded dimensions, and similarly for three-dimensional.

-
-
-

In-Place Arrays

-

In-place arrays are defined as arrays that are modified in-place. The -input values may or may not be used, but the values at the time the -function returns are significant. The provided python argument -must therefore be a NumPy array of the required type. The in-place -signatures are

-

1D:

-
-
    -
  • ( DATA_TYPE INPLACE_ARRAY1[ANY] )
  • -
  • ( DATA_TYPE* INPLACE_ARRAY1, int DIM1 )
  • -
  • ( int DIM1, DATA_TYPE* INPLACE_ARRAY1 )
  • -
-
-

2D:

-
-
    -
  • ( DATA_TYPE INPLACE_ARRAY2[ANY][ANY] )
  • -
  • ( DATA_TYPE* INPLACE_ARRAY2, int DIM1, int DIM2 )
  • -
  • ( int DIM1, int DIM2, DATA_TYPE* INPLACE_ARRAY2 )
  • -
  • ( DATA_TYPE* INPLACE_FARRAY2, int DIM1, int DIM2 )
  • -
  • ( int DIM1, int DIM2, DATA_TYPE* INPLACE_FARRAY2 )
  • -
-
-

3D:

-
-
    -
  • ( DATA_TYPE INPLACE_ARRAY3[ANY][ANY][ANY] )
  • -
  • ( DATA_TYPE* INPLACE_ARRAY3, int DIM1, int DIM2, int DIM3 )
  • -
  • ( int DIM1, int DIM2, int DIM3, DATA_TYPE* INPLACE_ARRAY3 )
  • -
  • ( DATA_TYPE* INPLACE_FARRAY3, int DIM1, int DIM2, int DIM3 )
  • -
  • ( int DIM1, int DIM2, int DIM3, DATA_TYPE* INPLACE_FARRAY3 )
  • -
-
-

These typemaps now check to make sure that the INPLACE_ARRAY -arguments use native byte ordering. If not, an exception is raised.

-
-
-

Argout Arrays

-

Argout arrays are arrays that appear in the input arguments in C, but -are in fact output arrays. This pattern occurs often when there is -more than one output variable and the single return argument is -therefore not sufficient. In python, the convential way to return -multiple arguments is to pack them into a sequence (tuple, list, etc.) -and return the sequence. This is what the argout typemaps do. If a -wrapped function that uses these argout typemaps has more than one -return argument, they are packed into a tuple or list, depending on -the version of python. The python user does not pass these -arrays in, they simply get returned. For the case where a dimension -is specified, the python user must provide that dimension as an -argument. The argout signatures are

-

1D:

-
-
    -
  • ( DATA_TYPE ARGOUT_ARRAY1[ANY] )
  • -
  • ( DATA_TYPE* ARGOUT_ARRAY1, int DIM1 )
  • -
  • ( int DIM1, DATA_TYPE* ARGOUT_ARRAY1 )
  • -
-
-

2D:

-
-
    -
  • ( DATA_TYPE ARGOUT_ARRAY2[ANY][ANY] )
  • -
-
-

3D:

-
-
    -
  • ( DATA_TYPE ARGOUT_ARRAY3[ANY][ANY][ANY] )
  • -
-
-

These are typically used in situations where in C/C++, you would -allocate a(n) array(s) on the heap, and call the function to fill the -array(s) values. In python, the arrays are allocated for you and -returned as new array objects.

-

Note that we support DATA_TYPE* argout typemaps in 1D, but not 2D -or 3D. This is because of a quirk with the SWIG typemap syntax and -cannot be avoided. Note that for these types of 1D typemaps, the -python function will take a single argument representing DIM1.

-
-
-

Argoutview Arrays

-

Argoutview arrays are for when your C code provides you with a view of -its internal data and does not require any memory to be allocated by -the user. This can be dangerous. There is almost no way to guarantee -that the internal data from the C code will remain in existence for -the entire lifetime of the NumPy array that encapsulates it. If -the user destroys the object that provides the view of the data before -destroying the NumPy array, then using that array my result in bad -memory references or segmentation faults. Nevertheless, there are -situations, working with large data sets, where you simply have no -other choice.

-

The C code to be wrapped for argoutview arrays are characterized by -pointers: pointers to the dimensions and double pointers to the data, -so that these values can be passed back to the user. The argoutview -typemap signatures are therefore

-

1D:

-
-
    -
  • ( DATA_TYPE** ARGOUTVIEW_ARRAY1, DIM_TYPE* DIM1 )
  • -
  • ( DIM_TYPE* DIM1, DATA_TYPE** ARGOUTVIEW_ARRAY1 )
  • -
-
-

2D:

-
-
    -
  • ( DATA_TYPE** ARGOUTVIEW_ARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2 )
  • -
  • ( DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_ARRAY2 )
  • -
  • ( DATA_TYPE** ARGOUTVIEW_FARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2 )
  • -
  • ( DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_FARRAY2 )
  • -
-
-

3D:

-
-
    -
  • ( DATA_TYPE** ARGOUTVIEW_ARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3)
  • -
  • ( DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_ARRAY3)
  • -
  • ( DATA_TYPE** ARGOUTVIEW_FARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3)
  • -
  • ( DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_FARRAY3)
  • -
-
-

Note that arrays with hard-coded dimensions are not supported. These -cannot follow the double pointer signatures of these typemaps.

-
-
-

Output Arrays

-

The numpy.i interface file does not support typemaps for output -arrays, for several reasons. First, C/C++ return arguments are -limited to a single value. This prevents obtaining dimension -information in a general way. Second, arrays with hard-coded lengths -are not permitted as return arguments. In other words:

-
-double[3] newVector(double x, double y, double z);
-
-

is not legal C/C++ syntax. Therefore, we cannot provide typemaps of -the form:

-
-%typemap(out) (TYPE[ANY]);
-
-

If you run into a situation where a function or method is returning a -pointer to an array, your best bet is to write your own version of the -function to be wrapped, either with %extend for the case of class -methods or %ignore and %rename for the case of functions.

-
-
-

Other Common Types: bool

-

Note that C++ type bool is not supported in the list in the -Available Typemaps section. NumPy bools are a single byte, while -the C++ bool is four bytes (at least on my system). Therefore:

-
-%numpy_typemaps(bool, NPY_BOOL, int)
-
-

will result in typemaps that will produce code that reference -improper data lengths. You can implement the following macro -expansion:

-
-%numpy_typemaps(bool, NPY_UINT, int)
-
-

to fix the data length problem, and Input Arrays will work fine, -but In-Place Arrays might fail type-checking.

-
-
-

Other Common Types: complex

-

Typemap conversions for complex floating-point types is also not -supported automatically. This is because python and NumPy are -written in C, which does not have native complex types. Both -python and NumPy implement their own (essentially equivalent) -struct definitions for complex variables:

-
-/* Python */
-typedef struct {double real; double imag;} Py_complex;
-
-/* NumPy */
-typedef struct {float  real, imag;} npy_cfloat;
-typedef struct {double real, imag;} npy_cdouble;
-
-

We could have implemented:

-
-%numpy_typemaps(Py_complex , NPY_CDOUBLE, int)
-%numpy_typemaps(npy_cfloat , NPY_CFLOAT , int)
-%numpy_typemaps(npy_cdouble, NPY_CDOUBLE, int)
-
-

which would have provided automatic type conversions for arrays of -type Py_complex, npy_cfloat and npy_cdouble. However, it -seemed unlikely that there would be any independent (non-python, -non-NumPy) application code that people would be using SWIG to -generate a python interface to, that also used these definitions -for complex types. More likely, these application codes will define -their own complex types, or in the case of C++, use std::complex. -Assuming these data structures are compatible with python and -NumPy complex types, %numpy_typemap expansions as above (with -the user's complex type substituted for the first argument) should -work.

-
-
-
-

NumPy Array Scalars and SWIG

-

SWIG has sophisticated type checking for numerical types. For -example, if your C/C++ routine expects an integer as input, the code -generated by SWIG will check for both python integers and -python long integers, and raise an overflow error if the provided -python integer is too big to cast down to a C integer. With the -introduction of NumPy scalar arrays into your python code, you -might conceivably extract an integer from a NumPy array and attempt -to pass this to a SWIG-wrapped C/C++ function that expects an -int, but the SWIG type checking will not recognize the NumPy -array scalar as an integer. (Often, this does in fact work -- it -depends on whether NumPy recognizes the integer type you are using -as inheriting from the python integer type on the platform you are -using. Sometimes, this means that code that works on a 32-bit machine -will fail on a 64-bit machine.)

-

If you get a python error that looks like the following:

-
-TypeError: in method 'MyClass_MyMethod', argument 2 of type 'int'
-
-

and the argument you are passing is an integer extracted from a -NumPy array, then you have stumbled upon this problem. The -solution is to modify the SWIG type conversion system to accept -Numpy array scalars in addition to the standard integer types. -Fortunately, this capabilitiy has been provided for you. Simply copy -the file:

-
-pyfragments.swg
-
-

to the working build directory for you project, and this problem will -be fixed. It is suggested that you do this anyway, as it only -increases the capabilities of your python interface.

-
-

Why is There a Second File?

-

The SWIG type checking and conversion system is a complicated -combination of C macros, SWIG macros, SWIG typemaps and SWIG -fragments. Fragments are a way to conditionally insert code into your -wrapper file if it is needed, and not insert it if not needed. If -multiple typemaps require the same fragment, the fragment only gets -inserted into your wrapper code once.

-

There is a fragment for converting a python integer to a C -long. There is a different fragment that converts a python -integer to a C int, that calls the rountine defined in the -long fragment. We can make the changes we want here by changing -the definition for the long fragment. SWIG determines the -active definition for a fragment using a "first come, first served" -system. That is, we need to define the fragment for long -conversions prior to SWIG doing it internally. SWIG allows us -to do this by putting our fragment definitions in the file -pyfragments.swg. If we were to put the new fragment definitions -in numpy.i, they would be ignored.

-
-
-
-

Helper Functions

-

The numpy.i file containes several macros and routines that it -uses internally to build its typemaps. However, these functions may -be useful elsewhere in your interface file. These macros and routines -are implemented as fragments, which are described briefly in the -previous section. If you try to use one or more of the following -macros or functions, but your compiler complains that it does not -recognize the symbol, then you need to force these fragments to appear -in your code using:

-
-%fragment("NumPy_Fragments");
-
-

in your SWIG interface file.

-
-

Macros

-
-
-
is_array(a)
-
Evaluates as true if a is non-NULL and can be cast to a -PyArrayObject*.
-
array_type(a)
-
Evaluates to the integer data type code of a, assuming a can -be cast to a PyArrayObject*.
-
array_numdims(a)
-
Evaluates to the integer number of dimensions of a, assuming -a can be cast to a PyArrayObject*.
-
array_dimensions(a)
-
Evaluates to an array of type npy_intp and length -array_numdims(a), giving the lengths of all of the dimensions -of a, assuming a can be cast to a PyArrayObject*.
-
array_size(a,i)
-
Evaluates to the i-th dimension size of a, assuming a -can be cast to a PyArrayObject*.
-
array_data(a)
-
Evaluates to a pointer of type void* that points to the data -buffer of a, assuming a can be cast to a PyArrayObject*.
-
array_is_contiguous(a)
-
Evaluates as true if a is a contiguous array. Equivalent to -(PyArray_ISCONTIGUOUS(a)).
-
array_is_native(a)
-
Evaluates as true if the data buffer of a uses native byte -order. Equivalent to (PyArray_ISNOTSWAPPED(a)).
-
array_is_fortran(a)
-
Evaluates as true if a is FORTRAN ordered.
-
-
-
-
-

Routines

-
-

pytype_string()

-
-

Return type: char*

-

Arguments:

-
    -
  • PyObject* py_obj, a general python object.
  • -
-

Return a string describing the type of py_obj.

-
-

typecode_string()

-
-

Return type: char*

-

Arguments:

-
    -
  • int typecode, a NumPy integer typecode.
  • -
-

Return a string describing the type corresponding to the NumPy -typecode.

-
-

type_match()

-
-

Return type: int

-

Arguments:

-
    -
  • int actual_type, the NumPy typecode of a NumPy array.
  • -
  • int desired_type, the desired NumPy typecode.
  • -
-

Make sure that actual_type is compatible with -desired_type. For example, this allows character and -byte types, or int and long types, to match. This is now -equivalent to PyArray_EquivTypenums().

-
-

obj_to_array_no_conversion()

-
-

Return type: PyArrayObject*

-

Arguments:

-
    -
  • PyObject* input, a general python object.
  • -
  • int typecode, the desired NumPy typecode.
  • -
-

Cast input to a PyArrayObject* if legal, and ensure that -it is of type typecode. If input cannot be cast, or the -typecode is wrong, set a python error and return NULL.

-
-

obj_to_array_allow_conversion()

-
-

Return type: PyArrayObject*

-

Arguments:

-
    -
  • PyObject* input, a general python object.
  • -
  • int typecode, the desired NumPy typecode of the resulting -array.
  • -
  • int* is_new_object, returns a value of 0 if no conversion -performed, else 1.
  • -
-

Convert input to a NumPy array with the given typecode. -On success, return a valid PyArrayObject* with the correct -type. On failure, the python error string will be set and the -routine returns NULL.

-
-

make_contiguous()

-
-

Return type: PyArrayObject*

-

Arguments:

-
    -
  • PyArrayObject* ary, a NumPy array.
  • -
  • int* is_new_object, returns a value of 0 if no conversion -performed, else 1.
  • -
  • int min_dims, minimum allowable dimensions.
  • -
  • int max_dims, maximum allowable dimensions.
  • -
-

Check to see if ary is contiguous. If so, return the input -pointer and flag it as not a new object. If it is not contiguous, -create a new PyArrayObject* using the original data, flag it -as a new object and return the pointer.

-
-

obj_to_array_contiguous_allow_conversion()

-
-

Return type: PyArrayObject*

-

Arguments:

-
    -
  • PyObject* input, a general python object.
  • -
  • int typecode, the desired NumPy typecode of the resulting -array.
  • -
  • int* is_new_object, returns a value of 0 if no conversion -performed, else 1.
  • -
-

Convert input to a contiguous PyArrayObject* of the -specified type. If the input object is not a contiguous -PyArrayObject*, a new one will be created and the new object -flag will be set.

-
-

require_contiguous()

-
-

Return type: int

-

Arguments:

-
    -
  • PyArrayObject* ary, a NumPy array.
  • -
-

Test whether ary is contiguous. If so, return 1. Otherwise, -set a python error and return 0.

-
-

require_native()

-
-

Return type: int

-

Arguments:

-
    -
  • PyArray_Object* ary, a NumPy array.
  • -
-

Require that ary is not byte-swapped. If the array is not -byte-swapped, return 1. Otherwise, set a python error and -return 0.

-
-

require_dimensions()

-
-

Return type: int

-

Arguments:

-
    -
  • PyArrayObject* ary, a NumPy array.
  • -
  • int exact_dimensions, the desired number of dimensions.
  • -
-

Require ary to have a specified number of dimensions. If the -array has the specified number of dimensions, return 1. -Otherwise, set a python error and return 0.

-
-

require_dimensions_n()

-
-

Return type: int

-

Arguments:

-
    -
  • PyArrayObject* ary, a NumPy array.
  • -
  • int* exact_dimensions, an array of integers representing -acceptable numbers of dimensions.
  • -
  • int n, the length of exact_dimensions.
  • -
-

Require ary to have one of a list of specified number of -dimensions. If the array has one of the specified number of -dimensions, return 1. Otherwise, set the python error string -and return 0.

-
-

require_size()

-
-

Return type: int

-

Arguments:

-
    -
  • PyArrayObject* ary, a NumPy array.
  • -
  • npy_int* size, an array representing the desired lengths of -each dimension.
  • -
  • int n, the length of size.
  • -
-

Require ary to have a specified shape. If the array has the -specified shape, return 1. Otherwise, set the python error -string and return 0.

-
-

require_fortran()

-
-

Return type: int

-

Arguments:

-
    -
  • PyArrayObject* ary, a NumPy array.
  • -
-

Require the given PyArrayObject to to be FORTRAN ordered. If -the the PyArrayObject is already FORTRAN ordered, do nothing. -Else, set the FORTRAN ordering flag and recompute the strides.

-
-
-
-
-
-

Beyond the Provided Typemaps

-

There are many C or C++ array/NumPy array situations not covered by -a simple %include "numpy.i" and subsequent %apply directives.

-
-

A Common Example

-

Consider a reasonable prototype for a dot product function:

-
-double dot(int len, double* vec1, double* vec2);
-
-

The python interface that we want is:

-
-def dot(vec1, vec2):
-    """
-    dot(PyObject,PyObject) -> double
-    """
-
-

The problem here is that there is one dimension argument and two array -arguments, and our typemaps are set up for dimensions that apply to a -single array (in fact, SWIG does not provide a mechanism for -associating len with vec2 that takes two python input -arguments). The recommended solution is the following:

-
-%apply (int DIM1, double* IN_ARRAY1) {(int len1, double* vec1),
-                                      (int len2, double* vec2)}
-%rename (dot) my_dot;
-%exception my_dot {
-    $action
-    if (PyErr_Occurred()) SWIG_fail;
-}
-%inline %{
-double my_dot(int len1, double* vec1, int len2, double* vec2) {
-    if (len1 != len2) {
-        PyErr_Format(PyExc_ValueError,
-                     "Arrays of lengths (%d,%d) given",
-                     len1, len2);
-        return 0.0;
-    }
-    return dot(len1, vec1, vec2);
-}
-%}
-
-

If the header file that contains the prototype for double dot() -also contains other prototypes that you want to wrap, so that you need -to %include this header file, then you will also need a %ignore -dot; directive, placed after the %rename and before the -%include directives. Or, if the function in question is a class -method, you will want to use %extend rather than %inline in -addition to %ignore.

-

A note on error handling: Note that my_dot returns a -double but that it can also raise a python error. The -resulting wrapper function will return a python float -representation of 0.0 when the vector lengths do not match. Since -this is not NULL, the python interpreter will not know to check -for an error. For this reason, we add the %exception directive -above for my_dot to get the behavior we want (note that -$action is a macro that gets expanded to a valid call to -my_dot). In general, you will probably want to write a SWIG -macro to perform this task.

-
-
-

Other Situations

-

There are other wrapping situations in which numpy.i may be -helpful when you encounter them.

-
-
    -
  • In some situations, it is possible that you could use the -%numpy_templates macro to implement typemaps for your own -types. See the Other Common Types: bool or Other Common -Types: complex sections for examples. Another situation is if -your dimensions are of a type other than int (say long for -example):

    -
    -%numpy_typemaps(double, NPY_DOUBLE, long)
    -
    -
  • -
  • You can use the code in numpy.i to write your own typemaps. -For example, if you had a four-dimensional array as a function -argument, you could cut-and-paste the appropriate -three-dimensional typemaps into your interface file. The -modifications for the fourth dimension would be trivial.

    -
  • -
  • Sometimes, the best approach is to use the %extend directive -to define new methods for your classes (or overload existing ones) -that take a PyObject* (that either is or can be converted to a -PyArrayObject*) instead of a pointer to a buffer. In this -case, the helper routines in numpy.i can be very useful.

    -
  • -
  • Writing typemaps can be a bit nonintuitive. If you have specific -questions about writing SWIG typemaps for NumPy, the -developers of numpy.i do monitor the -Numpy-discussion and -Swig-user mail lists.

    -
  • -
-
-
-
-

A Final Note

-

When you use the %apply directive, as is usually necessary to use -numpy.i, it will remain in effect until you tell SWIG that it -shouldn't be. If the arguments to the functions or methods that you -are wrapping have common names, such as length or vector, -these typemaps may get applied in situations you do not expect or -want. Therefore, it is always a good idea to add a %clear -directive after you are done with a specific typemap:

-
-%apply (double* IN_ARRAY1, int DIM1) {(double* vector, int length)}
-%include "my_header.h"
-%clear (double* vector, int length);
-
-

In general, you should target these typemap signatures specifically -where you want them, and then clear them after you are done.

-
-
-
-

Summary

-

Out of the box, numpy.i provides typemaps that support conversion -between NumPy arrays and C arrays:

-
-
    -
  • That can be one of 12 different scalar types: signed char, -unsigned char, short, unsigned short, int, -unsigned int, long, unsigned long, long long, -unsigned long long, float and double.
  • -
  • That support 41 different argument signatures for each data type, -including:
      -
    • One-dimensional, two-dimensional and three-dimensional arrays.
    • -
    • Input-only, in-place, argout and argoutview behavior.
    • -
    • Hard-coded dimensions, data-buffer-then-dimensions -specification, and dimensions-then-data-buffer specification.
    • -
    • Both C-ordering ("last dimension fastest") or FORTRAN-ordering -("first dimension fastest") support for 2D and 3D arrays.
    • -
    -
  • -
-
-

The numpy.i interface file also provides additional tools for -wrapper developers, including:

-
-
    -
  • A SWIG macro (%numpy_typemaps) with three arguments for -implementing the 41 argument signatures for the user's choice of -(1) C data type, (2) NumPy data type (assuming they match), and -(3) dimension type.
  • -
  • Nine C macros and 13 C functions that can be used to write -specialized typemaps, extensions, or inlined functions that handle -cases not covered by the provided typemaps.
  • -
-
-
-
-

Acknowledgements

-

Many people have worked to glue SWIG and NumPy together (as well -as SWIG and the predecessors of NumPy, Numeric and numarray). -The effort to standardize this work into numpy.i began at the 2005 -SciPy Conference with a conversation between -Fernando Perez and myself. Fernando collected helper functions and -typemaps from Eric Jones, Michael Hunter, Anna Omelchenko and Michael -Sanner. Sebastian Hasse and Georg Holzmann have also provided -additional error checking and use cases. The work of these -contributors has made this end result possible.

-
-
- - - diff --git a/doc/swig/doc/numpy_swig.pdf b/doc/swig/doc/numpy_swig.pdf deleted file mode 100644 index 1d4642cf7..000000000 Binary files a/doc/swig/doc/numpy_swig.pdf and /dev/null differ diff --git a/doc/swig/doc/testing.html b/doc/swig/doc/testing.html deleted file mode 100644 index 3622550df..000000000 --- a/doc/swig/doc/testing.html +++ /dev/null @@ -1,482 +0,0 @@ - - - - - -Testing the numpy.i Typemaps - - - - - -
-

Testing the numpy.i Typemaps

- --- - - - - - - - -
Author:Bill Spotz
Institution:Sandia National Laboratories
Date:6 April, 2007
- -
-

Introduction

-

Writing tests for the numpy.i SWIG -interface file is a combinatorial headache. At present, 12 different -data types are supported, each with 23 different argument signatures, -for a total of 276 typemaps supported "out of the box". Each of these -typemaps, in turn, might require several unit tests in order to verify -expected behavior for both proper and improper inputs. Currently, -this results in 1,020 individual unit tests that are performed when -make test is run in the numpy/docs/swig subdirectory.

-

To facilitate this many similar unit tests, some high-level -programming techniques are employed, including C and SWIG macros, -as well as python inheritance. The -purpose of this document is to describe the testing infrastructure -employed to verify that the numpy.i typemaps are working as -expected.

-
-
-

Testing Organization

-

There are three indepedent testing frameworks supported, for one-, -two-, and three-dimensional arrays respectively. For one-dimensional -arrays, there are two C++ files, a header and a source, named:

-
-Vector.h
-Vector.cxx
-
-

that contain prototypes and code for a variety of functions that have -one-dimensional arrays as function arguments. The file:

-
-Vector.i
-
-

is a SWIG interface file that defines a python module Vector -that wraps the functions in Vector.h while utilizing the typemaps -in numpy.i to correctly handle the C arrays.

-

The Makefile calls swig to generate Vector.py and -Vector_wrap.cxx, and also executes the setup.py script that -compiles Vector_wrap.cxx and links together the extension module -_Vector.so or _Vector.dylib, depending on the platform. This -extension module and the proxy file Vector.py are both placed in a -subdirectory under the build directory.

-

The actual testing takes place with a python script named:

-
-testVector.py
-
-

that uses the standard python library module unittest, which -performs several tests of each function defined in Vector.h for -each data type supported.

-

Two-dimensional arrays are tested in exactly the same manner. The -above description applies, but with Matrix substituted for -Vector. For three-dimensional tests, substitute Tensor for -Vector. For the descriptions that follow, we will reference the -Vector tests, but the same information applies to Matrix and -Tensor tests.

-

The command make test will ensure that all of the test software is -built and then run all three test scripts.

-
-
-

Testing Header Files

-

Vector.h is a C++ header file that defines a C macro called -TEST_FUNC_PROTOS that takes two arguments: TYPE, which is a -data type name such as unsigned int; and SNAME, which is a -short name for the same data type with no spaces, e.g. uint. This -macro defines several function prototypes that have the prefix -SNAME and have at least one argument that is an array of type -TYPE. Those functions that have return arguments return a -TYPE value.

-

TEST_FUNC_PROTOS is then implemented for all of the data types -supported by numpy.i:

-
-
    -
  • signed char
  • -
  • unsigned char
  • -
  • short
  • -
  • unsigned short
  • -
  • int
  • -
  • unsigned int
  • -
  • long
  • -
  • unsigned long
  • -
  • long long
  • -
  • unsigned long long
  • -
  • float
  • -
  • double
  • -
-
-
-
-

Testing Source Files

-

Vector.cxx is a C++ source file that implements compilable code -for each of the function prototypes specified in Vector.h. It -defines a C macro TEST_FUNCS that has the same arguments and works -in the same way as TEST_FUNC_PROTOS does in Vector.h. -TEST_FUNCS is implemented for each of the 12 data types as above.

-
-
-

Testing SWIG Interface Files

-

Vector.i is a SWIG interface file that defines python module -Vector. It follows the conventions for using numpy.i as -described in the numpy.i documentation. It -defines a SWIG macro %apply_numpy_typemaps that has a single -argument TYPE. It uses the SWIG directive %apply as -described in the numpy.i documentation to apply the provided -typemaps to the argument signatures found in Vector.h. This macro -is then implemented for all of the data types supported by -numpy.i. It then does a %include "Vector.h" to wrap all of -the function prototypes in Vector.h using the typemaps in -numpy.i.

-
-
-

Testing Python Scripts

-

After make is used to build the testing extension modules, -testVector.py can be run to execute the tests. As with other -scripts that use unittest to facilitate unit testing, -testVector.py defines a class that inherits from -unittest.TestCase:

-
-class VectorTestCase(unittest.TestCase):
-
-

However, this class is not run directly. Rather, it serves as a base -class to several other python classes, each one specific to a -particular data type. The VectorTestCase class stores two strings -for typing information:

-
-
-
self.typeStr
-
A string that matches one of the SNAME prefixes used in -Vector.h and Vector.cxx. For example, "double".
-
self.typeCode
-
A short (typically single-character) string that represents a -data type in numpy and corresponds to self.typeStr. For -example, if self.typeStr is "double", then -self.typeCode should be "d".
-
-
-

Each test defined by the VectorTestCase class extracts the python -function it is trying to test by accessing the Vector module's -dictionary:

-
-length = Vector.__dict__[self.typeStr + "Length"]
-
-

In the case of double precision tests, this will return the python -function Vector.doubleLength.

-

We then define a new test case class for each supported data type with -a short definition such as:

-
-class doubleTestCase(VectorTestCase):
-    def __init__(self, methodName="runTest"):
-        VectorTestCase.__init__(self, methodName)
-        self.typeStr  = "double"
-        self.typeCode = "d"
-
-

Each of these 12 classes is collected into a unittest.TestSuite, -which is then executed. Errors and failures are summed together and -returned as the exit argument. Any non-zero result indicates that at -least one test did not pass.

-
-
- - - diff --git a/doc/swig/doc/testing.pdf b/doc/swig/doc/testing.pdf deleted file mode 100644 index 9ffcf7575..000000000 Binary files a/doc/swig/doc/testing.pdf and /dev/null differ -- cgit v1.2.1