├── .gitignore ├── LICENSE ├── README.md ├── cython ├── MANIFEST.in ├── README.md ├── setup.py ├── src │ ├── kernel.cu │ ├── manager.cu │ └── manager.hh ├── test.py └── wrapper.pyx └── swig ├── README.md ├── setup.py ├── src ├── gpuadder.i ├── kernel.cu ├── manager.cu ├── manager.hh └── numpy.i └── test.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | 15 | *.py[cod] 16 | 17 | # C extensions 18 | *.so 19 | 20 | # Packages 21 | *.egg 22 | *.egg-info 23 | dist 24 | build 25 | eggs 26 | parts 27 | bin 28 | var 29 | sdist 30 | develop-eggs 31 | .installed.cfg 32 | lib 33 | lib64 34 | 35 | # Installer logs 36 | pip-log.txt 37 | 38 | # Unit test / coverage reports 39 | .coverage 40 | .tox 41 | nosetests.xml 42 | 43 | # Translations 44 | *.mo 45 | 46 | # Mr Developer 47 | .mr.developer.cfg 48 | .project 49 | .pydevproject 50 | 51 | # Specific files 52 | cython/wrapper.cpp 53 | 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Robert T. McGibbon and the Authors 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # npcuda-example 2 | 3 | This is an example of a simple Python C++ extension which uses CUDA and is compiled via nvcc. The idea is to use this coda as an example or template from which to build your own CUDA-accelerated Python extensions. 4 | 5 | The extension is a single C++ class which manages the GPU memory and provides methods to call operations on the GPU 6 | data. This C++ class is wrapped via *swig* or *cython* -- effectively exporting this class into python land. 7 | 8 | ## swig vs cython 9 | 10 | ### swig 11 | Swig is a widely used code generator for exposing C and C++ libraries in high level dynamically typed languages. 12 | In principle, it involves minimal code rewriting. You just have to write swig interface files that instruct swig 13 | on how to do the translation. 14 | 15 | In practice, swig and numpy don't work together that well. The numpy interface relies on a bunch of magical macros 16 | that are extremely difficult to debug. 17 | 18 | ### !!cython!! 19 | Cython is sweet. It's basically python, with optional static type declarations and the ability to call c functions 20 | directly. Take a look at `wrapper.pyx`. It looks like python, but it gets translated into C, and then compiled into 21 | a shared object file which you import from python (look at the `test.py` file) 22 | 23 | Cython is the way to go. 24 | 25 | ## difference from PyCUDA 26 | 27 | The point of this project is not to enable you to access the CUDA API in python, to write cuda code in strings and have 28 | them be dynamically compiled, or anything like that. 29 | 30 | Instead, the goal is to demonstrate some of the biolerplate and tricks needed to make a CPython extension module that 31 | uses CUDA compiled with setuptools/distutils just like your standard C exension modules. 32 | 33 | ## authors 34 | - Robert McGibbon 35 | - Yutong Zhao 36 | 37 | ## installation 38 | 39 | Requirements: 40 | - python 41 | - python setuptools, numpy 42 | - nvcc. I'm using version 4.2 43 | - nose (for testing) 44 | - swig for the swig wrapping method. I've tested with version 1.3.40 45 | - cython for the cython wrapping method. I've tested with version 0.16 46 | 47 | To install, `cd` into your directory of choice -- either `swig` or `cython`. Then, just run `$ python setup.py install`. To see if everything is working, run `$ nosetests` 48 | 49 | Silence is golden! 50 | 51 | -------------------------------------------------------------------------------- /cython/MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include src/ * 2 | include *.pxd 3 | include test.py 4 | include *.pyx 5 | include README.md 6 | -------------------------------------------------------------------------------- /cython/README.md: -------------------------------------------------------------------------------- 1 | ## cython wrapped CUDA/C++ 2 | 3 | This code makes an explicit cython class that wraps the C++ class, exposing it in python. It involves a little bit more repitition than the swig code in principle, but in practice it's MUCH easier. 4 | 5 | To install: 6 | 7 | `$ python setup.py install` 8 | 9 | to test: 10 | 11 | `$ pytest test.py` 12 | 13 | you need a relatively recent version of cython (>=0.16). 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /cython/setup.py: -------------------------------------------------------------------------------- 1 | # from future.utils import iteritems 2 | import os 3 | from os.path import join as pjoin 4 | from setuptools import setup 5 | from distutils.extension import Extension 6 | from Cython.Distutils import build_ext 7 | import numpy 8 | 9 | 10 | def find_in_path(name, path): 11 | """Find a file in a search path""" 12 | 13 | # Adapted fom http://code.activestate.com/recipes/52224 14 | for dir in path.split(os.pathsep): 15 | binpath = pjoin(dir, name) 16 | if os.path.exists(binpath): 17 | return os.path.abspath(binpath) 18 | return None 19 | 20 | 21 | def locate_cuda(): 22 | """Locate the CUDA environment on the system 23 | 24 | Returns a dict with keys 'home', 'nvcc', 'include', and 'lib64' 25 | and values giving the absolute path to each directory. 26 | 27 | Starts by looking for the CUDAHOME env variable. If not found, 28 | everything is based on finding 'nvcc' in the PATH. 29 | """ 30 | 31 | # First check if the CUDAHOME env variable is in use 32 | if 'CUDAHOME' in os.environ: 33 | home = os.environ['CUDAHOME'] 34 | nvcc = pjoin(home, 'bin', 'nvcc') 35 | else: 36 | # Otherwise, search the PATH for NVCC 37 | nvcc = find_in_path('nvcc', os.environ['PATH']) 38 | if nvcc is None: 39 | raise EnvironmentError('The nvcc binary could not be ' 40 | 'located in your $PATH. Either add it to your path, ' 41 | 'or set $CUDAHOME') 42 | home = os.path.dirname(os.path.dirname(nvcc)) 43 | 44 | cudaconfig = {'home': home, 'nvcc': nvcc, 45 | 'include': pjoin(home, 'include'), 46 | 'lib64': pjoin(home, 'lib64')} 47 | for k, v in iter(cudaconfig.items()): 48 | if not os.path.exists(v): 49 | raise EnvironmentError('The CUDA %s path could not be ' 50 | 'located in %s' % (k, v)) 51 | 52 | return cudaconfig 53 | 54 | 55 | def customize_compiler_for_nvcc(self): 56 | """Inject deep into distutils to customize how the dispatch 57 | to gcc/nvcc works. 58 | 59 | If you subclass UnixCCompiler, it's not trivial to get your subclass 60 | injected in, and still have the right customizations (i.e. 61 | distutils.sysconfig.customize_compiler) run on it. So instead of going 62 | the OO route, I have this. Note, it's kindof like a wierd functional 63 | subclassing going on. 64 | """ 65 | 66 | # Tell the compiler it can processes .cu 67 | self.src_extensions.append('.cu') 68 | 69 | # Save references to the default compiler_so and _comple methods 70 | default_compiler_so = self.compiler_so 71 | super = self._compile 72 | 73 | # Now redefine the _compile method. This gets executed for each 74 | # object but distutils doesn't have the ability to change compilers 75 | # based on source extension: we add it. 76 | def _compile(obj, src, ext, cc_args, extra_postargs, pp_opts): 77 | if os.path.splitext(src)[1] == '.cu': 78 | # use the cuda for .cu files 79 | self.set_executable('compiler_so', CUDA['nvcc']) 80 | # use only a subset of the extra_postargs, which are 1-1 81 | # translated from the extra_compile_args in the Extension class 82 | postargs = extra_postargs['nvcc'] 83 | else: 84 | postargs = extra_postargs['gcc'] 85 | 86 | super(obj, src, ext, cc_args, postargs, pp_opts) 87 | # Reset the default compiler_so, which we might have changed for cuda 88 | self.compiler_so = default_compiler_so 89 | 90 | # Inject our redefined _compile method into the class 91 | self._compile = _compile 92 | 93 | 94 | 95 | # Run the customize_compiler 96 | class custom_build_ext(build_ext): 97 | def build_extensions(self): 98 | customize_compiler_for_nvcc(self.compiler) 99 | build_ext.build_extensions(self) 100 | 101 | 102 | 103 | CUDA = locate_cuda() 104 | 105 | # Obtain the numpy include directory. This logic works across numpy versions. 106 | try: 107 | numpy_include = numpy.get_include() 108 | except AttributeError: 109 | numpy_include = numpy.get_numpy_include() 110 | 111 | 112 | ext = Extension('gpuadder', 113 | sources = ['src/manager.cu', 'wrapper.pyx'], 114 | library_dirs = [CUDA['lib64']], 115 | libraries = ['cudart'], 116 | language = 'c++', 117 | runtime_library_dirs = [CUDA['lib64']], 118 | # This syntax is specific to this build system 119 | # we're only going to use certain compiler args with nvcc 120 | # and not with gcc the implementation of this trick is in 121 | # customize_compiler() 122 | extra_compile_args= { 123 | 'gcc': [], 124 | 'nvcc': [ 125 | '-arch=sm_30', '--ptxas-options=-v', '-c', 126 | '--compiler-options', "'-fPIC'" 127 | ] 128 | }, 129 | include_dirs = [numpy_include, CUDA['include'], 'src'] 130 | ) 131 | 132 | 133 | 134 | setup(name = 'gpuadder', 135 | # Random metadata. there's more you can supply 136 | author = 'Robert McGibbon', 137 | version = '0.1', 138 | 139 | ext_modules = [ext], 140 | 141 | # Inject our custom trigger 142 | cmdclass = {'build_ext': custom_build_ext}, 143 | 144 | # Since the package has c code, the egg cannot be zipped 145 | zip_safe = False) 146 | -------------------------------------------------------------------------------- /cython/src/kernel.cu: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void __global__ kernel_add_one(int* a, int length) { 4 | int gid = threadIdx.x + blockDim.x*blockIdx.x; 5 | 6 | while(gid < length) { 7 | a[gid] += 1; 8 | gid += blockDim.x*gridDim.x; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /cython/src/manager.cu: -------------------------------------------------------------------------------- 1 | /* 2 | This is the central piece of code. This file implements a class 3 | (interface in gpuadder.hh) that takes data in on the cpu side, copies 4 | it to the gpu, and exposes functions (increment and retreive) that let 5 | you perform actions with the GPU 6 | 7 | This class will get translated into python via swig 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | using namespace std; 15 | 16 | GPUAdder::GPUAdder (int* array_host_, int length_) { 17 | array_host = array_host_; 18 | length = length_; 19 | int size = length * sizeof(int); 20 | cudaError_t err = cudaMalloc((void**) &array_device, size); 21 | assert(err == 0); 22 | err = cudaMemcpy(array_device, array_host, size, cudaMemcpyHostToDevice); 23 | assert(err == 0); 24 | } 25 | 26 | void GPUAdder::increment() { 27 | kernel_add_one<<<64, 64>>>(array_device, length); 28 | cudaError_t err = cudaGetLastError(); 29 | assert(err == 0); 30 | } 31 | 32 | void GPUAdder::retreive() { 33 | int size = length * sizeof(int); 34 | cudaMemcpy(array_host, array_device, size, cudaMemcpyDeviceToHost); 35 | cudaError_t err = cudaGetLastError(); 36 | if(err != 0) { cout << err << endl; assert(0); } 37 | } 38 | 39 | void GPUAdder::retreive_to (int* array_host_, int length_) { 40 | assert(length == length_); 41 | int size = length * sizeof(int); 42 | cudaMemcpy(array_host_, array_device, size, cudaMemcpyDeviceToHost); 43 | cudaError_t err = cudaGetLastError(); 44 | assert(err == 0); 45 | } 46 | 47 | GPUAdder::~GPUAdder() { 48 | cudaFree(array_device); 49 | } 50 | -------------------------------------------------------------------------------- /cython/src/manager.hh: -------------------------------------------------------------------------------- 1 | class GPUAdder { 2 | // pointer to the GPU memory where the array is stored 3 | int* array_device; 4 | // pointer to the CPU memory where the array is stored 5 | int* array_host; 6 | // length of the array (number of elements) 7 | int length; 8 | 9 | public: 10 | /* By using the swig default names INPLACE_ARRAY1, DIM1 in the header 11 | file (these aren't the names in the implementation file), we're giving 12 | swig the info it needs to cast to and from numpy arrays. 13 | 14 | If instead the constructor line said 15 | GPUAdder(int* myarray, int length); 16 | 17 | We would need a line like this in the swig.i file 18 | %apply (int* ARGOUT_ARRAY1, int DIM1) {(int* myarray, int length)} 19 | */ 20 | 21 | GPUAdder(int* INPLACE_ARRAY1, int DIM1); // constructor (copies to GPU) 22 | 23 | ~GPUAdder(); // destructor 24 | 25 | void increment(); // does operation inplace on the GPU 26 | 27 | void retreive(); //gets results back from GPU, putting them in the memory that was passed in 28 | // the constructor 29 | 30 | //gets results back from the gpu, putting them in the supplied memory location 31 | void retreive_to (int* INPLACE_ARRAY1, int DIM1); 32 | 33 | 34 | }; 35 | -------------------------------------------------------------------------------- /cython/test.py: -------------------------------------------------------------------------------- 1 | import gpuadder 2 | import numpy as np 3 | import numpy.testing as npt 4 | import gpuadder 5 | 6 | def test(): 7 | arr = np.array([1,2,2,2], dtype=np.int32) 8 | adder = gpuadder.GPUAdder(arr) 9 | adder.increment() 10 | 11 | adder.retreive_inplace() 12 | results2 = adder.retreive() 13 | 14 | npt.assert_array_equal(arr, [2,3,3,3]) 15 | npt.assert_array_equal(results2, [2,3,3,3]) 16 | -------------------------------------------------------------------------------- /cython/wrapper.pyx: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | cimport numpy as np 3 | 4 | assert sizeof(int) == sizeof(np.int32_t) 5 | 6 | cdef extern from "src/manager.hh": 7 | cdef cppclass C_GPUAdder "GPUAdder": 8 | C_GPUAdder(np.int32_t*, int) 9 | void increment() 10 | void retreive() 11 | void retreive_to(np.int32_t*, int) 12 | 13 | cdef class GPUAdder: 14 | cdef C_GPUAdder* g 15 | cdef int dim1 16 | 17 | def __cinit__(self, np.ndarray[ndim=1, dtype=np.int32_t] arr): 18 | self.dim1 = len(arr) 19 | self.g = new C_GPUAdder(&arr[0], self.dim1) 20 | 21 | def increment(self): 22 | self.g.increment() 23 | 24 | def retreive_inplace(self): 25 | self.g.retreive() 26 | 27 | def retreive(self): 28 | cdef np.ndarray[ndim=1, dtype=np.int32_t] a = np.zeros(self.dim1, dtype=np.int32) 29 | 30 | self.g.retreive_to(&a[0], self.dim1) 31 | 32 | return a 33 | -------------------------------------------------------------------------------- /swig/README.md: -------------------------------------------------------------------------------- 1 | ## files 2 | 3 | 1. `manager.cu`, `manager.hh`: Implementation and header file for the central C++ class. The function of this 4 | class is to manage the GPU memory and execution lifecycle, and generally act as a "window" to expose the GPU side kernels. The key methods are a constructor which takes as input an array and copies it over to the GPU, and a `retreive()` method which copies back the data from the GPU to the CPU. Other methods on the C++ class can trigger CUDA kernels to perform in place operations on the GPU memory. This trivial project's kernel contains only the code to increment all of the elements in an array by one. 5 | 6 | 2. `kernel.cu`: This is a CUDA file where the GPU kernels go. The kernels are called by methods in the manager. 7 | 8 | 3. `gpuadder.i`: This is a swig interface file that gives instructions for translating manager.cu into class that can be accessed from python. Beyond simply the bridge, the main functionality provided by swig here is the ability to automatically resolve numpy arrays into C pointers with without too much extra programmer pain. 9 | 10 | 4. `setup.py`: Python setup script that runs the compilation. 11 | 12 | ## compilation pipeline 13 | 14 | 1. Right at the top of the `setup.py` script, we re-run the swig inteface builder. It takes in the `gpuadder.i` file (along with `manager.hh` and `numpy.i`) and builds a python module and a c++ file called `swig_wrap.cpp`. 15 | 16 | 2. `manager.cu` is compiled by NVCC into `manager.o`. `manager.cu` #includes `kernel.cu`, so that's how the kernels get incorporated. A special setuptools hack prevents NVCC from trying to make a .so file -- we only want the .o. 17 | 18 | 3. `swig_wrap.cpp` is compiled by GCC into `swig_wrap.o` 19 | 20 | 4. `swig_wrap.o` and `manager.o` are linked together by GCC into a final .so file that can be imported from python. This `.so` file has an underscore at the start of its name, and goes along with the python file generated in step 1 by swig, which has the same name but without the underscore. In this example, they are `gpuadder.py` and `_gpuadder.so`. These files get put into your python site-packages. 21 | 22 | Note: the python module gets its name from the %module line in `gpuadder.i` (line 3). That name (in this case `gpuadder`) needs to match the name in the `py_modules` line of setup.py (line 130) so that the python file `gpuadder.py` and the shared object file `_gpuadder.so` match up. 23 | 24 | 25 | ## setuptools monkey patching and setup.py 26 | 27 | setuptools does not know anything about NVCC by default, and doesn't really support having multiple compilers that are on the same OS (it can deal with microsoft vs. linux, but not with nvcc vs gcc). So we need some tricks. 28 | 29 | To implement the "special hack" in step 2 above, we customize the compiler class used by setuptools to call NVCC for .cu files and its regular compiler (probably gcc) for all other files. We also use some special logic inthe extension class -- setting `extra_compile_args` as a dict -- so that we can specify separate compile arguments for gcc and nvcc. 30 | -------------------------------------------------------------------------------- /swig/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from os.path import join as pjoin 3 | from setuptools import setup 4 | from distutils.extension import Extension 5 | from distutils.command.build_ext import build_ext 6 | import subprocess 7 | import numpy 8 | 9 | def find_in_path(name, path): 10 | "Find a file in a search path" 11 | #adapted fom http://code.activestate.com/recipes/52224-find-a-file-given-a-search-path/ 12 | for dir in path.split(os.pathsep): 13 | binpath = pjoin(dir, name) 14 | if os.path.exists(binpath): 15 | return os.path.abspath(binpath) 16 | return None 17 | 18 | 19 | def locate_cuda(): 20 | """Locate the CUDA environment on the system 21 | 22 | Returns a dict with keys 'home', 'nvcc', 'include', and 'lib64' 23 | and values giving the absolute path to each directory. 24 | 25 | Starts by looking for the CUDAHOME env variable. If not found, everything 26 | is based on finding 'nvcc' in the PATH. 27 | """ 28 | 29 | # first check if the CUDAHOME env variable is in use 30 | if 'CUDAHOME' in os.environ: 31 | home = os.environ['CUDAHOME'] 32 | nvcc = pjoin(home, 'bin', 'nvcc') 33 | else: 34 | # otherwise, search the PATH for NVCC 35 | nvcc = find_in_path('nvcc', os.environ['PATH']) 36 | if nvcc is None: 37 | raise EnvironmentError('The nvcc binary could not be ' 38 | 'located in your $PATH. Either add it to your path, or set $CUDAHOME') 39 | home = os.path.dirname(os.path.dirname(nvcc)) 40 | 41 | cudaconfig = {'home':home, 'nvcc':nvcc, 42 | 'include': pjoin(home, 'include'), 43 | 'lib64': pjoin(home, 'lib64')} 44 | for k, v in cudaconfig.iteritems(): 45 | if not os.path.exists(v): 46 | raise EnvironmentError('The CUDA %s path could not be located in %s' % (k, v)) 47 | 48 | return cudaconfig 49 | CUDA = locate_cuda() 50 | 51 | 52 | # Obtain the numpy include directory. This logic works across numpy versions. 53 | try: 54 | numpy_include = numpy.get_include() 55 | except AttributeError: 56 | numpy_include = numpy.get_numpy_include() 57 | 58 | 59 | ext = Extension('_gpuadder', 60 | sources=['src/swig_wrap.cpp', 'src/manager.cu'], 61 | library_dirs=[CUDA['lib64']], 62 | libraries=['cudart'], 63 | runtime_library_dirs=[CUDA['lib64']], 64 | # this syntax is specific to this build system 65 | # we're only going to use certain compiler args with nvcc and not with gcc 66 | # the implementation of this trick is in customize_compiler() below 67 | extra_compile_args={'gcc': [], 68 | 'nvcc': ['-arch=sm_20', '--ptxas-options=-v', '-c', '--compiler-options', "'-fPIC'"]}, 69 | include_dirs = [numpy_include, CUDA['include'], 'src']) 70 | 71 | 72 | # check for swig 73 | if find_in_path('swig', os.environ['PATH']): 74 | subprocess.check_call('swig -python -c++ -o src/swig_wrap.cpp src/gpuadder.i', shell=True) 75 | else: 76 | raise EnvironmentError('the swig executable was not found in your PATH') 77 | 78 | 79 | 80 | def customize_compiler_for_nvcc(self): 81 | """inject deep into distutils to customize how the dispatch 82 | to gcc/nvcc works. 83 | 84 | If you subclass UnixCCompiler, it's not trivial to get your subclass 85 | injected in, and still have the right customizations (i.e. 86 | distutils.sysconfig.customize_compiler) run on it. So instead of going 87 | the OO route, I have this. Note, it's kindof like a wierd functional 88 | subclassing going on.""" 89 | 90 | # tell the compiler it can processes .cu 91 | self.src_extensions.append('.cu') 92 | 93 | # save references to the default compiler_so and _comple methods 94 | default_compiler_so = self.compiler_so 95 | super = self._compile 96 | 97 | # now redefine the _compile method. This gets executed for each 98 | # object but distutils doesn't have the ability to change compilers 99 | # based on source extension: we add it. 100 | def _compile(obj, src, ext, cc_args, extra_postargs, pp_opts): 101 | if os.path.splitext(src)[1] == '.cu': 102 | # use the cuda for .cu files 103 | self.set_executable('compiler_so', CUDA['nvcc']) 104 | # use only a subset of the extra_postargs, which are 1-1 translated 105 | # from the extra_compile_args in the Extension class 106 | postargs = extra_postargs['nvcc'] 107 | else: 108 | postargs = extra_postargs['gcc'] 109 | 110 | super(obj, src, ext, cc_args, postargs, pp_opts) 111 | # reset the default compiler_so, which we might have changed for cuda 112 | self.compiler_so = default_compiler_so 113 | 114 | # inject our redefined _compile method into the class 115 | self._compile = _compile 116 | 117 | 118 | # run the customize_compiler 119 | class custom_build_ext(build_ext): 120 | def build_extensions(self): 121 | customize_compiler_for_nvcc(self.compiler) 122 | build_ext.build_extensions(self) 123 | 124 | setup(name='gpuadder', 125 | # random metadata. there's more you can supploy 126 | author='Robert McGibbon', 127 | version='0.1', 128 | 129 | # this is necessary so that the swigged python file gets picked up 130 | py_modules=['gpuadder'], 131 | package_dir={'': 'src'}, 132 | 133 | ext_modules = [ext], 134 | 135 | # inject our custom trigger 136 | cmdclass={'build_ext': custom_build_ext}, 137 | 138 | # since the package has c code, the egg cannot be zipped 139 | zip_safe=False) 140 | -------------------------------------------------------------------------------- /swig/src/gpuadder.i: -------------------------------------------------------------------------------- 1 | /* -*- C -*- (not really, but good for syntax highlighting) */ 2 | 3 | %module gpuadder 4 | /* This is the swig "interface file" which gives instructions to swig 5 | on how to turn the class declared in manager.hh into the python module 6 | "gpuadder" 7 | 8 | The key thing that we want it to accomplish is automatic conversion of 9 | arrays from numpy (python) into CUDA/C++ (simply pointers and lengths). 10 | Provided that we give swig proper instructions, either by special naming 11 | of the variables in the header file (manager.hh) or by a instruction in this 12 | file (line 30), swig can do the numpy<->c++ conversion seamlessly. 13 | */ 14 | 15 | %{ 16 | #define SWIG_FILE_WITH_INIT 17 | #include "manager.hh" 18 | %} 19 | 20 | // swig doesn't know about numpy by default, so we need to give it an extra numpy interface 21 | // file that I downloaded from http://docs.scipy.org/doc/numpy/reference/swig.interface-file.html 22 | %include "numpy.i" 23 | 24 | %init %{ 25 | import_array(); 26 | %} 27 | 28 | /* Because gpuadder.hh uses the swig default names for variables being 29 | passed to methods which are supposed to be interpreted as arrays, 30 | we don't need the following line: */ 31 | 32 | // %apply (int* ARGOUT_ARRAY1, int DIM1) {(int* array_host_, int length_)} 33 | 34 | /* if instead the names of the pointers were not the standard ones, this 35 | type of translation would be necessary. 36 | http://www.scipy.org/Cookbook/SWIG_NumPy_examples */ 37 | 38 | %include "manager.hh" 39 | -------------------------------------------------------------------------------- /swig/src/kernel.cu: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void __global__ kernel_add_one(int* a, int length) { 4 | int gid = threadIdx.x + blockDim.x*blockIdx.x; 5 | 6 | while(gid < length) { 7 | a[gid] += 1; 8 | gid += blockDim.x*gridDim.x; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /swig/src/manager.cu: -------------------------------------------------------------------------------- 1 | /* 2 | This is the central piece of code. This file implements a class 3 | (interface in gpuadder.hh) that takes data in on the cpu side, copies 4 | it to the gpu, and exposes functions (increment and retreive) that let 5 | you perform actions with the GPU 6 | 7 | This class will get translated into python via swig 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | using namespace std; 15 | 16 | GPUAdder::GPUAdder (int* array_host_, int length_) { 17 | array_host = array_host_; 18 | length = length_; 19 | int size = length * sizeof(int); 20 | cudaError_t err = cudaMalloc((void**) &array_device, size); 21 | assert(err == 0); 22 | err = cudaMemcpy(array_device, array_host, size, cudaMemcpyHostToDevice); 23 | assert(err == 0); 24 | } 25 | 26 | void GPUAdder::increment() { 27 | kernel_add_one<<<64, 64>>>(array_device, length); 28 | cudaError_t err = cudaGetLastError(); 29 | assert(err == 0); 30 | } 31 | 32 | void GPUAdder::retreive() { 33 | int size = length * sizeof(int); 34 | cudaMemcpy(array_host, array_device, size, cudaMemcpyDeviceToHost); 35 | cudaError_t err = cudaGetLastError(); 36 | if(err != 0) { cout << err << endl; assert(0); } 37 | } 38 | 39 | void GPUAdder::retreive_to (int* array_host_, int length_) { 40 | assert(length == length_); 41 | int size = length * sizeof(int); 42 | cudaMemcpy(array_host_, array_device, size, cudaMemcpyDeviceToHost); 43 | cudaError_t err = cudaGetLastError(); 44 | assert(err == 0); 45 | } 46 | 47 | GPUAdder::~GPUAdder() { 48 | cudaFree(array_device); 49 | } 50 | -------------------------------------------------------------------------------- /swig/src/manager.hh: -------------------------------------------------------------------------------- 1 | class GPUAdder { 2 | // pointer to the GPU memory where the array is stored 3 | int* array_device; 4 | // pointer to the CPU memory where the array is stored 5 | int* array_host; 6 | // length of the array (number of elements) 7 | int length; 8 | 9 | public: 10 | /* By using the swig default names INPLACE_ARRAY1, DIM1 in the header 11 | file (these aren't the names in the implementation file), we're giving 12 | swig the info it needs to cast to and from numpy arrays. 13 | 14 | If instead the constructor line said 15 | GPUAdder(int* myarray, int length); 16 | 17 | We would need a line like this in the swig.i file 18 | %apply (int* ARGOUT_ARRAY1, int DIM1) {(int* myarray, int length)} 19 | */ 20 | 21 | 22 | GPUAdder(int* INPLACE_ARRAY1, int DIM1); // constructor (copies to GPU) 23 | 24 | ~GPUAdder(); // destructor 25 | 26 | void increment(); // does operation inplace on the GPU 27 | 28 | void retreive(); //gets results back from GPU, putting them in the memory that was passed in 29 | // the constructor 30 | 31 | //gets results back from the gpu, putting them in the supplied memory location 32 | void retreive_to (int* INPLACE_ARRAY1, int DIM1); 33 | 34 | 35 | }; 36 | -------------------------------------------------------------------------------- /swig/src/numpy.i: -------------------------------------------------------------------------------- 1 | /* -*- C -*- (not really, but good for syntax highlighting) */ 2 | #ifdef SWIGPYTHON 3 | 4 | %{ 5 | #ifndef SWIG_FILE_WITH_INIT 6 | # define NO_IMPORT_ARRAY 7 | #endif 8 | #include "stdio.h" 9 | #include 10 | %} 11 | 12 | /**********************************************************************/ 13 | 14 | /* The following code originally appeared in 15 | * enthought/kiva/agg/src/numeric.i written by Eric Jones. It was 16 | * translated from C++ to C by John Hunter. Bill Spotz has modified 17 | * it to fix some minor bugs, upgrade from Numeric to numpy (all 18 | * versions), add some comments and functionality, and convert from 19 | * direct code insertion to SWIG fragments. 20 | */ 21 | 22 | %fragment("NumPy_Macros", "header") 23 | { 24 | /* Macros to extract array attributes. 25 | */ 26 | %#define is_array(a) ((a) && PyArray_Check((PyArrayObject *)a)) 27 | %#define array_type(a) (int)(PyArray_TYPE(a)) 28 | %#define array_numdims(a) (((PyArrayObject *)a)->nd) 29 | %#define array_dimensions(a) (((PyArrayObject *)a)->dimensions) 30 | %#define array_size(a,i) (((PyArrayObject *)a)->dimensions[i]) 31 | %#define array_data(a) (((PyArrayObject *)a)->data) 32 | %#define array_is_contiguous(a) (PyArray_ISCONTIGUOUS(a)) 33 | %#define array_is_native(a) (PyArray_ISNOTSWAPPED(a)) 34 | %#define array_is_fortran(a) (PyArray_ISFORTRAN(a)) 35 | } 36 | 37 | /**********************************************************************/ 38 | 39 | %fragment("NumPy_Utilities", "header") 40 | { 41 | /* Given a PyObject, return a string describing its type. 42 | */ 43 | const char* pytype_string(PyObject* py_obj) { 44 | if (py_obj == NULL ) return "C NULL value"; 45 | if (py_obj == Py_None ) return "Python None" ; 46 | if (PyCallable_Check(py_obj)) return "callable" ; 47 | if (PyString_Check( py_obj)) return "string" ; 48 | if (PyInt_Check( py_obj)) return "int" ; 49 | if (PyFloat_Check( py_obj)) return "float" ; 50 | if (PyDict_Check( py_obj)) return "dict" ; 51 | if (PyList_Check( py_obj)) return "list" ; 52 | if (PyTuple_Check( py_obj)) return "tuple" ; 53 | if (PyFile_Check( py_obj)) return "file" ; 54 | if (PyModule_Check( py_obj)) return "module" ; 55 | if (PyInstance_Check(py_obj)) return "instance" ; 56 | 57 | return "unkown type"; 58 | } 59 | 60 | /* Given a NumPy typecode, return a string describing the type. 61 | */ 62 | const char* typecode_string(int typecode) { 63 | static const char* type_names[25] = {"bool", "byte", "unsigned byte", 64 | "short", "unsigned short", "int", 65 | "unsigned int", "long", "unsigned long", 66 | "long long", "unsigned long long", 67 | "float", "double", "long double", 68 | "complex float", "complex double", 69 | "complex long double", "object", 70 | "string", "unicode", "void", "ntypes", 71 | "notype", "char", "unknown"}; 72 | return typecode < 24 ? type_names[typecode] : type_names[24]; 73 | } 74 | 75 | /* Make sure input has correct numpy type. Allow character and byte 76 | * to match. Also allow int and long to match. This is deprecated. 77 | * You should use PyArray_EquivTypenums() instead. 78 | */ 79 | int type_match(int actual_type, int desired_type) { 80 | return PyArray_EquivTypenums(actual_type, desired_type); 81 | } 82 | } 83 | 84 | /**********************************************************************/ 85 | 86 | %fragment("NumPy_Object_to_Array", "header", 87 | fragment="NumPy_Backward_Compatibility", 88 | fragment="NumPy_Macros", 89 | fragment="NumPy_Utilities") 90 | { 91 | /* Given a PyObject pointer, cast it to a PyArrayObject pointer if 92 | * legal. If not, set the python error string appropriately and 93 | * return NULL. 94 | */ 95 | PyArrayObject* obj_to_array_no_conversion(PyObject* input, int typecode) 96 | { 97 | PyArrayObject* ary = NULL; 98 | if (is_array(input) && (typecode == NPY_NOTYPE || 99 | PyArray_EquivTypenums(array_type(input), typecode))) 100 | { 101 | ary = (PyArrayObject*) input; 102 | } 103 | else if is_array(input) 104 | { 105 | const char* desired_type = typecode_string(typecode); 106 | const char* actual_type = typecode_string(array_type(input)); 107 | PyErr_Format(PyExc_TypeError, 108 | "Array of type '%s' required. Array of type '%s' given", 109 | desired_type, actual_type); 110 | ary = NULL; 111 | } 112 | else 113 | { 114 | const char * desired_type = typecode_string(typecode); 115 | const char * actual_type = pytype_string(input); 116 | PyErr_Format(PyExc_TypeError, 117 | "Array of type '%s' required. A '%s' was given", 118 | desired_type, actual_type); 119 | ary = NULL; 120 | } 121 | return ary; 122 | } 123 | 124 | /* Convert the given PyObject to a NumPy array with the given 125 | * typecode. On success, return a valid PyArrayObject* with the 126 | * correct type. On failure, the python error string will be set and 127 | * the routine returns NULL. 128 | */ 129 | PyArrayObject* obj_to_array_allow_conversion(PyObject* input, int typecode, 130 | int* is_new_object) 131 | { 132 | PyArrayObject* ary = NULL; 133 | PyObject* py_obj; 134 | if (is_array(input) && (typecode == NPY_NOTYPE || 135 | PyArray_EquivTypenums(array_type(input),typecode))) 136 | { 137 | ary = (PyArrayObject*) input; 138 | *is_new_object = 0; 139 | } 140 | else 141 | { 142 | py_obj = PyArray_FROMANY(input, typecode, 0, 0, NPY_DEFAULT); 143 | /* If NULL, PyArray_FromObject will have set python error value.*/ 144 | ary = (PyArrayObject*) py_obj; 145 | *is_new_object = 1; 146 | } 147 | return ary; 148 | } 149 | 150 | /* Given a PyArrayObject, check to see if it is contiguous. If so, 151 | * return the input pointer and flag it as not a new object. If it is 152 | * not contiguous, create a new PyArrayObject using the original data, 153 | * flag it as a new object and return the pointer. 154 | */ 155 | PyArrayObject* make_contiguous(PyArrayObject* ary, int* is_new_object, 156 | int min_dims, int max_dims) 157 | { 158 | PyArrayObject* result; 159 | if (array_is_contiguous(ary)) 160 | { 161 | result = ary; 162 | *is_new_object = 0; 163 | } 164 | else 165 | { 166 | result = (PyArrayObject*) PyArray_ContiguousFromObject((PyObject*)ary, 167 | array_type(ary), 168 | min_dims, 169 | max_dims); 170 | *is_new_object = 1; 171 | } 172 | return result; 173 | } 174 | 175 | /* Given a PyArrayObject, check to see if it is Fortran-contiguous. 176 | * If so, return the input pointer, but do not flag it as not a new 177 | * object. If it is not Fortran-contiguous, create a new 178 | * PyArrayObject using the original data, flag it as a new object 179 | * and return the pointer. 180 | */ 181 | PyArrayObject* make_fortran(PyArrayObject* ary, int* is_new_object, 182 | int min_dims, int max_dims) 183 | { 184 | PyArrayObject* result; 185 | if (array_is_fortran(ary)) 186 | { 187 | result = ary; 188 | *is_new_object = 0; 189 | } 190 | else 191 | { 192 | Py_INCREF(ary->descr); 193 | result = (PyArrayObject*) PyArray_FromArray(ary, ary->descr, NPY_FORTRAN); 194 | *is_new_object = 1; 195 | } 196 | return result; 197 | } 198 | 199 | /* Convert a given PyObject to a contiguous PyArrayObject of the 200 | * specified type. If the input object is not a contiguous 201 | * PyArrayObject, a new one will be created and the new object flag 202 | * will be set. 203 | */ 204 | PyArrayObject* obj_to_array_contiguous_allow_conversion(PyObject* input, 205 | int typecode, 206 | int* is_new_object) 207 | { 208 | int is_new1 = 0; 209 | int is_new2 = 0; 210 | PyArrayObject* ary2; 211 | PyArrayObject* ary1 = obj_to_array_allow_conversion(input, typecode, 212 | &is_new1); 213 | if (ary1) 214 | { 215 | ary2 = make_contiguous(ary1, &is_new2, 0, 0); 216 | if ( is_new1 && is_new2) 217 | { 218 | Py_DECREF(ary1); 219 | } 220 | ary1 = ary2; 221 | } 222 | *is_new_object = is_new1 || is_new2; 223 | return ary1; 224 | } 225 | 226 | /* Convert a given PyObject to a Fortran-ordered PyArrayObject of the 227 | * specified type. If the input object is not a Fortran-ordered 228 | * PyArrayObject, a new one will be created and the new object flag 229 | * will be set. 230 | */ 231 | PyArrayObject* obj_to_array_fortran_allow_conversion(PyObject* input, 232 | int typecode, 233 | int* is_new_object) 234 | { 235 | int is_new1 = 0; 236 | int is_new2 = 0; 237 | PyArrayObject* ary2; 238 | PyArrayObject* ary1 = obj_to_array_allow_conversion(input, typecode, 239 | &is_new1); 240 | if (ary1) 241 | { 242 | ary2 = make_fortran(ary1, &is_new2, 0, 0); 243 | if (is_new1 && is_new2) 244 | { 245 | Py_DECREF(ary1); 246 | } 247 | ary1 = ary2; 248 | } 249 | *is_new_object = is_new1 || is_new2; 250 | return ary1; 251 | } 252 | 253 | } /* end fragment */ 254 | 255 | 256 | /**********************************************************************/ 257 | 258 | %fragment("NumPy_Array_Requirements", "header", 259 | fragment="NumPy_Backward_Compatibility", 260 | fragment="NumPy_Macros") 261 | { 262 | /* Test whether a python object is contiguous. If array is 263 | * contiguous, return 1. Otherwise, set the python error string and 264 | * return 0. 265 | */ 266 | int require_contiguous(PyArrayObject* ary) 267 | { 268 | int contiguous = 1; 269 | if (!array_is_contiguous(ary)) 270 | { 271 | PyErr_SetString(PyExc_TypeError, 272 | "Array must be contiguous. A non-contiguous array was given"); 273 | contiguous = 0; 274 | } 275 | return contiguous; 276 | } 277 | 278 | /* Require that a numpy array is not byte-swapped. If the array is 279 | * not byte-swapped, return 1. Otherwise, set the python error string 280 | * and return 0. 281 | */ 282 | int require_native(PyArrayObject* ary) 283 | { 284 | int native = 1; 285 | if (!array_is_native(ary)) 286 | { 287 | PyErr_SetString(PyExc_TypeError, 288 | "Array must have native byteorder. " 289 | "A byte-swapped array was given"); 290 | native = 0; 291 | } 292 | return native; 293 | } 294 | 295 | /* Require the given PyArrayObject to have a specified number of 296 | * dimensions. If the array has the specified number of dimensions, 297 | * return 1. Otherwise, set the python error string and return 0. 298 | */ 299 | int require_dimensions(PyArrayObject* ary, int exact_dimensions) 300 | { 301 | int success = 1; 302 | if (array_numdims(ary) != exact_dimensions) 303 | { 304 | PyErr_Format(PyExc_TypeError, 305 | "Array must have %d dimensions. Given array has %d dimensions", 306 | exact_dimensions, array_numdims(ary)); 307 | success = 0; 308 | } 309 | return success; 310 | } 311 | 312 | /* Require the given PyArrayObject to have one of a list of specified 313 | * number of dimensions. If the array has one of the specified number 314 | * of dimensions, return 1. Otherwise, set the python error string 315 | * and return 0. 316 | */ 317 | int require_dimensions_n(PyArrayObject* ary, int* exact_dimensions, int n) 318 | { 319 | int success = 0; 320 | int i; 321 | char dims_str[255] = ""; 322 | char s[255]; 323 | for (i = 0; i < n && !success; i++) 324 | { 325 | if (array_numdims(ary) == exact_dimensions[i]) 326 | { 327 | success = 1; 328 | } 329 | } 330 | if (!success) 331 | { 332 | for (i = 0; i < n-1; i++) 333 | { 334 | sprintf(s, "%d, ", exact_dimensions[i]); 335 | strcat(dims_str,s); 336 | } 337 | sprintf(s, " or %d", exact_dimensions[n-1]); 338 | strcat(dims_str,s); 339 | PyErr_Format(PyExc_TypeError, 340 | "Array must have %s dimensions. Given array has %d dimensions", 341 | dims_str, array_numdims(ary)); 342 | } 343 | return success; 344 | } 345 | 346 | /* Require the given PyArrayObject to have a specified shape. If the 347 | * array has the specified shape, return 1. Otherwise, set the python 348 | * error string and return 0. 349 | */ 350 | int require_size(PyArrayObject* ary, npy_intp* size, int n) 351 | { 352 | int i; 353 | int success = 1; 354 | int len; 355 | char desired_dims[255] = "["; 356 | char s[255]; 357 | char actual_dims[255] = "["; 358 | for(i=0; i < n;i++) 359 | { 360 | if (size[i] != -1 && size[i] != array_size(ary,i)) 361 | { 362 | success = 0; 363 | } 364 | } 365 | if (!success) 366 | { 367 | for (i = 0; i < n; i++) 368 | { 369 | if (size[i] == -1) 370 | { 371 | sprintf(s, "*,"); 372 | } 373 | else 374 | { 375 | sprintf(s, "%ld,", (long int)size[i]); 376 | } 377 | strcat(desired_dims,s); 378 | } 379 | len = strlen(desired_dims); 380 | desired_dims[len-1] = ']'; 381 | for (i = 0; i < n; i++) 382 | { 383 | sprintf(s, "%ld,", (long int)array_size(ary,i)); 384 | strcat(actual_dims,s); 385 | } 386 | len = strlen(actual_dims); 387 | actual_dims[len-1] = ']'; 388 | PyErr_Format(PyExc_TypeError, 389 | "Array must have shape of %s. Given array has shape of %s", 390 | desired_dims, actual_dims); 391 | } 392 | return success; 393 | } 394 | 395 | /* Require the given PyArrayObject to to be FORTRAN ordered. If the 396 | * the PyArrayObject is already FORTRAN ordered, do nothing. Else, 397 | * set the FORTRAN ordering flag and recompute the strides. 398 | */ 399 | int require_fortran(PyArrayObject* ary) 400 | { 401 | int success = 1; 402 | int nd = array_numdims(ary); 403 | int i; 404 | if (array_is_fortran(ary)) return success; 405 | /* Set the FORTRAN ordered flag */ 406 | ary->flags = NPY_FARRAY; 407 | /* Recompute the strides */ 408 | ary->strides[0] = ary->strides[nd-1]; 409 | for (i=1; i < nd; ++i) 410 | ary->strides[i] = ary->strides[i-1] * array_size(ary,i-1); 411 | return success; 412 | } 413 | } 414 | 415 | /* Combine all NumPy fragments into one for convenience */ 416 | %fragment("NumPy_Fragments", "header", 417 | fragment="NumPy_Backward_Compatibility", 418 | fragment="NumPy_Macros", 419 | fragment="NumPy_Utilities", 420 | fragment="NumPy_Object_to_Array", 421 | fragment="NumPy_Array_Requirements") { } 422 | 423 | /* End John Hunter translation (with modifications by Bill Spotz) 424 | */ 425 | 426 | /* %numpy_typemaps() macro 427 | * 428 | * This macro defines a family of 41 typemaps that allow C arguments 429 | * of the form 430 | * 431 | * (DATA_TYPE IN_ARRAY1[ANY]) 432 | * (DATA_TYPE* IN_ARRAY1, DIM_TYPE DIM1) 433 | * (DIM_TYPE DIM1, DATA_TYPE* IN_ARRAY1) 434 | * 435 | * (DATA_TYPE IN_ARRAY2[ANY][ANY]) 436 | * (DATA_TYPE* IN_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 437 | * (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_ARRAY2) 438 | * (DATA_TYPE* IN_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 439 | * (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_FARRAY2) 440 | * 441 | * (DATA_TYPE IN_ARRAY3[ANY][ANY][ANY]) 442 | * (DATA_TYPE* IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 443 | * (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_ARRAY3) 444 | * (DATA_TYPE* IN_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 445 | * (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_FARRAY3) 446 | * 447 | * (DATA_TYPE INPLACE_ARRAY1[ANY]) 448 | * (DATA_TYPE* INPLACE_ARRAY1, DIM_TYPE DIM1) 449 | * (DIM_TYPE DIM1, DATA_TYPE* INPLACE_ARRAY1) 450 | * 451 | * (DATA_TYPE INPLACE_ARRAY2[ANY][ANY]) 452 | * (DATA_TYPE* INPLACE_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 453 | * (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_ARRAY2) 454 | * (DATA_TYPE* INPLACE_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 455 | * (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_FARRAY2) 456 | * 457 | * (DATA_TYPE INPLACE_ARRAY3[ANY][ANY][ANY]) 458 | * (DATA_TYPE* INPLACE_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 459 | * (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* INPLACE_ARRAY3) 460 | * (DATA_TYPE* INPLACE_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 461 | * (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* INPLACE_FARRAY3) 462 | * 463 | * (DATA_TYPE ARGOUT_ARRAY1[ANY]) 464 | * (DATA_TYPE* ARGOUT_ARRAY1, DIM_TYPE DIM1) 465 | * (DIM_TYPE DIM1, DATA_TYPE* ARGOUT_ARRAY1) 466 | * 467 | * (DATA_TYPE ARGOUT_ARRAY2[ANY][ANY]) 468 | * 469 | * (DATA_TYPE ARGOUT_ARRAY3[ANY][ANY][ANY]) 470 | * 471 | * (DATA_TYPE** ARGOUTVIEW_ARRAY1, DIM_TYPE* DIM1) 472 | * (DIM_TYPE* DIM1, DATA_TYPE** ARGOUTVIEW_ARRAY1) 473 | * 474 | * (DATA_TYPE** ARGOUTVIEW_ARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) 475 | * (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_ARRAY2) 476 | * (DATA_TYPE** ARGOUTVIEW_FARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) 477 | * (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_FARRAY2) 478 | * 479 | * (DATA_TYPE** ARGOUTVIEW_ARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) 480 | * (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_ARRAY3) 481 | * (DATA_TYPE** ARGOUTVIEW_FARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) 482 | * (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_FARRAY3) 483 | * 484 | * where "DATA_TYPE" is any type supported by the NumPy module, and 485 | * "DIM_TYPE" is any int-like type suitable for specifying dimensions. 486 | * The difference between "ARRAY" typemaps and "FARRAY" typemaps is 487 | * that the "FARRAY" typemaps expect FORTRAN ordering of 488 | * multidimensional arrays. In python, the dimensions will not need 489 | * to be specified (except for the "DATA_TYPE* ARGOUT_ARRAY1" 490 | * typemaps). The IN_ARRAYs can be a numpy array or any sequence that 491 | * can be converted to a numpy array of the specified type. The 492 | * INPLACE_ARRAYs must be numpy arrays of the appropriate type. The 493 | * ARGOUT_ARRAYs will be returned as new numpy arrays of the 494 | * appropriate type. 495 | * 496 | * These typemaps can be applied to existing functions using the 497 | * %apply directive. For example: 498 | * 499 | * %apply (double* IN_ARRAY1, int DIM1) {(double* series, int length)}; 500 | * double prod(double* series, int length); 501 | * 502 | * %apply (int DIM1, int DIM2, double* INPLACE_ARRAY2) 503 | * {(int rows, int cols, double* matrix )}; 504 | * void floor(int rows, int cols, double* matrix, double f); 505 | * 506 | * %apply (double IN_ARRAY3[ANY][ANY][ANY]) 507 | * {(double tensor[2][2][2] )}; 508 | * %apply (double ARGOUT_ARRAY3[ANY][ANY][ANY]) 509 | * {(double low[2][2][2] )}; 510 | * %apply (double ARGOUT_ARRAY3[ANY][ANY][ANY]) 511 | * {(double upp[2][2][2] )}; 512 | * void luSplit(double tensor[2][2][2], 513 | * double low[2][2][2], 514 | * double upp[2][2][2] ); 515 | * 516 | * or directly with 517 | * 518 | * double prod(double* IN_ARRAY1, int DIM1); 519 | * 520 | * void floor(int DIM1, int DIM2, double* INPLACE_ARRAY2, double f); 521 | * 522 | * void luSplit(double IN_ARRAY3[ANY][ANY][ANY], 523 | * double ARGOUT_ARRAY3[ANY][ANY][ANY], 524 | * double ARGOUT_ARRAY3[ANY][ANY][ANY]); 525 | */ 526 | 527 | %define %numpy_typemaps(DATA_TYPE, DATA_TYPECODE, DIM_TYPE) 528 | 529 | /************************/ 530 | /* Input Array Typemaps */ 531 | /************************/ 532 | 533 | /* Typemap suite for (DATA_TYPE IN_ARRAY1[ANY]) 534 | */ 535 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 536 | fragment="NumPy_Macros") 537 | (DATA_TYPE IN_ARRAY1[ANY]) 538 | { 539 | $1 = is_array($input) || PySequence_Check($input); 540 | } 541 | %typemap(in, 542 | fragment="NumPy_Fragments") 543 | (DATA_TYPE IN_ARRAY1[ANY]) 544 | (PyArrayObject* array=NULL, int is_new_object=0) 545 | { 546 | npy_intp size[1] = { $1_dim0 }; 547 | array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, 548 | &is_new_object); 549 | if (!array || !require_dimensions(array, 1) || 550 | !require_size(array, size, 1)) SWIG_fail; 551 | $1 = ($1_ltype) array_data(array); 552 | } 553 | %typemap(freearg) 554 | (DATA_TYPE IN_ARRAY1[ANY]) 555 | { 556 | if (is_new_object$argnum && array$argnum) 557 | { Py_DECREF(array$argnum); } 558 | } 559 | 560 | /* Typemap suite for (DATA_TYPE* IN_ARRAY1, DIM_TYPE DIM1) 561 | */ 562 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 563 | fragment="NumPy_Macros") 564 | (DATA_TYPE* IN_ARRAY1, DIM_TYPE DIM1) 565 | { 566 | $1 = is_array($input) || PySequence_Check($input); 567 | } 568 | %typemap(in, 569 | fragment="NumPy_Fragments") 570 | (DATA_TYPE* IN_ARRAY1, DIM_TYPE DIM1) 571 | (PyArrayObject* array=NULL, int is_new_object=0) 572 | { 573 | npy_intp size[1] = { -1 }; 574 | array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, 575 | &is_new_object); 576 | if (!array || !require_dimensions(array, 1) || 577 | !require_size(array, size, 1)) SWIG_fail; 578 | $1 = (DATA_TYPE*) array_data(array); 579 | $2 = (DIM_TYPE) array_size(array,0); 580 | } 581 | %typemap(freearg) 582 | (DATA_TYPE* IN_ARRAY1, DIM_TYPE DIM1) 583 | { 584 | if (is_new_object$argnum && array$argnum) 585 | { Py_DECREF(array$argnum); } 586 | } 587 | 588 | /* Typemap suite for (DIM_TYPE DIM1, DATA_TYPE* IN_ARRAY1) 589 | */ 590 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 591 | fragment="NumPy_Macros") 592 | (DIM_TYPE DIM1, DATA_TYPE* IN_ARRAY1) 593 | { 594 | $1 = is_array($input) || PySequence_Check($input); 595 | } 596 | %typemap(in, 597 | fragment="NumPy_Fragments") 598 | (DIM_TYPE DIM1, DATA_TYPE* IN_ARRAY1) 599 | (PyArrayObject* array=NULL, int is_new_object=0) 600 | { 601 | npy_intp size[1] = {-1}; 602 | array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, 603 | &is_new_object); 604 | if (!array || !require_dimensions(array, 1) || 605 | !require_size(array, size, 1)) SWIG_fail; 606 | $1 = (DIM_TYPE) array_size(array,0); 607 | $2 = (DATA_TYPE*) array_data(array); 608 | } 609 | %typemap(freearg) 610 | (DIM_TYPE DIM1, DATA_TYPE* IN_ARRAY1) 611 | { 612 | if (is_new_object$argnum && array$argnum) 613 | { Py_DECREF(array$argnum); } 614 | } 615 | 616 | /* Typemap suite for (DATA_TYPE IN_ARRAY2[ANY][ANY]) 617 | */ 618 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 619 | fragment="NumPy_Macros") 620 | (DATA_TYPE IN_ARRAY2[ANY][ANY]) 621 | { 622 | $1 = is_array($input) || PySequence_Check($input); 623 | } 624 | %typemap(in, 625 | fragment="NumPy_Fragments") 626 | (DATA_TYPE IN_ARRAY2[ANY][ANY]) 627 | (PyArrayObject* array=NULL, int is_new_object=0) 628 | { 629 | npy_intp size[2] = { $1_dim0, $1_dim1 }; 630 | array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, 631 | &is_new_object); 632 | if (!array || !require_dimensions(array, 2) || 633 | !require_size(array, size, 2)) SWIG_fail; 634 | $1 = ($1_ltype) array_data(array); 635 | } 636 | %typemap(freearg) 637 | (DATA_TYPE IN_ARRAY2[ANY][ANY]) 638 | { 639 | if (is_new_object$argnum && array$argnum) 640 | { Py_DECREF(array$argnum); } 641 | } 642 | 643 | /* Typemap suite for (DATA_TYPE* IN_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 644 | */ 645 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 646 | fragment="NumPy_Macros") 647 | (DATA_TYPE* IN_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 648 | { 649 | $1 = is_array($input) || PySequence_Check($input); 650 | } 651 | %typemap(in, 652 | fragment="NumPy_Fragments") 653 | (DATA_TYPE* IN_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 654 | (PyArrayObject* array=NULL, int is_new_object=0) 655 | { 656 | npy_intp size[2] = { -1, -1 }; 657 | array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, 658 | &is_new_object); 659 | if (!array || !require_dimensions(array, 2) || 660 | !require_size(array, size, 2)) SWIG_fail; 661 | $1 = (DATA_TYPE*) array_data(array); 662 | $2 = (DIM_TYPE) array_size(array,0); 663 | $3 = (DIM_TYPE) array_size(array,1); 664 | } 665 | %typemap(freearg) 666 | (DATA_TYPE* IN_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 667 | { 668 | if (is_new_object$argnum && array$argnum) 669 | { Py_DECREF(array$argnum); } 670 | } 671 | 672 | /* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_ARRAY2) 673 | */ 674 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 675 | fragment="NumPy_Macros") 676 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_ARRAY2) 677 | { 678 | $1 = is_array($input) || PySequence_Check($input); 679 | } 680 | %typemap(in, 681 | fragment="NumPy_Fragments") 682 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_ARRAY2) 683 | (PyArrayObject* array=NULL, int is_new_object=0) 684 | { 685 | npy_intp size[2] = { -1, -1 }; 686 | array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, 687 | &is_new_object); 688 | if (!array || !require_dimensions(array, 2) || 689 | !require_size(array, size, 2)) SWIG_fail; 690 | $1 = (DIM_TYPE) array_size(array,0); 691 | $2 = (DIM_TYPE) array_size(array,1); 692 | $3 = (DATA_TYPE*) array_data(array); 693 | } 694 | %typemap(freearg) 695 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_ARRAY2) 696 | { 697 | if (is_new_object$argnum && array$argnum) 698 | { Py_DECREF(array$argnum); } 699 | } 700 | 701 | /* Typemap suite for (DATA_TYPE* IN_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 702 | */ 703 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 704 | fragment="NumPy_Macros") 705 | (DATA_TYPE* IN_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 706 | { 707 | $1 = is_array($input) || PySequence_Check($input); 708 | } 709 | %typemap(in, 710 | fragment="NumPy_Fragments") 711 | (DATA_TYPE* IN_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 712 | (PyArrayObject* array=NULL, int is_new_object=0) 713 | { 714 | npy_intp size[2] = { -1, -1 }; 715 | array = obj_to_array_fortran_allow_conversion($input, DATA_TYPECODE, 716 | &is_new_object); 717 | if (!array || !require_dimensions(array, 2) || 718 | !require_size(array, size, 2) || !require_fortran(array)) SWIG_fail; 719 | $1 = (DATA_TYPE*) array_data(array); 720 | $2 = (DIM_TYPE) array_size(array,0); 721 | $3 = (DIM_TYPE) array_size(array,1); 722 | } 723 | %typemap(freearg) 724 | (DATA_TYPE* IN_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 725 | { 726 | if (is_new_object$argnum && array$argnum) 727 | { Py_DECREF(array$argnum); } 728 | } 729 | 730 | /* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_FARRAY2) 731 | */ 732 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 733 | fragment="NumPy_Macros") 734 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_FARRAY2) 735 | { 736 | $1 = is_array($input) || PySequence_Check($input); 737 | } 738 | %typemap(in, 739 | fragment="NumPy_Fragments") 740 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_FARRAY2) 741 | (PyArrayObject* array=NULL, int is_new_object=0) 742 | { 743 | npy_intp size[2] = { -1, -1 }; 744 | array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, 745 | &is_new_object); 746 | if (!array || !require_dimensions(array, 2) || 747 | !require_size(array, size, 2) || !require_fortran(array)) SWIG_fail; 748 | $1 = (DIM_TYPE) array_size(array,0); 749 | $2 = (DIM_TYPE) array_size(array,1); 750 | $3 = (DATA_TYPE*) array_data(array); 751 | } 752 | %typemap(freearg) 753 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_FARRAY2) 754 | { 755 | if (is_new_object$argnum && array$argnum) 756 | { Py_DECREF(array$argnum); } 757 | } 758 | 759 | /* Typemap suite for (DATA_TYPE IN_ARRAY3[ANY][ANY][ANY]) 760 | */ 761 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 762 | fragment="NumPy_Macros") 763 | (DATA_TYPE IN_ARRAY3[ANY][ANY][ANY]) 764 | { 765 | $1 = is_array($input) || PySequence_Check($input); 766 | } 767 | %typemap(in, 768 | fragment="NumPy_Fragments") 769 | (DATA_TYPE IN_ARRAY3[ANY][ANY][ANY]) 770 | (PyArrayObject* array=NULL, int is_new_object=0) 771 | { 772 | npy_intp size[3] = { $1_dim0, $1_dim1, $1_dim2 }; 773 | array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, 774 | &is_new_object); 775 | if (!array || !require_dimensions(array, 3) || 776 | !require_size(array, size, 3)) SWIG_fail; 777 | $1 = ($1_ltype) array_data(array); 778 | } 779 | %typemap(freearg) 780 | (DATA_TYPE IN_ARRAY3[ANY][ANY][ANY]) 781 | { 782 | if (is_new_object$argnum && array$argnum) 783 | { Py_DECREF(array$argnum); } 784 | } 785 | 786 | /* Typemap suite for (DATA_TYPE* IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, 787 | * DIM_TYPE DIM3) 788 | */ 789 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 790 | fragment="NumPy_Macros") 791 | (DATA_TYPE* IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 792 | { 793 | $1 = is_array($input) || PySequence_Check($input); 794 | } 795 | %typemap(in, 796 | fragment="NumPy_Fragments") 797 | (DATA_TYPE* IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 798 | (PyArrayObject* array=NULL, int is_new_object=0) 799 | { 800 | npy_intp size[3] = { -1, -1, -1 }; 801 | array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, 802 | &is_new_object); 803 | if (!array || !require_dimensions(array, 3) || 804 | !require_size(array, size, 3)) SWIG_fail; 805 | $1 = (DATA_TYPE*) array_data(array); 806 | $2 = (DIM_TYPE) array_size(array,0); 807 | $3 = (DIM_TYPE) array_size(array,1); 808 | $4 = (DIM_TYPE) array_size(array,2); 809 | } 810 | %typemap(freearg) 811 | (DATA_TYPE* IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 812 | { 813 | if (is_new_object$argnum && array$argnum) 814 | { Py_DECREF(array$argnum); } 815 | } 816 | 817 | /* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, 818 | * DATA_TYPE* IN_ARRAY3) 819 | */ 820 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 821 | fragment="NumPy_Macros") 822 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_ARRAY3) 823 | { 824 | $1 = is_array($input) || PySequence_Check($input); 825 | } 826 | %typemap(in, 827 | fragment="NumPy_Fragments") 828 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_ARRAY3) 829 | (PyArrayObject* array=NULL, int is_new_object=0) 830 | { 831 | npy_intp size[3] = { -1, -1, -1 }; 832 | array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, 833 | &is_new_object); 834 | if (!array || !require_dimensions(array, 3) || 835 | !require_size(array, size, 3)) SWIG_fail; 836 | $1 = (DIM_TYPE) array_size(array,0); 837 | $2 = (DIM_TYPE) array_size(array,1); 838 | $3 = (DIM_TYPE) array_size(array,2); 839 | $4 = (DATA_TYPE*) array_data(array); 840 | } 841 | %typemap(freearg) 842 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_ARRAY3) 843 | { 844 | if (is_new_object$argnum && array$argnum) 845 | { Py_DECREF(array$argnum); } 846 | } 847 | 848 | /* Typemap suite for (DATA_TYPE* IN_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, 849 | * DIM_TYPE DIM3) 850 | */ 851 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 852 | fragment="NumPy_Macros") 853 | (DATA_TYPE* IN_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 854 | { 855 | $1 = is_array($input) || PySequence_Check($input); 856 | } 857 | %typemap(in, 858 | fragment="NumPy_Fragments") 859 | (DATA_TYPE* IN_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 860 | (PyArrayObject* array=NULL, int is_new_object=0) 861 | { 862 | npy_intp size[3] = { -1, -1, -1 }; 863 | array = obj_to_array_fortran_allow_conversion($input, DATA_TYPECODE, 864 | &is_new_object); 865 | if (!array || !require_dimensions(array, 3) || 866 | !require_size(array, size, 3) | !require_fortran(array)) SWIG_fail; 867 | $1 = (DATA_TYPE*) array_data(array); 868 | $2 = (DIM_TYPE) array_size(array,0); 869 | $3 = (DIM_TYPE) array_size(array,1); 870 | $4 = (DIM_TYPE) array_size(array,2); 871 | } 872 | %typemap(freearg) 873 | (DATA_TYPE* IN_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 874 | { 875 | if (is_new_object$argnum && array$argnum) 876 | { Py_DECREF(array$argnum); } 877 | } 878 | 879 | /* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, 880 | * DATA_TYPE* IN_FARRAY3) 881 | */ 882 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 883 | fragment="NumPy_Macros") 884 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_FARRAY3) 885 | { 886 | $1 = is_array($input) || PySequence_Check($input); 887 | } 888 | %typemap(in, 889 | fragment="NumPy_Fragments") 890 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_FARRAY3) 891 | (PyArrayObject* array=NULL, int is_new_object=0) 892 | { 893 | npy_intp size[3] = { -1, -1, -1 }; 894 | array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, 895 | &is_new_object); 896 | if (!array || !require_dimensions(array, 3) || 897 | !require_size(array, size, 3) || !require_fortran(array)) SWIG_fail; 898 | $1 = (DIM_TYPE) array_size(array,0); 899 | $2 = (DIM_TYPE) array_size(array,1); 900 | $3 = (DIM_TYPE) array_size(array,2); 901 | $4 = (DATA_TYPE*) array_data(array); 902 | } 903 | %typemap(freearg) 904 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_FARRAY3) 905 | { 906 | if (is_new_object$argnum && array$argnum) 907 | { Py_DECREF(array$argnum); } 908 | } 909 | 910 | /***************************/ 911 | /* In-Place Array Typemaps */ 912 | /***************************/ 913 | 914 | /* Typemap suite for (DATA_TYPE INPLACE_ARRAY1[ANY]) 915 | */ 916 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 917 | fragment="NumPy_Macros") 918 | (DATA_TYPE INPLACE_ARRAY1[ANY]) 919 | { 920 | $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), 921 | DATA_TYPECODE); 922 | } 923 | %typemap(in, 924 | fragment="NumPy_Fragments") 925 | (DATA_TYPE INPLACE_ARRAY1[ANY]) 926 | (PyArrayObject* array=NULL) 927 | { 928 | npy_intp size[1] = { $1_dim0 }; 929 | array = obj_to_array_no_conversion($input, DATA_TYPECODE); 930 | if (!array || !require_dimensions(array,1) || !require_size(array, size, 1) || 931 | !require_contiguous(array) || !require_native(array)) SWIG_fail; 932 | $1 = ($1_ltype) array_data(array); 933 | } 934 | 935 | /* Typemap suite for (DATA_TYPE* INPLACE_ARRAY1, DIM_TYPE DIM1) 936 | */ 937 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 938 | fragment="NumPy_Macros") 939 | (DATA_TYPE* INPLACE_ARRAY1, DIM_TYPE DIM1) 940 | { 941 | $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), 942 | DATA_TYPECODE); 943 | } 944 | %typemap(in, 945 | fragment="NumPy_Fragments") 946 | (DATA_TYPE* INPLACE_ARRAY1, DIM_TYPE DIM1) 947 | (PyArrayObject* array=NULL, int i=1) 948 | { 949 | array = obj_to_array_no_conversion($input, DATA_TYPECODE); 950 | if (!array || !require_dimensions(array,1) || !require_contiguous(array) 951 | || !require_native(array)) SWIG_fail; 952 | $1 = (DATA_TYPE*) array_data(array); 953 | $2 = 1; 954 | for (i=0; i < array_numdims(array); ++i) $2 *= array_size(array,i); 955 | } 956 | 957 | /* Typemap suite for (DIM_TYPE DIM1, DATA_TYPE* INPLACE_ARRAY1) 958 | */ 959 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 960 | fragment="NumPy_Macros") 961 | (DIM_TYPE DIM1, DATA_TYPE* INPLACE_ARRAY1) 962 | { 963 | $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), 964 | DATA_TYPECODE); 965 | } 966 | %typemap(in, 967 | fragment="NumPy_Fragments") 968 | (DIM_TYPE DIM1, DATA_TYPE* INPLACE_ARRAY1) 969 | (PyArrayObject* array=NULL, int i=0) 970 | { 971 | array = obj_to_array_no_conversion($input, DATA_TYPECODE); 972 | if (!array || !require_dimensions(array,1) || !require_contiguous(array) 973 | || !require_native(array)) SWIG_fail; 974 | $1 = 1; 975 | for (i=0; i < array_numdims(array); ++i) $1 *= array_size(array,i); 976 | $2 = (DATA_TYPE*) array_data(array); 977 | } 978 | 979 | /* Typemap suite for (DATA_TYPE INPLACE_ARRAY2[ANY][ANY]) 980 | */ 981 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 982 | fragment="NumPy_Macros") 983 | (DATA_TYPE INPLACE_ARRAY2[ANY][ANY]) 984 | { 985 | $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), 986 | DATA_TYPECODE); 987 | } 988 | %typemap(in, 989 | fragment="NumPy_Fragments") 990 | (DATA_TYPE INPLACE_ARRAY2[ANY][ANY]) 991 | (PyArrayObject* array=NULL) 992 | { 993 | npy_intp size[2] = { $1_dim0, $1_dim1 }; 994 | array = obj_to_array_no_conversion($input, DATA_TYPECODE); 995 | if (!array || !require_dimensions(array,2) || !require_size(array, size, 2) || 996 | !require_contiguous(array) || !require_native(array)) SWIG_fail; 997 | $1 = ($1_ltype) array_data(array); 998 | } 999 | 1000 | /* Typemap suite for (DATA_TYPE* INPLACE_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 1001 | */ 1002 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 1003 | fragment="NumPy_Macros") 1004 | (DATA_TYPE* INPLACE_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 1005 | { 1006 | $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), 1007 | DATA_TYPECODE); 1008 | } 1009 | %typemap(in, 1010 | fragment="NumPy_Fragments") 1011 | (DATA_TYPE* INPLACE_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 1012 | (PyArrayObject* array=NULL) 1013 | { 1014 | array = obj_to_array_no_conversion($input, DATA_TYPECODE); 1015 | if (!array || !require_dimensions(array,2) || !require_contiguous(array) 1016 | || !require_native(array)) SWIG_fail; 1017 | $1 = (DATA_TYPE*) array_data(array); 1018 | $2 = (DIM_TYPE) array_size(array,0); 1019 | $3 = (DIM_TYPE) array_size(array,1); 1020 | } 1021 | 1022 | /* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_ARRAY2) 1023 | */ 1024 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 1025 | fragment="NumPy_Macros") 1026 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_ARRAY2) 1027 | { 1028 | $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), 1029 | DATA_TYPECODE); 1030 | } 1031 | %typemap(in, 1032 | fragment="NumPy_Fragments") 1033 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_ARRAY2) 1034 | (PyArrayObject* array=NULL) 1035 | { 1036 | array = obj_to_array_no_conversion($input, DATA_TYPECODE); 1037 | if (!array || !require_dimensions(array,2) || !require_contiguous(array) || 1038 | !require_native(array)) SWIG_fail; 1039 | $1 = (DIM_TYPE) array_size(array,0); 1040 | $2 = (DIM_TYPE) array_size(array,1); 1041 | $3 = (DATA_TYPE*) array_data(array); 1042 | } 1043 | 1044 | /* Typemap suite for (DATA_TYPE* INPLACE_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 1045 | */ 1046 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 1047 | fragment="NumPy_Macros") 1048 | (DATA_TYPE* INPLACE_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 1049 | { 1050 | $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), 1051 | DATA_TYPECODE); 1052 | } 1053 | %typemap(in, 1054 | fragment="NumPy_Fragments") 1055 | (DATA_TYPE* INPLACE_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) 1056 | (PyArrayObject* array=NULL) 1057 | { 1058 | array = obj_to_array_no_conversion($input, DATA_TYPECODE); 1059 | if (!array || !require_dimensions(array,2) || !require_contiguous(array) 1060 | || !require_native(array) || !require_fortran(array)) SWIG_fail; 1061 | $1 = (DATA_TYPE*) array_data(array); 1062 | $2 = (DIM_TYPE) array_size(array,0); 1063 | $3 = (DIM_TYPE) array_size(array,1); 1064 | } 1065 | 1066 | /* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_FARRAY2) 1067 | */ 1068 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 1069 | fragment="NumPy_Macros") 1070 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_FARRAY2) 1071 | { 1072 | $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), 1073 | DATA_TYPECODE); 1074 | } 1075 | %typemap(in, 1076 | fragment="NumPy_Fragments") 1077 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_FARRAY2) 1078 | (PyArrayObject* array=NULL) 1079 | { 1080 | array = obj_to_array_no_conversion($input, DATA_TYPECODE); 1081 | if (!array || !require_dimensions(array,2) || !require_contiguous(array) || 1082 | !require_native(array) || !require_fortran(array)) SWIG_fail; 1083 | $1 = (DIM_TYPE) array_size(array,0); 1084 | $2 = (DIM_TYPE) array_size(array,1); 1085 | $3 = (DATA_TYPE*) array_data(array); 1086 | } 1087 | 1088 | /* Typemap suite for (DATA_TYPE INPLACE_ARRAY3[ANY][ANY][ANY]) 1089 | */ 1090 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 1091 | fragment="NumPy_Macros") 1092 | (DATA_TYPE INPLACE_ARRAY3[ANY][ANY][ANY]) 1093 | { 1094 | $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), 1095 | DATA_TYPECODE); 1096 | } 1097 | %typemap(in, 1098 | fragment="NumPy_Fragments") 1099 | (DATA_TYPE INPLACE_ARRAY3[ANY][ANY][ANY]) 1100 | (PyArrayObject* array=NULL) 1101 | { 1102 | npy_intp size[3] = { $1_dim0, $1_dim1, $1_dim2 }; 1103 | array = obj_to_array_no_conversion($input, DATA_TYPECODE); 1104 | if (!array || !require_dimensions(array,3) || !require_size(array, size, 3) || 1105 | !require_contiguous(array) || !require_native(array)) SWIG_fail; 1106 | $1 = ($1_ltype) array_data(array); 1107 | } 1108 | 1109 | /* Typemap suite for (DATA_TYPE* INPLACE_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, 1110 | * DIM_TYPE DIM3) 1111 | */ 1112 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 1113 | fragment="NumPy_Macros") 1114 | (DATA_TYPE* INPLACE_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 1115 | { 1116 | $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), 1117 | DATA_TYPECODE); 1118 | } 1119 | %typemap(in, 1120 | fragment="NumPy_Fragments") 1121 | (DATA_TYPE* INPLACE_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 1122 | (PyArrayObject* array=NULL) 1123 | { 1124 | array = obj_to_array_no_conversion($input, DATA_TYPECODE); 1125 | if (!array || !require_dimensions(array,3) || !require_contiguous(array) || 1126 | !require_native(array)) SWIG_fail; 1127 | $1 = (DATA_TYPE*) array_data(array); 1128 | $2 = (DIM_TYPE) array_size(array,0); 1129 | $3 = (DIM_TYPE) array_size(array,1); 1130 | $4 = (DIM_TYPE) array_size(array,2); 1131 | } 1132 | 1133 | /* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, 1134 | * DATA_TYPE* INPLACE_ARRAY3) 1135 | */ 1136 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 1137 | fragment="NumPy_Macros") 1138 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* INPLACE_ARRAY3) 1139 | { 1140 | $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), 1141 | DATA_TYPECODE); 1142 | } 1143 | %typemap(in, 1144 | fragment="NumPy_Fragments") 1145 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* INPLACE_ARRAY3) 1146 | (PyArrayObject* array=NULL) 1147 | { 1148 | array = obj_to_array_no_conversion($input, DATA_TYPECODE); 1149 | if (!array || !require_dimensions(array,3) || !require_contiguous(array) 1150 | || !require_native(array)) SWIG_fail; 1151 | $1 = (DIM_TYPE) array_size(array,0); 1152 | $2 = (DIM_TYPE) array_size(array,1); 1153 | $3 = (DIM_TYPE) array_size(array,2); 1154 | $4 = (DATA_TYPE*) array_data(array); 1155 | } 1156 | 1157 | /* Typemap suite for (DATA_TYPE* INPLACE_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, 1158 | * DIM_TYPE DIM3) 1159 | */ 1160 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 1161 | fragment="NumPy_Macros") 1162 | (DATA_TYPE* INPLACE_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 1163 | { 1164 | $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), 1165 | DATA_TYPECODE); 1166 | } 1167 | %typemap(in, 1168 | fragment="NumPy_Fragments") 1169 | (DATA_TYPE* INPLACE_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) 1170 | (PyArrayObject* array=NULL) 1171 | { 1172 | array = obj_to_array_no_conversion($input, DATA_TYPECODE); 1173 | if (!array || !require_dimensions(array,3) || !require_contiguous(array) || 1174 | !require_native(array) || !require_fortran(array)) SWIG_fail; 1175 | $1 = (DATA_TYPE*) array_data(array); 1176 | $2 = (DIM_TYPE) array_size(array,0); 1177 | $3 = (DIM_TYPE) array_size(array,1); 1178 | $4 = (DIM_TYPE) array_size(array,2); 1179 | } 1180 | 1181 | /* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, 1182 | * DATA_TYPE* INPLACE_FARRAY3) 1183 | */ 1184 | %typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, 1185 | fragment="NumPy_Macros") 1186 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* INPLACE_FARRAY3) 1187 | { 1188 | $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), 1189 | DATA_TYPECODE); 1190 | } 1191 | %typemap(in, 1192 | fragment="NumPy_Fragments") 1193 | (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* INPLACE_FARRAY3) 1194 | (PyArrayObject* array=NULL) 1195 | { 1196 | array = obj_to_array_no_conversion($input, DATA_TYPECODE); 1197 | if (!array || !require_dimensions(array,3) || !require_contiguous(array) 1198 | || !require_native(array) || !require_fortran(array)) SWIG_fail; 1199 | $1 = (DIM_TYPE) array_size(array,0); 1200 | $2 = (DIM_TYPE) array_size(array,1); 1201 | $3 = (DIM_TYPE) array_size(array,2); 1202 | $4 = (DATA_TYPE*) array_data(array); 1203 | } 1204 | 1205 | /*************************/ 1206 | /* Argout Array Typemaps */ 1207 | /*************************/ 1208 | 1209 | /* Typemap suite for (DATA_TYPE ARGOUT_ARRAY1[ANY]) 1210 | */ 1211 | %typemap(in,numinputs=0, 1212 | fragment="NumPy_Backward_Compatibility,NumPy_Macros") 1213 | (DATA_TYPE ARGOUT_ARRAY1[ANY]) 1214 | (PyObject * array = NULL) 1215 | { 1216 | npy_intp dims[1] = { $1_dim0 }; 1217 | array = PyArray_SimpleNew(1, dims, DATA_TYPECODE); 1218 | if (!array) SWIG_fail; 1219 | $1 = ($1_ltype) array_data(array); 1220 | } 1221 | %typemap(argout) 1222 | (DATA_TYPE ARGOUT_ARRAY1[ANY]) 1223 | { 1224 | $result = SWIG_Python_AppendOutput($result,array$argnum); 1225 | } 1226 | 1227 | /* Typemap suite for (DATA_TYPE* ARGOUT_ARRAY1, DIM_TYPE DIM1) 1228 | */ 1229 | %typemap(in,numinputs=1, 1230 | fragment="NumPy_Fragments") 1231 | (DATA_TYPE* ARGOUT_ARRAY1, DIM_TYPE DIM1) 1232 | (PyObject * array = NULL) 1233 | { 1234 | npy_intp dims[1]; 1235 | if (!PyInt_Check($input)) 1236 | { 1237 | const char* typestring = pytype_string($input); 1238 | PyErr_Format(PyExc_TypeError, 1239 | "Int dimension expected. '%s' given.", 1240 | typestring); 1241 | SWIG_fail; 1242 | } 1243 | $2 = (DIM_TYPE) PyInt_AsLong($input); 1244 | dims[0] = (npy_intp) $2; 1245 | array = PyArray_SimpleNew(1, dims, DATA_TYPECODE); 1246 | if (!array) SWIG_fail; 1247 | $1 = (DATA_TYPE*) array_data(array); 1248 | } 1249 | %typemap(argout) 1250 | (DATA_TYPE* ARGOUT_ARRAY1, DIM_TYPE DIM1) 1251 | { 1252 | $result = SWIG_Python_AppendOutput($result,array$argnum); 1253 | } 1254 | 1255 | /* Typemap suite for (DIM_TYPE DIM1, DATA_TYPE* ARGOUT_ARRAY1) 1256 | */ 1257 | %typemap(in,numinputs=1, 1258 | fragment="NumPy_Fragments") 1259 | (DIM_TYPE DIM1, DATA_TYPE* ARGOUT_ARRAY1) 1260 | (PyObject * array = NULL) 1261 | { 1262 | npy_intp dims[1]; 1263 | if (!PyInt_Check($input)) 1264 | { 1265 | const char* typestring = pytype_string($input); 1266 | PyErr_Format(PyExc_TypeError, 1267 | "Int dimension expected. '%s' given.", 1268 | typestring); 1269 | SWIG_fail; 1270 | } 1271 | $1 = (DIM_TYPE) PyInt_AsLong($input); 1272 | dims[0] = (npy_intp) $1; 1273 | array = PyArray_SimpleNew(1, dims, DATA_TYPECODE); 1274 | if (!array) SWIG_fail; 1275 | $2 = (DATA_TYPE*) array_data(array); 1276 | } 1277 | %typemap(argout) 1278 | (DIM_TYPE DIM1, DATA_TYPE* ARGOUT_ARRAY1) 1279 | { 1280 | $result = SWIG_Python_AppendOutput($result,array$argnum); 1281 | } 1282 | 1283 | /* Typemap suite for (DATA_TYPE ARGOUT_ARRAY2[ANY][ANY]) 1284 | */ 1285 | %typemap(in,numinputs=0, 1286 | fragment="NumPy_Backward_Compatibility,NumPy_Macros") 1287 | (DATA_TYPE ARGOUT_ARRAY2[ANY][ANY]) 1288 | (PyObject * array = NULL) 1289 | { 1290 | npy_intp dims[2] = { $1_dim0, $1_dim1 }; 1291 | array = PyArray_SimpleNew(2, dims, DATA_TYPECODE); 1292 | if (!array) SWIG_fail; 1293 | $1 = ($1_ltype) array_data(array); 1294 | } 1295 | %typemap(argout) 1296 | (DATA_TYPE ARGOUT_ARRAY2[ANY][ANY]) 1297 | { 1298 | $result = SWIG_Python_AppendOutput($result,array$argnum); 1299 | } 1300 | 1301 | /* Typemap suite for (DATA_TYPE ARGOUT_ARRAY3[ANY][ANY][ANY]) 1302 | */ 1303 | %typemap(in,numinputs=0, 1304 | fragment="NumPy_Backward_Compatibility,NumPy_Macros") 1305 | (DATA_TYPE ARGOUT_ARRAY3[ANY][ANY][ANY]) 1306 | (PyObject * array = NULL) 1307 | { 1308 | npy_intp dims[3] = { $1_dim0, $1_dim1, $1_dim2 }; 1309 | array = PyArray_SimpleNew(3, dims, DATA_TYPECODE); 1310 | if (!array) SWIG_fail; 1311 | $1 = ($1_ltype) array_data(array); 1312 | } 1313 | %typemap(argout) 1314 | (DATA_TYPE ARGOUT_ARRAY3[ANY][ANY][ANY]) 1315 | { 1316 | $result = SWIG_Python_AppendOutput($result,array$argnum); 1317 | } 1318 | 1319 | /*****************************/ 1320 | /* Argoutview Array Typemaps */ 1321 | /*****************************/ 1322 | 1323 | /* Typemap suite for (DATA_TYPE** ARGOUTVIEW_ARRAY1, DIM_TYPE* DIM1) 1324 | */ 1325 | %typemap(in,numinputs=0) 1326 | (DATA_TYPE** ARGOUTVIEW_ARRAY1, DIM_TYPE* DIM1 ) 1327 | (DATA_TYPE* data_temp , DIM_TYPE dim_temp) 1328 | { 1329 | $1 = &data_temp; 1330 | $2 = &dim_temp; 1331 | } 1332 | %typemap(argout, 1333 | fragment="NumPy_Backward_Compatibility") 1334 | (DATA_TYPE** ARGOUTVIEW_ARRAY1, DIM_TYPE* DIM1) 1335 | { 1336 | npy_intp dims[1] = { *$2 }; 1337 | PyObject * array = PyArray_SimpleNewFromData(1, dims, DATA_TYPECODE, (void*)(*$1)); 1338 | if (!array) SWIG_fail; 1339 | $result = SWIG_Python_AppendOutput($result,array); 1340 | } 1341 | 1342 | /* Typemap suite for (DIM_TYPE* DIM1, DATA_TYPE** ARGOUTVIEW_ARRAY1) 1343 | */ 1344 | %typemap(in,numinputs=0) 1345 | (DIM_TYPE* DIM1 , DATA_TYPE** ARGOUTVIEW_ARRAY1) 1346 | (DIM_TYPE dim_temp, DATA_TYPE* data_temp ) 1347 | { 1348 | $1 = &dim_temp; 1349 | $2 = &data_temp; 1350 | } 1351 | %typemap(argout, 1352 | fragment="NumPy_Backward_Compatibility") 1353 | (DIM_TYPE* DIM1, DATA_TYPE** ARGOUTVIEW_ARRAY1) 1354 | { 1355 | npy_intp dims[1] = { *$1 }; 1356 | PyObject * array = PyArray_SimpleNewFromData(1, dims, DATA_TYPECODE, (void*)(*$2)); 1357 | if (!array) SWIG_fail; 1358 | $result = SWIG_Python_AppendOutput($result,array); 1359 | } 1360 | 1361 | /* Typemap suite for (DATA_TYPE** ARGOUTVIEW_ARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) 1362 | */ 1363 | %typemap(in,numinputs=0) 1364 | (DATA_TYPE** ARGOUTVIEW_ARRAY2, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 ) 1365 | (DATA_TYPE* data_temp , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp) 1366 | { 1367 | $1 = &data_temp; 1368 | $2 = &dim1_temp; 1369 | $3 = &dim2_temp; 1370 | } 1371 | %typemap(argout, 1372 | fragment="NumPy_Backward_Compatibility") 1373 | (DATA_TYPE** ARGOUTVIEW_ARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) 1374 | { 1375 | npy_intp dims[2] = { *$2, *$3 }; 1376 | PyObject * array = PyArray_SimpleNewFromData(2, dims, DATA_TYPECODE, (void*)(*$1)); 1377 | if (!array) SWIG_fail; 1378 | $result = SWIG_Python_AppendOutput($result,array); 1379 | } 1380 | 1381 | /* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_ARRAY2) 1382 | */ 1383 | %typemap(in,numinputs=0) 1384 | (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DATA_TYPE** ARGOUTVIEW_ARRAY2) 1385 | (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DATA_TYPE* data_temp ) 1386 | { 1387 | $1 = &dim1_temp; 1388 | $2 = &dim2_temp; 1389 | $3 = &data_temp; 1390 | } 1391 | %typemap(argout, 1392 | fragment="NumPy_Backward_Compatibility") 1393 | (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_ARRAY2) 1394 | { 1395 | npy_intp dims[2] = { *$1, *$2 }; 1396 | PyObject * array = PyArray_SimpleNewFromData(2, dims, DATA_TYPECODE, (void*)(*$3)); 1397 | if (!array) SWIG_fail; 1398 | $result = SWIG_Python_AppendOutput($result,array); 1399 | } 1400 | 1401 | /* Typemap suite for (DATA_TYPE** ARGOUTVIEW_FARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) 1402 | */ 1403 | %typemap(in,numinputs=0) 1404 | (DATA_TYPE** ARGOUTVIEW_FARRAY2, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 ) 1405 | (DATA_TYPE* data_temp , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp) 1406 | { 1407 | $1 = &data_temp; 1408 | $2 = &dim1_temp; 1409 | $3 = &dim2_temp; 1410 | } 1411 | %typemap(argout, 1412 | fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements") 1413 | (DATA_TYPE** ARGOUTVIEW_FARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) 1414 | { 1415 | npy_intp dims[2] = { *$2, *$3 }; 1416 | PyObject * obj = PyArray_SimpleNewFromData(2, dims, DATA_TYPECODE, (void*)(*$1)); 1417 | PyArrayObject * array = (PyArrayObject*) obj; 1418 | if (!array || !require_fortran(array)) SWIG_fail; 1419 | $result = SWIG_Python_AppendOutput($result,obj); 1420 | } 1421 | 1422 | /* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_FARRAY2) 1423 | */ 1424 | %typemap(in,numinputs=0) 1425 | (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DATA_TYPE** ARGOUTVIEW_FARRAY2) 1426 | (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DATA_TYPE* data_temp ) 1427 | { 1428 | $1 = &dim1_temp; 1429 | $2 = &dim2_temp; 1430 | $3 = &data_temp; 1431 | } 1432 | %typemap(argout, 1433 | fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements") 1434 | (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_FARRAY2) 1435 | { 1436 | npy_intp dims[2] = { *$1, *$2 }; 1437 | PyObject * obj = PyArray_SimpleNewFromData(2, dims, DATA_TYPECODE, (void*)(*$3)); 1438 | PyArrayObject * array = (PyArrayObject*) obj; 1439 | if (!array || !require_fortran(array)) SWIG_fail; 1440 | $result = SWIG_Python_AppendOutput($result,obj); 1441 | } 1442 | 1443 | /* Typemap suite for (DATA_TYPE** ARGOUTVIEW_ARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, 1444 | DIM_TYPE* DIM3) 1445 | */ 1446 | %typemap(in,numinputs=0) 1447 | (DATA_TYPE** ARGOUTVIEW_ARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) 1448 | (DATA_TYPE* data_temp, DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp) 1449 | { 1450 | $1 = &data_temp; 1451 | $2 = &dim1_temp; 1452 | $3 = &dim2_temp; 1453 | $4 = &dim3_temp; 1454 | } 1455 | %typemap(argout, 1456 | fragment="NumPy_Backward_Compatibility") 1457 | (DATA_TYPE** ARGOUTVIEW_ARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) 1458 | { 1459 | npy_intp dims[3] = { *$2, *$3, *$4 }; 1460 | PyObject * array = PyArray_SimpleNewFromData(3, dims, DATA_TYPECODE, (void*)(*$1)); 1461 | if (!array) SWIG_fail; 1462 | $result = SWIG_Python_AppendOutput($result,array); 1463 | } 1464 | 1465 | /* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, 1466 | DATA_TYPE** ARGOUTVIEW_ARRAY3) 1467 | */ 1468 | %typemap(in,numinputs=0) 1469 | (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_ARRAY3) 1470 | (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DATA_TYPE* data_temp) 1471 | { 1472 | $1 = &dim1_temp; 1473 | $2 = &dim2_temp; 1474 | $3 = &dim3_temp; 1475 | $4 = &data_temp; 1476 | } 1477 | %typemap(argout, 1478 | fragment="NumPy_Backward_Compatibility") 1479 | (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_ARRAY3) 1480 | { 1481 | npy_intp dims[3] = { *$1, *$2, *$3 }; 1482 | PyObject * array = PyArray_SimpleNewFromData(3, dims, DATA_TYPECODE, (void*)(*$3)); 1483 | if (!array) SWIG_fail; 1484 | $result = SWIG_Python_AppendOutput($result,array); 1485 | } 1486 | 1487 | /* Typemap suite for (DATA_TYPE** ARGOUTVIEW_FARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, 1488 | DIM_TYPE* DIM3) 1489 | */ 1490 | %typemap(in,numinputs=0) 1491 | (DATA_TYPE** ARGOUTVIEW_FARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) 1492 | (DATA_TYPE* data_temp, DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp) 1493 | { 1494 | $1 = &data_temp; 1495 | $2 = &dim1_temp; 1496 | $3 = &dim2_temp; 1497 | $4 = &dim3_temp; 1498 | } 1499 | %typemap(argout, 1500 | fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements") 1501 | (DATA_TYPE** ARGOUTVIEW_FARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) 1502 | { 1503 | npy_intp dims[3] = { *$2, *$3, *$4 }; 1504 | PyObject * obj = PyArray_SimpleNewFromData(3, dims, DATA_TYPECODE, (void*)(*$1)); 1505 | PyArrayObject * array = (PyArrayObject*) obj; 1506 | if (!array || require_fortran(array)) SWIG_fail; 1507 | $result = SWIG_Python_AppendOutput($result,obj); 1508 | } 1509 | 1510 | /* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, 1511 | DATA_TYPE** ARGOUTVIEW_FARRAY3) 1512 | */ 1513 | %typemap(in,numinputs=0) 1514 | (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_FARRAY3) 1515 | (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DATA_TYPE* data_temp) 1516 | { 1517 | $1 = &dim1_temp; 1518 | $2 = &dim2_temp; 1519 | $3 = &dim3_temp; 1520 | $4 = &data_temp; 1521 | } 1522 | %typemap(argout, 1523 | fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements") 1524 | (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_FARRAY3) 1525 | { 1526 | npy_intp dims[3] = { *$1, *$2, *$3 }; 1527 | PyObject * obj = PyArray_SimpleNewFromData(3, dims, DATA_TYPECODE, (void*)(*$3)); 1528 | PyArrayObject * array = (PyArrayObject*) obj; 1529 | if (!array || require_fortran(array)) SWIG_fail; 1530 | $result = SWIG_Python_AppendOutput($result,obj); 1531 | } 1532 | 1533 | %enddef /* %numpy_typemaps() macro */ 1534 | /* *************************************************************** */ 1535 | 1536 | /* Concrete instances of the %numpy_typemaps() macro: Each invocation 1537 | * below applies all of the typemaps above to the specified data type. 1538 | */ 1539 | %numpy_typemaps(signed char , NPY_BYTE , int) 1540 | %numpy_typemaps(unsigned char , NPY_UBYTE , int) 1541 | %numpy_typemaps(short , NPY_SHORT , int) 1542 | %numpy_typemaps(unsigned short , NPY_USHORT , int) 1543 | %numpy_typemaps(int , NPY_INT , int) 1544 | %numpy_typemaps(unsigned int , NPY_UINT , int) 1545 | %numpy_typemaps(long , NPY_LONG , int) 1546 | %numpy_typemaps(unsigned long , NPY_ULONG , int) 1547 | %numpy_typemaps(long long , NPY_LONGLONG , int) 1548 | %numpy_typemaps(unsigned long long, NPY_ULONGLONG, int) 1549 | %numpy_typemaps(float , NPY_FLOAT , int) 1550 | %numpy_typemaps(double , NPY_DOUBLE , int) 1551 | 1552 | /* *************************************************************** 1553 | * The follow macro expansion does not work, because C++ bool is 4 1554 | * bytes and NPY_BOOL is 1 byte 1555 | * 1556 | * %numpy_typemaps(bool, NPY_BOOL, int) 1557 | */ 1558 | 1559 | /* *************************************************************** 1560 | * On my Mac, I get the following warning for this macro expansion: 1561 | * 'swig/python detected a memory leak of type 'long double *', no destructor found.' 1562 | * 1563 | * %numpy_typemaps(long double, NPY_LONGDOUBLE, int) 1564 | */ 1565 | 1566 | /* *************************************************************** 1567 | * Swig complains about a syntax error for the following macro 1568 | * expansions: 1569 | * 1570 | * %numpy_typemaps(complex float, NPY_CFLOAT , int) 1571 | * 1572 | * %numpy_typemaps(complex double, NPY_CDOUBLE, int) 1573 | * 1574 | * %numpy_typemaps(complex long double, NPY_CLONGDOUBLE, int) 1575 | */ 1576 | 1577 | #endif /* SWIGPYTHON */ -------------------------------------------------------------------------------- /swig/test.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import numpy.testing as npt 3 | import IPython as ip 4 | import gpuadder 5 | 6 | def test(): 7 | arr = np.array([1,2,2,2], dtype=np.int32) 8 | adder = gpuadder.GPUAdder(arr) 9 | adder.increment() 10 | adder.retreive() 11 | 12 | results2 = np.empty_like(arr) 13 | adder.retreive_to(results2) 14 | 15 | npt.assert_array_equal(arr, [2,3,3,3]) 16 | npt.assert_array_equal(results2, [2,3,3,3]) 17 | --------------------------------------------------------------------------------