From 4156e48ca73e83907f55185653d2cdd49ec4faa6 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 22 Dec 2015 18:58:23 -0500 Subject: [PATCH 001/212] Changing the test framework to be verbose on FAIL and exit with 1 --- tests/simple/_util.py | 41 ++++++++++++++++++++++------------------- tests/simple_tests.py | 2 +- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/tests/simple/_util.py b/tests/simple/_util.py index 7af14367b..4b38e9c4d 100644 --- a/tests/simple/_util.py +++ b/tests/simple/_util.py @@ -6,36 +6,22 @@ # The complete license agreement can be obtained at: # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## - import traceback import logging import arrayfire as af - -def display_func(verbose): - if (verbose): - return af.display - else: - def eval_func(foo): - res = foo - return eval_func - -def print_func(verbose): - def print_func_impl(*args): - if (verbose): - print(args) - else: - res = [args] - return print_func_impl +import sys class _simple_test_dict(dict): def __init__(self): self.print_str = "Simple %16s: %s" + self.failed = False super(_simple_test_dict, self).__init__() def run(self, name_list=None, verbose=False): test_list = name_list if name_list is not None else self.keys() for key in test_list: + self.print_log = '' try: test = self[key] except: @@ -47,8 +33,25 @@ def run(self, name_list=None, verbose=False): print(self.print_str % (key, "PASSED")) except Exception as e: print(self.print_str % (key, "FAILED")) - if (verbose): - logging.error(traceback.format_exc()) + self.failed = True + if (not verbose): + print(tests.print_log) + logging.error(traceback.format_exc()) + if (self.failed): + sys.exit(1) tests = _simple_test_dict() + +def print_func(verbose): + def print_func_impl(*args): + _print_log = '' + for arg in args: + _print_log += str(arg) + '\n' + if (verbose): + print(_print_log) + tests.print_log += _print_log + return print_func_impl + +def display_func(verbose): + return print_func(verbose) diff --git a/tests/simple_tests.py b/tests/simple_tests.py index 67fb8c982..370b16230 100755 --- a/tests/simple_tests.py +++ b/tests/simple_tests.py @@ -16,7 +16,7 @@ verbose = False if len(sys.argv) > 1: - verbose = int(sys.argv[1]) != False + verbose = int(sys.argv[1]) test_list = None if len(sys.argv) > 2: From 2ae92cb020db612ad7b93065df42fccffb427970 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 22 Dec 2015 19:19:26 -0500 Subject: [PATCH 002/212] Change tests to pass on windows - long vs long long issue --- tests/simple/array_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/simple/array_test.py b/tests/simple/array_test.py index 32c042063..3a65e8031 100644 --- a/tests/simple/array_test.py +++ b/tests/simple/array_test.py @@ -35,7 +35,7 @@ def simple_array(verbose=False): print_func(a.is_complex(), a.is_real(), a.is_double(), a.is_single()) print_func(a.is_real_floating(), a.is_floating(), a.is_integer(), a.is_bool()) - a = af.Array(host.array('l', [7, 8, 9] * 3), (3,3)) + a = af.Array(host.array('I', [7, 8, 9] * 3), (3,3)) display_func(a) print_func(a.elements(), a.type(), a.dims(), a.numdims()) print_func(a.is_empty(), a.is_scalar(), a.is_column(), a.is_row()) From b0b2fc459956d2ca7697dafe576e40d53e4955e5 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 23 Dec 2015 14:55:49 -0500 Subject: [PATCH 003/212] Updated README with jenkins status icons --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f3576d179..59447e4c5 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,14 @@ [ArrayFire](https://github.com/arrayfire/arrayfire) is a high performance library for parallel computing with an easy-to-use API. It enables users to write scientific computing code that is portable across CUDA, OpenCL and CPU devices. This project provides Python bindings for the ArrayFire library. +## Status +| | Linux | Windows | Mac OSX | +|:------:|:------------:|:--------------:|:-------:| +| Tests | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-linux)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-linux/) | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-windows)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-windows/) | | + ## Example -``` +```python import arrayfire as af # Display backend information From f4e30e001ec1faef1438c358fa6c06cdb5e5c957 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 23 Dec 2015 15:00:33 -0500 Subject: [PATCH 004/212] Cleaning up the status section of README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 59447e4c5..da6ef9cff 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,10 @@ [ArrayFire](https://github.com/arrayfire/arrayfire) is a high performance library for parallel computing with an easy-to-use API. It enables users to write scientific computing code that is portable across CUDA, OpenCL and CPU devices. This project provides Python bindings for the ArrayFire library. ## Status -| | Linux | Windows | Mac OSX | -|:------:|:------------:|:--------------:|:-------:| -| Tests | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-linux)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-linux/) | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-windows)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-windows/) | | +| OS | Status | +|:------:|:------:| +| Linux | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-linux)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-linux/) | +| Windows | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-windows)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-windows/) | ## Example From f128e6a3909c471b15caf370c5283dc71f7120fc Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 23 Dec 2015 15:01:19 -0500 Subject: [PATCH 005/212] Minor changes to test status tables --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index da6ef9cff..5223e1991 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ [ArrayFire](https://github.com/arrayfire/arrayfire) is a high performance library for parallel computing with an easy-to-use API. It enables users to write scientific computing code that is portable across CUDA, OpenCL and CPU devices. This project provides Python bindings for the ArrayFire library. ## Status -| OS | Status | +| OS | Tests | |:------:|:------:| -| Linux | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-linux)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-linux/) | +| Linux | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-linux)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-linux/) | | Windows | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-windows)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-windows/) | ## Example From d42dd8762029575727d01d8322e2e26d7ec3023d Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 24 Dec 2015 20:37:25 -0500 Subject: [PATCH 006/212] Minor change to packaging - Package only listed modules instead of excluding other modules --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2974351b9..832a072e8 100644 --- a/setup.py +++ b/setup.py @@ -23,5 +23,5 @@ description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", - packages=find_packages(exclude=['examples', 'tests']), + packages=['arrayfire'], ) From 48cf2b450d60056697bc086a86acabb349f31665 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 24 Dec 2015 21:38:55 -0500 Subject: [PATCH 007/212] Set the AF_PATH to one of known paths if none is found This helps users avoiding setting the path --- arrayfire/library.py | 46 ++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index 4854d9334..91ba1af70 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -322,18 +322,20 @@ def _setup(): platform_name = platform.system() try: - AF_SEARCH_PATH = os.environ['AF_PATH'] + AF_PATH = os.environ['AF_PATH'] except: - AF_SEARCH_PATH = None + AF_PATH = None pass + AF_SEARCH_PATH = AF_PATH + try: CUDA_PATH = os.environ['CUDA_PATH'] except: CUDA_PATH= None pass - CUDA_EXISTS = False + CUDA_FOUND = False assert(len(platform_name) >= 3) if platform_name == 'Windows' or platform_name[:3] == 'CYG': @@ -353,7 +355,7 @@ def _setup(): AF_SEARCH_PATH="C:/Program Files/ArrayFire/v3/" if CUDA_PATH is not None: - CUDA_EXISTS = os.path.isdir(CUDA_PATH + '/bin') and os.path.isdir(CUDA_PATH + '/nvvm/bin/') + CUDA_FOUND = os.path.isdir(CUDA_PATH + '/bin') and os.path.isdir(CUDA_PATH + '/nvvm/bin/') elif platform_name == 'Darwin': @@ -367,7 +369,7 @@ def _setup(): if CUDA_PATH is None: CUDA_PATH='/usr/local/cuda/' - CUDA_EXISTS = os.path.isdir(CUDA_PATH + '/lib') and os.path.isdir(CUDA_PATH + '/nvvm/lib') + CUDA_FOUND = os.path.isdir(CUDA_PATH + '/lib') and os.path.isdir(CUDA_PATH + '/nvvm/lib') elif platform_name == 'Linux': pre = 'lib' @@ -379,20 +381,23 @@ def _setup(): if CUDA_PATH is None: CUDA_PATH='/usr/local/cuda/' - if platform.architecture()[0][:2] == 64: - CUDA_EXISTS = os.path.isdir(CUDA_PATH + '/lib64') and os.path.isdir(CUDA_PATH + '/nvvm/lib64') + if platform.architecture()[0][:2] == '64': + CUDA_FOUND = os.path.isdir(CUDA_PATH + '/lib64') and os.path.isdir(CUDA_PATH + '/nvvm/lib64') else: - CUDA_EXISTS = os.path.isdir(CUDA_PATH + '/lib') and os.path.isdir(CUDA_PATH + '/nvvm/lib') + CUDA_FOUND = os.path.isdir(CUDA_PATH + '/lib') and os.path.isdir(CUDA_PATH + '/nvvm/lib') else: raise OSError(platform_name + ' not supported') - return pre, post, AF_SEARCH_PATH, CUDA_EXISTS + if AF_PATH is None: + os.environ['AF_PATH'] = AF_SEARCH_PATH + + return pre, post, AF_SEARCH_PATH, CUDA_FOUND class _clibrary(object): def __libname(self, name, head='af'): libname = self.__pre + head + name + self.__post - libname_full = self.AF_SEARCH_PATH + '/lib/' + libname + libname_full = self.AF_PATH + '/lib/' + libname return (libname, libname_full) def set_unsafe(self, name): @@ -405,25 +410,27 @@ def __init__(self): more_info_str = "Please look at https://github.com/arrayfire/arrayfire-python/wiki for more information." - pre, post, AF_SEARCH_PATH, CUDA_EXISTS = _setup() + pre, post, AF_PATH, CUDA_FOUND = _setup() self.__pre = pre self.__post = post - self.AF_SEARCH_PATH = AF_SEARCH_PATH + self.AF_PATH = AF_PATH + self.CUDA_FOUND = CUDA_FOUND self.__name = None - self.__clibs = {'cuda' : None, - 'opencl' : None, - 'cpu' : None, - '' : None} + self.__clibs = {'cuda' : None, + 'opencl' : None, + 'cpu' : None, + 'unified' : None} - self.__backend_map = {0 : 'default', + self.__backend_map = {0 : 'unified', 1 : 'cpu' , 2 : 'cuda' , 4 : 'opencl' } self.__backend_name_map = {'default' : 0, + 'unified' : 0, 'cpu' : 1, 'cuda' : 2, 'opencl' : 4} @@ -442,8 +449,9 @@ def __init__(self): for libname in libnames: try: ct.cdll.LoadLibrary(libname) - self.__clibs[name] = ct.CDLL(libname) - self.__name = name + __name = 'unified' if name == '' else name + self.__clibs[__name] = ct.CDLL(libname) + self.__name = __name break; except: pass From bb0045b74abea318c7d4692be63f5fa4671e0a3a Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 24 Dec 2015 21:47:50 -0500 Subject: [PATCH 008/212] Minor fixes to Heston model example to reduce memory footprint --- examples/financial/heston_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/financial/heston_model.py b/examples/financial/heston_model.py index 041f9d3c2..640127eeb 100644 --- a/examples/financial/heston_model.py +++ b/examples/financial/heston_model.py @@ -67,9 +67,9 @@ def simulateHestonModel( T, N, R, mu, kappa, vBar, sigmaV, rho, x0, v0 ) : def main(): T = 1 - nT = 10 * T + nT = 20 * T R_first = 1000 - R = 20000000 + R = 5000000 x0 = 0 # initial log stock price v0 = 0.087**2 # initial volatility From a509d025b45a0fc9b49884713982d201f18e6549 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 24 Dec 2015 21:48:30 -0500 Subject: [PATCH 009/212] Updating version number --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6b7ee9a5e..6ee5bea16 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ author="Pavan Yalamanchili", author_email="pavan@arrayfire.com", name="arrayfire", - version="3.2.20151214", + version="3.2.20151224", description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From dffa4f28da6a564b721b2d7fd12572c16d8efe60 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 24 Dec 2015 21:58:08 -0500 Subject: [PATCH 010/212] Updating Changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e446bc598..316c45641 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +### v3.2.20151224 +- Bug fixes: + - A default `AF_PATH` is set if none is found as an environment variable. + +- Examples: + - Heston model example uses a smaller data set to help run on low end GPUs. + ### v3.2.20151214 - Bug fixes: - `get_version()` now returns ints instead of `c_int` From 4ed70d61ceec045cd4be016f6f5655282bf12d13 Mon Sep 17 00:00:00 2001 From: Shehzan Mohammed Date: Mon, 28 Dec 2015 13:32:28 -0500 Subject: [PATCH 011/212] Fixing types in arith test --- tests/simple/arith.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/simple/arith.py b/tests/simple/arith.py index e55881e6c..f8407c17f 100644 --- a/tests/simple/arith.py +++ b/tests/simple/arith.py @@ -15,8 +15,8 @@ def simple_arith(verbose = False): display_func = _util.display_func(verbose) print_func = _util.print_func(verbose) - a = af.randu(3,3,dtype=af.Dtype.u32) - b = af.constant(4, 3, 3, dtype=af.Dtype.u32) + a = af.randu(3,3) + b = af.constant(4, 3, 3) display_func(a) display_func(b) @@ -99,6 +99,9 @@ def simple_arith(verbose = False): display_func(a == 0.5) display_func(0.5 == a) + a = af.randu(3,3,dtype=af.Dtype.u32) + b = af.constant(4, 3, 3, dtype=af.Dtype.u32) + display_func(a & b) display_func(a & 2) c = a From 6e2271ab3365bb5f63839e7f9e5e1649e2c93038 Mon Sep 17 00:00:00 2001 From: Shehzan Mohammed Date: Mon, 28 Dec 2015 13:33:50 -0500 Subject: [PATCH 012/212] Add OSX status badge to readme --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5223e1991..be1c4eb51 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,11 @@ [ArrayFire](https://github.com/arrayfire/arrayfire) is a high performance library for parallel computing with an easy-to-use API. It enables users to write scientific computing code that is portable across CUDA, OpenCL and CPU devices. This project provides Python bindings for the ArrayFire library. ## Status -| OS | Tests | -|:------:|:------:| -| Linux | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-linux)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-linux/) | -| Windows | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-windows)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-windows/) | +| OS | Tests | +|:-------:|:-------:| +| Linux | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-linux)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-linux/) | +| Windows | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-windows)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-windows/) | +| OSX | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-osx)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-osx/) | ## Example From 9d89307522893a97709b4e4ed1a26b4615cc1f15 Mon Sep 17 00:00:00 2001 From: Filipe Maia Date: Sun, 14 Feb 2016 00:10:22 +0100 Subject: [PATCH 013/212] Adding raw_ptr() --- arrayfire/array.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 13a5fc8fa..350c2a1a6 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -454,6 +454,25 @@ def __del__(self): backend.get().af_release_array(self.arr) def device_ptr(self): + """ + Return the device pointer exclusively held by the array. + + Returns + ------ + ptr : int + Contains location of the device pointer + + Note + ---- + - This can be used to integrate with custom C code and / or PyCUDA or PyOpenCL. + - No other arrays will share the same device pointer. + - If multiple arrays share the same memory a copy of the memory is done and a pointer to the new copy is returned. + """ + ptr = ct.c_void_p(0) + backend.get().af_get_device_ptr(ct.pointer(ptr), self.arr) + return ptr.value + + def raw_ptr(self): """ Return the device pointer held by the array. @@ -466,9 +485,10 @@ def device_ptr(self): ---- - This can be used to integrate with custom C code and / or PyCUDA or PyOpenCL. - No mem copy is peformed, this function returns the raw device pointer. + - This pointer may be shared with other arrays. Use this function with caution. """ ptr = ct.c_void_p(0) - backend.get().af_get_device_ptr(ct.pointer(ptr), self.arr) + backend.get().af_get_raw_ptr(ct.pointer(ptr), self.arr) return ptr.value def elements(self): From ed12077e6f473c5a3b03be31732466ee6e55bc52 Mon Sep 17 00:00:00 2001 From: Filipe Maia Date: Sun, 14 Feb 2016 00:11:42 +0100 Subject: [PATCH 014/212] Adding is_linear() --- arrayfire/array.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index 350c2a1a6..e724977ec 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -642,6 +642,14 @@ def is_bool(self): safe_call(backend.get().af_is_bool(ct.pointer(res), self.arr)) return res.value + def is_linear(self): + """ + Check if all elements of the array are contiguous. + """ + res = ct.c_bool(False) + safe_call(backend.get().af_is_linear(ct.pointer(res), self.arr)) + return res.value + def __add__(self, other): """ Return self + other. From 11612e896453ad61fcbb711779816e7437c463bf Mon Sep 17 00:00:00 2001 From: Filipe Maia Date: Sun, 14 Feb 2016 00:13:50 +0100 Subject: [PATCH 015/212] Adding is_owner() --- arrayfire/array.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index e724977ec..4e9832237 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -650,6 +650,14 @@ def is_linear(self): safe_call(backend.get().af_is_linear(ct.pointer(res), self.arr)) return res.value + def is_owner(self): + """ + Check if the array owns the raw pointer or is a derived array. + """ + res = ct.c_bool(False) + safe_call(backend.get().af_is_owner(ct.pointer(res), self.arr)) + return res.value + def __add__(self, other): """ Return self + other. From 9bb9061783afcc628138339c972440a6a07f9345 Mon Sep 17 00:00:00 2001 From: Filipe Maia Date: Sun, 14 Feb 2016 00:25:27 +0100 Subject: [PATCH 016/212] Adding strides() --- arrayfire/array.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index 4e9832237..871d9764a 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -491,6 +491,24 @@ def raw_ptr(self): backend.get().af_get_raw_ptr(ct.pointer(ptr), self.arr) return ptr.value + def strides(self): + """ + Return the distance in bytes between consecutive elements for each dimension. + + Returns + ------ + strides : tuple + The strides for each dimension + """ + s0 = ct.c_longlong(0) + s1 = ct.c_longlong(0) + s2 = ct.c_longlong(0) + s3 = ct.c_longlong(0) + safe_call(backend.get().af_get_strides(ct.pointer(s0), ct.pointer(s1), + ct.pointer(s2), ct.pointer(s3), self.arr)) + strides = (s0.value,s1.value,s2.value,s3.value) + return strides[:self.numdims()] + def elements(self): """ Return the number of elements in the array. From b726e89727d8a8230e19197a6d28a86834b993f4 Mon Sep 17 00:00:00 2001 From: Filipe Maia Date: Sun, 14 Feb 2016 00:29:54 +0100 Subject: [PATCH 017/212] Adding offset() --- arrayfire/array.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index 871d9764a..cb6465949 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -491,6 +491,19 @@ def raw_ptr(self): backend.get().af_get_raw_ptr(ct.pointer(ptr), self.arr) return ptr.value + def offset(self): + """ + Return the offset, of the first element relative to the raw pointer. + + Returns + ------ + offset : int + The offset in number of elements + """ + offset = ct.c_longlong(0) + safe_call(backend.get().af_get_offset(ct.pointer(offset), self.arr)) + return offset.value + def strides(self): """ Return the distance in bytes between consecutive elements for each dimension. From cf28938162f8d25be3dfa0bcb8f6dfe3fd5339c1 Mon Sep 17 00:00:00 2001 From: Filipe Maia Date: Sun, 14 Feb 2016 15:16:03 +0100 Subject: [PATCH 018/212] Enabling to pass offset and strides to the array constructor --- arrayfire/array.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index cb6465949..d413a2dba 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -31,6 +31,27 @@ def _create_array(buf, numdims, idims, dtype, is_device): numdims, ct.pointer(c_dims), dtype.value)) return out_arr +def _create_strided_array(buf, numdims, idims, dtype, is_device, offset, strides): + out_arr = ct.c_void_p(0) + c_dims = dim4(idims[0], idims[1], idims[2], idims[3]) + if offset is None: + offset = 0 + offset = ct.c_ulonglong(offset) + if strides is None: + strides = (1, idims[0], idims[0]*idims[1], idims[0]*idims[1]*idims[2]) + while len(strides) < 4: + strides = strides + (strides[-1],) + strides = dim4(strides[0], strides[1], strides[2], strides[3]) + if is_device: + location = Source.device + else: + location = Source.host + safe_call(backend.get().af_create_strided_array(ct.pointer(out_arr), ct.c_void_p(buf), + offset, numdims, ct.pointer(c_dims), + ct.pointer(strides), dtype.value, + location.value)) + return out_arr + def _create_empty_array(numdims, idims, dtype): out_arr = ct.c_void_p(0) c_dims = dim4(idims[0], idims[1], idims[2], idims[3]) @@ -352,7 +373,7 @@ class Array(BaseArray): """ - def __init__(self, src=None, dims=(0,), dtype=None, is_device=False): + def __init__(self, src=None, dims=(0,), dtype=None, is_device=False, offset=None, strides=None): super(Array, self).__init__() @@ -409,8 +430,10 @@ def __init__(self, src=None, dims=(0,), dtype=None, is_device=False): if (type_char is not None and type_char != _type_char): raise TypeError("Can not create array of requested type from input data type") - - self.arr = _create_array(buf, numdims, idims, to_dtype[_type_char], is_device) + if(offset is None and strides is None): + self.arr = _create_array(buf, numdims, idims, to_dtype[_type_char], is_device) + else: + self.arr = _create_strided_array(buf, numdims, idims, to_dtype[_type_char], is_device, offset, strides) else: From f18515f710b2d385f4aed957d42bd3e1533dbbf3 Mon Sep 17 00:00:00 2001 From: Filipe Maia Date: Sun, 14 Feb 2016 16:14:09 +0100 Subject: [PATCH 019/212] Improving the documentation of raw_ptr() and device_ptr() --- arrayfire/array.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index d413a2dba..40a0fcd9d 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -489,7 +489,8 @@ def device_ptr(self): ---- - This can be used to integrate with custom C code and / or PyCUDA or PyOpenCL. - No other arrays will share the same device pointer. - - If multiple arrays share the same memory a copy of the memory is done and a pointer to the new copy is returned. + - A copy of the memory is done if multiple arrays share the same memory or the array is not the owner of the memory. + - In case of a copy the return value points to the newly allocated memory which is now exclusively owned by the array. """ ptr = ct.c_void_p(0) backend.get().af_get_device_ptr(ct.pointer(ptr), self.arr) @@ -509,6 +510,8 @@ def raw_ptr(self): - This can be used to integrate with custom C code and / or PyCUDA or PyOpenCL. - No mem copy is peformed, this function returns the raw device pointer. - This pointer may be shared with other arrays. Use this function with caution. + - In particular the JIT compiler will not be aware of the shared arrays. + - This results in JITed operations not being immediately visible through the other array. """ ptr = ct.c_void_p(0) backend.get().af_get_raw_ptr(ct.pointer(ptr), self.arr) From da1cad5257185196e7bd82824ed9b962b7725c60 Mon Sep 17 00:00:00 2001 From: Matthew Bergkoetter Date: Sun, 21 Feb 2016 12:29:00 -0500 Subject: [PATCH 020/212] Fixes typo that prevented setting backend. --- arrayfire/library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index 91ba1af70..9748f6c39 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -496,7 +496,7 @@ def set_backend(name, unsafe=False): unsafe : optional: bool. Default: False. If False, does not switch backend if current backend is not unified backend. """ - if (backend.is_unified() == False and unsanfe == False): + if (backend.is_unified() == False and unsafe == False): raise RuntimeError("Can not change backend after loading %s" % name) if (backend.is_unified()): From 7b9f5ac6e9a0030392933cd8f993f9961845c5e7 Mon Sep 17 00:00:00 2001 From: Matthew Bergkoetter Date: Sun, 21 Feb 2016 12:29:00 -0500 Subject: [PATCH 021/212] Fixes typo that prevented setting backend. --- arrayfire/library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index 4854d9334..936b840e3 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -488,7 +488,7 @@ def set_backend(name, unsafe=False): unsafe : optional: bool. Default: False. If False, does not switch backend if current backend is not unified backend. """ - if (backend.is_unified() == False and unsanfe == False): + if (backend.is_unified() == False and unsafe == False): raise RuntimeError("Can not change backend after loading %s" % name) if (backend.is_unified()): From 3f7ddf94fef8659ad3a5d15dcf595d92a3f84d7d Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 22 Feb 2016 16:36:58 -0500 Subject: [PATCH 022/212] Fixing a test which was double freeing the data --- tests/simple/device.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/simple/device.py b/tests/simple/device.py index 98a2b710a..3fe019ce5 100644 --- a/tests/simple/device.py +++ b/tests/simple/device.py @@ -46,7 +46,9 @@ def simple_device(verbose=False): print_func(dev_ptr) b = af.Array(src=dev_ptr, dims=a.dims(), dtype=a.dtype(), is_device=True) display_func(b) - af.lock_device_ptr(b) - af.unlock_device_ptr(b) + + c = af.randu(10,10) + af.lock_device_ptr(c) + af.unlock_device_ptr(c) _util.tests['device'] = simple_device From 2e951d1e72c82ff210b0b4d035264524c5a6c676 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 2 Mar 2016 14:51:23 -0500 Subject: [PATCH 023/212] FEAT: Adding new graphics functions from 3.3 --- arrayfire/graphics.py | 50 +++++++++++++++++++++++++++++++++++++++++++ arrayfire/library.py | 13 +++++++++++ 2 files changed, 63 insertions(+) diff --git a/arrayfire/graphics.py b/arrayfire/graphics.py index b1b4f821a..0597b83a5 100644 --- a/arrayfire/graphics.py +++ b/arrayfire/graphics.py @@ -140,6 +140,46 @@ def image(self, img, title=None): _cell = _Cell(self._r, self._c, title, self._cmap) safe_call(backend.get().af_draw_image(self._wnd, img.arr, ct.pointer(_cell))) + def scatter(self, X, Y, marker=MARKER.POINT, title=None): + """ + Renders input arrays as 2D scatter plot. + + Paramters + --------- + + X: af.Array. + A 1 dimensional array containing X co-ordinates. + + Y: af.Array. + A 1 dimensional array containing Y co-ordinates. + + marker: af.MARKER + Specifies how the points look + + title: str. + Title used for the plot. + """ + _cell = _Cell(self._r, self._c, title, self._cmap) + safe_call(backend.get().af_draw_scatter(self._wnd, X.arr, Y.arr, + marker.value, ct.pointer(_cell))) + + def scatter3(self, P, marker=MARKER.POINT, title=None): + """ + Renders the input array as a 3D Scatter plot. + + Paramters + --------- + + P: af.Array. + A 2 dimensional array containing (X,Y,Z) co-ordinates. + + title: str. + Title used for the plot. + """ + _cell = _Cell(self._r, self._c, title, self._cmap) + safe_call(backend.get().af_draw_scatter3(self._wnd, P.arr, + marker.value, ct.pointer(_cell))) + def plot(self, X, Y, title=None): """ Display a 2D Plot. @@ -255,6 +295,16 @@ def close(self): safe_call(backend.get().af_is_window_closed(ct.pointer(tmp), self._wnd)) return tmp + def set_visibility(is_visible): + """ + A flag that shows or hides the window as requested. + + Parameters + ---------- + is_visible: Flag specifying the visibility of the flag. + """ + safe_call(backend.get().af_set_visibility(self._wnd, is_visible)) + def __getitem__(self, keys): """ Get access to a specific grid location within the window. diff --git a/arrayfire/library.py b/arrayfire/library.py index 936b840e3..ea0e90fdb 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -315,6 +315,19 @@ class BACKEND(_Enum): CUDA = _Enum_Type(2) OPENCL = _Enum_Type(4) +class MARKER(_Enum): + """ + Markers used for different points in graphics plots + """ + NONE = _Enum_Type(0) + POINT = _Enum_Type(1) + CIRCLE = _Enum_Type(2) + SQUARE = _Enum_Type(3) + TRIANGE = _Enum_Type(4) + CROSS = _Enum_Type(5) + PLUS = _Enum_Type(6) + STAR = _Enum_Type(7) + def _setup(): import platform import os From 6545b5a7614b5925c1e94aac864824d09f69ce62 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 2 Mar 2016 15:03:49 -0500 Subject: [PATCH 024/212] Changing deprecated functions --- arrayfire/device.py | 22 ++++++++++++++++++---- tests/simple/device.py | 4 ++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/arrayfire/device.py b/arrayfire/device.py index f84404f07..cfdbb764a 100644 --- a/arrayfire/device.py +++ b/arrayfire/device.py @@ -240,6 +240,14 @@ def get_device_ptr(a): return ptr def lock_device_ptr(a): + """ + This functions is deprecated. Please use lock_array instead. + """ + import warnings + warnings.warn("This function is deprecated. Use lock_array instead.", DeprecationWarning) + lock_array(a) + +def lock_array(a): """ Ask arrayfire to not perform garbage collection on raw data held by an array. @@ -252,10 +260,17 @@ def lock_device_ptr(a): ----- - The device pointer of `a` is not freed by memory manager until `unlock_device_ptr()` is called. """ - ptr = ct.c_void_p(0) - safe_call(backend.get().af_lock_device_ptr(a.arr)) + safe_call(backend.get().af_lock_array(a.arr)) def unlock_device_ptr(a): + """ + This functions is deprecated. Please use unlock_array instead. + """ + import warnings + warnings.warn("This function is deprecated. Use unlock_array instead.", DeprecationWarning) + unlock_array(a) + +def unlock_array(a): """ Tell arrayfire to resume garbage collection on raw data held by an array. @@ -265,7 +280,6 @@ def unlock_device_ptr(a): - A multi dimensional arrayfire array. """ - ptr = ct.c_void_p(0) - safe_call(backend.get().af_unlock_device_ptr(a.arr)) + safe_call(backend.get().af_unlock_array(a.arr)) from .array import Array diff --git a/tests/simple/device.py b/tests/simple/device.py index 3fe019ce5..925add294 100644 --- a/tests/simple/device.py +++ b/tests/simple/device.py @@ -48,7 +48,7 @@ def simple_device(verbose=False): display_func(b) c = af.randu(10,10) - af.lock_device_ptr(c) - af.unlock_device_ptr(c) + af.lock_array(c) + af.unlock_array(c) _util.tests['device'] = simple_device From 842e42713602e097ef422b13b5ffda210f32b2e4 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 2 Mar 2016 15:22:22 -0500 Subject: [PATCH 025/212] FEAT: Functions to allocate and free memory on host, device --- arrayfire/device.py | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/arrayfire/device.py b/arrayfire/device.py index cfdbb764a..a33ba51cf 100644 --- a/arrayfire/device.py +++ b/arrayfire/device.py @@ -282,4 +282,52 @@ def unlock_array(a): """ safe_call(backend.get().af_unlock_array(a.arr)) +def alloc_device(num_bytes): + """ + Allocate a buffer on the device with specified number of bytes. + """ + ptr = ct.c_void_p(0) + c_num_bytes = ct.c_longlong(num_bytes) + safe_call(backend.get().af_alloc_device(ct.pointer(ptr), c_num_bytes)) + return ptr.value + +def alloc_host(num_bytes): + """ + Allocate a buffer on the host with specified number of bytes. + """ + ptr = ct.c_void_p(0) + c_num_bytes = ct.c_longlong(num_bytes) + safe_call(backend.get().af_alloc_host(ct.pointer(ptr), c_num_bytes)) + return ptr.value + +def alloc_pinned(num_bytes): + """ + Allocate a buffer on the host using pinned memory with specified number of bytes. + """ + ptr = ct.c_void_p(0) + c_num_bytes = ct.c_longlong(num_bytes) + safe_call(backend.get().af_alloc_pinned(ct.pointer(ptr), c_num_bytes)) + return ptr.value + +def free_device(ptr): + """ + Free the device memory allocated by alloc_device + """ + cptr = ct.c_void_p(ptr) + safe_call(backend.get().af_free_device(cptr)) + +def free_host(ptr): + """ + Free the host memory allocated by alloc_host + """ + cptr = ct.c_void_p(ptr) + safe_call(backend.get().af_free_host(cptr)) + +def free_pinned(ptr): + """ + Free the pinned memory allocated by alloc_pinned + """ + cptr = ct.c_void_p(ptr) + safe_call(backend.get().af_free_pinned(cptr)) + from .array import Array From a9be255ba2eef98f9e6564fbba6c19bee2c9214a Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 2 Mar 2016 15:36:12 -0500 Subject: [PATCH 026/212] Functions to check if arrayfire has imageio and lapack support --- arrayfire/image.py | 9 +++++++++ arrayfire/lapack.py | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/arrayfire/image.py b/arrayfire/image.py index 49cc76d4e..fd516c60c 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -208,6 +208,7 @@ def transform(image, trans_mat, odim0 = 0, odim1 = 0, method=INTERP.NEAREST, is_ method.value, is_inverse)) return output + def rotate(image, theta, is_crop = True, method = INTERP.NEAREST): """ Rotate an image. @@ -1154,3 +1155,11 @@ def rgb2ycbcr(image, standard=YCC_STD.BT_601): out = Array() safe_call(backend.get().af_rgb2ycbcr(ct.pointer(out.arr), image.arr, standard.value)) return out + +def is_image_io_available(): + """ + Function to check if the arrayfire library was built with Image IO support. + """ + res = ct.c_bool(False) + safe_call(backend.get().af_is_image_io_available(ct.pointer(res))) + return res.value diff --git a/arrayfire/lapack.py b/arrayfire/lapack.py index ae62f3c90..346cddb01 100644 --- a/arrayfire/lapack.py +++ b/arrayfire/lapack.py @@ -408,3 +408,11 @@ def svd_inplace(A): safe_call(backend.get().af_svd_inplace(ct.pointer(U.arr), ct.pointer(S.arr), ct.pointer(Vt.arr), A.arr)) return U, S, Vt + +def is_lapack_available(): + """ + Function to check if the arrayfire library was built with lapack support. + """ + res = ct.c_bool(False) + safe_call(backend.get().af_is_lapack_available(ct.pointer(res))) + return res.value From a1f48ac8f9ef1627a5914918edaa31c8f895822b Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 2 Mar 2016 15:46:10 -0500 Subject: [PATCH 027/212] FEAT: Adding functions to query device and active backends --- arrayfire/library.py | 57 ++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index ea0e90fdb..08bd486e9 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -45,6 +45,7 @@ class ERR(_Enum): TYPE = _Enum_Type(204) DIFF_TYPE = _Enum_Type(205) BATCH = _Enum_Type(207) + DEVICE = _Enum_Type(208) # 300-399 Errors for missing software features NOT_SUPPORTED = _Enum_Type(301) @@ -524,12 +525,9 @@ def get_backend_id(A): name : str. Backend name """ - if (backend.is_unified()): - backend_id = ct.c_int(BACKEND.DEFAULT.value) - safe_call(backend.get().af_get_backend_id(ct.pointer(backend_id), A.arr)) - return backend.get_name(backend_id.value) - else: - return backend.name() + backend_id = ct.c_int(BACKEND.CPU.value) + safe_call(backend.get().af_get_backend_id(ct.pointer(backend_id), A.arr)) + return backend.get_name(backend_id.value) def get_backend_count(): """ @@ -541,12 +539,9 @@ def get_backend_count(): count : int Number of available backends """ - if (backend.is_unified()): - count = ct.c_int(0) - safe_call(backend.get().af_get_backend_count(ct.pointer(count))) - return count.value - else: - return 1 + count = ct.c_int(0) + safe_call(backend.get().af_get_backend_count(ct.pointer(count))) + return count.value def get_available_backends(): """ @@ -558,11 +553,37 @@ def get_available_backends(): names : tuple of strings Names of available backends """ - if (backend.is_unified()): - available = ct.c_int(0) - safe_call(backend.get().af_get_available_backends(ct.pointer(available))) - return backend.parse(int(available.value)) - else: - return (backend.name(),) + available = ct.c_int(0) + safe_call(backend.get().af_get_available_backends(ct.pointer(available))) + return backend.parse(int(available.value)) + +def get_active_backend(): + """ + Get the current active backend + + name : str. + Backend name + """ + backend_id = ct.c_int(BACKEND.CPU.value) + safe_call(backend.get().af_get_active_backend(ct.pointer(backend_id))) + return backend.get_name(backend_id.value) + +def get_device_id(A): + """ + Get the device id of the array + + Parameters + ---------- + A : af.Array + + Returns + ---------- + + dev : Integer + id of the device array was created on + """ + device_id = ct.c_int(0) + safe_call(backend.get().af_get_device_id(ct.pointer(device_id), A.arr)) + return device_id from .util import safe_call From d385b4d1246d9f040ae487068599bdde0a07526b Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 2 Mar 2016 15:49:44 -0500 Subject: [PATCH 028/212] Function to get the current revision of arrayfire --- arrayfire/util.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arrayfire/util.py b/arrayfire/util.py index a20002cd6..db2286d74 100644 --- a/arrayfire/util.py +++ b/arrayfire/util.py @@ -75,12 +75,21 @@ def safe_call(af_error): raise RuntimeError(to_str(err_str), af_error) def get_version(): + """ + Function to get the version of arrayfire. + """ major=ct.c_int(0) minor=ct.c_int(0) patch=ct.c_int(0) safe_call(backend.get().af_get_version(ct.pointer(major), ct.pointer(minor), ct.pointer(patch))) return major.value,minor.value,patch.value +def get_reversion(): + """ + Function to get the revision hash of the library. + """ + return to_str(backend.get().af_get_revision()) + to_dtype = {'f' : Dtype.f32, 'd' : Dtype.f64, 'b' : Dtype.b8, From 9adae094e4888543c44a0b2cdfd773dfd30357ae Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 2 Mar 2016 16:22:05 -0500 Subject: [PATCH 029/212] BUGFIX: Append SO names to the full library path --- arrayfire/library.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index 08bd486e9..ced4db4cd 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -373,7 +373,7 @@ def _setup(): ## OSX specific setup pre = 'lib' - post = '.dylib' + post = '.3.dylib' if AF_SEARCH_PATH is None: AF_SEARCH_PATH='/usr/local/' @@ -385,7 +385,7 @@ def _setup(): elif platform_name == 'Linux': pre = 'lib' - post = '.so' + post = '.so.3' if AF_SEARCH_PATH is None: AF_SEARCH_PATH='/opt/arrayfire-3/' From cf38ac38b838d925eb533ce57d588c25380bacec Mon Sep 17 00:00:00 2001 From: Filipe Maia Date: Thu, 3 Mar 2016 00:20:55 +0100 Subject: [PATCH 030/212] Ensure that the types of the enums values are correct When the enum package is not available it's necessary to change the type of the _Enum_Type attributes inside a class derived from _Enum to match the type of the containing class (e.g. set the type of NONE inside the class ERR to ERR). Otherwise the behaviour with or without the enum package would be different. --- arrayfire/library.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index 4854d9334..dc77eaeae 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -19,8 +19,15 @@ def _Enum_Type(v): return v except: + class _MetaEnum(type): + def __init__(cls, name, bases, attrs): + for attrname, attrvalue in attrs.iteritems(): + if name != '_Enum' and isinstance(attrvalue, _Enum_Type): + attrvalue.__class__ = cls + attrs[attrname] = attrvalue + class _Enum(object): - pass + __metaclass__ = _MetaEnum class _Enum_Type(object): def __init__(self, v): @@ -31,7 +38,7 @@ class ERR(_Enum): Error values. For internal use only. """ - NONE = _Enum_Type(0) + NONE = _Enum_Type(0) #100-199 Errors in environment NO_MEM = _Enum_Type(101) From 4f43aabc62f349d84d858c61836bbaa84ccca3ec Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 18 Mar 2016 14:31:13 -0400 Subject: [PATCH 031/212] BUGFIX: Fixes to image processing functions. Bugs were caused by passing doubles instead of floats for scalar parameters in image processing functions. --- arrayfire/image.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arrayfire/image.py b/arrayfire/image.py index fd516c60c..8de53a6d9 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -235,7 +235,7 @@ def rotate(image, theta, is_crop = True, method = INTERP.NEAREST): """ output = Array() safe_call(backend.get().af_rotate(ct.pointer(output.arr), image.arr, - ct.c_double(theta), is_crop, method.value)) + ct.c_float(theta), is_crop, method.value)) return output def translate(image, trans0, trans1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST): @@ -318,7 +318,7 @@ def scale(image, scale0, scale1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST): """ output = Array() safe_call(backend.get().af_scale(ct.pointer(output.arr), - image.arr, ct.c_double(scale0), ct.c_double(scale1), + image.arr, ct.c_float(scale0), ct.c_float(scale1), ct.c_longlong(odim0), ct.c_longlong(odim1), method.value)) return output @@ -363,7 +363,7 @@ def skew(image, skew0, skew1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST, is_ """ output = Array() safe_call(backend.get().af_skew(ct.pointer(output.arr), - image.arr, ct.c_double(skew0), ct.c_double(skew1), + image.arr, ct.c_float(skew0), ct.c_float(skew1), ct.c_longlong(odim0), ct.c_longlong(odim1), method.value, is_inverse)) @@ -408,7 +408,7 @@ def histogram(image, nbins, min_val = None, max_val = None): output = Array() safe_call(backend.get().af_histogram(ct.pointer(output.arr), image.arr, ct.c_uint(nbins), - ct.c_double(min_val), ct.c_double(max_val))) + ct.c_float(min_val), ct.c_float(max_val))) return output def hist_equal(image, hist): @@ -580,8 +580,8 @@ def bilateral(image, s_sigma, c_sigma, is_color = False): """ output = Array() safe_call(backend.get().af_bilateral(ct.pointer(output.arr), - image.arr, ct.c_double(s_sigma), - ct.c_double(c_sigma), is_color)) + image.arr, ct.c_float(s_sigma), + ct.c_float(c_sigma), is_color)) return output def mean_shift(image, s_sigma, c_sigma, n_iter, is_color = False): @@ -615,7 +615,7 @@ def mean_shift(image, s_sigma, c_sigma, n_iter, is_color = False): """ output = Array() safe_call(backend.get().af_mean_shift(ct.pointer(output.arr), - image.arr, ct.c_double(s_sigma), ct.c_double(c_sigma), + image.arr, ct.c_float(s_sigma), ct.c_float(c_sigma), ct.c_uint(n_iter), is_color)) return output From 5f4e8603046424c0de43d95ffedafcf1087863da Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 18 Mar 2016 14:33:28 -0400 Subject: [PATCH 032/212] RuntimeError now prints the proper error message from arrayfire --- arrayfire/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrayfire/util.py b/arrayfire/util.py index db2286d74..ae08e29e5 100644 --- a/arrayfire/util.py +++ b/arrayfire/util.py @@ -72,7 +72,7 @@ def safe_call(af_error): err_str = ct.c_char_p(0) err_len = ct.c_longlong(0) backend.get().af_get_last_error(ct.pointer(err_str), ct.pointer(err_len)) - raise RuntimeError(to_str(err_str), af_error) + raise RuntimeError(to_str(err_str)) def get_version(): """ From 196f1103cb923fe77450e340a18a2f439f06d127 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 20 Mar 2016 01:03:38 -0400 Subject: [PATCH 033/212] Adding function to interop with pycuda --- arrayfire/__init__.py | 5 +++++ arrayfire/interop.py | 47 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/arrayfire/__init__.py b/arrayfire/__init__.py index 79959bb8c..40cc23122 100644 --- a/arrayfire/__init__.py +++ b/arrayfire/__init__.py @@ -35,6 +35,11 @@ """ +try: + import pycuda.autoinit +except: + pass + from .library import * from .array import * from .data import * diff --git a/arrayfire/interop.py b/arrayfire/interop.py index 809562927..deaaa999d 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -13,9 +13,11 @@ This module provides interoperability with the following python packages. 1. numpy + 2. pycuda """ from .array import * +from .device import lock_array try: import numpy as np @@ -60,3 +62,48 @@ def np_to_af_array(np_arr): from_ndarray = np_to_af_array except: AF_NUMPY_FOUND=False + +try: + import pycuda.gpuarray as CudaArray + AF_PYCUDA_FOUND=True + + def pycuda_to_af_array(pycu_arr): + """ + Convert pycuda.gpuarray to arrayfire.Array + + Parameters + ----------- + pycu_arr : pycuda.GPUArray() + + Returns + ---------- + af_arr : arrayfire.Array() + """ + if (pycu_arr.flags.f_contiguous): + res = Array(pycu_arr.ptr, pycu_arr.shape, pycu_arr.dtype.char, is_device=True) + lock_array(res) + return res + elif (pycu_arr.flags.c_contiguous): + if pycu_arr.ndim == 1: + return Array(pycu_arr.ptr, pycu_arr.shape, pycu_arr.dtype.char, is_device=True) + elif pycu_arr.ndim == 2: + shape = (pycu_arr.shape[1], pycu_arr.shape[0]) + res = Array(pycu_arr.ptr, shape, pycu_arr.dtype.char, is_device=True) + lock_array(res) + return reorder(res, 1, 0) + elif pycu_arr.ndim == 3: + shape = (pycu_arr.shape[2], pycu_arr.shape[1], pycu_arr.shape[0]) + res = Array(pycu_arr.ptr, shape, pycu_arr.dtype.char, is_device=True) + lock_array(res) + return reorder(res, 2, 1, 0) + elif pycu_arr.ndim == 4: + shape = (pycu_arr.shape[3], pycu_arr.shape[2], pycu_arr.shape[1], pycu_arr.shape[0]) + res = Array(pycu_arr.ptr, shape, pycu_arr.dtype.char, is_device=True) + lock_array(res) + return reorder(res, 3, 2, 1, 0) + else: + raise RuntimeError("Unsupported ndim") + else: + return pycuda_to_af_array(pycu_arr.copy()) +except: + AF_PYCUDA_FOUND=False From ced0322386f1ad46dcf7d8ebef39258312eaa737 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 20 Mar 2016 02:25:05 -0400 Subject: [PATCH 034/212] FEAT: Adding functions to interact with other opencl libraries --- arrayfire/opencl.py | 108 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/arrayfire/opencl.py b/arrayfire/opencl.py index 5c075df3b..d41be1df8 100644 --- a/arrayfire/opencl.py +++ b/arrayfire/opencl.py @@ -13,6 +13,30 @@ This module provides interoperability with other OpenCL libraries. """ +from .util import * +from .library import (_Enum, _Enum_Type) + +class DEVICE_TYPE(_Enum): + """ + ArrayFire wrapper for CL_DEVICE_TYPE + """ + CPU = _Enum_Type(1<<1) + GPU = _Enum_Type(1<<2) + ACC = _Enum_Type(1<<3) + UNKNOWN = _Enum_Type(-1) + +class PLATFORM(_Enum): + """ + ArrayFire enum for common platforms + """ + AMD = _Enum_Type(0) + APPLE = _Enum_Type(1) + INTEL = _Enum_Type(2) + NVIDIA = _Enum_Type(3) + BEIGNET = _Enum_Type(4) + POCL = _Enum_Type(5) + UNKNOWN = _Enum_Type(-1) + def get_context(retain=False): """ Get the current OpenCL context being used by ArrayFire. @@ -107,3 +131,87 @@ def set_device_id(idx): safe_call(backend.get().afcl_set_device_id(idx)) return + +def add_device_context(dev, ctx, que): + """ + Add a new device to arrayfire opencl device manager + + Parameters + ---------- + + dev : cl_device_id + + ctx : cl_context + + que : cl_command_queue + + """ + if (backend.name() != "opencl"): + raise RuntimeError("Invalid backend loaded") + + safe_call(backend.get().afcl_add_device_context(dev, ctx, que)) + +def set_device_context(dev, ctx): + """ + Set a device as current active device + + Parameters + ---------- + + dev : cl_device_id + + ctx : cl_context + + """ + if (backend.name() != "opencl"): + raise RuntimeError("Invalid backend loaded") + + safe_call(backend.get().afcl_set_device_context(dev, ctx)) + +def delete_device_context(dev, ctx): + """ + Delete a device + + Parameters + ---------- + + dev : cl_device_id + + ctx : cl_context + + """ + if (backend.name() != "opencl"): + raise RuntimeError("Invalid backend loaded") + + safe_call(backend.get().afcl_delete_device_context(dev, ctx)) + + +_to_device_type = {DEVICE_TYPE.CPU.value : DEVICE_TYPE.CPU, + DEVICE_TYPE.GPU.value : DEVICE_TYPE.GPU, + DEVICE_TYPE.ACC.value : DEVICE_TYPE.ACC, + DEVICE_TYPE.UNKNOWN.value : DEVICE_TYPE.UNKNOWN} + +_to_platform = {PLATFORM.AMD.value : PLATFORM.AMD, + PLATFORM.APPLE.value : PLATFORM.APPLE, + PLATFORM.INTEL.value : PLATFORM.INTEL, + PLATFORM.NVIDIA.value : PLATFORM.NVIDIA, + PLATFORM.BEIGNET.value : PLATFORM.BEIGNET, + PLATFORM.POCL.value : PLATFORM.POCL, + PLATFORM.UNKNOWN.value : PLATFORM.UNKNOWN} + + +def get_device_type(): + """ + Get opencl device type + """ + res = ct.c_int(DEVICE_TYPE.UNKNOWN.value) + safe_call(backend.get().afcl_get_device_type(ct.pointer(res))) + return _to_device_type[res.value] + +def get_platform(): + """ + Get opencl platform + """ + res = ct.c_int(PLATFORM.UNKNOWN.value) + safe_call(backend.get().afcl_get_platform(ct.pointer(res))) + return _to_platform[res.value] From b5d5c873a4717cdcf3b9ec9bfe93cd7c49fb2de6 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 20 Mar 2016 03:49:19 -0400 Subject: [PATCH 035/212] Cleaning up interop.py --- arrayfire/interop.py | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/arrayfire/interop.py b/arrayfire/interop.py index deaaa999d..d60034174 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -37,22 +37,27 @@ def np_to_af_array(np_arr): --------- af_arr : arrayfire.Array() """ + + in_shape = np_arr.shape + in_ptr = np_arr.ctypes.data + in_dtype = np_arr.dtype.char + if (np_arr.flags['F_CONTIGUOUS']): - return Array(np_arr.ctypes.data, np_arr.shape, np_arr.dtype.char) + return Array(in_ptr, in_shape, in_dtype) elif (np_arr.flags['C_CONTIGUOUS']): if np_arr.ndim == 1: - return Array(np_arr.ctypes.data, np_arr.shape, np_arr.dtype.char) + return Array(in_ptr, in_shape, in_dtype) elif np_arr.ndim == 2: - shape = (np_arr.shape[1], np_arr.shape[0]) - res = Array(np_arr.ctypes.data, shape, np_arr.dtype.char) + shape = (in_shape[1], in_shape[0]) + res = Array(in_ptr, shape, in_dtype) return reorder(res, 1, 0) elif np_arr.ndim == 3: - shape = (np_arr.shape[2], np_arr.shape[1], np_arr.shape[0]) - res = Array(np_arr.ctypes.data, shape, np_arr.dtype.char) + shape = (in_shape[2], in_shape[1], in_shape[0]) + res = Array(in_ptr, shape, in_dtype) return reorder(res, 2, 1, 0) elif np_arr.ndim == 4: - shape = (np_arr.shape[3], np_arr.shape[2], np_arr.shape[1], np_arr.shape[0]) - res = Array(np_arr.ctypes.data, shape, np_arr.dtype.char) + shape = (in_shape[3], in_shape[2], in_shape[1], in_shape[0]) + res = Array(in_ptr, shape, in_dtype) return reorder(res, 3, 2, 1, 0) else: raise RuntimeError("Unsupported ndim") @@ -79,26 +84,31 @@ def pycuda_to_af_array(pycu_arr): ---------- af_arr : arrayfire.Array() """ + + in_ptr = pycu_arr.ptr + in_shape = pycu_arr.shape + in_dtype = pycu_arr.dtype.char + if (pycu_arr.flags.f_contiguous): - res = Array(pycu_arr.ptr, pycu_arr.shape, pycu_arr.dtype.char, is_device=True) + res = Array(in_ptr, in_shape, in_dtype, is_device=True) lock_array(res) return res elif (pycu_arr.flags.c_contiguous): if pycu_arr.ndim == 1: - return Array(pycu_arr.ptr, pycu_arr.shape, pycu_arr.dtype.char, is_device=True) + return Array(in_ptr, in_shape, in_dtype, is_device=True) elif pycu_arr.ndim == 2: - shape = (pycu_arr.shape[1], pycu_arr.shape[0]) - res = Array(pycu_arr.ptr, shape, pycu_arr.dtype.char, is_device=True) + shape = (in_shape[1], in_shape[0]) + res = Array(in_ptr, shape, in_dtype, is_device=True) lock_array(res) return reorder(res, 1, 0) elif pycu_arr.ndim == 3: - shape = (pycu_arr.shape[2], pycu_arr.shape[1], pycu_arr.shape[0]) - res = Array(pycu_arr.ptr, shape, pycu_arr.dtype.char, is_device=True) + shape = (in_shape[2], in_shape[1], in_shape[0]) + res = Array(in_ptr, shape, in_dtype, is_device=True) lock_array(res) return reorder(res, 2, 1, 0) elif pycu_arr.ndim == 4: - shape = (pycu_arr.shape[3], pycu_arr.shape[2], pycu_arr.shape[1], pycu_arr.shape[0]) - res = Array(pycu_arr.ptr, shape, pycu_arr.dtype.char, is_device=True) + shape = (in_shape[3], in_shape[2], in_shape[1], in_shape[0]) + res = Array(in_ptr, shape, in_dtype, is_device=True) lock_array(res) return reorder(res, 3, 2, 1, 0) else: From 54a0cab6c84a9d9187fc5b06aa507918ca121235 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 20 Mar 2016 04:30:47 -0400 Subject: [PATCH 036/212] Adding interop functionality with pyopencl --- arrayfire/interop.py | 74 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/arrayfire/interop.py b/arrayfire/interop.py index d60034174..0c6348d12 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -17,7 +17,7 @@ """ from .array import * -from .device import lock_array +from .device import * try: import numpy as np @@ -117,3 +117,75 @@ def pycuda_to_af_array(pycu_arr): return pycuda_to_af_array(pycu_arr.copy()) except: AF_PYCUDA_FOUND=False + +try: + import pyopencl.array as CLArray + from .opencl import add_device_context as _add_device_context + from .opencl import set_device_context as _set_device_context + from .opencl import get_device_id as _get_device_id + from .opencl import get_context as _get_context + AF_PYOPENCL_FOUND=True + + def pyopencl_to_af_array(pycl_arr): + """ + Convert pyopencl.gpuarray to arrayfire.Array + + Parameters + ----------- + pycl_arr : pyopencl.Array() + + Returns + ---------- + af_arr : arrayfire.Array() + """ + + ctx = pycl_arr.context.int_ptr + que = pycl_arr.queue.int_ptr + dev = pycl_arr.queue.device.int_ptr + + dev_idx = None + ctx_idx = None + for n in range(get_device_count()): + set_device(n) + dev_idx = _get_device_id() + ctx_idx = _get_context() + if (dev_idx == dev and ctx_idx == ctx): + break + + if (dev_idx == None or ctx_idx == None or + dev_idx != dev or ctx_idx != ctx): + _add_device_context(dev, ctx, que) + _set_device_context(dev, ctx) + + in_ptr = pycl_arr.base_data.int_ptr + in_shape = pycl_arr.shape + in_dtype = pycl_arr.dtype.char + + if (pycl_arr.flags.f_contiguous): + res = Array(in_ptr, in_shape, in_dtype, is_device=True) + lock_array(res) + return res + elif (pycl_arr.flags.c_contiguous): + if pycl_arr.ndim == 1: + return Array(in_ptr, in_shape, in_dtype, is_device=True) + elif pycl_arr.ndim == 2: + shape = (in_shape[1], in_shape[0]) + res = Array(in_ptr, shape, in_dtype, is_device=True) + lock_array(res) + return reorder(res, 1, 0) + elif pycl_arr.ndim == 3: + shape = (in_shape[2], in_shape[1], in_shape[0]) + res = Array(in_ptr, shape, in_dtype, is_device=True) + lock_array(res) + return reorder(res, 2, 1, 0) + elif pycl_arr.ndim == 4: + shape = (in_shape[3], in_shape[2], in_shape[1], in_shape[0]) + res = Array(in_ptr, shape, in_dtype, is_device=True) + lock_array(res) + return reorder(res, 3, 2, 1, 0) + else: + raise RuntimeError("Unsupported ndim") + else: + return pyopencl_to_af_array(pycl_arr.copy()) +except: + AF_PYOPENCL_FOUND=False From 1030103c01f5ed81f19ddd1d93808b6725db8eed Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 20 Mar 2016 04:44:53 -0400 Subject: [PATCH 037/212] Adding a simple "to_array" function to ease interoperability --- arrayfire/interop.py | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/arrayfire/interop.py b/arrayfire/interop.py index 0c6348d12..0fb55c165 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -21,6 +21,7 @@ try: import numpy as np + from numpy import ndarray as NumpyArray from .data import reorder AF_NUMPY_FOUND=True @@ -69,7 +70,8 @@ def np_to_af_array(np_arr): AF_NUMPY_FOUND=False try: - import pycuda.gpuarray as CudaArray + import pycuda.gpuarray + from pycuda.gpuarray import GPUArray as CudaArray AF_PYCUDA_FOUND=True def pycuda_to_af_array(pycu_arr): @@ -83,6 +85,10 @@ def pycuda_to_af_array(pycu_arr): Returns ---------- af_arr : arrayfire.Array() + + Note + ---------- + The input array is copied to af.Array """ in_ptr = pycu_arr.ptr @@ -92,6 +98,7 @@ def pycuda_to_af_array(pycu_arr): if (pycu_arr.flags.f_contiguous): res = Array(in_ptr, in_shape, in_dtype, is_device=True) lock_array(res) + res = res.copy() return res elif (pycu_arr.flags.c_contiguous): if pycu_arr.ndim == 1: @@ -119,7 +126,7 @@ def pycuda_to_af_array(pycu_arr): AF_PYCUDA_FOUND=False try: - import pyopencl.array as CLArray + from pyopencl.array import Array as OpenclArray from .opencl import add_device_context as _add_device_context from .opencl import set_device_context as _set_device_context from .opencl import get_device_id as _get_device_id @@ -137,6 +144,10 @@ def pyopencl_to_af_array(pycl_arr): Returns ---------- af_arr : arrayfire.Array() + + Note + ---------- + The input array is copied to af.Array """ ctx = pycl_arr.context.int_ptr @@ -189,3 +200,28 @@ def pyopencl_to_af_array(pycl_arr): return pyopencl_to_af_array(pycl_arr.copy()) except: AF_PYOPENCL_FOUND=False + + +def to_array(in_array): + """ + Helper function to convert input from a different module to af.Array + + Parameters + ------------- + + in_array : array like object + Can be one of numpy.ndarray, pycuda.GPUArray, pyopencl.Array, array.array, list + + Returns + -------------- + af.Array of same dimensions as input after copying the data from the input + + + """ + if AF_NUMPY_FOUND and isinstance(in_array, NumpyArray): + return np_to_af_array(in_array) + if AF_PYCUDA_FOUND and isinstance(in_array, CudaArray): + return pycuda_to_af_array(in_array) + if AF_PYOPENCL_FOUND and isinstance(in_array, OpenclArray): + return pyopencl_to_af_array(in_array) + return Array(src=in_array) From 15eb9a0c71114f9bc754389abafc459b8250f8e7 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 20 Mar 2016 05:32:23 -0400 Subject: [PATCH 038/212] BUGFIX: Fixing issues with boolean indexing --- arrayfire/array.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 40a0fcd9d..e539b057a 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -488,7 +488,7 @@ def device_ptr(self): Note ---- - This can be used to integrate with custom C code and / or PyCUDA or PyOpenCL. - - No other arrays will share the same device pointer. + - No other arrays will share the same device pointer. - A copy of the memory is done if multiple arrays share the same memory or the array is not the owner of the memory. - In case of a copy the return value points to the newly allocated memory which is now exclusively owned by the array. """ @@ -985,6 +985,12 @@ def __getitem__(self, key): try: out = Array() n_dims = self.numdims() + + if (isinstance(key, Array) and key.type() == Dtype.b8.value): + n_dims = 1 + if (count(key) == 0): + return out + inds = _get_indices(key) safe_call(backend.get().af_index_gen(ct.pointer(out.arr), @@ -1005,9 +1011,21 @@ def __setitem__(self, key, val): try: n_dims = self.numdims() + is_boolean_idx = isinstance(key, Array) and key.type() == Dtype.b8.value + + if (is_boolean_idx): + n_dims = 1 + num = count(key) + if (num == 0): + return + if (_is_number(val)): tdims = _get_assign_dims(key, self.dims()) - other_arr = constant_array(val, tdims[0], tdims[1], tdims[2], tdims[3], self.type()) + if (is_boolean_idx): + n_dims = 1 + other_arr = constant_array(val, int(num), dtype=self.type()) + else: + other_arr = constant_array(val, tdims[0] , tdims[1], tdims[2], tdims[3], self.type()) del_other = True else: other_arr = val.arr @@ -1017,8 +1035,8 @@ def __setitem__(self, key, val): inds = _get_indices(key) safe_call(backend.get().af_assign_gen(ct.pointer(out_arr), - self.arr, ct.c_longlong(n_dims), inds.pointer, - other_arr)) + self.arr, ct.c_longlong(n_dims), inds.pointer, + other_arr)) safe_call(backend.get().af_release_array(self.arr)) if del_other: safe_call(backend.get().af_release_array(other_arr)) @@ -1235,5 +1253,5 @@ def read_array(filename, index=None, key=None): return out -from .algorithm import sum +from .algorithm import (sum, count) from .arith import cast From 03a65bd18eb8fb6b61047227bb69613df0db6d8d Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 24 Dec 2015 21:58:08 -0500 Subject: [PATCH 039/212] Updating Changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e446bc598..316c45641 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +### v3.2.20151224 +- Bug fixes: + - A default `AF_PATH` is set if none is found as an environment variable. + +- Examples: + - Heston model example uses a smaller data set to help run on low end GPUs. + ### v3.2.20151214 - Bug fixes: - `get_version()` now returns ints instead of `c_int` From 9436ae7ec3b82aa5d7df38d2991ff38433e5c0b4 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 20 Mar 2016 19:32:45 -0400 Subject: [PATCH 040/212] Updating CHANGELOG for 3.3 release --- CHANGELOG.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 316c45641..78ce3249d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,48 @@ +### v3.3.20160320 +- Feature parity with Arrayfire 3.3 libs + - Functions to interact with arryafire's internal data structures. + - `Array.offset` + - `Array.strides` + - `Array.is_owner` + - `Array.is_linear` + - `Array.raw_ptr` + - Array constructor now takes `offset` and `strides` as optional parameters. + - New visualization functions: `scatter` and `scatter3` + - OpenCL backend specific functions: + - `get_device_type` + - `get_platform` + - `add_device_context` + - `delete_device_context` + - `set_device_context` + - Functions to allocate and free memory on host and device + - `alloc_host` and `free_host` + - `alloc_pinned` and `free_pinned` + - `alloc_device` and `free_device` + - Function to query which device and backend an array was created on + - `get_device_id` + - `get_backend_id` + - Miscellaneous functions + - `is_lapack_available` + - `is_image_io_available` + +- Interopability + - Transfer PyCUDA GPUArrays using `af.pycuda_to_af_array` + - Transfer PyOpenCL Arrays using `af.pyopencl_to_af_array` + - New helper function `af.to_array` added to convert a different `array` to arrayfire Array. + - This function can be used in place of `af.xyz_to_af_array` functions mentioned above. + +- Deprecated functions list + - `lock_device_ptr` is deprecated. Use `lock_array` instead. + - `unlock_device_ptr` is deprecated. Use `unlock_array` instead. + +- Bug Fixes: + - [Boolean indexing giving faulty results](https://github.com/arrayfire/arrayfire-python/issues/68) for multi dimensional arrays. + - [Enum types comparision failures](https://github.com/arrayfire/arrayfire-python/issues/65) in Python 2.x + - [Support loading SO versioned libraries](https://github.com/arrayfire/arrayfire-python/issues/64) in Linux and OSX. + - Fixed typo that prevented changing backend + - Fixed image processing functions that accepted floating point scalar paramters. + - Affected functions include: `translate`, `scale`, `skew`, `histogram`, `bilateral`, `mean_shift`. + ### v3.2.20151224 - Bug fixes: - A default `AF_PATH` is set if none is found as an environment variable. From 92068a880867b112f8f27eb6869f9b672c2bb736 Mon Sep 17 00:00:00 2001 From: Filipe Maia Date: Thu, 24 Mar 2016 19:29:31 +0100 Subject: [PATCH 041/212] Ensure arrayfire is called in infix operations with numpy --- arrayfire/array.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index e539b057a..9c3dfba85 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -373,6 +373,12 @@ class Array(BaseArray): """ + # Numpy checks this attribute to know which class handles binary builtin operations, such as __add__. + # Setting to such a high value should make sure that arrayfire has priority over + # other classes, ensuring that e.g. numpy.float32(1)*arrayfire.randu(3) is handled by + # arrayfire's __radd__() instead of numpy's __add__() + __array_priority__ = 30 + def __init__(self, src=None, dims=(0,), dtype=None, is_device=False, offset=None, strides=None): super(Array, self).__init__() From a6d78633185a588fbabd7d8ac3d4d8b99541f48f Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 28 Mar 2016 15:45:36 -0400 Subject: [PATCH 042/212] BUGFIX: Fixing bug for 32 bit architectures --- arrayfire/array.py | 30 +++++++++++++++--------------- arrayfire/device.py | 6 +++--- arrayfire/features.py | 4 ++-- arrayfire/graphics.py | 2 +- arrayfire/image.py | 38 +++++++++++++++++++------------------- arrayfire/library.py | 13 +++++++++++++ arrayfire/signal.py | 18 +++++++++--------- arrayfire/util.py | 4 ++-- arrayfire/vision.py | 4 ++-- 9 files changed, 66 insertions(+), 53 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index e539b057a..74f78a609 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -36,7 +36,7 @@ def _create_strided_array(buf, numdims, idims, dtype, is_device, offset, strides c_dims = dim4(idims[0], idims[1], idims[2], idims[3]) if offset is None: offset = 0 - offset = ct.c_ulonglong(offset) + offset = c_dim_t(offset) if strides is None: strides = (1, idims[0], idims[0]*idims[1], idims[0]*idims[1]*idims[2]) while len(strides) < 4: @@ -85,10 +85,10 @@ def constant_array(val, d0, d1=None, d2=None, d3=None, dtype=Dtype.f32): safe_call(backend.get().af_constant_complex(ct.pointer(out), c_real, c_imag, 4, ct.pointer(dims), dtype)) elif dtype.value == Dtype.s64.value: - c_val = ct.c_longlong(val.real) + c_val = c_dim_t(val.real) safe_call(backend.get().af_constant_long(ct.pointer(out), c_val, 4, ct.pointer(dims))) elif dtype.value == Dtype.u64.value: - c_val = ct.c_ulonglong(val.real) + c_val = c_dim_t(val.real) safe_call(backend.get().af_constant_ulong(ct.pointer(out), c_val, 4, ct.pointer(dims))) else: c_val = ct.c_double(val) @@ -526,7 +526,7 @@ def offset(self): offset : int The offset in number of elements """ - offset = ct.c_longlong(0) + offset = c_dim_t(0) safe_call(backend.get().af_get_offset(ct.pointer(offset), self.arr)) return offset.value @@ -539,10 +539,10 @@ def strides(self): strides : tuple The strides for each dimension """ - s0 = ct.c_longlong(0) - s1 = ct.c_longlong(0) - s2 = ct.c_longlong(0) - s3 = ct.c_longlong(0) + s0 = c_dim_t(0) + s1 = c_dim_t(0) + s2 = c_dim_t(0) + s3 = c_dim_t(0) safe_call(backend.get().af_get_strides(ct.pointer(s0), ct.pointer(s1), ct.pointer(s2), ct.pointer(s3), self.arr)) strides = (s0.value,s1.value,s2.value,s3.value) @@ -552,7 +552,7 @@ def elements(self): """ Return the number of elements in the array. """ - num = ct.c_ulonglong(0) + num = c_dim_t(0) safe_call(backend.get().af_get_elements(ct.pointer(num), self.arr)) return num.value @@ -574,10 +574,10 @@ def dims(self): """ Return the shape of the array as a tuple. """ - d0 = ct.c_longlong(0) - d1 = ct.c_longlong(0) - d2 = ct.c_longlong(0) - d3 = ct.c_longlong(0) + d0 = c_dim_t(0) + d1 = c_dim_t(0) + d2 = c_dim_t(0) + d3 = c_dim_t(0) safe_call(backend.get().af_get_dims(ct.pointer(d0), ct.pointer(d1), ct.pointer(d2), ct.pointer(d3), self.arr)) dims = (d0.value,d1.value,d2.value,d3.value) @@ -994,7 +994,7 @@ def __getitem__(self, key): inds = _get_indices(key) safe_call(backend.get().af_index_gen(ct.pointer(out.arr), - self.arr, ct.c_longlong(n_dims), inds.pointer)) + self.arr, c_dim_t(n_dims), inds.pointer)) return out except RuntimeError as e: raise IndexError(str(e)) @@ -1035,7 +1035,7 @@ def __setitem__(self, key, val): inds = _get_indices(key) safe_call(backend.get().af_assign_gen(ct.pointer(out_arr), - self.arr, ct.c_longlong(n_dims), inds.pointer, + self.arr, c_dim_t(n_dims), inds.pointer, other_arr)) safe_call(backend.get().af_release_array(self.arr)) if del_other: diff --git a/arrayfire/device.py b/arrayfire/device.py index a33ba51cf..6336ea783 100644 --- a/arrayfire/device.py +++ b/arrayfire/device.py @@ -287,7 +287,7 @@ def alloc_device(num_bytes): Allocate a buffer on the device with specified number of bytes. """ ptr = ct.c_void_p(0) - c_num_bytes = ct.c_longlong(num_bytes) + c_num_bytes = c_dim_t(num_bytes) safe_call(backend.get().af_alloc_device(ct.pointer(ptr), c_num_bytes)) return ptr.value @@ -296,7 +296,7 @@ def alloc_host(num_bytes): Allocate a buffer on the host with specified number of bytes. """ ptr = ct.c_void_p(0) - c_num_bytes = ct.c_longlong(num_bytes) + c_num_bytes = c_dim_t(num_bytes) safe_call(backend.get().af_alloc_host(ct.pointer(ptr), c_num_bytes)) return ptr.value @@ -305,7 +305,7 @@ def alloc_pinned(num_bytes): Allocate a buffer on the host using pinned memory with specified number of bytes. """ ptr = ct.c_void_p(0) - c_num_bytes = ct.c_longlong(num_bytes) + c_num_bytes = c_dim_t(num_bytes) safe_call(backend.get().af_alloc_pinned(ct.pointer(ptr), c_num_bytes)) return ptr.value diff --git a/arrayfire/features.py b/arrayfire/features.py index 190bdde40..04f725f24 100644 --- a/arrayfire/features.py +++ b/arrayfire/features.py @@ -28,13 +28,13 @@ def __init__(self, num=0): self.feat = ct.c_void_p(0) if num is not None: assert(isinstance(num, numbers.Number)) - safe_call(backend.get().af_create_features(ct.pointer(self.feat), ct.c_longlong(num))) + safe_call(backend.get().af_create_features(ct.pointer(self.feat), c_dim_t(num))) def num_features(): """ Returns the number of features detected. """ - num = ct.c_longlong(0) + num = c_dim_t(0) safe_call(backend.get().af_get_features_num(ct.pointer(num), self.feat)) return num diff --git a/arrayfire/graphics.py b/arrayfire/graphics.py index 0597b83a5..ef5ef0943 100644 --- a/arrayfire/graphics.py +++ b/arrayfire/graphics.py @@ -48,7 +48,7 @@ class Window(object): def __init__(self, width=1280, height=720, title="ArrayFire"): self._r = -1 self._c = -1 - self._wnd = ct.c_longlong(0) + self._wnd = ct.c_void_p(0) self._cmap = COLORMAP.DEFAULT _width = 1280 if width is None else width diff --git a/arrayfire/image.py b/arrayfire/image.py index 8de53a6d9..c0c3d7cd5 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -160,8 +160,8 @@ def resize(image, scale=None, odim0=None, odim1=None, method=INTERP.NEAREST): output = Array() safe_call(backend.get().af_resize(ct.pointer(output.arr), - image.arr, ct.c_longlong(odim0), - ct.c_longlong(odim1), method.value)) + image.arr, c_dim_t(odim0), + c_dim_t(odim1), method.value)) return output @@ -204,7 +204,7 @@ def transform(image, trans_mat, odim0 = 0, odim1 = 0, method=INTERP.NEAREST, is_ output = Array() safe_call(backend.get().af_transform(ct.pointer(output.arr), image.arr, trans_mat.arr, - ct.c_longlong(odim0), ct.c_longlong(odim1), + c_dim_t(odim0), c_dim_t(odim1), method.value, is_inverse)) return output @@ -277,7 +277,7 @@ def translate(image, trans0, trans1, odim0 = 0, odim1 = 0, method = INTERP.NEARE output = Array() safe_call(backend.get().af_translate(ct.pointer(output.arr), image.arr, trans0, trans1, - ct.c_longlong(odim0), ct.c_longlong(odim1), method.value)) + c_dim_t(odim0), c_dim_t(odim1), method.value)) return output def scale(image, scale0, scale1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST): @@ -319,7 +319,7 @@ def scale(image, scale0, scale1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST): output = Array() safe_call(backend.get().af_scale(ct.pointer(output.arr), image.arr, ct.c_float(scale0), ct.c_float(scale1), - ct.c_longlong(odim0), ct.c_longlong(odim1), method.value)) + c_dim_t(odim0), c_dim_t(odim1), method.value)) return output def skew(image, skew0, skew1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST, is_inverse=True): @@ -364,7 +364,7 @@ def skew(image, skew0, skew1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST, is_ output = Array() safe_call(backend.get().af_skew(ct.pointer(output.arr), image.arr, ct.c_float(skew0), ct.c_float(skew1), - ct.c_longlong(odim0), ct.c_longlong(odim1), + c_dim_t(odim0), c_dim_t(odim1), method.value, is_inverse)) return output @@ -647,8 +647,8 @@ def medfilt(image, w0 = 3, w1 = 3, edge_pad = PAD.ZERO): """ output = Array() safe_call(backend.get().af_medfilt(ct.pointer(output.arr), - image.arr, ct.c_longlong(w0), - ct.c_longlong(w1), edge_pad.value)) + image.arr, c_dim_t(w0), + c_dim_t(w1), edge_pad.value)) return output def minfilt(image, w_len = 3, w_wid = 3, edge_pad = PAD.ZERO): @@ -679,8 +679,8 @@ def minfilt(image, w_len = 3, w_wid = 3, edge_pad = PAD.ZERO): """ output = Array() safe_call(backend.get().af_minfilt(ct.pointer(output.arr), - image.arr, ct.c_longlong(w_len), - ct.c_longlong(w_wid), edge_pad.value)) + image.arr, c_dim_t(w_len), + c_dim_t(w_wid), edge_pad.value)) return output def maxfilt(image, w_len = 3, w_wid = 3, edge_pad = PAD.ZERO): @@ -711,8 +711,8 @@ def maxfilt(image, w_len = 3, w_wid = 3, edge_pad = PAD.ZERO): """ output = Array() safe_call(backend.get().af_maxfilt(ct.pointer(output.arr), - image.arr, ct.c_longlong(w_len), - ct.c_longlong(w_wid), edge_pad.value)) + image.arr, c_dim_t(w_len), + c_dim_t(w_wid), edge_pad.value)) return output def regions(image, conn = CONNECTIVITY.FOUR, out_type = Dtype.f32): @@ -996,9 +996,9 @@ def unwrap(image, wx, wy, sx, sy, px=0, py=0, is_column=True): out = Array() safe_call(backend.get().af_unwrap(ct.pointer(out.arr), image.arr, - ct.c_longlong(wx), ct.c_longlong(wy), - ct.c_longlong(sx), ct.c_longlong(sy), - ct.c_longlong(px), ct.c_longlong(py), + c_dim_t(wx), c_dim_t(wy), + c_dim_t(sx), c_dim_t(sy), + c_dim_t(px), c_dim_t(py), is_column)) return out @@ -1078,10 +1078,10 @@ def wrap(a, ox, oy, wx, wy, sx, sy, px=0, py=0, is_column=True): out = Array() safe_call(backend.get().af_wrap(ct.pointer(out.arr), a.arr, - ct.c_longlong(ox), ct.c_longlong(oy), - ct.c_longlong(wx), ct.c_longlong(wy), - ct.c_longlong(sx), ct.c_longlong(sy), - ct.c_longlong(px), ct.c_longlong(py), + c_dim_t(ox), c_dim_t(oy), + c_dim_t(wx), c_dim_t(wy), + c_dim_t(sx), c_dim_t(sy), + c_dim_t(px), c_dim_t(py), is_column)) return out diff --git a/arrayfire/library.py b/arrayfire/library.py index 5aa46ba57..184bcc35e 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -14,6 +14,19 @@ import platform import ctypes as ct +# Work around for unexpected architectures +if 'c_dim_t_forced' in globals(): + global c_dim_t_forced + c_dim_t = c_dim_t_forced +else: + # dim_t is long long by default + c_dim_t = ct.c_longlong + # Change to int for 32 bit x86 and amr architectures + if (platform.architecture()[0][0:2] == '32' and + (platform.machine()[-2:] == '86' or + platform.machine()[0:3] == 'arm')): + c_dim_t = ct.c_int + try: from enum import Enum as _Enum def _Enum_Type(v): diff --git a/arrayfire/signal.py b/arrayfire/signal.py index b66386954..f201a2304 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -127,7 +127,7 @@ def fft(signal, dim0 = None , scale = None): scale = 1.0 output = Array() - safe_call(backend.get().af_fft(ct.pointer(output.arr), signal.arr, ct.c_double(scale), ct.c_longlong(dim0))) + safe_call(backend.get().af_fft(ct.pointer(output.arr), signal.arr, ct.c_double(scale), c_dim_t(dim0))) return output def fft2(signal, dim0 = None, dim1 = None , scale = None): @@ -170,7 +170,7 @@ def fft2(signal, dim0 = None, dim1 = None , scale = None): output = Array() safe_call(backend.get().af_fft2(ct.pointer(output.arr), signal.arr, ct.c_double(scale), - ct.c_longlong(dim0), ct.c_longlong(dim1))) + c_dim_t(dim0), c_dim_t(dim1))) return output def fft3(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): @@ -220,7 +220,7 @@ def fft3(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): output = Array() safe_call(backend.get().af_fft3(ct.pointer(output.arr), signal.arr, ct.c_double(scale), - ct.c_longlong(dim0), ct.c_longlong(dim1), ct.c_longlong(dim2))) + c_dim_t(dim0), c_dim_t(dim1), c_dim_t(dim2))) return output def ifft(signal, dim0 = None , scale = None): @@ -261,7 +261,7 @@ def ifft(signal, dim0 = None , scale = None): scale = 1.0/float(dim0) output = Array() - safe_call(backend.get().af_ifft(ct.pointer(output.arr), signal.arr, ct.c_double(scale), ct.c_longlong(dim0))) + safe_call(backend.get().af_ifft(ct.pointer(output.arr), signal.arr, ct.c_double(scale), c_dim_t(dim0))) return output def ifft2(signal, dim0 = None, dim1 = None , scale = None): @@ -312,7 +312,7 @@ def ifft2(signal, dim0 = None, dim1 = None , scale = None): output = Array() safe_call(backend.get().af_ifft2(ct.pointer(output.arr), signal.arr, ct.c_double(scale), - ct.c_longlong(dim0), ct.c_longlong(dim1))) + c_dim_t(dim0), c_dim_t(dim1))) return output def ifft3(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): @@ -370,7 +370,7 @@ def ifft3(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): output = Array() safe_call(backend.get().af_ifft3(ct.pointer(output.arr), signal.arr, ct.c_double(scale), - ct.c_longlong(dim0), ct.c_longlong(dim1), ct.c_longlong(dim2))) + c_dim_t(dim0), c_dim_t(dim1), c_dim_t(dim2))) return output def fft_inplace(signal, scale = None): @@ -539,7 +539,7 @@ def fft_r2c(signal, dim0 = None , scale = None): scale = 1.0 output = Array() - safe_call(backend.get().af_fft_r2c(ct.pointer(output.arr), signal.arr, ct.c_double(scale), ct.c_longlong(dim0))) + safe_call(backend.get().af_fft_r2c(ct.pointer(output.arr), signal.arr, ct.c_double(scale), c_dim_t(dim0))) return output def fft2_r2c(signal, dim0 = None, dim1 = None , scale = None): @@ -582,7 +582,7 @@ def fft2_r2c(signal, dim0 = None, dim1 = None , scale = None): output = Array() safe_call(backend.get().af_fft2_r2c(ct.pointer(output.arr), signal.arr, ct.c_double(scale), - ct.c_longlong(dim0), ct.c_longlong(dim1))) + c_dim_t(dim0), c_dim_t(dim1))) return output def fft3_r2c(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): @@ -632,7 +632,7 @@ def fft3_r2c(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): output = Array() safe_call(backend.get().af_fft3_r2c(ct.pointer(output.arr), signal.arr, ct.c_double(scale), - ct.c_longlong(dim0), ct.c_longlong(dim1), ct.c_longlong(dim2))) + c_dim_t(dim0), c_dim_t(dim1), c_dim_t(dim2))) return output def _get_c2r_dim(dim, is_odd): diff --git a/arrayfire/util.py b/arrayfire/util.py index ae08e29e5..f5c37eedc 100644 --- a/arrayfire/util.py +++ b/arrayfire/util.py @@ -11,7 +11,7 @@ import numbers def dim4(d0=1, d1=1, d2=1, d3=1): - c_dim4 = ct.c_longlong * 4 + c_dim4 = c_dim_t * 4 out = c_dim4(1, 1, 1, 1) for i, dim in enumerate((d0, d1, d2, d3)): @@ -70,7 +70,7 @@ def to_str(c_str): def safe_call(af_error): if (af_error != ERR.NONE.value): err_str = ct.c_char_p(0) - err_len = ct.c_longlong(0) + err_len = c_dim_t(0) backend.get().af_get_last_error(ct.pointer(err_str), ct.pointer(err_len)) raise RuntimeError(to_str(err_str)) diff --git a/arrayfire/vision.py b/arrayfire/vision.py index e605865cf..6cc6914fa 100644 --- a/arrayfire/vision.py +++ b/arrayfire/vision.py @@ -166,7 +166,7 @@ def hamming_matcher(query, database, dim = 0, num_nearest = 1): dist = Array() safe_call(backend.get().af_hamming_matcher(ct.pointer(idx.arr), ct.pointer(dist.arr), query.arr, database.arr, - ct.c_longlong(dim), ct.c_longlong(num_nearest))) + c_dim_t(dim), c_dim_t(num_nearest))) return index, dist def nearest_neighbour(query, database, dim = 0, num_nearest = 1, match_type=MATCH.SSD): @@ -202,7 +202,7 @@ def nearest_neighbour(query, database, dim = 0, num_nearest = 1, match_type=MATC dist = Array() safe_call(backend.get().af_nearest_neighbour(ct.pointer(idx.arr), ct.pointer(dist.arr), query.arr, database.arr, - ct.c_longlong(dim), ct.c_longlong(num_nearest), + c_dim_t(dim), c_dim_t(num_nearest), match_type.value)) return index, dist From 3c6c47c6b8968e4c686910c3880a824ff7226780 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 28 Mar 2016 17:10:32 -0400 Subject: [PATCH 043/212] BUGFIX: Fixing the bug in constant for 64 bit int types --- arrayfire/array.py | 4 ++-- arrayfire/util.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 74f78a609..d3f9e3bbe 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -85,10 +85,10 @@ def constant_array(val, d0, d1=None, d2=None, d3=None, dtype=Dtype.f32): safe_call(backend.get().af_constant_complex(ct.pointer(out), c_real, c_imag, 4, ct.pointer(dims), dtype)) elif dtype.value == Dtype.s64.value: - c_val = c_dim_t(val.real) + c_val = ct.c_longlong(val.real) safe_call(backend.get().af_constant_long(ct.pointer(out), c_val, 4, ct.pointer(dims))) elif dtype.value == Dtype.u64.value: - c_val = c_dim_t(val.real) + c_val = ct.c_ulonglong(val.real) safe_call(backend.get().af_constant_ulong(ct.pointer(out), c_val, 4, ct.pointer(dims))) else: c_val = ct.c_double(val) diff --git a/arrayfire/util.py b/arrayfire/util.py index f5c37eedc..a610fa9c8 100644 --- a/arrayfire/util.py +++ b/arrayfire/util.py @@ -15,7 +15,7 @@ def dim4(d0=1, d1=1, d2=1, d3=1): out = c_dim4(1, 1, 1, 1) for i, dim in enumerate((d0, d1, d2, d3)): - if (dim is not None): out[i] = dim + if (dim is not None): out[i] = c_dim_t(dim) return out From 57f0045e1be09300b22c4f8a8d3f2395dfa83813 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 28 Mar 2016 17:14:33 -0400 Subject: [PATCH 044/212] Changing setup.py to avoid conflicts between master and devel --- setup.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6311b847e..f871c97f0 100644 --- a/setup.py +++ b/setup.py @@ -15,11 +15,16 @@ ## 1) Look for af libraries during setup ## 2) Include test suite +# Some hackery to avoid merge conflicts between master and devel +current_version = "3.3.20160320" +devel_version = "3.3.0" +release_version = current_version if current_version > devel_version else devel_version + setup( author="Pavan Yalamanchili", author_email="pavan@arrayfire.com", name="arrayfire", - version="3.3.20160320", + version=release_version description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From ca848faf46aefc8eddff694f87d4ae3227f2e73f Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 28 Mar 2016 17:18:35 -0400 Subject: [PATCH 045/212] Updating devel version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f871c97f0..e362898ce 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ # Some hackery to avoid merge conflicts between master and devel current_version = "3.3.20160320" -devel_version = "3.3.0" +devel_version = "3.4.0" release_version = current_version if current_version > devel_version else devel_version setup( From 52e1857508c36d0ddca3645afb19ce54c849352e Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 28 Mar 2016 17:19:08 -0400 Subject: [PATCH 046/212] Updating master tag for release --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f871c97f0..6815839d9 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ ## 2) Include test suite # Some hackery to avoid merge conflicts between master and devel -current_version = "3.3.20160320" +current_version = "3.3.20160328" devel_version = "3.3.0" release_version = current_version if current_version > devel_version else devel_version From 99b1c8c2b47f641e9ac1ccd844a3a8ba82925ad0 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 28 Mar 2016 17:21:44 -0400 Subject: [PATCH 047/212] Updated changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62438ed0d..697255b01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### v3.3.20160328 +- Fixes to make arrayfire-python to work on 32 bit systems + ### v3.3.20160320 - Feature parity with Arrayfire 3.3 libs - Functions to interact with arryafire's internal data structures. From f5efab48675e47f84e37c5388c3a7ada7e154862 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 28 Mar 2016 17:30:07 -0400 Subject: [PATCH 048/212] BUGFIX installer: Add missing comma --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6815839d9..6c9d93384 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ author="Pavan Yalamanchili", author_email="pavan@arrayfire.com", name="arrayfire", - version=release_version + version=release_version, description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From 06aa0d67fc5f7c757d9487b3430bb0dbc59d2704 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 28 Mar 2016 17:39:59 -0400 Subject: [PATCH 049/212] Fixing link in README for installing devel version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index be1c4eb51..2f9c5c5d7 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ pip install arrayfire **Install the development version:** ``` -pip install git+git://github.com/arrayfire/arrayfire.git@devel +pip install git+git://github.com/arrayfire/arrayfire-python.git@devel ``` **Installing offline** From 7c134f38db58dc21382ba9e12963aa29650f5638 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 28 Mar 2016 18:23:50 -0400 Subject: [PATCH 050/212] Adding Linux on ARM build status --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2f9c5c5d7..d6b0636ae 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ | Linux | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-linux)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-linux/) | | Windows | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-windows)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-windows/) | | OSX | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-osx)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-osx/) | +| Linux on ARM | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-tegrak1)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-tegrak1/)| ## Example From 30a3d05a3467e0080f4efc0d0e81e6f68ea7546e Mon Sep 17 00:00:00 2001 From: Filipe Maia Date: Wed, 30 Mar 2016 17:36:28 +0200 Subject: [PATCH 051/212] Use the correct unified backend name --- arrayfire/library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index 184bcc35e..432ebb8d7 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -507,7 +507,7 @@ def name(self): return self.__name def is_unified(self): - return self.__name == '' + return self.__name == 'unified' def parse(self, res): lst = [] From 316050fa20ff54332a41f380aeee6e646b416064 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 4 Apr 2016 07:36:46 -0400 Subject: [PATCH 052/212] Fixing graphics examples --- examples/graphics/conway.py | 2 +- examples/graphics/histogram.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/graphics/conway.py b/examples/graphics/conway.py index f4d515c0a..49ad43bb9 100644 --- a/examples/graphics/conway.py +++ b/examples/graphics/conway.py @@ -66,7 +66,7 @@ A2 = (state == 0) & C1 A3 = (state == 1) & (neighborhood > 3) - display = (af.join(2, A0 + A1, A1 + A2, A3).as_type(af.Dtype.f32) + display = af.join(2, A0 + A1, A1 + A2, A3).as_type(af.Dtype.f32) state = state * C0 + C1 diff --git a/examples/graphics/histogram.py b/examples/graphics/histogram.py index 3a3d29ae5..9a15dcf30 100644 --- a/examples/graphics/histogram.py +++ b/examples/graphics/histogram.py @@ -29,7 +29,7 @@ hist_win = af.Window(512, 512, "3D Plot example using ArrayFire") img_win = af.Window(480, 640, "Input Image") - img = (af.load_image(sys.argv[1])).(af.Dtype.u8) + img = af.load_image(sys.argv[1]).as_type(af.Dtype.u8) hist = af.histogram(img, 256, 0, 255) while (not hist_win.close()) and (not img_win.close()): From 72748526bebc5a89e550daef677bd01dca84c4da Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 4 Apr 2016 07:37:32 -0400 Subject: [PATCH 053/212] BUGFIX: Fixing issue with double free --- arrayfire/array.py | 1 + 1 file changed, 1 insertion(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index d3f9e3bbe..660baefd6 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -475,6 +475,7 @@ def __del__(self): """ if self.arr.value: backend.get().af_release_array(self.arr) + self.arr.value = 0 def device_ptr(self): """ From 1594809a8774cc025274626526c01aba328cdaf8 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 27 Apr 2016 19:12:08 -0400 Subject: [PATCH 054/212] BUGFIX: Fixes issue with numpy interop on Windows + python2.7 --- arrayfire/array.py | 2 +- arrayfire/interop.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 660baefd6..8ec9d8251 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -407,7 +407,7 @@ def __init__(self, src=None, dims=(0,), dtype=None, is_device=False, offset=None buf,buf_len = tmp.buffer_info() _type_char = tmp.typecode numdims, idims = _get_info(dims, buf_len) - elif isinstance(src, int) or isinstance(src, ct.c_void_p): + elif isinstance(src, long) or isinstance(src, int) or isinstance(src, ct.c_void_p): buf = src if not isinstance(src, ct.c_void_p) else src.value numdims, idims = _get_info(dims, buf_len) diff --git a/arrayfire/interop.py b/arrayfire/interop.py index 0fb55c165..e512b7548 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -40,7 +40,7 @@ def np_to_af_array(np_arr): """ in_shape = np_arr.shape - in_ptr = np_arr.ctypes.data + in_ptr = np_arr.ctypes.data_as(ct.c_void_p) in_dtype = np_arr.dtype.char if (np_arr.flags['F_CONTIGUOUS']): From 3643e2fc3a594dc7692153a77385b080a14fa988 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 27 Apr 2016 19:16:00 -0400 Subject: [PATCH 055/212] Updating version and changelog for release --- CHANGELOG.md | 5 +++++ setup.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 697255b01..4bdf57c31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### v3.3.20160427 +- Fixes to numpy interop on Windows +- Fixes issues with occasional double free +- Fixes to graphics examples + ### v3.3.20160328 - Fixes to make arrayfire-python to work on 32 bit systems diff --git a/setup.py b/setup.py index 6c9d93384..0237d5851 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ ## 2) Include test suite # Some hackery to avoid merge conflicts between master and devel -current_version = "3.3.20160328" +current_version = "3.3.20160427" devel_version = "3.3.0" release_version = current_version if current_version > devel_version else devel_version From 86fe60400915f6549308f068328c2d4557166528 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 27 Apr 2016 19:21:59 -0400 Subject: [PATCH 056/212] Post release with af.to_array fix for python3 --- arrayfire/array.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 8ec9d8251..660baefd6 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -407,7 +407,7 @@ def __init__(self, src=None, dims=(0,), dtype=None, is_device=False, offset=None buf,buf_len = tmp.buffer_info() _type_char = tmp.typecode numdims, idims = _get_info(dims, buf_len) - elif isinstance(src, long) or isinstance(src, int) or isinstance(src, ct.c_void_p): + elif isinstance(src, int) or isinstance(src, ct.c_void_p): buf = src if not isinstance(src, ct.c_void_p) else src.value numdims, idims = _get_info(dims, buf_len) diff --git a/setup.py b/setup.py index 0237d5851..7ffbf9090 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ ## 2) Include test suite # Some hackery to avoid merge conflicts between master and devel -current_version = "3.3.20160427" +current_version = "3.3.20160427.post1" devel_version = "3.3.0" release_version = current_version if current_version > devel_version else devel_version From 9e32b6e2df491ad0bc5ea467bfa452b927dac2a4 Mon Sep 17 00:00:00 2001 From: Dzhelil Rufat Date: Mon, 2 May 2016 11:51:36 -0700 Subject: [PATCH 057/212] Contribute numpy example. --- examples/benchmarks/monte_carlo_pi.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/examples/benchmarks/monte_carlo_pi.py b/examples/benchmarks/monte_carlo_pi.py index fc35b3d4a..93e393107 100755 --- a/examples/benchmarks/monte_carlo_pi.py +++ b/examples/benchmarks/monte_carlo_pi.py @@ -11,7 +11,7 @@ from random import random from time import time -from arrayfire import (array, randu) +import numpy as np import arrayfire as af import sys @@ -21,16 +21,21 @@ except NameError: frange = range #Python3 - -def calc_pi_device(samples): - x = randu(samples) - y = randu(samples) - return 4 * af.sum((x * x + y * y) < 1) / samples - # Having the function outside is faster than the lambda inside def in_circle(x, y): return (x*x + y*y) < 1 +def calc_pi_device(samples): + x = af.randu(samples) + y = af.randu(samples) + return 4 * af.sum(in_circle(x, y)) / samples + +def calc_pi_numpy(samples): + np.random.seed(1) + x = np.random.rand(samples) + y = np.random.rand(samples) + return 4 * np.sum(in_circle(x, y)) / samples + def calc_pi_host(samples): count = sum(1 for k in frange(samples) if in_circle(random(), random())) return 4 * float(count) / samples @@ -53,4 +58,5 @@ def bench(calc_pi, samples=1000000, iters=25): af.info() bench(calc_pi_device) + bench(calc_pi_numpy) bench(calc_pi_host) From 2baa648e69c47db2c762dddacb375b6d3cb71399 Mon Sep 17 00:00:00 2001 From: Dzhelil Rufat Date: Mon, 2 May 2016 12:21:43 -0700 Subject: [PATCH 058/212] Fixes to monte carlo example --- examples/benchmarks/monte_carlo_pi.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/benchmarks/monte_carlo_pi.py b/examples/benchmarks/monte_carlo_pi.py index 93e393107..f3198d4e7 100755 --- a/examples/benchmarks/monte_carlo_pi.py +++ b/examples/benchmarks/monte_carlo_pi.py @@ -11,10 +11,14 @@ from random import random from time import time -import numpy as np import arrayfire as af import sys +try: + import numpy as np +except: + np = None + #alias range / xrange because xrange is faster than range in python2 try: frange = xrange #Python2 @@ -32,8 +36,8 @@ def calc_pi_device(samples): def calc_pi_numpy(samples): np.random.seed(1) - x = np.random.rand(samples) - y = np.random.rand(samples) + x = np.random.rand(samples).astype(np.float32) + y = np.random.rand(samples).astype(np.float32) return 4 * np.sum(in_circle(x, y)) / samples def calc_pi_host(samples): @@ -58,5 +62,6 @@ def bench(calc_pi, samples=1000000, iters=25): af.info() bench(calc_pi_device) - bench(calc_pi_numpy) + if np: + bench(calc_pi_numpy) bench(calc_pi_host) From ed52b90ac407a9e18cd2bd7d3ed5bb81386a5ec8 Mon Sep 17 00:00:00 2001 From: Dzhelil Rufat Date: Tue, 3 May 2016 12:11:32 -0700 Subject: [PATCH 059/212] Add numpy benchmarks to fft and blas. * Add numpy benchmarks to fft and blas. Switch to timeit for benchmark measurements. * Use a more descriptive name for benchmark. * Switch back to using time module for benchmarks to ensure that af.sync() is run only once. --- examples/benchmarks/bench_blas.py | 57 +++++++++++++++++++++-------- examples/benchmarks/bench_fft.py | 60 +++++++++++++++++++++++-------- 2 files changed, 88 insertions(+), 29 deletions(-) diff --git a/examples/benchmarks/bench_blas.py b/examples/benchmarks/bench_blas.py index 1b315900d..aaf4eb1de 100644 --- a/examples/benchmarks/bench_blas.py +++ b/examples/benchmarks/bench_blas.py @@ -12,15 +12,49 @@ import sys from time import time -from arrayfire import (array, randu, matmul) import arrayfire as af -def bench(A, iters = 100): - start = time() - for t in range(iters): - B = af.matmul(A, A) +try: + import numpy as np +except: + np = None + + +def calc_arrayfire(n): + A = af.randu(n, n) af.sync() - return (time() - start) / iters + + def run(iters): + for t in range(iters): + B = af.matmul(A, A) + af.sync() + + return run + + +def calc_numpy(n): + np.random.seed(1) + A = np.random.rand(n, n).astype(np.float32) + + def run(iters): + for t in range(iters): + B = np.dot(A, A) + + return run + + +def bench(calc, iters=100, upto=2048): + _, name = calc.__name__.split("_") + print("Benchmark N x N matrix multiply on %s" % name) + + for n in range(128, upto + 128, 128): + run = calc(n) + start = time() + run(iters) + t = (time() - start) / iters + gflops = 2.0 * (n ** 3) / (t * 1E9) + print("Time taken for %4d x %4d: %0.4f Gflops" % (n, n, gflops)) + if __name__ == "__main__": @@ -28,12 +62,7 @@ def bench(A, iters = 100): af.set_device(int(sys.argv[1])) af.info() - print("Benchmark N x N matrix multiply") - - for n in range(128, 2048 + 128, 128): - A = af.randu(n, n) - af.sync() - t = bench(A) - gflops = 2.0 * (n**3) / (t * 1E9) - print("Time taken for %4d x %4d: %0.4f Gflops" % (n, n, gflops)) + bench(calc_arrayfire) + if np: + bench(calc_numpy, upto=512) diff --git a/examples/benchmarks/bench_fft.py b/examples/benchmarks/bench_fft.py index 735e8d6ed..9a2d283ed 100644 --- a/examples/benchmarks/bench_fft.py +++ b/examples/benchmarks/bench_fft.py @@ -12,15 +12,51 @@ import sys from time import time -from arrayfire import (array, randu, matmul) import arrayfire as af -def bench(A, iters = 100): - start = time() - for t in range(iters): - B = af.fft2(A) +try: + import numpy as np +except: + np = None + + +def calc_arrayfire(n): + A = af.randu(n, n) af.sync() - return (time() - start) / iters + + def run(iters): + for t in range(iters): + B = af.fft2(A) + + af.sync() + + return run + + +def calc_numpy(n): + np.random.seed(1) + A = np.random.rand(n, n).astype(np.float32) + + def run(iters): + for t in range(iters): + B = np.fft.fft2(A) + + return run + + +def bench(calc, iters=100, upto=13): + _, name = calc.__name__.split("_") + print("Benchmark N x N 2D fft on %s" % name) + + for M in range(7, upto): + N = 1 << M + run = calc(N) + start = time() + run(iters) + t = (time() - start) / iters + gflops = (10.0 * N * N * M) / (t * 1E9) + print("Time taken for %4d x %4d: %0.4f Gflops" % (N, N, gflops)) + if __name__ == "__main__": @@ -28,13 +64,7 @@ def bench(A, iters = 100): af.set_device(int(sys.argv[1])) af.info() - print("Benchmark N x N 2D fft") - for M in range(7, 13): - N = 1 << M - A = af.randu(N, N) - af.sync() - - t = bench(A) - gflops = (10.0 * N * N * M) / (t * 1E9) - print("Time taken for %4d x %4d: %0.4f Gflops" % (N, N, gflops)) + bench(calc_arrayfire) + if np: + bench(calc_numpy, upto=10) From 4a49c385b931be331d76fd62644e27b65335da57 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 10 May 2016 14:35:10 -0400 Subject: [PATCH 060/212] BUGFIX: fixing a bug in histogram --- arrayfire/image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrayfire/image.py b/arrayfire/image.py index c0c3d7cd5..2487abe75 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -408,7 +408,7 @@ def histogram(image, nbins, min_val = None, max_val = None): output = Array() safe_call(backend.get().af_histogram(ct.pointer(output.arr), image.arr, ct.c_uint(nbins), - ct.c_float(min_val), ct.c_float(max_val))) + ct.c_double(min_val), ct.c_double(max_val))) return output def hist_equal(image, hist): From 7f3f8442dc5ae2758ec0ed5b335b23fe1149aa5a Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 10 May 2016 14:35:34 -0400 Subject: [PATCH 061/212] FEAT: Add gaussian_kernel and necessary tests --- arrayfire/image.py | 42 ++++++++++++++++++++++++++++++++++++++++++ tests/simple/image.py | 2 ++ 2 files changed, 44 insertions(+) diff --git a/arrayfire/image.py b/arrayfire/image.py index 2487abe75..ec68f8aa7 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -769,6 +769,48 @@ def sobel_derivatives(image, w_len=3): image.arr, ct.c_uint(w_len))) return dx,dy +def gaussian_kernel(rows, cols, sigma_r = None, sigma_c = None): + """ + Create a gaussian kernel with the given parameters. + + Parameters + ---------- + image : af.Array + - A 2 D arrayfire array representing an image, or + - A multi dimensional array representing batch of images. + + rows : int + - The number of rows in the gaussian kernel. + + cols : int + - The number of columns in the gaussian kernel. + + sigma_r : optional: number. default: None. + - The sigma value along rows + - If None, calculated as (0.25 * rows + 0.75) + + sigma_c : optional: number. default: None. + - The sigma value along columns + - If None, calculated as (0.25 * cols + 0.75) + + Returns + ------- + out : af.Array + - A gaussian kernel of size (rows, cols) + """ + out = Array() + + if (sigma_r is None): + sigma_r = 0.25 * rows + 0.75 + + if (sigma_c is None): + sigma_c = 0.25 * cols + 0.75 + + safe_call(backend.get().af_gaussian_kernel(ct.pointer(out.arr), + ct.c_int(rows), ct.c_int(cols), + ct.c_double(sigma_r), ct.c_double(sigma_c))) + return out + def sobel_filter(image, w_len = 3, is_fast = False): """ Apply sobel filter to the image. diff --git a/tests/simple/image.py b/tests/simple/image.py index 7fdfa90df..209013a2e 100644 --- a/tests/simple/image.py +++ b/tests/simple/image.py @@ -54,6 +54,8 @@ def simple_image(verbose = False): display_func(dx) display_func(dy) display_func(af.sobel_filter(a)) + display_func(af.gaussian_kernel(3, 3)) + display_func(af.gaussian_kernel(3, 3, 1, 1)) ac = af.gray2rgb(a) display_func(ac) From 376135d368d4ff517a597aa27db759b7a2927a06 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 10 May 2016 14:52:22 -0400 Subject: [PATCH 062/212] FEAT: Adding new array properties - Array.T now returns transpose - Array.H now returns hermitian transpose - Array.shape now returns shape --- arrayfire/array.py | 21 +++++++++++++++++++++ tests/simple/array_test.py | 3 +++ 2 files changed, 24 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index 660baefd6..712c7ea31 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -571,6 +571,20 @@ def type(self): """ return self.dtype().value + @property + def T(self): + """ + Return the transpose of the array + """ + return transpose(self, False) + + @property + def H(self): + """ + Return the hermitian transpose of the array + """ + return transpose(self, False) + def dims(self): """ Return the shape of the array as a tuple. @@ -584,6 +598,13 @@ def dims(self): dims = (d0.value,d1.value,d2.value,d3.value) return dims[:self.numdims()] + @property + def shape(self): + """ + The shape of the array + """ + return self.dims() + def numdims(self): """ Return the number of dimensions of the array. diff --git a/tests/simple/array_test.py b/tests/simple/array_test.py index 3a65e8031..1aec93494 100644 --- a/tests/simple/array_test.py +++ b/tests/simple/array_test.py @@ -18,6 +18,9 @@ def simple_array(verbose=False): a = af.Array([1, 2, 3]) display_func(a) + display_func(a.T) + display_func(a.H) + print_func(a.shape) b = a.as_type(af.Dtype.s32) display_func(b) From b2a2efe4fdefd49472dbf3275aad11631b1f4ff1 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 10 May 2016 14:53:49 -0400 Subject: [PATCH 063/212] Updating version info and CHANGELOG --- CHANGELOG.md | 11 +++++++++++ setup.py | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bdf57c31..1c0b16da3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +### v3.3.20160510 +- Bugfix to `af.histogram` + +- Added missing functions / methods + - `gaussian_kernel` + +- Added new array properties + - `Array.T` now returns transpose + - `Array.H` now returns hermitian transpose + - `Array.shape` now allows easier access individual dimensions + ### v3.3.20160427 - Fixes to numpy interop on Windows - Fixes issues with occasional double free diff --git a/setup.py b/setup.py index 7ffbf9090..76a892868 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ ## 2) Include test suite # Some hackery to avoid merge conflicts between master and devel -current_version = "3.3.20160427.post1" +current_version = "3.3.20160510" devel_version = "3.3.0" release_version = current_version if current_version > devel_version else devel_version From 5ddeb97c27a72aa77a6979d3fd8c78b777dbfb77 Mon Sep 17 00:00:00 2001 From: Filipe Maia Date: Thu, 24 Mar 2016 19:29:31 +0100 Subject: [PATCH 064/212] Ensure arrayfire is called in infix operations with numpy --- arrayfire/array.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index 712c7ea31..327fd6bee 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -373,6 +373,12 @@ class Array(BaseArray): """ + # Numpy checks this attribute to know which class handles binary builtin operations, such as __add__. + # Setting to such a high value should make sure that arrayfire has priority over + # other classes, ensuring that e.g. numpy.float32(1)*arrayfire.randu(3) is handled by + # arrayfire's __radd__() instead of numpy's __add__() + __array_priority__ = 30 + def __init__(self, src=None, dims=(0,), dtype=None, is_device=False, offset=None, strides=None): super(Array, self).__init__() From 87fdd110685cd639a036170ff8c0d1c3f07a78d8 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 16 May 2016 00:15:29 -0400 Subject: [PATCH 065/212] FEAT: Adding additional helper library functions - get_backend: returns name of the backend --- arrayfire/library.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index 432ebb8d7..822d75af5 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -531,7 +531,7 @@ def set_backend(name, unsafe=False): If False, does not switch backend if current backend is not unified backend. """ if (backend.is_unified() == False and unsafe == False): - raise RuntimeError("Can not change backend after loading %s" % name) + raise RuntimeError("Can not change backend to %s after loading %s" % (name, backend.name())) if (backend.is_unified()): safe_call(backend.get().af_set_backend(backend.get_id(name))) @@ -539,6 +539,12 @@ def set_backend(name, unsafe=False): backend.set_unsafe(name) return +def get_backend(): + """ + Return the name of the backend + """ + return backend.name() + def get_backend_id(A): """ Get backend name of an array From b1cac6125d3cdae0047475a79e04a80f0cdce1b0 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 16 May 2016 00:19:18 -0400 Subject: [PATCH 066/212] Updating changelog and setup.py --- CHANGELOG.md | 6 ++++++ setup.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c0b16da3..ea809cd92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### v3.3.20160516 +- Bugfix: Increase arrayfire's priority over numpy for mixed operations + +- Added new library functions + - `get_backend` returns backend name + ### v3.3.20160510 - Bugfix to `af.histogram` diff --git a/setup.py b/setup.py index 76a892868..0c4318e32 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ ## 2) Include test suite # Some hackery to avoid merge conflicts between master and devel -current_version = "3.3.20160510" +current_version = "3.3.20160516" devel_version = "3.3.0" release_version = current_version if current_version > devel_version else devel_version From 2efb2ad62892ed0b90eae2dc5b33648809378ada Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 16 May 2016 09:57:11 -0400 Subject: [PATCH 067/212] Fixing mistake in documentation --- arrayfire/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrayfire/__init__.py b/arrayfire/__init__.py index 40cc23122..a129392f2 100644 --- a/arrayfire/__init__.py +++ b/arrayfire/__init__.py @@ -29,7 +29,7 @@ The backend can be chosen at the beginning of the program by using the following function - >>> af.backend.set(name) + >>> af.set_backend(name) where name is one of 'cuda', 'opencl' or 'cpu' From 2851540ad727453dba0b5bc8307aad09d3c44679 Mon Sep 17 00:00:00 2001 From: aha66 Date: Mon, 20 Jun 2016 23:13:21 +0200 Subject: [PATCH 068/212] Add support for short types * Update array.py * Update util.py * Update util.py --- arrayfire/array.py | 4 ++++ arrayfire/util.py | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index 327fd6bee..c3542e6c2 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -300,6 +300,8 @@ class Array(BaseArray): - 'd' for double - 'b' for bool - 'B' for unsigned char + - 'h' for signed 16 bit integer + - 'H' for unsigned 16 bit integer - 'i' for signed 32 bit integer - 'I' for unsigned 32 bit integer - 'l' for signed 64 bit integer @@ -311,6 +313,8 @@ class Array(BaseArray): - Dtype.f64 for double - Dtype.b8 for bool - Dtype.u8 for unsigned char + - Dtype.s16 for signed 16 bit integer + - Dtype.u16 for unsigned 16 bit integer - Dtype.s32 for signed 32 bit integer - Dtype.u32 for unsigned 32 bit integer - Dtype.s64 for signed 64 bit integer diff --git a/arrayfire/util.py b/arrayfire/util.py index a610fa9c8..733afdf3a 100644 --- a/arrayfire/util.py +++ b/arrayfire/util.py @@ -94,6 +94,8 @@ def get_reversion(): 'd' : Dtype.f64, 'b' : Dtype.b8, 'B' : Dtype.u8, + 'h' : Dtype.s16, + 'H' : Dtype.u16, 'i' : Dtype.s32, 'I' : Dtype.u32, 'l' : Dtype.s64, @@ -105,6 +107,8 @@ def get_reversion(): Dtype.f64.value : 'd', Dtype.b8.value : 'b', Dtype.u8.value : 'B', + Dtype.s16.value : 'h', + Dtype.u16.value : 'H', Dtype.s32.value : 'i', Dtype.u32.value : 'I', Dtype.s64.value : 'l', @@ -116,6 +120,8 @@ def get_reversion(): Dtype.f64.value : ct.c_double, Dtype.b8.value : ct.c_char, Dtype.u8.value : ct.c_ubyte, + Dtype.s16.value : ct.c_short, + Dtype.u16.value : ct.c_ushort, Dtype.s32.value : ct.c_int, Dtype.u32.value : ct.c_uint, Dtype.s64.value : ct.c_longlong, @@ -127,6 +133,8 @@ def get_reversion(): Dtype.f64.value : 'double', Dtype.b8.value : 'bool', Dtype.u8.value : 'unsigned char', + Dtype.s16.value : 'short int', + Dtype.u16.value : 'unsigned short int', Dtype.s32.value : 'int', Dtype.u32.value : 'unsigned int', Dtype.s64.value : 'long int', From 47b892483129077547962a05fc2df6e15dab34cd Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 24 Jun 2016 20:03:15 -0400 Subject: [PATCH 069/212] Moving the version number into it's own file --- __af_version__.py | 14 ++++++++++++++ setup.py | 14 +++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 __af_version__.py diff --git a/__af_version__.py b/__af_version__.py new file mode 100644 index 000000000..7ccd73785 --- /dev/null +++ b/__af_version__.py @@ -0,0 +1,14 @@ +#!/usr/bin/python + +####################################################### +# Copyright (c) 2015, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +version = "3.4" +release = "0" +full_version = version + "." + release diff --git a/setup.py b/setup.py index 0c4318e32..294871d09 100644 --- a/setup.py +++ b/setup.py @@ -10,21 +10,17 @@ ######################################################## from setuptools import setup, find_packages +from __af_version__ import full_version -## TODO: -## 1) Look for af libraries during setup -## 2) Include test suite - -# Some hackery to avoid merge conflicts between master and devel -current_version = "3.3.20160516" -devel_version = "3.3.0" -release_version = current_version if current_version > devel_version else devel_version +TODO: +1) Look for af libraries during setup +2) Include test suite setup( author="Pavan Yalamanchili", author_email="pavan@arrayfire.com", name="arrayfire", - version=release_version, + version=full_version, description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From 76c173ae27a6a3a749a90dc6eb2ca18bc2b5e79f Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 24 Jun 2016 20:46:47 -0400 Subject: [PATCH 070/212] Files required to generate documentation --- arrayfire/__init__.py | 33 +++- arrayfire/algorithm.py | 4 +- arrayfire/arith.py | 2 +- arrayfire/array.py | 16 +- arrayfire/blas.py | 2 +- arrayfire/data.py | 6 +- arrayfire/device.py | 6 +- arrayfire/features.py | 2 +- arrayfire/graphics.py | 2 +- arrayfire/image.py | 2 +- arrayfire/index.py | 2 +- arrayfire/interop.py | 1 + arrayfire/lapack.py | 2 +- arrayfire/library.py | 2 +- arrayfire/signal.py | 2 +- arrayfire/statistics.py | 4 + arrayfire/timer.py | 2 +- arrayfire/util.py | 4 + arrayfire/vision.py | 2 +- docs/Makefile | 225 ++++++++++++++++++++++ docs/arrayfire.algorithm.rst | 7 + docs/arrayfire.arith.rst | 7 + docs/arrayfire.array.rst | 7 + docs/arrayfire.base.rst | 7 + docs/arrayfire.bcast.rst | 7 + docs/arrayfire.blas.rst | 7 + docs/arrayfire.cuda.rst | 7 + docs/arrayfire.data.rst | 7 + docs/arrayfire.device.rst | 7 + docs/arrayfire.features.rst | 7 + docs/arrayfire.graphics.rst | 7 + docs/arrayfire.image.rst | 7 + docs/arrayfire.index.rst | 7 + docs/arrayfire.interop.rst | 7 + docs/arrayfire.lapack.rst | 7 + docs/arrayfire.library.rst | 7 + docs/arrayfire.opencl.rst | 7 + docs/arrayfire.rst | 34 ++++ docs/arrayfire.signal.rst | 7 + docs/arrayfire.statistics.rst | 7 + docs/arrayfire.timer.rst | 7 + docs/arrayfire.util.rst | 7 + docs/arrayfire.vision.rst | 7 + docs/arrayfire_logo_symbol.png | Bin 0 -> 35688 bytes docs/conf.py | 341 +++++++++++++++++++++++++++++++++ docs/index.rst | 1 + docs/make.bat | 281 +++++++++++++++++++++++++++ docs/modules.rst | 7 + 48 files changed, 1102 insertions(+), 37 deletions(-) create mode 100644 docs/Makefile create mode 100644 docs/arrayfire.algorithm.rst create mode 100644 docs/arrayfire.arith.rst create mode 100644 docs/arrayfire.array.rst create mode 100644 docs/arrayfire.base.rst create mode 100644 docs/arrayfire.bcast.rst create mode 100644 docs/arrayfire.blas.rst create mode 100644 docs/arrayfire.cuda.rst create mode 100644 docs/arrayfire.data.rst create mode 100644 docs/arrayfire.device.rst create mode 100644 docs/arrayfire.features.rst create mode 100644 docs/arrayfire.graphics.rst create mode 100644 docs/arrayfire.image.rst create mode 100644 docs/arrayfire.index.rst create mode 100644 docs/arrayfire.interop.rst create mode 100644 docs/arrayfire.lapack.rst create mode 100644 docs/arrayfire.library.rst create mode 100644 docs/arrayfire.opencl.rst create mode 100644 docs/arrayfire.rst create mode 100644 docs/arrayfire.signal.rst create mode 100644 docs/arrayfire.statistics.rst create mode 100644 docs/arrayfire.timer.rst create mode 100644 docs/arrayfire.util.rst create mode 100644 docs/arrayfire.vision.rst create mode 100644 docs/arrayfire_logo_symbol.png create mode 100644 docs/conf.py create mode 120000 docs/index.rst create mode 100644 docs/make.bat create mode 100644 docs/modules.rst diff --git a/arrayfire/__init__.py b/arrayfire/__init__.py index 40cc23122..bd7617f86 100644 --- a/arrayfire/__init__.py +++ b/arrayfire/__init__.py @@ -8,18 +8,22 @@ ######################################################## """ -A high performance scientific computing library for CUDA, OpenCL and CPU devices. +ArrayFire is a high performance scientific computing library with an easy to use API. -The functionality provided by ArrayFire spans the following domains: - 1. Vector Algorithms - 2. Image Processing - 3. Signal Processing - 4. Computer Vision - 5. Linear Algebra - 6. Statistics + >>> # Monte Carlo estimation of pi + >>> def calc_pi_device(samples): + # Simple, array based API + # Generate uniformly distributed random numers + x = af.randu(samples) + y = af.randu(samples) + # Supports Just In Time Compilation + # The following line generates a single kernel + within_unit_circle = (x * x + y * y) < 1 + # Intuitive function names + return 4 * af.count(within_unit_circle) / samples -Programs written using ArrayFire are portable across CUDA, OpenCL and CPU devices +Programs written using ArrayFire are portable across CUDA, OpenCL and CPU devices. The default backend is chosen in the following order of preference based on the available libraries: @@ -31,7 +35,16 @@ >>> af.backend.set(name) -where name is one of 'cuda', 'opencl' or 'cpu' +where name is one of 'cuda', 'opencl' or 'cpu'. + +The functionality provided by ArrayFire spans the following domains: + + 1. Vector Algorithms + 2. Image Processing + 3. Signal Processing + 4. Computer Vision + 5. Linear Algebra + 6. Statistics """ diff --git a/arrayfire/algorithm.py b/arrayfire/algorithm.py index 823663766..6701d96a8 100644 --- a/arrayfire/algorithm.py +++ b/arrayfire/algorithm.py @@ -8,7 +8,7 @@ ######################################################## """ -Vector algorithms for ArrayFire +Vector algorithms (sum, min, sort, etc). """ from .library import * @@ -283,7 +283,7 @@ def imax(a, dim=None): def accum(a, dim=0): """ - Cumulative sum of an array along a specified dimension. + Cumulative sum of an array along a specified dimension Parameters ---------- diff --git a/arrayfire/arith.py b/arrayfire/arith.py index 9dc8c666f..4c73e59bf 100644 --- a/arrayfire/arith.py +++ b/arrayfire/arith.py @@ -8,7 +8,7 @@ ######################################################## """ -Math functions for ArrayFire +Math functions (sin, sqrt, exp, etc). """ from .library import * diff --git a/arrayfire/array.py b/arrayfire/array.py index 327fd6bee..ede0da0c5 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -8,7 +8,7 @@ ######################################################## """ -arrayfire.Array class and helper functions. +Array class and helper functions. """ import inspect @@ -488,7 +488,7 @@ def device_ptr(self): Return the device pointer exclusively held by the array. Returns - ------ + -------- ptr : int Contains location of the device pointer @@ -508,7 +508,7 @@ def raw_ptr(self): Return the device pointer held by the array. Returns - ------ + -------- ptr : int Contains location of the device pointer @@ -529,7 +529,7 @@ def offset(self): Return the offset, of the first element relative to the raw pointer. Returns - ------ + -------- offset : int The offset in number of elements """ @@ -542,7 +542,7 @@ def strides(self): Return the distance in bytes between consecutive elements for each dimension. Returns - ------ + -------- strides : tuple The strides for each dimension """ @@ -1078,7 +1078,7 @@ def to_ctype(self, row_major=False, return_shape=False): Return the data as a ctype C array after copying to host memory Parameters - --------- + ----------- row_major: optional: bool. default: False. Specifies if a transpose needs to occur before copying to host memory. @@ -1112,7 +1112,7 @@ def to_array(self, row_major=False, return_shape=False): Return the data as array.array Parameters - --------- + ----------- row_major: optional: bool. default: False. Specifies if a transpose needs to occur before copying to host memory. @@ -1147,7 +1147,7 @@ def to_list(self, row_major=False): Return the data as list Parameters - --------- + ----------- row_major: optional: bool. default: False. Specifies if a transpose needs to occur before copying to host memory. diff --git a/arrayfire/blas.py b/arrayfire/blas.py index c476c1c58..a3774f106 100644 --- a/arrayfire/blas.py +++ b/arrayfire/blas.py @@ -8,7 +8,7 @@ ######################################################## """ -BLAS functions for arrayfire. +BLAS functions (matmul, dot, etc) """ from .library import * diff --git a/arrayfire/data.py b/arrayfire/data.py index 2e6c9fc01..0df045fca 100644 --- a/arrayfire/data.py +++ b/arrayfire/data.py @@ -384,7 +384,7 @@ def join(dim, first, second, third=None, fourth=None): An array containing the input arrays joined along the specified dimension. Examples - ------- + --------- >>> import arrayfire as af >>> a = af.randu(2, 3) @@ -460,7 +460,7 @@ def tile(a, d0, d1=1, d2=1, d3=1): An array containing the input after tiling the the specified number of times. Examples - ------- + --------- >>> import arrayfire as af >>> a = af.randu(2, 3) @@ -710,7 +710,7 @@ def flip(a, dim=0): The output after flipping `a` along `dim`. Examples - ------- + --------- >>> import arrayfire as af >>> a = af.randu(3, 3) diff --git a/arrayfire/device.py b/arrayfire/device.py index 6336ea783..0a303851e 100644 --- a/arrayfire/device.py +++ b/arrayfire/device.py @@ -76,7 +76,7 @@ def set_device(num): Change the active device to the specified id. Parameters - --------- + ----------- num: int. id of the desired device. """ @@ -136,7 +136,7 @@ def is_dbl_supported(device=None): Check if double precision is supported on specified device. Parameters - --------- + ----------- device: optional: int. default: None. id of the desired device. @@ -155,7 +155,7 @@ def sync(device=None): Block until all the functions on the device have completed execution. Parameters - --------- + ----------- device: optional: int. default: None. id of the desired device. """ diff --git a/arrayfire/features.py b/arrayfire/features.py index 04f725f24..d21471a0d 100644 --- a/arrayfire/features.py +++ b/arrayfire/features.py @@ -7,7 +7,7 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## """ -arrayfire.Features class +Features class used for Computer Vision algorithms. """ from .library import * from .array import * diff --git a/arrayfire/graphics.py b/arrayfire/graphics.py index ef5ef0943..3d0b3f213 100644 --- a/arrayfire/graphics.py +++ b/arrayfire/graphics.py @@ -8,7 +8,7 @@ ######################################################## """ -graphics functions for arrayfire +Graphics functions (plot, image, etc). """ from .library import * diff --git a/arrayfire/image.py b/arrayfire/image.py index ec68f8aa7..ac4b8ed19 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -8,7 +8,7 @@ ######################################################## """ -Image processing functions for arrayfire. +Image processing functions. """ from .library import * diff --git a/arrayfire/index.py b/arrayfire/index.py index baad324c0..a23e2e203 100644 --- a/arrayfire/index.py +++ b/arrayfire/index.py @@ -7,7 +7,7 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## """ -classes required for indexing operations +Index and Seq classes used in indexing operations. """ from .library import * diff --git a/arrayfire/interop.py b/arrayfire/interop.py index e512b7548..44858e87f 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -14,6 +14,7 @@ 1. numpy 2. pycuda + 3. pyopencl """ from .array import * diff --git a/arrayfire/lapack.py b/arrayfire/lapack.py index 346cddb01..161b1ee78 100644 --- a/arrayfire/lapack.py +++ b/arrayfire/lapack.py @@ -8,7 +8,7 @@ ######################################################## """ -Dense Linear Algebra functions for arrayfire. +Dense Linear Algebra functions (solve, inverse, etc). """ from .library import * diff --git a/arrayfire/library.py b/arrayfire/library.py index 822d75af5..ff09f051d 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -8,7 +8,7 @@ ######################################################## """ -module containing enums and other constants from arrayfire library +Module containing enums and other constants. """ import platform diff --git a/arrayfire/signal.py b/arrayfire/signal.py index f201a2304..fe377ed1c 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -8,7 +8,7 @@ ######################################################## """ -signal processing functions for arrayfire. +Signal processing functions (fft, convolve, etc). """ from .library import * diff --git a/arrayfire/statistics.py b/arrayfire/statistics.py index 597dc68e4..d95336944 100644 --- a/arrayfire/statistics.py +++ b/arrayfire/statistics.py @@ -7,6 +7,10 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## +""" +Statistical algorithms (mean, var, stdev, etc). +""" + from .library import * from .array import * diff --git a/arrayfire/timer.py b/arrayfire/timer.py index 6f6c3efc3..d523fcd93 100644 --- a/arrayfire/timer.py +++ b/arrayfire/timer.py @@ -7,7 +7,7 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## """ -Functions to time arrayfire functions +Functions to time arrayfire. """ from .library import * diff --git a/arrayfire/util.py b/arrayfire/util.py index a610fa9c8..fe3e2257c 100644 --- a/arrayfire/util.py +++ b/arrayfire/util.py @@ -7,6 +7,10 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## +""" +Utility functions to help with Array metadata. +""" + from .library import * import numbers diff --git a/arrayfire/vision.py b/arrayfire/vision.py index 6cc6914fa..9598a6b5f 100644 --- a/arrayfire/vision.py +++ b/arrayfire/vision.py @@ -8,7 +8,7 @@ ######################################################## """ -Computer vision functions for arrayfire. +Computer vision functions (FAST, ORB, etc) """ from .library import * diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 000000000..45690fe35 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,225 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ArrayFire.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ArrayFire.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/ArrayFire" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ArrayFire" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/docs/arrayfire.algorithm.rst b/docs/arrayfire.algorithm.rst new file mode 100644 index 000000000..e41092935 --- /dev/null +++ b/docs/arrayfire.algorithm.rst @@ -0,0 +1,7 @@ +arrayfire.algorithm module +========================== + +.. automodule:: arrayfire.algorithm + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.arith.rst b/docs/arrayfire.arith.rst new file mode 100644 index 000000000..d874a2ecd --- /dev/null +++ b/docs/arrayfire.arith.rst @@ -0,0 +1,7 @@ +arrayfire.arith module +====================== + +.. automodule:: arrayfire.arith + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.array.rst b/docs/arrayfire.array.rst new file mode 100644 index 000000000..84e335108 --- /dev/null +++ b/docs/arrayfire.array.rst @@ -0,0 +1,7 @@ +arrayfire.array module +====================== + +.. automodule:: arrayfire.array + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.base.rst b/docs/arrayfire.base.rst new file mode 100644 index 000000000..be1e420aa --- /dev/null +++ b/docs/arrayfire.base.rst @@ -0,0 +1,7 @@ +arrayfire.base module +===================== + +.. automodule:: arrayfire.base + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.bcast.rst b/docs/arrayfire.bcast.rst new file mode 100644 index 000000000..0bcd4e521 --- /dev/null +++ b/docs/arrayfire.bcast.rst @@ -0,0 +1,7 @@ +arrayfire.bcast module +====================== + +.. automodule:: arrayfire.bcast + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.blas.rst b/docs/arrayfire.blas.rst new file mode 100644 index 000000000..054f98fc5 --- /dev/null +++ b/docs/arrayfire.blas.rst @@ -0,0 +1,7 @@ +arrayfire.blas module +===================== + +.. automodule:: arrayfire.blas + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.cuda.rst b/docs/arrayfire.cuda.rst new file mode 100644 index 000000000..f0f3a48b9 --- /dev/null +++ b/docs/arrayfire.cuda.rst @@ -0,0 +1,7 @@ +arrayfire.cuda module +===================== + +.. automodule:: arrayfire.cuda + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.data.rst b/docs/arrayfire.data.rst new file mode 100644 index 000000000..de208ff1d --- /dev/null +++ b/docs/arrayfire.data.rst @@ -0,0 +1,7 @@ +arrayfire.data module +===================== + +.. automodule:: arrayfire.data + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.device.rst b/docs/arrayfire.device.rst new file mode 100644 index 000000000..ad98bf639 --- /dev/null +++ b/docs/arrayfire.device.rst @@ -0,0 +1,7 @@ +arrayfire.device module +======================= + +.. automodule:: arrayfire.device + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.features.rst b/docs/arrayfire.features.rst new file mode 100644 index 000000000..44629c6f4 --- /dev/null +++ b/docs/arrayfire.features.rst @@ -0,0 +1,7 @@ +arrayfire.features module +========================= + +.. automodule:: arrayfire.features + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.graphics.rst b/docs/arrayfire.graphics.rst new file mode 100644 index 000000000..3a1505eae --- /dev/null +++ b/docs/arrayfire.graphics.rst @@ -0,0 +1,7 @@ +arrayfire.graphics module +========================= + +.. automodule:: arrayfire.graphics + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.image.rst b/docs/arrayfire.image.rst new file mode 100644 index 000000000..d4934b44b --- /dev/null +++ b/docs/arrayfire.image.rst @@ -0,0 +1,7 @@ +arrayfire.image module +====================== + +.. automodule:: arrayfire.image + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.index.rst b/docs/arrayfire.index.rst new file mode 100644 index 000000000..95c3dcde1 --- /dev/null +++ b/docs/arrayfire.index.rst @@ -0,0 +1,7 @@ +arrayfire.index module +====================== + +.. automodule:: arrayfire.index + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.interop.rst b/docs/arrayfire.interop.rst new file mode 100644 index 000000000..f7886aa07 --- /dev/null +++ b/docs/arrayfire.interop.rst @@ -0,0 +1,7 @@ +arrayfire.interop module +======================== + +.. automodule:: arrayfire.interop + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.lapack.rst b/docs/arrayfire.lapack.rst new file mode 100644 index 000000000..4f14e4c24 --- /dev/null +++ b/docs/arrayfire.lapack.rst @@ -0,0 +1,7 @@ +arrayfire.lapack module +======================= + +.. automodule:: arrayfire.lapack + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.library.rst b/docs/arrayfire.library.rst new file mode 100644 index 000000000..6c9c78d10 --- /dev/null +++ b/docs/arrayfire.library.rst @@ -0,0 +1,7 @@ +arrayfire.library module +======================== + +.. automodule:: arrayfire.library + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.opencl.rst b/docs/arrayfire.opencl.rst new file mode 100644 index 000000000..b4622b38d --- /dev/null +++ b/docs/arrayfire.opencl.rst @@ -0,0 +1,7 @@ +arrayfire.opencl module +======================= + +.. automodule:: arrayfire.opencl + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.rst b/docs/arrayfire.rst new file mode 100644 index 000000000..2ccfd3b41 --- /dev/null +++ b/docs/arrayfire.rst @@ -0,0 +1,34 @@ +ArrayFire Python Wrapper +======================== + +Introduction +--------------- + +.. automodule:: arrayfire + + Submodules +---------- + +.. autosummary:: + arrayfire.algorithm + arrayfire.arith + arrayfire.array + arrayfire.base + arrayfire.bcast + arrayfire.blas + arrayfire.cuda + arrayfire.data + arrayfire.device + arrayfire.features + arrayfire.graphics + arrayfire.image + arrayfire.index + arrayfire.interop + arrayfire.lapack + arrayfire.library + arrayfire.opencl + arrayfire.signal + arrayfire.statistics + arrayfire.timer + arrayfire.util + arrayfire.vision diff --git a/docs/arrayfire.signal.rst b/docs/arrayfire.signal.rst new file mode 100644 index 000000000..ae06fdf9e --- /dev/null +++ b/docs/arrayfire.signal.rst @@ -0,0 +1,7 @@ +arrayfire.signal module +======================= + +.. automodule:: arrayfire.signal + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.statistics.rst b/docs/arrayfire.statistics.rst new file mode 100644 index 000000000..a20ef21a2 --- /dev/null +++ b/docs/arrayfire.statistics.rst @@ -0,0 +1,7 @@ +arrayfire.statistics module +=========================== + +.. automodule:: arrayfire.statistics + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.timer.rst b/docs/arrayfire.timer.rst new file mode 100644 index 000000000..cb9cac2ed --- /dev/null +++ b/docs/arrayfire.timer.rst @@ -0,0 +1,7 @@ +arrayfire.timer module +====================== + +.. automodule:: arrayfire.timer + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.util.rst b/docs/arrayfire.util.rst new file mode 100644 index 000000000..c5192aeb8 --- /dev/null +++ b/docs/arrayfire.util.rst @@ -0,0 +1,7 @@ +arrayfire.util module +===================== + +.. automodule:: arrayfire.util + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.vision.rst b/docs/arrayfire.vision.rst new file mode 100644 index 000000000..d2f229a08 --- /dev/null +++ b/docs/arrayfire.vision.rst @@ -0,0 +1,7 @@ +arrayfire.vision module +======================= + +.. automodule:: arrayfire.vision + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire_logo_symbol.png b/docs/arrayfire_logo_symbol.png new file mode 100644 index 0000000000000000000000000000000000000000..7a2476d11ca15b45f44fe51fde2ae20fbcfe41ee GIT binary patch literal 35688 zcmb??bx@Sw`{*J_NQ+8$Nh>Mc(v8w3ARyAcOE*#yf;5P9O4pK-(%s#$OE1lR@$+S{uH!Gzw`?W+-x0lyAgy zHCC)IPo~k1Qidx{~`_2eg%5=QQ1yeEU3H|)H;ZVSph=F z0=-fT4PpYJKtRSlw6yM^z$DPKx5rvSM=YgyTg(8bk}8Di>G-An^w8NH(6qGJDP9iB z5wbkvHF;!`EXLmMkwnbt$Bnyu(hmY<#ykh8J-Kxs#3>yd@L}z4 zW2nep3udeY z%*OiqwES-gJ(E5yuRDu&qgJik&zIgpH;A+4=2bdBP6Iy~l#Au|{!_&qvY}Xvzz_4A z(K0u+nD;m2V>G|zKGbV7KU-6K>JTNB9C5;#LlY(u%hX9fdT+M6#CnY^vcv-_|0IG0 ziDAn(FhxFBV8qjQZe2xyK*x=CZR0P|k$o)#R)*Z};i9)Pne-svk8-gNAdsOH9lK^< zrD!)g2qcy1$6PK>dfGTrbZaj#6!)7xG)`C*`l_n;G)P|t=UefXkH8--4o6m&t| zCX4bkoQ|qD^qCrsLJW`WYxOUhRPSWTkA)o{@rUTYZHN)<0de}@1UJdNj`yoj6CTH^ zmaNa`BME%_19RBS`E_#ii_DZ^$0`!x2;Qu%;UY`i*=P~T?pLkbL}*;UKfhw{>X7*L zh7}{u^v^GvVyvPrlJfV($c9QFD{3oG%jQ#&(Q)I? zV(?)g2dcF*(!}K}R53K*U;ZZg!1+2vTb7k}@@X^y2OcC;@;4vd(=bU+#`>?1+J8k9~X3ys_eNVp0e`EMY%FLlzP?%e|Scv)V`;;Xsh0W6XsxM> z3e%Lh(w&vs8oMai#gFGV!>@rEPgmx~@3-WQ;lhOlS^Sb*@?2V#>L>9ZMbXy2J6xnX zD`RZE%u77+{<8QC&a}!zn#-+N|Jq#Nx-cOzLAyw{NUca_56WA5ke8MVm2T9z_QMhH zmS@ywl(C2&e4MtWF{81N_ayIylCZ#8DSM%H4rx}Slv|5!9_)L1v!QRgqFvsi2XyO- z%!}hz^Va4n?@R_u8?_RP4s{M|kVvSL$H7jBoTGd0NKMk9LrgNq` zhdoh*J%zMup$EDy?|kN9umT=EOG~LtX+OxHD}(XEtY9JY8U5TDOzApYPQx8NlFMov zBchlY-(FcS6?>~ls`yz{Z_#p?a>QtrOqJK>xD_Hy;DjRQB90krB5Oi?i=2x(M*V!P zwLP_eR66X^je?dWeQ58^?!osXpgdoCBn#v)KXE_3N7ol%PwJK^QGq%0^NN`R@rcZN z@#o^v{w4k!Z6(x}J^Novs1aM=2V(}UaDr65we3L$ygp zUMKRnjm%3rElFKTB}gr%SiDx@FJqJEVHPQ5|0Fca*TCH%+Qt4+r+-2_O0vSI$ zb1ARw=jNrGgOiZev{lSC2;p~*9s_%itikrvpu86a>`z$*62ufkmEXi4isLcozlfke zCUB#Vdg9Se-fls|F~U0%IxVTsOrd-%%d7;B-H&PF@u2JE%3!3tVzx#}<2LwhDXcebvF)x%3=I;=s$f#()~h`s@~=x+e3y-oXJuQO%#4 zr7CNV#|iUmx$8=VXlYpC&PBqt zjX{aBjl)4V@+k5x8ZA!ERQ>n_`KYj_dh{gAo(xVmW%FGc+>H&J7yDggYS${Qy_CoL z4gzBdL4hqW>ly(mUO^k9bS1YS=lCR%e4P9?MI-rI?}J{0O25d+<`?OU3cH~Zzh@!XFZ$d>8g(kEOycmtmE%Bb{x_?BRk;Gq6- zo%3HF)0Hn({xTgE;{(^!Nt&aE7?LBq)yJEG#9*@n(&#H+oY34eA zeg0D+#9jp(?awdJ8s1-!rF~af^p?aRPn))PwoY%~(28$gi^?_dc0V1DxoKoDzxu^T zD9Aa$@pnYymsXD#NmMbdy-t7P!W7pL1b+Fpk7Ui#6+taR7hC-D)@%T}pjn%6hKFx- zAaefSV;lLy^S?%_I%MF*zeg0ehbezY-(?)&@!uofJQDEc-=n|a!}NcRV)kgji+{#{ zgZ}6FU!ea%6hcfK3}0S=S=@0KfdT4lezSP zh4-wq8-!dgy}%~XuU_e<^get6K?i-h-lycfh^56(V)Ys1xIvhE6X4h1Ty)?X{z_~R zw^p)8d+PN{w7&yk%oLF#!4LQte(oC^`LdIKm++?8-xBwx)3Ljim3m9*bJ6yE0M%b`_US0)CZ%x*CLaiN^-=U*L?7oY z5!26G_B&b|xf1G`3?`)_vMve;R1|RIT6Jh3fO{m_Tbf1F6R;dbCw?n_XTqg@GYlC2 z2+qk|ulm=POhXD3x4_`D5E{o+w6lk$z90Q>))-Y7X&hrhE>x^Y@a9dP?BO1ldn;-|c??vvb$x+;@gv#N< zz)CnBsmQMH3nWmc8!8Pa_-1{FE7^ZJ>OAH==}4cS%>7vy2VK=8Q?4d*j?Q^4D{NcPHG1Tt8U6SuZkqNC5o3UZ-*t;MQVB_DkR+(my4&Q>r6+l< ze*upPRZM`j{0swS@^VN?eVa#EuC(CNUq8Mw-U)Udq!jf4UmS%{HvM2ihaKVqu)@{$ z(60R1a)#eD0s53wO9myy0vhQvPC zMYvLC$KP6RyIFLRg)tD}S$EJeG7w_G<7V##w*NME8NN)>TbE;2X`WUPDAQ4UMGLD<& z(w`2-8^vSXHA(zSCVY>KOq|f31H6hn8qNnaMEfBtej-)qHlV1ts-~M_42GytlmU!3q;Q?c1|wg>n50kfew2mNWh-S#MO)3EmV#iiV35s z74?hmTDsd6gWvvC-w6k0(=6Tv!qo-JVz8 z9k~~R(?>LQ>{(}o!~+QaPjivMv1h2wnM}U&Z;_&fV~X$6n1)6yv|?R|$j6>N&f^BO z=Q62Sb*_0^v4VJR+Z=5)6(wYvFedz{w&lw0v^jfgvl>p2EFmQoMKqPR9MzAZr1~bz zBjY0|mblYf4igG*ZE_AiOivr99Kk|C7(xKKN}9}{cMcDRz7`YozrG1iUUUQ09PY#j z088UTLO&2wYCf*LzhG|r5JlJMeumHXq#aU5?ij<|28BmiK9Uertu*mBCkySdzd0xq z$>twfJM@;|`l^Qx6Fvi+Z*5Sx`Vg?o!CQ<(m*nVc{KM~FawjbBwba-p?HTJ3+_Gd2=%C0ny1W_=ot=INHwSoI`^o@5 zh~R638Xb?AokQ+&EmB=Gi4%F)uRjA=+_x?NO6@F>H1R#4J^Ptf>-}(mWL;d47e3p5@lz=vIOJ zF57DwM`d@J=+txPM%9!<0*oNrTU2y zc7nqns-0UhB7C+oZok$@$koU2(iWCmGW`-cEmfTX#*C>4L2!2!9LV7} zfOEPS6N-fapEf2m0}cuP9=MsmwZt-Eu|xvNV)vU`{)W0NU?!P%=O%JMl3Sc+|n z#hhU5{uc;n@294oZJ^udisr`%Nmu?huQ6_aJw|tao zqxr|yQRr^LXArB1s*Ye@+}&8YJ7sT;f$1P@SA=v zSB8gZ$T$vLz`eqxAuY-WZjtXMlc;F<2skhwCvqc|d#^2BC)Jv7{J1!GE7MDj_JJFz zDTJ32ji6A~1uWyV#tFy^7O1oB5jhIt#WkdYGD zn>%eqWtyP^$%O2BECXl~<{nUMWAri!2?zmW-K7aYdt7%=pIcQaZ2#TvcLTMjgum1| z18PVgfFXnS<5R~4>lDTX-Zc@cJR0n7xi4c%64x{M=U4d+@pJbM6~)b3FMNLUGUSI9 z4ckBM<^=CQaY>#9<>PWxt`GRo(E zsi^~o_7Id-rPtR&wFZxQ|K?1Y6Ut^zjQYpFIP~+MJjB?Rl}BqKMbLvRNmgEPTtjf4 z5HYa3M=L(k-(QOe)IN!Nwr9J@y{6XO*-UkO^EY+V?Vg@n#LO|dcfYxy?vQ-+fT!-3 z;+4Uit)o1_KT}L^E>@6dPIc7Ru(neNn+^1z7vi3@0%Ff(qt0mh`Y(U55r z-CwRRWFh(mdu(q43r18#9yWJ-lkgW(HBrXR9DuC7DQYx^h($r{gcgN;KmOytd(l>j zKKppDNPLR67U%P4`0HPS*9SEir?B(C73>CfJb6IuYyZXik_bUe$3Ti@0gM1Y&oqkt zFHj%`ti-L93wRb8BeD&TR`EW!nZ@|KqMct!wTL$PZ@#VCd$DeD@-%7un8ISBVh$|t z8P&}w`bV+wFSPAp*y}HfpJfwV-!IOaA*P2Z4?<~i9yY-v{xDIm1?raAj>fqFSoxq_ zbw}6trMXXu<56z1fyXFE;=iv|Eq&-p0OVZO%BEIAvvD7mFO$w9=z3pr+N50MpAo#q zpZ{w%;>yzNnc#~B=V}zMKJ&jEvRy;m-_qi{j4r)u9?bMH71Kj{(4x;-UMf=TBm;#8 z&ZP^BnuxcLKIt&WD)TZ=NAJKNg08hRcuQeD0${$%4*! z?e=@v6XK#mZLsYU0svI+sAcH?S~FACeFz$j;|q#DHR0_<5ofXMzu*$m!t=c(Jc`?b41F#57*c9VmWF%EF)clPsBUKLqEYD{j{ zMTJ&hK7KGV2?%f!Vxvq&5^cV|499w-{+H@JM=rrnKQiS)AU_DH>yWo`KFuR#zFlJ! zMbw0*qHHMsv}QbjQuzz|PG$qU?>;$D@v&8@2ut|F|7&v5K36%?27VNmVJh@j2-^ji zY86Io0q0huInQiVtwxY>bU-$53$Q@r#y6*1iv(rIn4e5XLp({X5BjMO&>l1m`sCpL zC@WNi_PZPVG_ED(Kl6WLA9xr*QslM3s(;eE#GCIyncubn!mE^XCSx(*?Z8~QikqA? zzpq!8QGDsa#4!cgNJR^R=s3NvC_93^xly$`l-L%38cpR22<|4%=7BrN9O;lPS-|r# zv-C>7>A~j{S(K4XqmsL># z{`q3_cwe2sOYE=?*@KR`lJ=m@w>LUL_U? zs9qixB7|%MFr4iGd?jCsy06oQI?^xgxYrxoq5RX7!|4w;HSDkkzsp1Xw&)R)egl`P z)9OM25<_O-{83+B)dW4{EYbt56g1m#-31sK%gO==mB48ovagEe zeSpz4!N^u;W-TnUp6Nqv&LpumkcmE*5dkRWodNiZ?ZW&62SU(OR2ppiNB(VDk4T7+ zZ%vjaDvDdH$qiad`KwdY!d4y08QGLVE!|4?5loTw9<*WJhy8`CWN>c3=WjLr!ntTL zlI5%XBrxI6gC?p@H2QEli8-899dt#xWTRkU^K>>i25HiSMxV=1iU=?rTghu=9pbBBQR0I(y|YfL zCoT~K&4UB%3kg@eo;M*zKCO+9Fe3iO18)I&G$;X9e+wS7{h_*eZSakGUXOfu7&IHG zP7ECJ_{8@sQ;EUeiZQGm@K5Y#HGYQhkDsOjUUncYMLzIoP6Bc<99@FGZ2$*H8~7N& z|LiGQ8U59{zDUbQ&abK(L%f~op}NQ9S-*7WER!h!I?BHfqikn#y`JQpA|I6t*~3P} zw`IPTOa>L$J20y^{KOchUlY9ni=3MFN{7p_KRMW*$SGVcsU+2YwQTSxQ)$~lM!p{} z1SjbHzCz&CG^cgOzp8Myj{V(syC}J?gYifx0|3Q_D+^>UycxW3J?Bj-0vm6TH(!Gj&dW~+1alQzrh9%YLKnOz>OsE zbe2t0bdqS)W+hd#e$!ZG@2>^F$L4jPd%JH~C0Zq_OLFxq_^aWI;i+_-cWAb3SZAQ6 z7)$(5^Wt`ouGTfB$bbHU>^*T!A$ciT8~(%9xy!7h)-JragIIR zIgr_%79bEr-AHJ|bGMj{c)#dV9bcc%!%=wPSGjw&b11$0Vqal-GAESm^LEWaB?L$X zHjRPst{o=LB6&@TP4Q*YVn@M9vm=~J_NvzJ9P;EHCskdZa}Uf0HHVXIoGD@&YH4CQ zv^&d^*sS?7=aBtmndVOw(o#0LmF=NH(l}5AqO1tVfT6gFMEGjwt-u?9Q>Xo$zE#CN zG>{vlu0tr`zKy4@%YN78!|hII2uJ{bbne;UI~ltYt0HPR1D$jI${e3D;Z!t<8_wo4 zA~jT-CkG0Z+3X>ep+bai7LiDm$Q;=zV23XgBg7G`0e#yJc3mT=c5`1B!V~xt+tJbd zgzLqHcU5~h?51iGG4^npE zJ!Ek2UeU1L#6HCZ_`sS^WJxvA1h?iWenHV5o=hO(>3bD%e?hpEkZ)A2exA!m%@P0T=<4P%|DO_$G2IJ~!S-_r(b*Br^qU`42yVgOF#l1$Ny6?F$~B+A2b&jZ8oJNX#HUtm6wJlI?<@oat|glMYUg;_`53Hc$}n zdpTsuhc!UsrZ?R!r+llaW|Oj>+3t)noc_EoJNtG74+6q7nJPnG%Vp7VG-!& zoR$Jr_q`m#Pw5#4P79|-QkqL0alpr0I7ctkw2BQ@=N1#wXjW;j5J@G8PU+1_p} z#jb^M4$MTuF|%R$s!A}}yO=tk5jRLF@OZj)p=z4Imx0&BBx{VX%pH;SkptrDFWZaN z=5-E_CZfu>J|hqZ@3%5Y*@EJZ#E_U#X$pTLtEN#`lM98oeVO- ztv^GyOBPJ+U_F0u5Q?rI9^6t3QX#FE-cJOxTnsuz{ILAHz_0_Y@3{=}C+q{CD;8Yo zaVuIAXiX+X5}h?>mJJMC=8#rYy%Fk0JGm@>B|Oi$k_KR;vK^m|#1nG9{{#NE9h@c( zEft$V^d?HQdvBa)97g?4PCfIyMo63e2CCLT;saF2!=)&4WW}#;f;LX!YT+{Y~XK^jD+2y67T>xUyzXgyT%(TnM znwbMnBhj}ENW-ChywCL)Z#=G&`Cd+rg!!>H-GBW^Rd*eD?)EbyjwK08dj0W$F9}c~ zCxU$c&<>thCL$gmqq|B7vK@+zb19YdI&jgs5gg9fYB$Dn>VBy0UpIXwMnQaQZBEQs zNE;(bz04jl-KSF0E+d&PL^;cqun=3e`5^Xv*2t6%$w$hzJ2`C_g%34$0_rpZlrZst zEP1lgQ_*^!=n3>7f8;{NhleA^inADk(wv{UsQD&wAcLESxsuU3R3WLk{zo&p_1hB2 zh@TnlpejPyp3nnuiF57J`Kd?QJHzRTJr_}rVwsD(%?=yX9n9Xy40|XWOB#-5T83$u z1ZGQL$4)^JQ0Ls*Hm@x1O^JL9BUg4B4lC4g&kyd)gEOzKCh&*-1FlFOUFoXZqA{8l zKHH6S!_p!I6?d|j*rUgp?s)7das)s`KK0AKjC`Gh{$D7cWqmKr$mb?e6e|PIBQw)= zHk^E#k^zVDXXPKzb9jXOkWR;Jd6Y!9zH+NW$#i1JbstDzQB@d9R+ zS=XlO@gkymyxGn(8Y1$cKPi;V!BbBuaFlwSc=mpOiXwD-Y#q8+eO3&(wZ)28`N_JX z2WNRapAT32BHmL16;+ldj+ye%5N_!LjovOVQT!McJ`YK~g|*W7LT3nk$1P)nvMbQF z*0h&B7-`p$;m3K0L_+uD+#EMLBEQ_xRT7xE(LU2Tl&8i!*NDZ_PAL@*M0~W1KP)fZ zP6I!d3*g0sBhtMQ@I}bg0@}M{(-a%CXo%qpCwBAf_pNyOyw_OI_jv9qjUel8kI2U= z)62CC=yjFJ>np;htmrp>?KB*!&;hN!eRGOM4$CKbwD|lFU95u8R4;&aq%I4KZzt*= zdSri_UxpRBHWG~)S!SXgNG<|yA(hkVXWyx`)w3xoBjQaOin~*j-CAzdO1ix@r}M`6 zxLIa5HC6*?VgkP+>=6#F5B*xPoBHD^W7)zuffHn*nyKm z;91OAwCGJ{CF5=y>$eB<2=JU7Q^3)e5Y#aVDEUnAud@ovR z{8zQ>!hKY72iX6sp@QmC;49!zraY;y<6c!F>0X2TtO<)?tD3rtW)U-^UDP&Kt){*F zi&MwVGF@>V#=&V-Hb!1o(*{CD#xmRk-1+Lg^^8I!b(8g_;Z*&|?D@?1h6S8spP{a$ z`>u5s(F;mN+YkXyIvtD6db6{6blk%LpeSu9|6XG33Sm_g0J-DpvRW+9-;|K@PWdQC z@PMV=Qj=ZWL}}5-4ltXzLA9gWKn^6$_MLOZL2A$G*&mYGb>o$mq3)&oV7x`OIF+C* z8jU8SEy7>v;XNlcrIvFF=BVw8CQP_}XxzvojtRN0P_yl~OIv{-8-AK|V93AmFA~>W zFJZ!%;#kM*H2FlAnMzfVHo=^ArD#@ zlU48dMn$@IeNw92O~kqG%J&OAz+%bM_!6s`Nc4J>BIAYZa@vicS4M8AE7J^5JlaFI z@%mvXswuO#=yDh$Jy~eF+t#d8t(JGs$N;I?g^eq(f4q=cYJHxZ_(5J-{WLevTYi^n zQM%#ocDX^dIz22AhYW!&y>9KPpZNjk+7dHAK3CR{Xef4Cs~bbk=&uhI`a%4)?_$Wu zR7EQ7BB&@CGNrXUVcOBKWi22GE;>)=n{a|Q^$8rmw-{ELz|q)kPdm{ zeXi8yj+W&m?00*yhAVnez#e?AjOr%oODStWNNCfHnYBs2lNx%$IQO-cLW9FF2Ze!3 zd+O;Z0ouv-aM}`c8s0V!)Z3mEr(}bBZ0Z+wIott@GCIR6?)4)6E_D_(!_Nz*JcW=F zu{qGY9FDPQe@v2P#4g$E4K@DkCiMqA_lMyT23ts2zD{)RQz6#Pv!dWt3Np>U>@;WD z>%G`zTfMi=lDPAKMrmj))-0CDyf!X_~UBaXGxlY{)Tx+UR^F9pDkdnqZA2RFcVbhSefdna`u9&l#w!ulbsotM%RWGcJcg;dlcqj%3U;va@69pHg65uA zdJvi`V{@14>XUVeI_>8$Jg_X6JF)!x7bl+x_-w5;5W3#ME>z?Gmjd|g@1<{k(K-n4 ziy*P)+Ct^az~3lb=B(fC2pe^D7L;ILJ)c{tN%Yn>k_lb8_(l0X1VI0aR775NmE43* zm@<*Z@$`Wy)dg8z*#QuWMWBeNjT_{MN4XVyONQo7e1B;N3(Gfc>5Y|;vBF>rI?`@F z#@J)>ZzyoimVZ^kvi-tNe!|JRG>~DlT~qHz)UJo{(3* zOi>C)^zJY~h0jZ}_Ntuk;W_a^>GfzF>Bd{;$k4|aX#2xn&e+Mo!LsRygLeq5_%`7k zrbk68pu|i)1Bs~)(L*iEqMdzdVJH2aj%BXyInlIel>#@JwtCfLYbPd}0MFx}hFBH9 zCMwBqtQJWn-c&z+E&p-ZkH^!vKh*yrUIc9!n-X0tPxZ)nfl2eK^m`bwd(vrn42izo=d1rFW=z5aB}4X#o? zq4Dte;I*BUAV~(HrsxbG zYn6z~T-2b8j-wqr;kC6K#Q6m~J5R5Q<>C-m+CxwC^%nkoBgM3W>!t#}2MaDG!6Mq@ zkXQpO#$d`G! z3W(gYd0+lCUHAQ{{knf{Lt1B(w$4qc3UVR4?ZwAWz^*ABc7*UbNt@&NHrz__bkbDb zgr=iGD-tZLdcG%(z|D6FUgTX+w_E!Xra18@KTf$;+#x25(dY5j%y8^>78*?r=WoNU z*xKK(P1bV}%}X=CBfm_WlpP1G2(RQ7)Zg9&tnn)$N%oyxt7A|=3?45Ya6O6G5Gfmt z`?{P0tZj4|JIl@3h z2A&;f8Vdi+!`f6z$P4^}al;e<4Gq;d6STD=_7h()Uan=&qBhKkR%ww&llMs-Md5oJ z`^~KRvyQTUk#b_+cpX8h)H+b!B(|gBf6-_Dl@y2!aOqNTO?W&}&PuNrHwtxX=eMw2 zMW~%jlr+DYOA8t1xR)qp3eU=Vh$uy$o({fS;b&fb!y~M_<2NZXG_?_}hKX287$ZZc z=koexapQSlXGs~Foi5DF=UVTX8z&6I25!U>dRGYGz5U)+689|=f4&3el&Au4u;Q;t zKN~hYs~AnZz|{N$(eJFB5_*TX7>}vWHfIJaX|bnBKiYuHbgt3wyK|KdDXHA_UYzR1 z_n)qvxMY0%8ZIDlo$P4ln6~R+q(M8hS2zf{GdT_eoe<3Ef~RRAQ)#rW7lF;5YTqCe zF2))^vDOT7izpSm|3D9QU6=oOo(C+szx;vwBBRNj)v83erelV{hk?dujW!=GqwE$) zBH+AfEREyHOJU24{*^zPLlBbq9xpL=`-cr4q9AghMZ#as$P`kb{$xy5RfS}93a`Hi zr%C+}^ByycS3#MZ;bhgVObw{nGxd2ulUt}LndtpyWtq@5Jf7V)H;CF5Vm)nU3IF74 z=VEU+GeqQt3uoK|OJ>o>3)nK0PmMIDGZ$Z@o=uPIb{|Gr??#qAy{VR;_h!a@O#dgX zxwHXE26m>_WjZYSn*~26?&!oW-DhLQ$EOo*w2L2hc^>`q@!74x%Z!;-=u@)AA#lTi zO#ARxD3AB~0GhhMr>+m%suVu&6MR>Rp68zOpX)H+zV*fLKCbp?jNsX6rmmDIsU3ys zX(?DX)v$37?}ZDzKdYp?xst^9B7(49PIX%2k6e57V)2G|Z|!x3ocoPyk2TBblF#d1 z#dThf4(Yr{1Qjh@@Bch%g}G!E2vc<$XzR+TMq};t`djyaT~gbnfViz2_!JkkBZV>u5B$XOH2$n&ac^Itj{ea4=@x;E6e#crajPBmrMP4aRPMcxMT6m~_{Zjry(6Sj6ICJdPT@T1M$0}u0`5?Y7# zN=cz!UEMihB+t}=!xVT;_jhe>H@F7P4YhISzY*&|(Og8&b@N6$FM<1bIouW*x66F> zu>9*NNW%gl%`v_Xr@n=SvW*<>jTObGE9V-|ra?Z^N%16=$->iet(PHcZ5^zix*N2} zl)9`Nnb{GOFL4jFb_b&=&EPWEobjKQ(dCXwW?U^T;_`>h4Y&8Mwaz!JP89T8*u5q# ze2$86ZTrkp_i_g!%~=bMNGa5rW`SIp732CM^O%?4)3YC!0*R-@8N(RR^HSnB1{Q5xi&|L=nz9ph-M9GUSj{j~u;Jzlo z^gJ8)PH&4edWEX!TJuV0FUtE3^AI%>{p-OMvH>3>@~+p#Rhf0kG1BV78^LEx%R0z-M=xe-&u!0Ls8zWMrx&6LA=+9P?G0{`;A(1` z6W?afl+YeySFaX({ME@cN>Occ!KPdj!YLY&d5-EOSrs><$B{OoUbGZv2aKHe^zw4Q zk5=lIba7i6*dGX{I1H0^-S!Q8HS(+tN^dCF@==q#{0~H|S8cY{@P)o-mjMD@+$HFY zPJDrURH1ntwQ}#81FMba2vRP&RtqUPiFE34FtB318M-@8L`a>=HJElgwv0AI5A!^Y zT?W(5a`LqotKAzww0>7*_s6os3Ob1B^%R z{_cgk^QT?qR|aSi?+QJKqSY=OyvG!&sXV{LOI|;q8nUA8mPi^hEXd15SFx~ ztN^7~BDW>A=H?%lV>uIhT4C4jrrTI09(-wLFEh%w314=A$4Y{0vlhrSYhgFrS>Hd} zoa6L07}WM5wQvv1xc-c9$yC2$ZK2X+Hi##Aw#tThu61@%*>d61<+3GM70Di?GlcnvRR`;en@c;&;LE53%6%W=r zQ)BA#;>WF1B4e&|8%yIUE97f={)mg98#5DV(@l=9Djx!8Z|ByHjj)hiRx z!wLEFmfpaN8Zlr7_H7}!4c1oq;&4or@a*5? zgwt%)-8!b}G{qq(>#?5h5W%UbM)(!G(Zc0XdhyNg#m?jJ%#1`?8Eq4@YbPyNowc31 z{;@Q_^IqoEJG5J9?~$LI2{MkBF{1!C6ThRl6+5*A8@iJS$oH$iDtJ0Q^i_9xi5^c$`q#b}UwhM_zE1>ofm zY(%`=L=9sw{cpZLSfLfiZRb#4{K5D!`bG0V7|5i>xFeu>Ducj2tK_^_Va>JsViYA>a4xkj5pRN$k#A&N80bFc@X-r5 z^^kv3_u+ycmn(2h)7m20>y@#VT@-Nii+m|FRl%S30+UKg#@lHlFpLCv^ErZCqmPMB zwwchn4&Rfs3qp>GNcS1R;CqcZ)eLZh!RO^s7XP!$0S>ZBBm7mBiyKML!|M-+Ge$Se z1e`}{^~$up0!M>2-;d3jllas0H05)Wu~4ioQ8VHW=L<_tTAfmHUK|H)0dQXy zu%E?SHoSv3l=LhF8=bN_TIU_ zQ1^) zLja8G`keDuoX71=aHb;hB(&pLDxS6#ce!epj9+Gyc=L0+Ij7l!w_gpQ_^2D^uXBydpZStv>|=nZ0@@oa zLRoP=8G$h4&$gJZ{$>_S>NV<7%^~&`MV5DdUSrv3KRp$AN#JJ5LXm}sr6~G*8Gd&d z%kQZX%ra>y%A=9Dj9LNgK_h0s)npG>>cgz-QxkoT#&b->NsBbf`Gq5q4)*>#hE^ur z2?j=h5`wa?FrL(G5&NK%)?4VN-WT5%ZH6_=p`bNmYqw)d;L{>~YBda|-;3l6bjJ{` zv4I{w?)I!1>6PB3uIpIJN1Lk~vW3+Qc^{@gPtcshdT2TFjb%uv3ox>99q&(K4^45_8P=|(!pq?EJmj`K$SS3fH~Q#iizK#d#INLuFf4W=*GIW`tt82_?c^dVC0y zp;EUkMsl>8?laS$#N9QJv*GS4Jw-dui;BJ_EsAcBo$rT1TV$ShS}i^0Ur`VZ5!0P0 zZaCYv{APS^@v)LlY>jq05nhiN5I>a*kQ+)xFHD;cx!)Nl9=B3F``o{`k3UJcG?eEpynBb_ z`eCQx>{DXF5%>0^_=P$AkZ z5pSN&=d=Q^usps97`orn8?WcHYeAcH@3m#9vrAS3u55f=nD1>BIfR?@p*^~<_?|do7B&(B{GxJM2-+~)9r zuL%GDRoi<q^Wd}uCxe()X)`af+7OaL_mp23X&4S99zk%h#$xCaXa;WO4i$FRiMu_>TJ6^OZr<&?^4%d-BW7T28TY{_ zfdP!y$~m)JK{xshY8ULzU;_tl)cB^oialisxl{dW6^=rY6Swm7tMsQYPJnxynm`E~ zZKB4nYgFniH7b-ab%c5794!8Lc%gGI^AH$15m~b{s&52>^8K|q{6lgI@GiAylHQwL z*xoC6zCh;dJtTRlTf^QCVABMOr4cqYQ%P|3Fzc_PtLuivpWP<}1~38DyL`C)2R%Lx zQbXrcu7UezN`V9Nax`_2!PSS%qo0BYh_X>s{- zz;B|7A=aCNr(sVtxwjlR!P5a%=3uz(urdZx?cx!?iD0je(qHSH*R9&NMQsQB{74$y zOZt@rMwCR}1j-8KL3?|;!WkQ36&KfIc<->4k*K-lYvKpZxNeuKvN#A{b@P<8di%JMH#z^qfUdO=_ zsg4o`8aj3zZ$48M=l#+C<<>h;q_;}lp)U&)?t7bBbX*($+7V=Y#*4EX!a^Ma|J(@5 z>{Tl4o4=8;jK+t#uOlu=P-(VFsZ@N=|gbV6}2A*mck3K^|a-f&H zTW83WRqBS<0ztXt@34CP#xE6VN#G5O9>=$2Q@zC>YMa)rHrF?toNwJ%^+zhb_2Nyw z)&~MfmAGo;Duq4Md~)n4_>OETowv0S@%iPMFSdg;03n^3HgDEGaOSBGb2e#ZKc1b# z=G+1k(iP}Ti_oI%n81OLffoXNe`zU~z5E)2Ob$w`jsM^c1;?`r+8HjG-~1rlk|(qe zyk&Y{nCODt={A<}Eznv)^z$(OENP<#2cj$G-d61Q*I85xv=PI^auOmPT5WXpN}PC1`GfgOzh zNk=wesi7hFKlzjju97bNE8=0_<+R z|BZrk7&a=q0(Eir9R8xO#h;|StJJzc$J^#5@rbLR-c~1xm%kNPZ6VM7Iji8T$Dt5= zm-`f>!*(LvjuK6(NPMJY^r*Ek&cSYUyE|nH=fnaYx5AaJNJyIBNy#7vWJqUy+5FS* zWi;G@UpcQ&q8ET)-c{aJ>p&X0y%j+-?e*!NKAGd^9?HOBa?&9q6})XRjd4g!i#NT& zNUY0=neEKSX_|#x6XrCxvWD%YxKrrHYR*xtEYU2?yK6B~OpIHq?cc18p6iP!YwO%i z>bX>{`!P2!!cMd)b$aEQwu_vc;>P!-t1biJXR?Sz#bow$yO{nr4+7a7TaMh@HwF#th7w#W+m z$~B_MlAC*LPO>pyR{qBnnLBt0We^XOO4ge?KvUgLgT=L6JpxE+Z zJVPNDsOh3Jb9g1m++hJ3ALSk^MXtFXaSq6W*B`Iy+m)93qy#lrt=O9qkoP7Xq^ooA z1JAw~>LAMo@ez65!BKm4_Is=HJg(0{l*UiSw18RZz@WE9OsiGtlPYQ@%43}?^HG~D z8;~ni*gBHp(tr*aYRs$f)K<@&Seo~heOc!IEH$&t74{kjKzh0?NI{DF5E^Bgkvms zCF8B_;teKF@jc774BYbcKX*^j+q5Mi!F^6;f*cSEnYTl3$^~pjfH#+xuIXwV1Jwr4 zW!p(>NXy#1Nb@<^ z;=rB<{zmCy9;qCNcQgs6Yk0#Glsj7WYW2fgshqA%y?;SpRxT#+SYRPafS3rKZd6}4CVE*NUJ!n)LM76z44tbE zCV!$Mwsgj6EvUwws^SLb0l`J2H!`*39>1KpczJC2LkA>5$CO}CLBwD+MoCLXbtpl> zY>V-P1f=@yUY>65MMk4v6Z`eWh~fiMGD%RTmu4^4{06COt;KUw zMtzo4D8^snw&}3>>Z+@!+Xp`e7FhbA*ocoED6|vHvX{I@AyLVf(tF)Q9dw1`B}U~v z#T1T~9`zicvOPKA`9?DaaU^B7cI~F{PKG|?x37ZPAH^7r>-kNwvF5PX} zPafcc%;<;WsiuLVDD*x$jDxl~CeVq+*BI2OzxRN9@Y`;_-s0oJdqWMfQTR1v3*$K% zT&_+`g8yM_u2{y_AX(Tt-eyP=Vg3d~DaY*P##+Fjb1!q6e^V0<1#I{=?wS%%tAuLy zTb^1RKs}0rj~f#m91iS$1x^()Deb}WL9q095qOTwuTe$vl_v|Evgx@m0@=lUvQ+P{E zK}rOz-0ONXbc$;F2G9>4O5m4yk7$3r)@>|J1>bP1-8K8#{>wQudu7POW~1O|4~vfL z4Lkej0nefb+d?w>g)aU+Q>60ik{}cI_-snmLVYK>)hOh7JU${d0YesYkq7okt<;5I z8yG3J^xu{|=9boPWy(F+3M8z-2(`B^ZJK|gh)Ykwe*JIO&#k#UR$6EQm1QhFnyijo zODWZTn!plba)o)zQ37^_I@Fr-c56!nT7FW6iniZrf%k}$<#umD?Vdk?r@~x<^|#aw z(lp6|gJOi1^Q2*m{lgFGYK4SFI)MAh$}P8x!ff| zzlFEobEnb(T7L*WDZtAW*;*~UsD8a_hSnkHDM3@J_yo!dqaIn(WC7#Xn3 zX7^=^KqL$htFVONj4~xADPOvZk_MJq(yv3GF4A^KusyFIz$A!gn8W6Q&tTL~=mTU&WuqKunI zgsj+d4wjZl4HIDa%LUrDwOH>C;Df#IfuL4dh-?gOF8o>1fZLUwC42|n4PBN>)H(iR zWOg5B}d*Jv4vAC9t?7uBdFIExu2x60n&p{5vYYEn^p*SH-xzEefO%!D^ z<7U}5H`c=r-FprgZU1!nusIf-_V?OsaK3_gO)64h>TT54 zoYZo!TA6)}p)?}yzeJdVp>8L(HaZ>hMF3SV@-wtSd)rKNkOq%np$odYp)CvV>Gp~+WJYjruX9OT(MehQ>Mhm>^ru#OzmF}b7{S503gQi^ z)5?7dMZ5Kq$H_vuo$6t$`f@p^^rHLcA<`y*1Gfg?$Dd48*q3FF=uhRg~f|1}{ zDI`xGk&hzcHBa6othNSAE9V{J#s@AZ#wrln-x?2H8W9YS^3@`mlwK? z0}Bj}s({C%alP@CG)bKogx@7B*)mU}w2{h*2_a+p$D8i-*jQOT=eq(uIH5*w4WZ_2 zEeA*7+Zk=J=Qia4Nfy1`^qKCfC)2c_CeU2v?cG?-Z=cWMB1HO<;&^>R`@2HnUlutF z47Iq(OfVyDWO*cZe=DNOpY)*3tH!S&31y{!8KE@w`P{CBPN+E*CY%x%YdNqm!gjJS zOX)VcpdbR90~?c%s|m3yXJ%{z5~k?EdTX^ z>syxXT)kkxA_)zNQ9xCfX4XlVE8?7@I!Q9_Pm9@SM6MMyN z9-JFLg4bS^a=&*Ap|G)NZF|{gUAfqme~^|^NF6%7ot_-X)#JG`>^q6xkNe0sNb|E^ zm*W(S1vk>{a4YcpLYQ1RU34H}RF;4Kj(R6TAcRi9;=1z!7$FbK<92~TSG9Q{*@se*u89k>viF}f#bE{faUq}IaqP^FuRWqbH!MrhQ8-prx33p#!B zKE%$s$^o@aaOKARyT9i>^W(1O>gYiG&J-0s*w1KoC@ZW&&z{$yyuT|~`RUKQYScmI zd_v0dgJQy;iNS%dk0u zA;YtAO?4rlRGQ$G0~)Q&zjrco_%zo?%hNxsgWZ&3Sa$MF1so^Qy{Os2sRhD0o%X8> z93v)k6SYdypv?Y@F-f*6i49m@vw@fKF{<9(y09G~jWVX53$u2;Pp2$BXPg!e6DOHz zCO)66?CzYq*Zzc5qrHn=$yRhryzU1tGp;02{%>HgDt!VBW{P9}NMBAG4SBJ8Jn>=k zYL4)aecIqee*hg2_9?ix-;Kzrc$?Of2nl-nZ1_;D$GH{N4D^z^MwJBUopo5hTL`xc z5f>}u83+SiE=i54mxOQEki!Czje{P7NK;oegkE=)zvF82Bx`uuO#k7i+KmJa;6C7u&WC~&pS_?xnJtN9-pn}0+gN6tc7a^)Kzdpm@;WW4{nAB_S?`!ICgyj` z_P&3i2FvyLm2xCl5Z*fG+>gX;eAD1iRw|@nr|cDzUbpB$YQ#Mu`zD>xF{awGQ-TKv zK!mowLh~jlv&;Ro`d>|Hv1b=&TF72O;@jNe(|(KG&GvzaV>089BV8>F;5G4%NNeA9 zflpI1Tdj7Nm!>e@g2k>u_OG6#^$m`?&p%e_zFe~3&&Z~dumqQR`64u#Rd9qcN4$lO zhysY0c>OR!`z8m+NtnRyA>*=P&Y$SOof}00R8!5VuwVIHJp@`?zI8}eyR}si^@|1> z+ZFhss{a9bX-OuUGWg+BB{9AdU(F($BKX-gs7%lKQq4pV;Sw-7N_?}p0q~U^tG7>2 zP=RMr2+N9{E4{JC_g=I_Rb$)X;0)5p>Fu0X72hXM?G6oT`|%%lEnYM@eiEJ8nlU<^ z3G+{X;kVVW>Q~yolYnZ-s+|MRMi!Q_5;$iM+bRQd^iuocGLD7kf-_0sGAH)S6pB8& z$0*}#4k(;fskOz)&cx|tg>5?DxT_kwp>xWg6le4D&tS1#V~ptA#l;*r_Y-Llf&pZ#)h-Qg=%tL>H6Gx|Jy6A6}DFV-3QIjREK^lpJcYK8>IvY7P?4H*O?u_h%a1yeG zoWE;zV|Z={M(6=W_rT675;1Kdo9ET0l6|r5m8%=VpUpi=z&rW4hZXH4pt+luW_n5( z^hUa@bCAX)+o{2I>2e&pn0;o-5M*c)bef%O-s9Zn1;|W%`+ebsLywm!hlE3F!SGva zVt+x5=u6F0B5wTs&uVrIzW`e2Y!g}WGFbljB5Q|p&e{>(WI4Q+o8Zj~&-4cMlFsb> zD=NiYRc&=`har0Oo%MR;&5(_29?%~L^1=mF7-Cw~zUhuby}HivHpnfh`(zen@J{Rq z*e+eDSW;lTBfuf0q96BK>fN)H*7GU2=FH)89PjUdXY8U2#T*H@%Q+x9Q4`o;5{ktoa3y4H$F{i;P6btFa!g@yH92FQf!cx#7y{Ot8jcH^Rs3BlKOqZ|$eAMO*D8t}bbuBw@b- ziq=B7PUaZOH1jE3nC-0%cw((@Z3m_77(r)T|L!eb-7oEb;hkF1A0WEzjAPB)7bmia z8*?t#>^ajVy>cQ3MM?$)ZB(VcD(0%CtShH)W*Y?592zE}iV6y+L(tP3Gdo{9%P!X! zAvButr+f&o0YN{>N;Obuj?X#_giSm?Ks5K$UAkMJ|CbxEVB_P>)ALMd)s?f~PLv+^ zEAR0S<5^KDD%A|nCo0bSRdb;gh5Jj|V7Hun?w^JEzZX5<(M^j&57Qj4GRpQzoUvov z?AQzw8V6ZxcOKww>8cfn=aB(P%NJ_Ob-##c{7%r2SzJeXxbV*Q84tJ7L^ybPvF&A)Yk)t5JDW)b-U%ZTRA;|sJBBqJwqmbcIoymNH)!+UmqdZRnUEumUrq^zPNm2~ zMTI**g*wa-_L{F;lRx?h>>P0@TC)Dex-4A?j6-jCqim0y>+!2H%Tk!~^yLUz_O@WJh(K}SI+i3i)|taph3QtaHh&2eTcAy<>l!iA3%Rg>Z6@Om|o ztUAm;JG6@e@=;a;*a?fSiXPe4b6JjDuK|z;xDZ8hRW_#^T)757_xPit0-NQ&n2=>6 z6AlME)u1gq?5WBBJ5uUyBTf-X5`zcm1WsQhEO|M2SlBQc)BIEv7ZuOE*}o*PHlCH* zEAi`7XzGP6EXR7q%m*Cbw_-qR!d-_W7v_lEcrnyO_6{6npD+?vV~6npY0}%`hC2H% z+6GxKoJX|+6bZ@4_kVAH8|jsJFldDQvOM@c*PguWF>T5L^5F`6zsxZDnmW|#xkf+Y zf}AEsq-jP#@Pe!5nJ(afh26)7v($kBo%8z}n7eLd`d?z;N$aPf)=X|dkjZYq9om}( zH1cO^5H9MZ^GT&7hSoXgmJ&I0Aha_=Df=z%m8BL6)4(pa!p!HIGC@Me`fxgP*4wMb zZzZrgTxrrLqH?eq>36^&9mPYQYcne;PYIbhr_L&!B+fH7-ivEtbsFWa?w{j$a;}F` zwX6R#GEheNPYYk)ly(u<rbv!G`3B%Zr2~A!c(`wQ-t?_Fu69*LgDCIgL{>0|u?WZ|* z&b8+mES6#cU8Nvao|5~WwIkUPP=T_b_Gw;0`-^v_QUf%}Lc4DO zk?LV&t=;cJL)qYacmc}foyT9JNNFp{!?mF3jd3C}x7>a#6mUF_FR3tXyv2>6z0X}kwSnE)#5zCi<}ahe+|C(JaE)=c1>Lf02LBp=$F%+r z==Kg=asfFG5&8te5tr}O8iiC66OZW^`+t@ypb^otM)4dUF4F9^l3Ol;By7SEky)p@ z=5LIX;Fo;F?S)%*z-j%FfY`;#r5Prcv0*#lfuF8^UleW3anJeNsmxoKN*vJ7~) z#$23m#k7Tta`)K{eE~%Wwk^c9U)Rg`TjY8cwfr)}b}3B~17N=HA9vxzjb7wzFNYW< z?zpVSP!wONdH#3njr`%1Yiwc?+WL+Lx5x~H!hw-{$jt)Xx3p*W)T?-VoNOh2eJw!- zstbIk#^~O11F-UU*tK03_Cl)02I{2X18D^HORXnvoZpz)tW~OFUv+68INuPf?2@Iq z=1QnjECL}Xs*BY-YFDNtSm_4xKYn^SXKe2y*61d~NEpEh+-F#^r_yK$EflTV7s#8~ zSY2meolytA=Q^)4)deY*>vP3A%S8boABSD z;Qe*EX$K!W19<+G?Q3}A$PQ4!2i=gJ(t(a9cRG1WG#)Ko3vtUy?Tl;^WQNt95K*nz4;X_`+h*kY>IYZ@S=@%um9*~8u}`-s$}rFz|cbG7^e-w+qC3GRu88Q z2&;Pg@U|8cc*}yiiHO>MHgUs;v&SjvjXH`N)7DNz188!>otW5TAOB+i6`-Rc0jyBJ zf*%GY_e#fX53kU~1d0j&=}*4vo1gS0TNS`GTZ}_fPCyF$1*C5wChYtUy_WN=?0>*Z zXgvCTwX5+{!5(bs3jD(%%^{B&3L}CI`@%EZ2ALUfsUa$+r%Pmg{k`ukmAC~iOZs1c zGn8Nv&<)6S0(_cY_|PmP zhobx|53cSCm-X#(0qFZ>rMG!q*iz2n^yhO zy^vTxbviO?rP;S$_iq@=I@K)?XiaY!{<$W-$ky2S5)LMOuZ|`qH?KWMqpmuwZuB!I zhM4$QqqEhn#z>F;-YlLh=c#FvU}LwqzL6LH+StlU=}Z_u=N@NFwEs-pHls~jU(HUy z4v4p67j1g~_C-&edA;7__SbziGXeaT%P_2RSxU|Lq53G|Nzr%v0n|?PhVKh#&hC;i zG0krJ=r5?sj2rjI;I*sv5Yk zs47MkRAYX2wE($O>2<8T5L;^6PFUIGptLIdx;q>4LVo&188sI-b&U@w)LM(&NU$oL z6r^O`t3TazymJV}O=F+;!~r_BB7kBo()5pSA>?vWZ;NgO+Mz7CYxA{{PZ7DY4ubeY!AvlB>aidsza!Ni#)U1nzdW=qf|hm z$$Z-Q^9DZfuDe{WZ0hSN8Tzf>2=#pR4(>;B_h)#u;b0bggXpV$QYJLgR{yG0)`ejn zG`~?mrg88&IR2b61{K}qI z8K?fQFUsmg(!@`xDQ74|R4TD6{I7)I)l&UI1b3VM$;iww0UH}24RHidR(BsVqTba( zgP2&jFHDH#So=QZINzq*_^Rvs$aMI`4zodRWv8rXFA=QUMS9XkaW*0MzJ#DP46c1N zIY{`RoJ560GVpof>u+Iri-YH@EeDN`_4Ic3O;%*NsxMfnT4+`NiN{%HDk# zbZ)!Rpi?9AlyPDGi<5k# zWO;u8z!)<1_H|sAQK-%X3`>~A=`hYBOcFPDxQXr=mJ@oR->lC^4)`ciMB9EQdUbp{ z_iES>7SDupp^|HUb7kOt*#LQh3w{9&~xlTf_ zjIRcth#f19q0m@N1mHriW;@#2gkx%V!$9OvtQzRXqTZ*+7It4114z$T#AKxu7af-* z+tKy`*MCpK`G%rr&x}%W21}}Nin(q>u+v2V%y$?az8_m~+fepH-+OnBW!W3uaNACz9TC5tE?Fdt`9VoM_{M4WeNw;?7+xt4#d$%ml9re@B z$G}TW7d|%yYRT!zD6L(5hqa7eM-ozA7vwjQr~T(~ewnNoj^NK|1GHdH1(qHU8>ziE zD#8|$F^v)4DfeExG9YffO^*|b=s4c84j%1voUBq;ura=+5JN;i-#E9noV}AyP~PnL z@QuIuc_`ANbV}Ud)j8x|p!S@wW&8*BVL17LV}_L6Em`}2C+&;bLW(M zGmN5;YhiQ#HOl#mJ+FV;4Sa}B3E|jDUif8Spm;1+V2gh?p)c%v8Br??y~vMUBie6q zogN&{K&bkA`tLMCbNWudfF3u!KQeJHAINBy`5UJDFo{Yof8Lj7iVch;KQdGCJySfq zRa)&jn;nC-dq(bvNsT(+>(rAiIHv0*et9c@O6;_24WYv(pw4Uk>!>ZUzrzbpVC%Llv%<t;|q|>eQJedlPlx`}1Kib4S08=anMH3Rr!=Rrk zdAWc8L@q)g%?d?`-(tK_D=A2&80oi`|G0i2PYx_>iVva%WDpJy(0*1}d%mEdev-qxEFaPu2V=XIS2kHL@y1o%p&8QrbUt!?vVL5RsR#s z-(Nf{4=`sWwjUhUG~I8vHnUibDs&_$c|lESc2OCKAoLainiO(r{2}{3c>2i5QGpu> zSbPv`s!ftfql+ZzJS6c8`@(~!xRoE<7`a@Nidg9)%$r&AZ_P`WG;UE1qoE}T-Og|a zd(5M>AQRL=@RaXB@S8cocSsy+za?Pa@$BG{NEZ{Zq)@7az(e`Ehc{KwlcxvEsne*5crICBuRCA?kET(;j|DC945wE!6Hvh3*a`LSylkm&=U!&rzZd#w9dq?b3NklE? z{iqG1X=M2R`h~izj%}_{gDOdzk+{x^IMfo z=a^2X08-H3-@f6daw^nd6QfR#m#nCR3G2^QuPn1-H~4F5i3OI8fyteFq|E)u_ADZw z17Zl)?i^9u1L6>-Yyov<*Bh_3SW4x5OX*aG&K#Pyn1qAuLvKGP@80@jCs4UJeek9& zVm8jgRqA_Q_-(yKLew)1FS|fbWo{FoT!M3%L+ZHY%xF$Sgeq7umK}cajM!S_LUg(X z^$UQm2Tkha8f_~t`R&y3nPD=b_X@4wj8o9uGMU~7hID}h{duYAe`yr*zE5x{K z{}*e|@O*a~?$7xzn-3B^yYzMTy#ViqpVqQT+xx|c3uZDx)oH({J)MO17R*MAR1F;8 zKTDtoUP*)RBSv@RSuN6d=N@8>ax|qQH!1%oSKvjD$z7&nD@x>`*#qapr52u9iTBLJ zy+O5HOXkfei^=PK+^oTw(o+tebiIgcu}A_CKQ@I5ZwC#|2nnVFT0Lie0;0Dn8q)In z6uJ(UC=6NrugEf%v&XevXthbVaqjp-Bq_vnkyCR^UX#KrGZnPK^s}ZSWvy&Z4(nK2C5m^5A|>(s#9G_=`4vRp-=fB2Yfx(aPv79i(CAg0u{a1i!aLlw+EA;!bBkezL3yY-68+%+*bSdk8K>C@T4b~|)=@#tPtnzv9 zS1RJM=EU*GSD7;-^+p=I^T=F*ojtf z))zI~l_j}#m#L?TLgdo7!GJm@3u5rU_z1NE2KPUO$R>42^8k``G(o{RbGO~1dG|vy z4tyLJ(a;9{iX5Nd0ajq z#3~+aup{%#zygc6xc?!SGdQfZoNM9+?e+tt^z@M`;58Jq*rU9FLp>-6TRgh?fRV>V zUQFN?sTgloGTOR3LVwaXIa2V^>BUO~Hi~V9z#g4~fyqC;2>a`7CP2!K;clfMPBXQn z^RVlXr%Z10e{dmmu@g?MN1pb_IEU-bIQYPXIwQ{Kw~@#GJ=sJ#pLlGYJi(^(S#{M< z{7QY83AP$QrQaM39Rr>R-H{VcZ z-V@6Ox5j;7ELmtKoPUhCTlK;LHSJQ|_N1s!aqNLZM<(%rJt(!I4*HAessDQ8u-qnLy0Im7@2WA zeIZx3$LY}v$B*bR=(EqJ&+jJ+1Pr`QNq74H*ZABDRd!_@5eCNKN+ zCOU(6^P)KN1$K%|$Y*i2NcmJ+Fs<}fU)}o(>l37mp-G-@ zBl+;FXIBT5szA!IH;(1E>ZXc7e7bk6r)hB%X*kjLKvvDi^4a|n{nIe*wW!8 zx8sNS3)_sn{s%nHO^7`*rLeDzV91D_5_}V479FCce;5}fZ~j8h8X0n^=gzY;qVBpDglw*5||N?O*GSN0ZjhFCS% zL~(yKL@g%t2rM2$xFca|KA3t$)OnBs8_{4NGI zDV(bG98UFlzi;Vb3b=ugIKisVg-@$`vyvUn*=gPEL63{RI_vj+-OvqWt;T=%wj=$c zejE!kwwOaCYT(TSjS&b%&j|8GX;}TH7|PGHMql>!6er~?^mfg;6}fvD zGC(k9m|Oxzaes;(pS8o0YYK;5VoElCsxM;Cj!9Ig;-#)6TuoeN#b>5yh%WZ}4gkFB zAUgP?w5|W-UfyxA}Gf_AXxd3Vg6*JVdR76SNp5qj+h{y77iUu&s#8^Kl=KBtpeu(fj#%PHj6 zoQn{kcu=uIM>3o2u`1*JBY7(@qSQ4Z=uGe=eMd&=I_L2p5=t%n_0y@;_){)TCoaR7 zmWU1j%dk6=;ne4zFx-pVtcjht*L^0wXIjJ|*ghE@w$nVB4YzX*z>l=Z0;C|$^COI) zwc$LxpdL{ADc^{(TdR)8e6Hj_-n0&S*N9!bbR!qoh%e5XARO0S5a(xc5}f0!28?<0 zdQF;5w`d@!_DVZYR94`#}&W{UPT6KVe%yRCMnr~lg0?Y!)mWj0e5yio!f|olWx!i3$u#3mj$x^|vs zCrt*rJWNfq4VAAl%PqG37xwoS;GE{0=oNGYW!w?s9GZ>{@&hf6q-tEF<=!t3M&%_& z(gd{W8K4%Li!0b)H?FZn-K$2k^9MlXoCDZKEHpb>L-~r&~o9{i*zNd7Lf-Vod*pB-_tV)d{Gr(bC$No~vw{DhY!14{2+IA zu>9jjjT@3p7gbl)kITYkcPluizR6LAIjlzL3++xbGT=ya^kBe=^oiQczEm}nc|J{d z9Oy()^uLecMOxHiVvV_G8H;PY(ym?FRJN{b9y^x;&_AFv7r;1Pfw7rn&sT21nTioq zM_PKfBYA?kPCp&Ld_n3vX-y;XlQZi)(y&iIU-bP@7cea#l9amZaH%k6r5&XaSAP-_(Zp0XiVk1S$f#`kS zspG^~2T9JH<(WgGuyY$_zUfP5s6Uyr=rTRMnP+|1c?2eW`mcoTx}+bvg%dUYcd`g| z&@*s~xZ5`0&@?nMMH0M>sC@y&)9>14rXkaTQ`^9}4+2hW>dwRf>>;6$$ zPi=GDDG=mJd8&`iQv&ozDphS4bo}CGx^ax1;q{Qg2mt4V>3rCo1dai!FFv52<6sN9 zWNmto=sYBn=L3fYS~_DHp>7Toz%?j}&i&*Xq~~QPL60lEq`3bJ!hKx&FPm$vv*Yj&RB0qrYvRfLK(_VjU*3G48LkJy_|V*@}uQ~qY7y%(3)_z`;l z@np*Ay@LIl9$r4X1s`n5J3SbLar#7JIlzHH%z>T&xULPV3gFt-WaWup7UJbz8; zGrgr>!daV@ia}M-tcOWwATc3smNk!u09FU|Xd5=pb2288_EM-Zv2>cxXz zc5643`c+E|b<E@DEHcmXmTdZ0qDAMSxwTz4w50=jfPa`xHR@qgA*QRCMsjr1~(b zB<1zg&tp6T8l{L6C{R$0CQZhw!A@7bVX9}85C#GiUlhJ};!u)}!268Y|1T&z*WeqU zqdj-Z;p1Kc(T++ZUvK%pK*=Zqr#rj zRsgX6hwneoiT0Le{C`5yMkdgEW}~kKZN7cB9}d|V-qh)F8Uom&pUE(RiFZW25EV+a z$uy`0sLBhfoEXX)Zhiup;l0}3Mwx#%$O#l2y6@Oi+OIa(o}Z_qG{-26HULcS8CYBJ zkA;-ei6fJrek-U}L1z#>(Vk75W)18$8+%%%)Hw@VX=^oIHTtEEG7IT9eYd9b*8*E0 zmS;aoUT;zBaV=y1pz`E@!p{uV_+-1~+Fz~BB5(kv#YS?bpC*)$QEEa&Ix<^A=FE5 zz9(i6Q2%kB^V!V>4%E|u9nIwMyf~cFt(U1+0nT=9Zvh#77fggtV|@w})F;`h55=!m z@wyKZv!t8!qXNm>CcUu&M_bDjvJ@@xJ)F>L#@&Y^$izSLcukc8m#`*kJrvpw8r2lV$NeoxixEPVtpeN<9;B zHn^MG(|2E^F2K>vm{~HGU zv)li^|Ca{*^U?oC=l?eY{yFY{-~USk{@LySz3u;o0ssGY{(m#z|K;fa%eDh#FJR)8 ea~~a3og#mBVSf{^=mvan%HYOry)vDLFa9s}-hGn* literal 0 HcmV?d00001 diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 000000000..04937888d --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,341 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# ArrayFire documentation build configuration file, created by +# sphinx-quickstart on Fri Jun 24 20:20:43 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('..')) +from __af_version__ import full_version + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.mathjax', + 'sphinx.ext.viewcode', + 'numpydoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.doctest', + 'sphinx.ext.inheritance_diagram'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +# +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'ArrayFire' +copyright = '2016, Pavan Yalamanchili' +author = 'Pavan Yalamanchili' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = full_version +# The full version, including alpha/beta/rc tags. +release = full_version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# +# today = '' +# +# Else, today_fmt is used as the format for a strftime call. +# +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +# +html_title = 'ArrayFire Python documentation' + +# A shorter title for the navigation bar. Default is the same as html_title. +# +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# +html_logo = "arrayfire_logo_symbol.png" + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# +# html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# +# html_last_updated_fmt = None + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# +# html_additional_pages = {} + +# If false, no module index is generated. +# +# html_domain_indices = True + +# If false, no index is generated. +# +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh' +# +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'ArrayFiredoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'ArrayFire.tex', 'ArrayFire Documentation', + 'Pavan Yalamanchili', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# +# latex_use_parts = False + +# If true, show page references after internal links. +# +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# +# latex_appendices = [] + +# If false, no module index is generated. +# +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'arrayfire', 'ArrayFire Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +# +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'ArrayFire', 'ArrayFire Documentation', + author, 'ArrayFire', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +# +# texinfo_appendices = [] + +# If false, no module index is generated. +# +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# +# texinfo_no_detailmenu = False diff --git a/docs/index.rst b/docs/index.rst new file mode 120000 index 000000000..4c689ce14 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1 @@ +arrayfire.rst \ No newline at end of file diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 000000000..1b46d26d8 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,281 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. epub3 to make an epub3 + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + echo. dummy to check syntax errors of document sources + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 1>NUL 2>NUL +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\ArrayFire.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\ArrayFire.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "epub3" ( + %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "coverage" ( + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ +results in %BUILDDIR%/coverage/python.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +if "%1" == "dummy" ( + %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. Dummy builder generates no files. + goto end +) + +:end diff --git a/docs/modules.rst b/docs/modules.rst new file mode 100644 index 000000000..c5f5de84d --- /dev/null +++ b/docs/modules.rst @@ -0,0 +1,7 @@ +arrayfire +========= + +.. toctree:: + :maxdepth: 4 + + arrayfire From fef2063db7be61de5b2113f5eb9806e15393116c Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 24 Jun 2016 22:02:35 -0400 Subject: [PATCH 071/212] Changing the release version --- __af_version__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/__af_version__.py b/__af_version__.py index 7ccd73785..72e423a40 100644 --- a/__af_version__.py +++ b/__af_version__.py @@ -9,6 +9,6 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -version = "3.4" -release = "0" +version = "3.3" +release = "20160624" full_version = version + "." + release From 863f3950b5aade9c5c4ff3392f849038596698f4 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 24 Jun 2016 22:04:29 -0400 Subject: [PATCH 072/212] Fixing setup.py --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 294871d09..c95e524e7 100644 --- a/setup.py +++ b/setup.py @@ -12,9 +12,9 @@ from setuptools import setup, find_packages from __af_version__ import full_version -TODO: -1) Look for af libraries during setup -2) Include test suite +#TODO: +#1) Look for af libraries during setup +#2) Include test suite setup( author="Pavan Yalamanchili", From c53dd65f099493ab13a38a86fe57d078ed50c66a Mon Sep 17 00:00:00 2001 From: aha66 Date: Mon, 20 Jun 2016 23:13:21 +0200 Subject: [PATCH 073/212] Add support for short types * Update array.py * Update util.py * Update util.py --- arrayfire/array.py | 4 ++++ arrayfire/util.py | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index ede0da0c5..06db29aa8 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -300,6 +300,8 @@ class Array(BaseArray): - 'd' for double - 'b' for bool - 'B' for unsigned char + - 'h' for signed 16 bit integer + - 'H' for unsigned 16 bit integer - 'i' for signed 32 bit integer - 'I' for unsigned 32 bit integer - 'l' for signed 64 bit integer @@ -311,6 +313,8 @@ class Array(BaseArray): - Dtype.f64 for double - Dtype.b8 for bool - Dtype.u8 for unsigned char + - Dtype.s16 for signed 16 bit integer + - Dtype.u16 for unsigned 16 bit integer - Dtype.s32 for signed 32 bit integer - Dtype.u32 for unsigned 32 bit integer - Dtype.s64 for signed 64 bit integer diff --git a/arrayfire/util.py b/arrayfire/util.py index fe3e2257c..35cc5a8f8 100644 --- a/arrayfire/util.py +++ b/arrayfire/util.py @@ -98,6 +98,8 @@ def get_reversion(): 'd' : Dtype.f64, 'b' : Dtype.b8, 'B' : Dtype.u8, + 'h' : Dtype.s16, + 'H' : Dtype.u16, 'i' : Dtype.s32, 'I' : Dtype.u32, 'l' : Dtype.s64, @@ -109,6 +111,8 @@ def get_reversion(): Dtype.f64.value : 'd', Dtype.b8.value : 'b', Dtype.u8.value : 'B', + Dtype.s16.value : 'h', + Dtype.u16.value : 'H', Dtype.s32.value : 'i', Dtype.u32.value : 'I', Dtype.s64.value : 'l', @@ -120,6 +124,8 @@ def get_reversion(): Dtype.f64.value : ct.c_double, Dtype.b8.value : ct.c_char, Dtype.u8.value : ct.c_ubyte, + Dtype.s16.value : ct.c_short, + Dtype.u16.value : ct.c_ushort, Dtype.s32.value : ct.c_int, Dtype.u32.value : ct.c_uint, Dtype.s64.value : ct.c_longlong, @@ -131,6 +137,8 @@ def get_reversion(): Dtype.f64.value : 'double', Dtype.b8.value : 'bool', Dtype.u8.value : 'unsigned char', + Dtype.s16.value : 'short int', + Dtype.u16.value : 'unsigned short int', Dtype.s32.value : 'int', Dtype.u32.value : 'unsigned int', Dtype.s64.value : 'long int', From 2299b2a6ea853e8ec0c3e1ac03c5aad5f971b5cd Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 24 Jun 2016 22:08:59 -0400 Subject: [PATCH 074/212] Updating changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea809cd92..a55a2bd6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### v3.3.20160624 +- Adding 16 bit integer support +- Adding support for sphinx documentation + ### v3.3.20160516 - Bugfix: Increase arrayfire's priority over numpy for mixed operations From 298465fd48becc413cef37c258b7ac027edff2d3 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 24 Jun 2016 22:21:36 -0400 Subject: [PATCH 075/212] Updating the README - Added documentation link - Fixed the code sample - Removed sample outputs --- README.md | 84 ++++++++++--------------------------------------------- 1 file changed, 15 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index be1c4eb51..f6458198b 100644 --- a/README.md +++ b/README.md @@ -9,80 +9,26 @@ | Windows | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-windows)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-windows/) | | OSX | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-osx)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-osx/) | -## Example - -```python -import arrayfire as af - -# Display backend information -af.info() - -# Generate a uniform random array with a size of 5 elements -a = af.randu(5, 1) - -# Print a and its minimum value -af.display(a) - -# Print min and max values of a -print("Minimum, Maximum: ", af.min(a), af.max(a)) -``` - -## Sample outputs +## Documentation -On an AMD GPU: +Documentation for this project can be found [over here](http://arrayfire.org/arrayfire-python/). -``` -Using opencl backend -ArrayFire v3.0.1 (OpenCL, 64-bit Linux, build 17db1c9) -[0] AMD : Spectre --1- AMD : AMD A10-7850K Radeon R7, 12 Compute Cores 4C+8G - -[5 1 1 1] -0.4107 -0.8224 -0.9518 -0.1794 -0.4198 - -Minimum, Maximum: 0.17936542630195618 0.9517996311187744 -``` - -On an NVIDIA GPU: +## Example +```python +# Monte Carlo estimation of pi +def calc_pi_device(samples): + # Simple, array based API + # Generate uniformly distributed random numers + x = af.randu(samples) + y = af.randu(samples) + # Supports Just In Time Compilation + # The following line generates a single kernel + within_unit_circle = (x * x + y * y) < 1 + # Intuitive function names + return 4 * af.count(within_unit_circle) / samples ``` -Using cuda backend -ArrayFire v3.0.0 (CUDA, 64-bit Linux, build 86426db) -Platform: CUDA Toolkit 7, Driver: 346.46 -[0] Tesla K40c, 12288 MB, CUDA Compute 3.5 --1- GeForce GTX 750, 1024 MB, CUDA Compute 5.0 - -Generate a random matrix a: -[5 1 1 1] -0.7402 -0.9210 -0.0390 -0.9690 -0.9251 - -Minimum, Maximum: 0.039020489901304245 0.9689629077911377 -``` - -Fallback to CPU when CUDA and OpenCL are not availabe: -``` -Using cpu backend -ArrayFire v3.0.0 (CPU, 64-bit Linux, build 86426db) - -Generate a random matrix a: -[5 1 1 1] -0.0000 -0.1315 -0.7556 -0.4587 -0.5328 - -Minimum, Maximum: 7.825903594493866e-06 0.7556053400039673 -``` Choosing a particular backend can be done using `af.backend.set( backend_name )` where backend_name can be one of: "_cuda_", "_opencl_", or "_cpu_". The default device is chosen in the same order of preference. From 619de82c657ee99c62354f2ec297a169d6638959 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 24 Jun 2016 22:25:27 -0400 Subject: [PATCH 076/212] Fixing setup.py --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index c95e524e7..549b64aa0 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ ######################################################## from setuptools import setup, find_packages -from __af_version__ import full_version +#from __af_version__ import full_version #TODO: #1) Look for af libraries during setup @@ -20,7 +20,7 @@ author="Pavan Yalamanchili", author_email="pavan@arrayfire.com", name="arrayfire", - version=full_version, + version="3.3.20160624.post1", description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From 084f7c3337a08c843f1f5d21556c16de9e4da916 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 24 Jun 2016 22:38:30 -0400 Subject: [PATCH 077/212] Fixing bug in setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 7ca96a56b..b5b2ed290 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ author="Pavan Yalamanchili", author_email="pavan@arrayfire.com", name="arrayfire", - version="3.4.0" + version="3.4.0", description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From 0081fe9ad0e18b6c5a00200a0026e791454bd7e7 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 24 Jun 2016 22:52:58 -0400 Subject: [PATCH 078/212] Adding delimiters to functions in documentation --- docs/_static/style.css | 3 +++ docs/_templates/page.html | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 docs/_static/style.css create mode 100644 docs/_templates/page.html diff --git a/docs/_static/style.css b/docs/_static/style.css new file mode 100644 index 000000000..e4f24f884 --- /dev/null +++ b/docs/_static/style.css @@ -0,0 +1,3 @@ +dl { + border-top-style: solid; +} diff --git a/docs/_templates/page.html b/docs/_templates/page.html new file mode 100644 index 000000000..fb7091880 --- /dev/null +++ b/docs/_templates/page.html @@ -0,0 +1,3 @@ +{% extends "!page.html" %} + +{% set css_files = css_files + ["_static/style.css"] %} From af9854a8781eb090d9c80a20776cabeea553997a Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sat, 25 Jun 2016 00:03:35 -0400 Subject: [PATCH 079/212] Another minor change to style.css --- docs/_static/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_static/style.css b/docs/_static/style.css index e4f24f884..bef0f094c 100644 --- a/docs/_static/style.css +++ b/docs/_static/style.css @@ -1,3 +1,3 @@ -dl { +dl.function { border-top-style: solid; } From b65abb1fb4e5a16ccda1cca07ac2308553f98396 Mon Sep 17 00:00:00 2001 From: Lukas Bindreiter Date: Fri, 9 Sep 2016 10:49:42 +0200 Subject: [PATCH 080/212] Add self as parameter to all methods of class Feature --- arrayfire/features.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arrayfire/features.py b/arrayfire/features.py index d21471a0d..21705e260 100644 --- a/arrayfire/features.py +++ b/arrayfire/features.py @@ -30,7 +30,7 @@ def __init__(self, num=0): assert(isinstance(num, numbers.Number)) safe_call(backend.get().af_create_features(ct.pointer(self.feat), c_dim_t(num))) - def num_features(): + def num_features(self): """ Returns the number of features detected. """ @@ -38,7 +38,7 @@ def num_features(): safe_call(backend.get().af_get_features_num(ct.pointer(num), self.feat)) return num - def get_xpos(): + def get_xpos(self): """ Returns the x-positions of the features detected. """ @@ -46,7 +46,7 @@ def get_xpos(): safe_call(backend.get().af_get_features_xpos(ct.pointer(out.arr), self.feat)) return out - def get_ypos(): + def get_ypos(self): """ Returns the y-positions of the features detected. """ @@ -54,7 +54,7 @@ def get_ypos(): safe_call(backend.get().af_get_features_ypos(ct.pointer(out.arr), self.feat)) return out - def get_score(): + def get_score(self): """ Returns the scores of the features detected. """ @@ -62,7 +62,7 @@ def get_score(): safe_call(backend.get().af_get_features_score(ct.pointer(out.arr), self.feat)) return out - def get_orientation(): + def get_orientation(self): """ Returns the orientations of the features detected. """ @@ -70,7 +70,7 @@ def get_orientation(): safe_call(backend.get().af_get_features_orientation(ct.pointer(out.arr), self.feat)) return out - def get_size(): + def get_size(self): """ Returns the sizes of the features detected. """ From 726605c58b7bf6c54be87a7ca7b7cbbd92e43a50 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 11 Sep 2016 01:01:46 -0400 Subject: [PATCH 081/212] BUGFIX: array.H() now calls af_transpose with proper options --- arrayfire/array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 327fd6bee..beb2eb8ef 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -589,7 +589,7 @@ def H(self): """ Return the hermitian transpose of the array """ - return transpose(self, False) + return transpose(self, True) def dims(self): """ From 7b30010cb4e3dcf11c304d17229868c24df5ea26 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 11 Sep 2016 01:03:24 -0400 Subject: [PATCH 082/212] BUGFIX: Fixing typo in QR (was calling af_lu instead) --- arrayfire/lapack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrayfire/lapack.py b/arrayfire/lapack.py index 346cddb01..add6f555a 100644 --- a/arrayfire/lapack.py +++ b/arrayfire/lapack.py @@ -98,7 +98,7 @@ def qr(A): Q = Array() R = Array() T = Array() - safe_call(backend.get().af_lu(ct.pointer(Q.arr), ct.pointer(R.arr), ct.pointer(T.arr), A.arr)) + safe_call(backend.get().af_qr(ct.pointer(Q.arr), ct.pointer(R.arr), ct.pointer(T.arr), A.arr)) return Q,R,T def qr_inplace(A): From 2196fe51901095144ab33308d18076f441bfe377 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 11 Sep 2016 02:16:51 -0400 Subject: [PATCH 083/212] BUGFIX: Fix conversion between numpy and arrayfire arrays --- arrayfire/interop.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arrayfire/interop.py b/arrayfire/interop.py index e512b7548..4f5e39d22 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -26,6 +26,18 @@ AF_NUMPY_FOUND=True + _nptype_to_aftype = {'f4' : Dtype.f32, + 'f8' : Dtype.f64, + 'b1' : Dtype.b8, + 'u1' : Dtype.u8, + 'i4' : Dtype.s32, + 's4' : Dtype.u32, + 'i8' : Dtype.s64, + 's8' : Dtype.u64, + 'c8' : Dtype.c32, + 'c16' : Dtype.c64} + + def np_to_af_array(np_arr): """ Convert numpy.ndarray to arrayfire.Array. @@ -41,7 +53,7 @@ def np_to_af_array(np_arr): in_shape = np_arr.shape in_ptr = np_arr.ctypes.data_as(ct.c_void_p) - in_dtype = np_arr.dtype.char + in_dtype = _nptype_to_aftype[np_arr.dtype.str[1:]] if (np_arr.flags['F_CONTIGUOUS']): return Array(in_ptr, in_shape, in_dtype) From fb73d7e70f9e6380dc4e2fabd0bcd7b06e901655 Mon Sep 17 00:00:00 2001 From: Carlos De la Guardia Date: Thu, 15 Sep 2016 18:02:13 -0700 Subject: [PATCH 084/212] Corrected 'set_backend' command in readme. Now the readme matches the online documentation [here](http://arrayfire.org/arrayfire-python/). --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c0b81005e..3e83f9901 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ def calc_pi_device(samples): ``` -Choosing a particular backend can be done using `af.backend.set( backend_name )` where backend_name can be one of: "_cuda_", "_opencl_", or "_cpu_". The default device is chosen in the same order of preference. +Choosing a particular backend can be done using `af.set_backend(name)` where name is either "_cuda_", "_opencl_", or "_cpu_". The default device is chosen in the same order of preference. ## Requirements From 0002f8d0fe01c060cbf5801b7cd9423e97b128e5 Mon Sep 17 00:00:00 2001 From: Ghislain Antony Vaillant Date: Fri, 16 Sep 2016 09:56:01 +0100 Subject: [PATCH 085/212] Fix standalone tests module. Gbp-Pq: Name Fix-standalone-tests-module.patch --- tests/__init__.py | 8 ++++++++ tests/__main__.py | 4 +++- tests/simple_tests.py | 4 +++- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/__init__.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..be7669881 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,8 @@ +####################################################### +# Copyright (c) 2015, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## diff --git a/tests/__main__.py b/tests/__main__.py index 5b1e4738c..468396566 100644 --- a/tests/__main__.py +++ b/tests/__main__.py @@ -7,8 +7,10 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## +from __future__ import absolute_import + import sys -from simple_tests import * +from .simple_tests import * tests = {} tests['simple'] = simple.tests diff --git a/tests/simple_tests.py b/tests/simple_tests.py index 370b16230..603ae9f37 100755 --- a/tests/simple_tests.py +++ b/tests/simple_tests.py @@ -9,7 +9,9 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -import simple +from __future__ import absolute_import + +from . import simple import sys if __name__ == "__main__": From da596b0b23935bd356730d158e0bc0cd99f881f7 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 16 Sep 2016 21:38:06 -0400 Subject: [PATCH 086/212] Moving tests to be part of the arrayfire module - They can now be tested using "python -m arrayfire.tests" --- {tests => arrayfire/tests}/__init__.py | 0 {tests => arrayfire/tests}/__main__.py | 0 {tests => arrayfire/tests}/simple/__init__.py | 0 {tests => arrayfire/tests}/simple/_util.py | 0 {tests => arrayfire/tests}/simple/algorithm.py | 0 {tests => arrayfire/tests}/simple/arith.py | 0 {tests => arrayfire/tests}/simple/array_test.py | 0 {tests => arrayfire/tests}/simple/blas.py | 0 {tests => arrayfire/tests}/simple/data.py | 0 {tests => arrayfire/tests}/simple/device.py | 0 {tests => arrayfire/tests}/simple/image.py | 0 {tests => arrayfire/tests}/simple/index.py | 0 {tests => arrayfire/tests}/simple/lapack.py | 0 {tests => arrayfire/tests}/simple/signal.py | 0 {tests => arrayfire/tests}/simple/statistics.py | 0 {tests => arrayfire/tests}/simple_tests.py | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename {tests => arrayfire/tests}/__init__.py (100%) rename {tests => arrayfire/tests}/__main__.py (100%) rename {tests => arrayfire/tests}/simple/__init__.py (100%) rename {tests => arrayfire/tests}/simple/_util.py (100%) rename {tests => arrayfire/tests}/simple/algorithm.py (100%) rename {tests => arrayfire/tests}/simple/arith.py (100%) rename {tests => arrayfire/tests}/simple/array_test.py (100%) rename {tests => arrayfire/tests}/simple/blas.py (100%) rename {tests => arrayfire/tests}/simple/data.py (100%) rename {tests => arrayfire/tests}/simple/device.py (100%) rename {tests => arrayfire/tests}/simple/image.py (100%) rename {tests => arrayfire/tests}/simple/index.py (100%) rename {tests => arrayfire/tests}/simple/lapack.py (100%) rename {tests => arrayfire/tests}/simple/signal.py (100%) rename {tests => arrayfire/tests}/simple/statistics.py (100%) rename {tests => arrayfire/tests}/simple_tests.py (100%) diff --git a/tests/__init__.py b/arrayfire/tests/__init__.py similarity index 100% rename from tests/__init__.py rename to arrayfire/tests/__init__.py diff --git a/tests/__main__.py b/arrayfire/tests/__main__.py similarity index 100% rename from tests/__main__.py rename to arrayfire/tests/__main__.py diff --git a/tests/simple/__init__.py b/arrayfire/tests/simple/__init__.py similarity index 100% rename from tests/simple/__init__.py rename to arrayfire/tests/simple/__init__.py diff --git a/tests/simple/_util.py b/arrayfire/tests/simple/_util.py similarity index 100% rename from tests/simple/_util.py rename to arrayfire/tests/simple/_util.py diff --git a/tests/simple/algorithm.py b/arrayfire/tests/simple/algorithm.py similarity index 100% rename from tests/simple/algorithm.py rename to arrayfire/tests/simple/algorithm.py diff --git a/tests/simple/arith.py b/arrayfire/tests/simple/arith.py similarity index 100% rename from tests/simple/arith.py rename to arrayfire/tests/simple/arith.py diff --git a/tests/simple/array_test.py b/arrayfire/tests/simple/array_test.py similarity index 100% rename from tests/simple/array_test.py rename to arrayfire/tests/simple/array_test.py diff --git a/tests/simple/blas.py b/arrayfire/tests/simple/blas.py similarity index 100% rename from tests/simple/blas.py rename to arrayfire/tests/simple/blas.py diff --git a/tests/simple/data.py b/arrayfire/tests/simple/data.py similarity index 100% rename from tests/simple/data.py rename to arrayfire/tests/simple/data.py diff --git a/tests/simple/device.py b/arrayfire/tests/simple/device.py similarity index 100% rename from tests/simple/device.py rename to arrayfire/tests/simple/device.py diff --git a/tests/simple/image.py b/arrayfire/tests/simple/image.py similarity index 100% rename from tests/simple/image.py rename to arrayfire/tests/simple/image.py diff --git a/tests/simple/index.py b/arrayfire/tests/simple/index.py similarity index 100% rename from tests/simple/index.py rename to arrayfire/tests/simple/index.py diff --git a/tests/simple/lapack.py b/arrayfire/tests/simple/lapack.py similarity index 100% rename from tests/simple/lapack.py rename to arrayfire/tests/simple/lapack.py diff --git a/tests/simple/signal.py b/arrayfire/tests/simple/signal.py similarity index 100% rename from tests/simple/signal.py rename to arrayfire/tests/simple/signal.py diff --git a/tests/simple/statistics.py b/arrayfire/tests/simple/statistics.py similarity index 100% rename from tests/simple/statistics.py rename to arrayfire/tests/simple/statistics.py diff --git a/tests/simple_tests.py b/arrayfire/tests/simple_tests.py similarity index 100% rename from tests/simple_tests.py rename to arrayfire/tests/simple_tests.py From 135b6d5130b4731b0e494eaf0d3d3c047c74810d Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 16 Sep 2016 21:56:43 -0400 Subject: [PATCH 087/212] Updating setup.py to reflect package structure --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b5b2ed290..d229aa831 100644 --- a/setup.py +++ b/setup.py @@ -24,5 +24,5 @@ description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", - packages=['arrayfire'], + packages=find_packages() ) From a796a89e7aeb3d654296e1d6882df197353843f1 Mon Sep 17 00:00:00 2001 From: syurkevi Date: Tue, 5 Jul 2016 18:05:22 -0400 Subject: [PATCH 088/212] initial v34 api additions to python wrapper --- arrayfire/algorithm.py | 57 ++++++++++++++++++++++++++++++++++++++++++ arrayfire/image.py | 22 ++++++++++++++++ arrayfire/library.py | 19 ++++++++++++++ arrayfire/signal.py | 12 +++++++++ 4 files changed, 110 insertions(+) diff --git a/arrayfire/algorithm.py b/arrayfire/algorithm.py index 6701d96a8..50c9b618d 100644 --- a/arrayfire/algorithm.py +++ b/arrayfire/algorithm.py @@ -299,6 +299,63 @@ def accum(a, dim=0): """ return _parallel_dim(a, dim, backend.get().af_accum) +def scan(a, dim=0, op=BINARYOP.BINARY_ADD, inclusive_scan=True): + """ + Generalized scan of an array. + + Parameters + ---------- + a : af.Array + Multi dimensional arrayfire array. + + dim : optional: int. default: 0 + Dimension along which the scan is performed. + + op : optional: af.BINARYOP. default: af.BINARYOP.BINARY_ADD. + - Interpolation method used for resizing. + + inclusive_scan: optional: bool. default: True + Specifies if the scan is inclusive + + Returns + --------- + out : af.Array + - will contain scan of input. + """ + out = Array() + safe_call(backend.get().af_scan(ct.pointer(out.arr), a.arr, dim, op, inclusive_scan)) + return out + +def scan_by_key(key, a, dim=0, op=BINARYOP.BINARY_ADD, inclusive_scan=True): + """ + Generalized scan by key of an array. + + Parameters + ---------- + key : af.Array + key array. + + a : af.Array + Multi dimensional arrayfire array. + + dim : optional: int. default: 0 + Dimension along which the scan is performed. + + op : optional: af.BINARYOP. default: af.BINARYOP.BINARY_ADD. + - Interpolation method used for resizing. + + inclusive_scan: optional: bool. default: True + Specifies if the scan is inclusive + + Returns + --------- + out : af.Array + - will contain scan of input. + """ + out = Array() + safe_call(backend.get().af_scan_by_key(ct.pointer(out.arr), key.arr, a.arr, dim, op, inclusive_scan)) + return out + def where(a): """ Find the indices of non zero elements diff --git a/arrayfire/image.py b/arrayfire/image.py index ac4b8ed19..94a424a21 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -1198,6 +1198,28 @@ def rgb2ycbcr(image, standard=YCC_STD.BT_601): safe_call(backend.get().af_rgb2ycbcr(ct.pointer(out.arr), image.arr, standard.value)) return out +def moments(image, moment = MOMENT.MOMENT_FIRST_ORDER): + """ + Calculate image moments. + + Parameters + ---------- + image : af.Array + - A 2 D arrayfire array representing an image, or + - A multi dimensional array representing batch of images. + + moment : optional: af.MOMENT. default: af.MOMENT.MOMENT_FIRST_ORDER. + - Moment(s) to calculate + + Returns + --------- + out : af.Array + - array containing requested moment(s) of each image + """ + output = Array() + safe_call(backend.get().af_moments(ct.pointer(output.arr), image.arr, moment.value)) + return output + def is_image_io_available(): """ Function to check if the arrayfire library was built with Image IO support. diff --git a/arrayfire/library.py b/arrayfire/library.py index ff09f051d..79aa82343 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -349,6 +349,25 @@ class MARKER(_Enum): PLUS = _Enum_Type(6) STAR = _Enum_Type(7) +class MOMENT(_Enum): + """ + Image Moments + """ + MOMENT_M00 = _Enum_Type(1) + MOMENT_M01 = _Enum_Type(2) + MOMENT_M10 = _Enum_Type(4) + MOMENT_M11 = _Enum_Type(8) + MOMENT_FIRST_ORDER = _Enum_Type(15) + +class BINARYOP(_Enum): + """ + Binary Operators + """ + BINARY_ADD = _Enum_Type(0) + BINARY_MUL = _Enum_Type(1) + BINARY_MIN = _Enum_Type(2) + BINARY_MAX = _Enum_Type(3) + def _setup(): import platform import os diff --git a/arrayfire/signal.py b/arrayfire/signal.py index fe377ed1c..78f2c6f2a 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -1264,3 +1264,15 @@ def iir(B, A, X): Y = Array() safe_call(backend.get().af_iir(ct.pointer(Y.arr), B.arr, A.arr, X.arr)) return Y + +def set_fft_plan_cache_size(cache_size): + """ + Sets plan cache size. + + Parameters + ---------- + + cache_size : scalar + the number of plans that shall be cached + """ + safe_call(backend.get().af_set_fft_plan_cache_size(ct.c_size_t(cache_size))) From 204d9000ea2080afeb5f1591a5b7bfcfab33739d Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 22 Sep 2016 14:12:46 -0700 Subject: [PATCH 089/212] Cleaning up scan, scan_by_key and moments - Use consistent naming scheme for enums - Fixed minor bugs when passing enum to the C function --- arrayfire/algorithm.py | 24 ++++++++++++++++-------- arrayfire/image.py | 11 ++++++++--- arrayfire/library.py | 36 +++++++++++++++++++++--------------- 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/arrayfire/algorithm.py b/arrayfire/algorithm.py index 50c9b618d..a219ea663 100644 --- a/arrayfire/algorithm.py +++ b/arrayfire/algorithm.py @@ -299,7 +299,7 @@ def accum(a, dim=0): """ return _parallel_dim(a, dim, backend.get().af_accum) -def scan(a, dim=0, op=BINARYOP.BINARY_ADD, inclusive_scan=True): +def scan(a, dim=0, op=BINARYOP.ADD, inclusive_scan=True): """ Generalized scan of an array. @@ -311,8 +311,12 @@ def scan(a, dim=0, op=BINARYOP.BINARY_ADD, inclusive_scan=True): dim : optional: int. default: 0 Dimension along which the scan is performed. - op : optional: af.BINARYOP. default: af.BINARYOP.BINARY_ADD. - - Interpolation method used for resizing. + op : optional: af.BINARYOP. default: af.BINARYOP.ADD. + Binary option the scan algorithm uses. Can be one of: + - af.BINARYOP.ADD + - af.BINARYOP.MUL + - af.BINARYOP.MIN + - af.BINARYOP.MAX inclusive_scan: optional: bool. default: True Specifies if the scan is inclusive @@ -323,10 +327,10 @@ def scan(a, dim=0, op=BINARYOP.BINARY_ADD, inclusive_scan=True): - will contain scan of input. """ out = Array() - safe_call(backend.get().af_scan(ct.pointer(out.arr), a.arr, dim, op, inclusive_scan)) + safe_call(backend.get().af_scan(ct.pointer(out.arr), a.arr, dim, op.value, inclusive_scan)) return out -def scan_by_key(key, a, dim=0, op=BINARYOP.BINARY_ADD, inclusive_scan=True): +def scan_by_key(key, a, dim=0, op=BINARYOP.ADD, inclusive_scan=True): """ Generalized scan by key of an array. @@ -341,8 +345,12 @@ def scan_by_key(key, a, dim=0, op=BINARYOP.BINARY_ADD, inclusive_scan=True): dim : optional: int. default: 0 Dimension along which the scan is performed. - op : optional: af.BINARYOP. default: af.BINARYOP.BINARY_ADD. - - Interpolation method used for resizing. + op : optional: af.BINARYOP. default: af.BINARYOP.ADD. + Binary option the scan algorithm uses. Can be one of: + - af.BINARYOP.ADD + - af.BINARYOP.MUL + - af.BINARYOP.MIN + - af.BINARYOP.MAX inclusive_scan: optional: bool. default: True Specifies if the scan is inclusive @@ -353,7 +361,7 @@ def scan_by_key(key, a, dim=0, op=BINARYOP.BINARY_ADD, inclusive_scan=True): - will contain scan of input. """ out = Array() - safe_call(backend.get().af_scan_by_key(ct.pointer(out.arr), key.arr, a.arr, dim, op, inclusive_scan)) + safe_call(backend.get().af_scan_by_key(ct.pointer(out.arr), key.arr, a.arr, dim, op.value, inclusive_scan)) return out def where(a): diff --git a/arrayfire/image.py b/arrayfire/image.py index 94a424a21..842ce22fd 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -1198,7 +1198,7 @@ def rgb2ycbcr(image, standard=YCC_STD.BT_601): safe_call(backend.get().af_rgb2ycbcr(ct.pointer(out.arr), image.arr, standard.value)) return out -def moments(image, moment = MOMENT.MOMENT_FIRST_ORDER): +def moments(image, moment = MOMENT.FIRST_ORDER): """ Calculate image moments. @@ -1208,8 +1208,13 @@ def moments(image, moment = MOMENT.MOMENT_FIRST_ORDER): - A 2 D arrayfire array representing an image, or - A multi dimensional array representing batch of images. - moment : optional: af.MOMENT. default: af.MOMENT.MOMENT_FIRST_ORDER. - - Moment(s) to calculate + moment : optional: af.MOMENT. default: af.MOMENT.FIRST_ORDER. + Moment(s) to calculate. Can be one of: + - af.MOMENT.M00 + - af.MOMENT.M01 + - af.MOMENT.M10 + - af.MOMENT.M11 + - af.MOMENT.FIRST_ORDER Returns --------- diff --git a/arrayfire/library.py b/arrayfire/library.py index 79aa82343..ef108d4d6 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -113,11 +113,16 @@ class INTERP(_Enum): """ Interpolation method """ - NEAREST = _Enum_Type(0) - LINEAR = _Enum_Type(1) - BILINEAR = _Enum_Type(2) - CUBIC = _Enum_Type(3) - LOWER = _Enum_Type(4) + NEAREST = _Enum_Type(0) + LINEAR = _Enum_Type(1) + BILINEAR = _Enum_Type(2) + CUBIC = _Enum_Type(3) + LOWER = _Enum_Type(4) + LINEAR_COSINE = _Enum_Type(5) + BILINEAR_COSINE = _Enum_Type(6) + BICUBIC = _Enum_Type(7) + CUBIC_SPLINE = _Enum_Type(8) + BICUBIC_SPLINE = _Enum_Type(9) class PAD(_Enum): """ @@ -351,22 +356,23 @@ class MARKER(_Enum): class MOMENT(_Enum): """ - Image Moments + Image Moments types """ - MOMENT_M00 = _Enum_Type(1) - MOMENT_M01 = _Enum_Type(2) - MOMENT_M10 = _Enum_Type(4) - MOMENT_M11 = _Enum_Type(8) - MOMENT_FIRST_ORDER = _Enum_Type(15) + M00 = _Enum_Type(1) + M01 = _Enum_Type(2) + M10 = _Enum_Type(4) + M11 = _Enum_Type(8) + FIRST_ORDER = _Enum_Type(15) class BINARYOP(_Enum): """ Binary Operators """ - BINARY_ADD = _Enum_Type(0) - BINARY_MUL = _Enum_Type(1) - BINARY_MIN = _Enum_Type(2) - BINARY_MAX = _Enum_Type(3) + ADD = _Enum_Type(0) + MUL = _Enum_Type(1) + MIN = _Enum_Type(2) + MAX = _Enum_Type(3) + def _setup(): import platform From 48803553cb872d45f426b2299f161da26ce33a0f Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 22 Sep 2016 14:14:13 -0700 Subject: [PATCH 090/212] Adding tests for scan and scan_by_key --- arrayfire/tests/simple/algorithm.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arrayfire/tests/simple/algorithm.py b/arrayfire/tests/simple/algorithm.py index f68e354e4..75ab814d4 100644 --- a/arrayfire/tests/simple/algorithm.py +++ b/arrayfire/tests/simple/algorithm.py @@ -16,6 +16,7 @@ def simple_algorithm(verbose = False): print_func = _util.print_func(verbose) a = af.randu(3, 3) + k = af.constant(1, 3, 3, dtype=af.Dtype.u32) print_func(af.sum(a), af.product(a), af.min(a), af.max(a), af.count(a), af.any_true(a), af.all_true(a)) @@ -44,6 +45,12 @@ def simple_algorithm(verbose = False): display_func(af.accum(a, 0)) display_func(af.accum(a, 1)) + display_func(af.scan(a, 0, af.BINARYOP.ADD)) + display_func(af.scan(a, 1, af.BINARYOP.MAX)) + + display_func(af.scan_by_key(k, a, 0, af.BINARYOP.ADD)) + display_func(af.scan_by_key(k, a, 1, af.BINARYOP.MAX)) + display_func(af.sort(a, is_ascending=True)) display_func(af.sort(a, is_ascending=False)) From bdfed50cdffdf04f6bbaadb773cf3440cfca3d3a Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 22 Sep 2016 14:14:35 -0700 Subject: [PATCH 091/212] Add missing enums from arrayfire 3.4 release --- arrayfire/library.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arrayfire/library.py b/arrayfire/library.py index ef108d4d6..cbf85f2e1 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -373,6 +373,25 @@ class BINARYOP(_Enum): MIN = _Enum_Type(2) MAX = _Enum_Type(3) +class RANDOM_ENGINE(_Enum): + """ + Random engine types + """ + PHILOX_4X32_10 = _Enum_Type(100) + THREEFRY_2X32_16 = _Enum_Type(200) + MERSENNE_GP11213 = _Enum_Type(300) + PHILOX = PHILOX_4X32_10 + THREEFRY = THREEFRY_2X32_16 + DEFAULT = PHILOX + +class STORAGE(_Enum): + """ + Matrix Storage types + """ + DENSE = _Enum_Type(0) + CSR = _Enum_Type(1) + CSC = _Enum_Type(2) + COO = _Enum_Type(3) def _setup(): import platform From 596951d9ecc16c74c446f1b21ebe3644f3c39067 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 22 Sep 2016 14:28:34 -0700 Subject: [PATCH 092/212] FEAT: Adding clamp function and relevant tests --- arrayfire/arith.py | 38 +++++++++++++++++++++++++++++++++ arrayfire/tests/simple/arith.py | 5 +++++ 2 files changed, 43 insertions(+) diff --git a/arrayfire/arith.py b/arrayfire/arith.py index 4c73e59bf..3b397c4a5 100644 --- a/arrayfire/arith.py +++ b/arrayfire/arith.py @@ -126,6 +126,44 @@ def maxof(lhs, rhs): """ return _arith_binary_func(lhs, rhs, backend.get().af_maxof) +def clamp(val, low, high): + """ + Clamp the input value between low and high + + + Parameters + ---------- + val : af.Array + Multi dimensional arrayfire array to be clamped. + + low : af.Array or scalar + Multi dimensional arrayfire array or a scalar number denoting the lower value(s). + + high : af.Array or scalar + Multi dimensional arrayfire array or a scalar number denoting the higher value(s). + """ + out = Array() + + is_low_array = isinstance(low, Array) + is_high_array = isinstance(high, Array) + + vdims = dim4_to_tuple(val.dims()) + vty = val.type() + + if not is_low_array: + low_arr = constant_array(low, vdims[0], vdims[1], vdims[2], vdims[3], vty) + else: + low_arr = low.arr + + if not is_high_array: + high_arr = constant_array(high, vdims[0], vdims[1], vdims[2], vdims[3], vty) + else: + high_arr = high.arr + + safe_call(backend.get().af_clamp(ct.pointer(out.arr), val.arr, low_arr, high_arr, _bcast_var.get())) + + return out + def rem(lhs, rhs): """ Find the remainder. diff --git a/arrayfire/tests/simple/arith.py b/arrayfire/tests/simple/arith.py index f8407c17f..84c291aec 100644 --- a/arrayfire/tests/simple/arith.py +++ b/arrayfire/tests/simple/arith.py @@ -134,6 +134,11 @@ def simple_arith(verbose = False): display_func(af.cast(a, af.Dtype.c32)) display_func(af.maxof(a,b)) display_func(af.minof(a,b)) + + display_func(af.clamp(a, 0, 1)) + display_func(af.clamp(a, 0, b)) + display_func(af.clamp(a, b, 1)) + display_func(af.rem(a,b)) a = af.randu(3,3) - 0.5 From d8db269942e92a9eeab482d1dc5b3d6788e31122 Mon Sep 17 00:00:00 2001 From: pradeep Date: Sun, 18 Sep 2016 22:17:39 +0530 Subject: [PATCH 093/212] Check and load a functional backend Though libraries of a given backend can be present on the target machine, there can be scenarios where a compatible hardware device is not available. In such cases, backend loader checks if current selected backend has a device ready for use. If no appropriate device exists, the next backend in the priority list is checked for same criteria. This process is repeated until a working backend is found. In the event that no functional backend is found, the program throws a runtime error. --- arrayfire/library.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index cbf85f2e1..93d3cd548 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -534,9 +534,23 @@ def __init__(self): except: pass + c_dim4 = c_dim_t*4 + + out = c_dim_t(0) + dims = c_dim4(10, 10, 10, 10) + + for key, value in self.__clibs: + err = value.af_randu(ct.pointer(out), 4, ct.pointer(dims), 0) + if (err == ERR.NONE.value): + if (self.__name != key): + self.__name = key + break + else: + self.__name = None + pass + if (self.__name is None): - raise RuntimeError("Could not load any ArrayFire libraries.\n" + - more_info_str) + raise RuntimeError("Could not load any ArrayFire libraries.\n" + more_info_str) def get_id(self, name): return self.__backend_name_map[name] From 2f8503d8a60c402f751a065334d7ce7065dbfdb0 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 22 Sep 2016 14:45:48 -0700 Subject: [PATCH 094/212] Check if arrayfire can be run immediately after loading the library --- arrayfire/library.py | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index 93d3cd548..fc76c9fa8 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -521,6 +521,10 @@ def __init__(self): except: pass + c_dim4 = c_dim_t*4 + out = ct.c_void_p(0) + dims = c_dim4(10, 10, 1, 1) + # Iterate in reverse order of preference for name in ('cpu', 'opencl', 'cuda', ''): libnames = self.__libname(name) @@ -528,27 +532,16 @@ def __init__(self): try: ct.cdll.LoadLibrary(libname) __name = 'unified' if name == '' else name - self.__clibs[__name] = ct.CDLL(libname) - self.__name = __name + clib = ct.CDLL(libname) + self.__clibs[__name] = clib + err = clib.af_randu(ct.pointer(out), 4, ct.pointer(dims), Dtype.f32.value) + if (err == ERR.NONE.value): + self.__name = __name + clib.af_release_array(out) break; except: pass - c_dim4 = c_dim_t*4 - - out = c_dim_t(0) - dims = c_dim4(10, 10, 10, 10) - - for key, value in self.__clibs: - err = value.af_randu(ct.pointer(out), 4, ct.pointer(dims), 0) - if (err == ERR.NONE.value): - if (self.__name != key): - self.__name = key - break - else: - self.__name = None - pass - if (self.__name is None): raise RuntimeError("Could not load any ArrayFire libraries.\n" + more_info_str) From 7594769fd905e1aff0a7f1518cf2283bc1c27710 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 22 Sep 2016 15:26:09 -0700 Subject: [PATCH 095/212] Adding functions from array.h and device.h - is_sparse - is_locked_array - modified eval to use af_eval_multiple - set_manual_eval_flag - get_manual_eval_flag - Added necessary tests --- arrayfire/array.py | 8 +++ arrayfire/device.py | 100 ++++++++++++++++++++++++--- arrayfire/tests/simple/array_test.py | 2 + arrayfire/tests/simple/device.py | 19 +++++ 4 files changed, 119 insertions(+), 10 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 2c2eda464..4e27af691 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -667,6 +667,14 @@ def is_vector(self): safe_call(backend.get().af_is_vector(ct.pointer(res), self.arr)) return res.value + def is_sparse(self): + """ + Check if the array is a sparse matrix. + """ + res = ct.c_bool(False) + safe_call(backend.get().af_is_sparse(ct.pointer(res), self.arr)) + return res.value + def is_complex(self): """ Check if the array is of complex type. diff --git a/arrayfire/device.py b/arrayfire/device.py index 0a303851e..b13989b65 100644 --- a/arrayfire/device.py +++ b/arrayfire/device.py @@ -163,24 +163,87 @@ def sync(device=None): safe_call(backend.get().af_sync(dev)) def __eval(*args): - for A in args: - if isinstance(A, tuple): - __eval(*A) - if isinstance(A, list): - __eval(*A) - if isinstance(A, Array): - safe_call(backend.get().af_eval(A.arr)) + nargs = len(args) + if (nargs == 1): + safe_call(backend.get().af_eval(args[0].arr)) + else: + c_void_p_n = ct.c_void_p * nargs + arrs = c_void_p_n() + for n in range(nargs): + arrs[n] = args[n].arr + safe_call(backend.get().af_eval_multiple(ct.c_int(nargs), ct.pointer(arrs))) + return def eval(*args): """ - Evaluate the input + Evaluate one or more inputs together Parameters ----------- args : arguments to be evaluated + + Note + ----- + + All the input arrays to this function should be of the same size. + + Examples + -------- + + >>> a = af.constant(1, 3, 3) + >>> b = af.constant(2, 3, 3) + >>> c = a + b + >>> d = a - b + >>> af.eval(c, d) # A single kernel is launched here + >>> c + arrayfire.Array() + Type: float + [3 3 1 1] + 3.0000 3.0000 3.0000 + 3.0000 3.0000 3.0000 + 3.0000 3.0000 3.0000 + + >>> d + arrayfire.Array() + Type: float + [3 3 1 1] + -1.0000 -1.0000 -1.0000 + -1.0000 -1.0000 -1.0000 + -1.0000 -1.0000 -1.0000 + """ + for arg in args: + if not isinstance(arg, Array): + raise RuntimeError("All inputs to eval must be of type arrayfire.Array") + + __eval(*args) + +def set_manual_eval_flag(flag): + """ + Tells the backend JIT engine to disable heuristics for determining when to evaluate a JIT tree. + + Parameters + ---------- + + flag : optional: bool. + - Specifies if the heuristic evaluation of the JIT tree needs to be disabled. + + Note + ---- + This does not affect the evaluation that occurs when a non JIT function forces the evaluation. """ + safe_call(backend.get().af_set_manual_eval_flag(flag)) - __eval(args) +def get_manual_eval_flag(): + """ + Query the backend JIT engine to see if the user disabled heuristic evaluation of the JIT tree. + + Note + ---- + This does not affect the evaluation that occurs when a non JIT function forces the evaluation. + """ + res = ct.c_bool(False) + safe_call(backend.get().af_get_manual_eval_flag(ct.pointer(res))) + return res.value def device_mem_info(): """ @@ -258,10 +321,27 @@ def lock_array(a): Note ----- - - The device pointer of `a` is not freed by memory manager until `unlock_device_ptr()` is called. + - The device pointer of `a` is not freed by memory manager until `unlock_array()` is called. """ safe_call(backend.get().af_lock_array(a.arr)) +def is_locked_array(a): + """ + Check if the input array is locked by the user. + + Parameters + ---------- + a: af.Array + - A multi dimensional arrayfire array. + + Returns + ----------- + A bool specifying if the input array is locked. + """ + res = ct.c_bool(False) + safe_call(backend.get().af_is_locked_array(ct.pointer(res), a.arr)) + return res.value + def unlock_device_ptr(a): """ This functions is deprecated. Please use unlock_array instead. diff --git a/arrayfire/tests/simple/array_test.py b/arrayfire/tests/simple/array_test.py index 1aec93494..0c6ab5262 100644 --- a/arrayfire/tests/simple/array_test.py +++ b/arrayfire/tests/simple/array_test.py @@ -60,4 +60,6 @@ def simple_array(verbose=False): print_func(arr) print_func(lst) + print_func(a.is_sparse()) + _util.tests['array'] = simple_array diff --git a/arrayfire/tests/simple/device.py b/arrayfire/tests/simple/device.py index 925add294..279fa3168 100644 --- a/arrayfire/tests/simple/device.py +++ b/arrayfire/tests/simple/device.py @@ -51,4 +51,23 @@ def simple_device(verbose=False): af.lock_array(c) af.unlock_array(c) + a = af.constant(1, 3, 3) + b = af.constant(2, 3, 3) + af.eval(a) + af.eval(b) + print_func(a) + print_func(b) + c = a + b + d = a - b + af.eval(c, d) + print_func(c) + print_func(d) + + print_func(af.set_manual_eval_flag(True)) + assert(af.get_manual_eval_flag() == True) + print_func(af.set_manual_eval_flag(False)) + assert(af.get_manual_eval_flag() == False) + + display_func(af.is_locked_array(a)) + _util.tests['device'] = simple_device From fe18684550281f9fedfcaf7a76badba177a14aaa Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 23 Sep 2016 14:34:55 -0700 Subject: [PATCH 096/212] Adding random engine class and relavent methods - Also added necessary tests --- arrayfire/data.py | 100 +------------ arrayfire/features.py | 2 + arrayfire/random.py | 232 +++++++++++++++++++++++++++++++ arrayfire/tests/simple/data.py | 10 -- arrayfire/tests/simple/random.py | 38 +++++ 5 files changed, 273 insertions(+), 109 deletions(-) create mode 100644 arrayfire/random.py create mode 100644 arrayfire/tests/simple/random.py diff --git a/arrayfire/data.py b/arrayfire/data.py index 0df045fca..786d64902 100644 --- a/arrayfire/data.py +++ b/arrayfire/data.py @@ -16,6 +16,7 @@ from .array import * from .util import * from .util import _is_number +from .random import randu, randn, set_seed, get_seed def constant(val, d0, d1=None, d2=None, d3=None, dtype=Dtype.f32): """ @@ -186,105 +187,6 @@ def iota(d0, d1=None, d2=None, d3=None, dim=-1, tile_dims=None, dtype=Dtype.f32) 4, ct.pointer(tdims), dtype.value)) return out -def randu(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32): - """ - Create a multi dimensional array containing values from a uniform distribution. - - Parameters - ---------- - d0 : int. - Length of first dimension. - - d1 : optional: int. default: None. - Length of second dimension. - - d2 : optional: int. default: None. - Length of third dimension. - - d3 : optional: int. default: None. - Length of fourth dimension. - - dtype : optional: af.Dtype. default: af.Dtype.f32. - Data type of the array. - - Returns - ------- - - out : af.Array - Multi dimensional array whose elements are sampled uniformly between [0, 1]. - - If d1 is None, `out` is 1D of size (d0,). - - If d1 is not None and d2 is None, `out` is 2D of size (d0, d1). - - If d1 and d2 are not None and d3 is None, `out` is 3D of size (d0, d1, d2). - - If d1, d2, d3 are all not None, `out` is 4D of size (d0, d1, d2, d3). - """ - out = Array() - dims = dim4(d0, d1, d2, d3) - - safe_call(backend.get().af_randu(ct.pointer(out.arr), 4, ct.pointer(dims), dtype.value)) - return out - -def randn(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32): - """ - Create a multi dimensional array containing values from a normal distribution. - - Parameters - ---------- - d0 : int. - Length of first dimension. - - d1 : optional: int. default: None. - Length of second dimension. - - d2 : optional: int. default: None. - Length of third dimension. - - d3 : optional: int. default: None. - Length of fourth dimension. - - dtype : optional: af.Dtype. default: af.Dtype.f32. - Data type of the array. - - Returns - ------- - - out : af.Array - Multi dimensional array whose elements are sampled from a normal distribution with mean 0 and sigma of 1. - - If d1 is None, `out` is 1D of size (d0,). - - If d1 is not None and d2 is None, `out` is 2D of size (d0, d1). - - If d1 and d2 are not None and d3 is None, `out` is 3D of size (d0, d1, d2). - - If d1, d2, d3 are all not None, `out` is 4D of size (d0, d1, d2, d3). - """ - - out = Array() - dims = dim4(d0, d1, d2, d3) - - safe_call(backend.get().af_randn(ct.pointer(out.arr), 4, ct.pointer(dims), dtype.value)) - return out - -def set_seed(seed=0): - """ - Set the seed for the random number generator. - - Parameters - ---------- - seed: int. - Seed for the random number generator - """ - safe_call(backend.get().af_set_seed(ct.c_ulonglong(seed))) - -def get_seed(): - """ - Get the seed for the random number generator. - - Returns - ---------- - seed: int. - Seed for the random number generator - """ - seed = ct.c_ulonglong(0) - safe_call(backend.get().af_get_seed(ct.pointer(seed))) - return seed.value - def identity(d0, d1, d2=None, d3=None, dtype=Dtype.f32): """ Create an identity matrix or batch of identity matrices. diff --git a/arrayfire/features.py b/arrayfire/features.py index 21705e260..6e006afcc 100644 --- a/arrayfire/features.py +++ b/arrayfire/features.py @@ -6,9 +6,11 @@ # The complete license agreement can be obtained at: # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## + """ Features class used for Computer Vision algorithms. """ + from .library import * from .array import * import numbers diff --git a/arrayfire/random.py b/arrayfire/random.py new file mode 100644 index 000000000..60148a8da --- /dev/null +++ b/arrayfire/random.py @@ -0,0 +1,232 @@ +####################################################### +# Copyright (c) 2015, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +""" +Random engine class and functions to generate random numbers. +""" + +from .library import * +from .array import * +import numbers + +class Random_Engine(object): + """ + Class to handle random number generator engines. + + Parameters + ---------- + + engine_type : optional: RANDOME_ENGINE. default: RANDOM_ENGINE.PHILOX + - Specifies the type of random engine to be created. Can be one of: + - RANDOM_ENGINE.PHILOX_4X32_10 + - RANDOM_ENGINE.THREEFRY_2X32_16 + - RANDOM_ENGINE.MERSENNE_GP11213 + - RANDOM_ENGINE.PHILOX (same as RANDOM_ENGINE.PHILOX_4X32_10) + - RANDOM_ENGINE.THREEFRY (same as RANDOM_ENGINE.THREEFRY_2X32_16) + - RANDOM_ENGINE.DEFAULT + - Not used if engine is not None + + seed : optional int. default: 0 + - Specifies the seed for the random engine + - Not used if engine is not None + + engine : optional ctypes.c_void_p. default: None. + - Used a handle created by the C api to create the Random_Engine. + """ + + def __init__(self, engine_type = RANDOM_ENGINE.PHILOX, seed = 0, engine = None): + if (engine is None): + self.engine = ct.c_void_p(0) + safe_call(backend.get().af_create_random_engine(ct.pointer(self.engine), engine_type.value, ct.c_longlong(seed))) + else: + self.engine = engine + + def __del__(self): + safe_call(backend.get().af_release_random_engine(self.engine)) + + def set_type(self, engine_type): + """ + Set the type of the random engine. + """ + safe_call(backend.get().af_random_engine_set_type(ct.pointer(self.engine), engine_type.value)) + + def get_type(self): + """ + Get the type of the random engine. + """ + __to_random_engine_type = [RANDOM_ENGINE.PHILOX_4X32_10, + RANDOM_ENGINE.THREEFRY_2X32_16, + RANDOM_ENGINE.MERSENNE_GP11213] + rty = ct.c_int(RANDOM_ENGINE.PHILOX.value) + safe_call(backend.get().af_random_engine_get_type(ct.pointer(rty), self.engine)) + return __to_random_engine_type[rty] + + def set_seed(self, seed): + """ + Set the seed for the random engine. + """ + safe_call(backend.get().af_random_engine_set_seed(ct.pointer(self.engine), ct.c_longlong(seed))) + + def get_seed(self): + """ + Get the seed for the random engine. + """ + seed = ct.c_longlong(0) + safe_call(backend.get().af_random_engine_get_seed(ct.pointer(seed), self.engine)) + return seed.value + +def randu(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, random_engine=None): + """ + Create a multi dimensional array containing values from a uniform distribution. + + Parameters + ---------- + d0 : int. + Length of first dimension. + + d1 : optional: int. default: None. + Length of second dimension. + + d2 : optional: int. default: None. + Length of third dimension. + + d3 : optional: int. default: None. + Length of fourth dimension. + + dtype : optional: af.Dtype. default: af.Dtype.f32. + Data type of the array. + + random_engine : optional: Random_Engine. default: None. + If random_engine is None, uses a default engine created by arrayfire. + + Returns + ------- + + out : af.Array + Multi dimensional array whose elements are sampled uniformly between [0, 1]. + - If d1 is None, `out` is 1D of size (d0,). + - If d1 is not None and d2 is None, `out` is 2D of size (d0, d1). + - If d1 and d2 are not None and d3 is None, `out` is 3D of size (d0, d1, d2). + - If d1, d2, d3 are all not None, `out` is 4D of size (d0, d1, d2, d3). + """ + out = Array() + dims = dim4(d0, d1, d2, d3) + + if random_engine is None: + safe_call(backend.get().af_randu(ct.pointer(out.arr), 4, ct.pointer(dims), dtype.value)) + else: + safe_call(backend.get().af_random_uniform(ct.pointer(out.arr), 4, ct.pointer(dims), random_engine.engine)) + + return out + +def randn(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, random_engine=None): + """ + Create a multi dimensional array containing values from a normal distribution. + + Parameters + ---------- + d0 : int. + Length of first dimension. + + d1 : optional: int. default: None. + Length of second dimension. + + d2 : optional: int. default: None. + Length of third dimension. + + d3 : optional: int. default: None. + Length of fourth dimension. + + dtype : optional: af.Dtype. default: af.Dtype.f32. + Data type of the array. + + random_engine : optional: Random_Engine. default: None. + If random_engine is None, uses a default engine created by arrayfire. + + Returns + ------- + + out : af.Array + Multi dimensional array whose elements are sampled from a normal distribution with mean 0 and sigma of 1. + - If d1 is None, `out` is 1D of size (d0,). + - If d1 is not None and d2 is None, `out` is 2D of size (d0, d1). + - If d1 and d2 are not None and d3 is None, `out` is 3D of size (d0, d1, d2). + - If d1, d2, d3 are all not None, `out` is 4D of size (d0, d1, d2, d3). + """ + + out = Array() + dims = dim4(d0, d1, d2, d3) + + if random_engine is None: + safe_call(backend.get().af_randn(ct.pointer(out.arr), 4, ct.pointer(dims), dtype.value)) + else: + safe_call(backend.get().af_random_normal(ct.pointer(out.arr), 4, ct.pointer(dims), random_engine.engine)) + + return out + +def set_seed(seed=0): + """ + Set the seed for the random number generator. + + Parameters + ---------- + seed: int. + Seed for the random number generator + """ + safe_call(backend.get().af_set_seed(ct.c_ulonglong(seed))) + +def get_seed(): + """ + Get the seed for the random number generator. + + Returns + ---------- + seed: int. + Seed for the random number generator + """ + seed = ct.c_ulonglong(0) + safe_call(backend.get().af_get_seed(ct.pointer(seed))) + return seed.value + +def set_default_random_engine_type(engine_type): + """ + Set random engine type for default random engine. + + Parameters + ---------- + engine_type : RANDOME_ENGINE. + - Specifies the type of random engine to be created. Can be one of: + - RANDOM_ENGINE.PHILOX_4X32_10 + - RANDOM_ENGINE.THREEFRY_2X32_16 + - RANDOM_ENGINE.MERSENNE_GP11213 + - RANDOM_ENGINE.PHILOX (same as RANDOM_ENGINE.PHILOX_4X32_10) + - RANDOM_ENGINE.THREEFRY (same as RANDOM_ENGINE.THREEFRY_2X32_16) + - RANDOM_ENGINE.DEFAULT + + Note + ---- + + This only affects randu and randn when a random engine is not specified. + """ + safe_call(backend.get().af_set_default_random_engine_type(ct.pointer(self.engine), engine_type.value)) + +def get_default_random_engine(): + """ + Get the default random engine + + Returns + ------ + + The default random engine used by randu and randn + """ + engine = ct.c_void_p(0) + default_engine = ct.c_void_p(0) + safe_call(backend.get().af_get_default_random_engine(ct.pointer(default_engine))) + safe_call(backend.get().af_retain_random_engine(ct.pointer(engine), default_engine)) + return Random_Engine(engine=engine) diff --git a/arrayfire/tests/simple/data.py b/arrayfire/tests/simple/data.py index 7c95a8194..86b900baf 100644 --- a/arrayfire/tests/simple/data.py +++ b/arrayfire/tests/simple/data.py @@ -24,16 +24,6 @@ def simple_data(verbose=False): display_func(af.range(3, 3)) display_func(af.iota(3, 3, tile_dims=(2,2))) - display_func(af.randu(3, 3, 1, 2)) - display_func(af.randu(3, 3, 1, 2, af.Dtype.b8)) - display_func(af.randu(3, 3, dtype=af.Dtype.c32)) - - display_func(af.randn(3, 3, 1, 2)) - display_func(af.randn(3, 3, dtype=af.Dtype.c32)) - - af.set_seed(1024) - assert(af.get_seed() == 1024) - display_func(af.identity(3, 3, 1, 2, af.Dtype.b8)) display_func(af.identity(3, 3, dtype=af.Dtype.c32)) diff --git a/arrayfire/tests/simple/random.py b/arrayfire/tests/simple/random.py new file mode 100644 index 000000000..6b72a910a --- /dev/null +++ b/arrayfire/tests/simple/random.py @@ -0,0 +1,38 @@ +#!/usr/bin/python +####################################################### +# Copyright (c) 2015, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +import arrayfire as af +from . import _util + +def simple_random(verbose=False): + display_func = _util.display_func(verbose) + print_func = _util.print_func(verbose) + + display_func(af.randu(3, 3, 1, 2)) + display_func(af.randu(3, 3, 1, 2, af.Dtype.b8)) + display_func(af.randu(3, 3, dtype=af.Dtype.c32)) + + display_func(af.randn(3, 3, 1, 2)) + display_func(af.randn(3, 3, dtype=af.Dtype.c32)) + + af.set_seed(1024) + assert(af.get_seed() == 1024) + + engine = Random_Engine(RANDOM_ENGINE.MERSENNE_GP11213, 100) + + display_func(af.randu(3, 3, 1, 2, engine=engine)) + display_func(af.randu(3, 3, 1, 2, af.Dtype.s32, engine=engine)) + display_func(af.randu(3, 3, dtype=af.Dtype.c32, engine=engine)) + + display_func(af.randn(3, 3, engine=engine)) + engine.set_seed(100) + assert(engine.get_seed() == 100) + +_util.tests['random'] = simple_random From 208465d1cd72542922876e6ed897765137871661 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 23 Sep 2016 14:46:22 -0700 Subject: [PATCH 097/212] Adding medfilt1 and medfilt2 and necessary tests --- arrayfire/image.py | 33 +----------- arrayfire/signal.py | 91 ++++++++++++++++++++++++++++++++ arrayfire/tests/simple/signal.py | 4 ++ 3 files changed, 96 insertions(+), 32 deletions(-) diff --git a/arrayfire/image.py b/arrayfire/image.py index 842ce22fd..7ddb6de9a 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -14,6 +14,7 @@ from .library import * from .array import * from .data import constant +from .signal import medfilt import os def gradient(image): @@ -619,38 +620,6 @@ def mean_shift(image, s_sigma, c_sigma, n_iter, is_color = False): ct.c_uint(n_iter), is_color)) return output -def medfilt(image, w0 = 3, w1 = 3, edge_pad = PAD.ZERO): - """ - Apply median filter for the image. - - Parameters - ---------- - image : af.Array - - A 2 D arrayfire array representing an image, or - - A multi dimensional array representing batch of images. - - w0 : optional: int. default: 3. - - The length of the filter along the first dimension. - - w1 : optional: int. default: 3. - - The length of the filter along the second dimension. - - edge_pad : optional: af.PAD. default: af.PAD.ZERO - - Flag specifying how the median at the edge should be treated. - - Returns - --------- - - output : af.Array - - The image after median filter is applied. - - """ - output = Array() - safe_call(backend.get().af_medfilt(ct.pointer(output.arr), - image.arr, c_dim_t(w0), - c_dim_t(w1), edge_pad.value)) - return output - def minfilt(image, w_len = 3, w_wid = 3, edge_pad = PAD.ZERO): """ Apply min filter for the image. diff --git a/arrayfire/signal.py b/arrayfire/signal.py index 78f2c6f2a..363ed248c 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -1265,6 +1265,97 @@ def iir(B, A, X): safe_call(backend.get().af_iir(ct.pointer(Y.arr), B.arr, A.arr, X.arr)) return Y +def medfilt(signal, w0 = 3, w1 = 3, edge_pad = PAD.ZERO): + """ + Apply median filter for the signal. + + Parameters + ---------- + signal : af.Array + - A 2 D arrayfire array representing a signal, or + - A multi dimensional array representing batch of signals. + + w0 : optional: int. default: 3. + - The length of the filter along the first dimension. + + w1 : optional: int. default: 3. + - The length of the filter along the second dimension. + + edge_pad : optional: af.PAD. default: af.PAD.ZERO + - Flag specifying how the median at the edge should be treated. + + Returns + --------- + + output : af.Array + - The signal after median filter is applied. + + """ + output = Array() + safe_call(backend.get().af_medfilt(ct.pointer(output.arr), + signal.arr, c_dim_t(w0), + c_dim_t(w1), edge_pad.value)) + return output + +def medfilt1(signal, length = 3, edge_pad = PAD.ZERO): + """ + Apply median filter for the signal. + + Parameters + ---------- + signal : af.Array + - A 1 D arrayfire array representing a signal, or + - A multi dimensional array representing batch of signals. + + length : optional: int. default: 3. + - The length of the filter. + + edge_pad : optional: af.PAD. default: af.PAD.ZERO + - Flag specifying how the median at the edge should be treated. + + Returns + --------- + + output : af.Array + - The signal after median filter is applied. + + """ + output = Array() + safe_call(backend.get().af_medfilt1(ct.pointer(output.arr), signal.arr, c_dim_t(length), edge_pad.value)) + return output + +def medfilt2(signal, w0 = 3, w1 = 3, edge_pad = PAD.ZERO): + """ + Apply median filter for the signal. + + Parameters + ---------- + signal : af.Array + - A 2 D arrayfire array representing a signal, or + - A multi dimensional array representing batch of signals. + + w0 : optional: int. default: 3. + - The length of the filter along the first dimension. + + w1 : optional: int. default: 3. + - The length of the filter along the second dimension. + + edge_pad : optional: af.PAD. default: af.PAD.ZERO + - Flag specifying how the median at the edge should be treated. + + Returns + --------- + + output : af.Array + - The signal after median filter is applied. + + """ + output = Array() + safe_call(backend.get().af_medfilt2(ct.pointer(output.arr), + signal.arr, c_dim_t(w0), + c_dim_t(w1), edge_pad.value)) + return output + def set_fft_plan_cache_size(cache_size): """ Sets plan cache size. diff --git a/arrayfire/tests/simple/signal.py b/arrayfire/tests/simple/signal.py index 03d89b4a8..817685c5a 100644 --- a/arrayfire/tests/simple/signal.py +++ b/arrayfire/tests/simple/signal.py @@ -110,4 +110,8 @@ def simple_signal(verbose=False): display_func(af.fir(b, x)) display_func(af.iir(b, a, x)) + display_func(af.medfilt1(a)) + display_func(af.medfilt2(a)) + display_func(af.medfilt(a)) + _util.tests['signal'] = simple_signal From ef44a7a21f7118616c23c377d4257ca039b858a6 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 23 Sep 2016 16:09:21 -0700 Subject: [PATCH 098/212] Adding new graphics functions from v3.4 --- arrayfire/graphics.py | 225 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 208 insertions(+), 17 deletions(-) diff --git a/arrayfire/graphics.py b/arrayfire/graphics.py index 3d0b3f213..59da8dbf7 100644 --- a/arrayfire/graphics.py +++ b/arrayfire/graphics.py @@ -140,9 +140,9 @@ def image(self, img, title=None): _cell = _Cell(self._r, self._c, title, self._cmap) safe_call(backend.get().af_draw_image(self._wnd, img.arr, ct.pointer(_cell))) - def scatter(self, X, Y, marker=MARKER.POINT, title=None): + def scatter(self, X, Y, Z=None, points=None, marker=MARKER.POINT, title=None): """ - Renders input arrays as 2D scatter plot. + Renders input arrays as 2D or 3D scatter plot. Paramters --------- @@ -153,67 +153,212 @@ def scatter(self, X, Y, marker=MARKER.POINT, title=None): Y: af.Array. A 1 dimensional array containing Y co-ordinates. + Z: optional: af.Array. default: None. + - A 1 dimensional array containing Z co-ordinates. + - Not used if line is not None + + points: optional: af.Array. default: None. + - A 2 dimensional array of size [n 2]. Each column denotes X and Y co-ordinates for 2D scatter plot. + - A 3 dimensional array of size [n 3]. Each column denotes X, Y, and Z co-ordinates for 3D scatter plot. + + marker: af.MARKER + Specifies how the points look + + title: str. + Title used for the plot. + """ + _cell = _Cell(self._r, self._c, title, self._cmap) + + if points is None: + if Z is None: + safe_call(backend.get().af_draw_scatter_2d(self._wnd, X.arr, Y.arr, + marker.value, ct.pointer(_cell))) + else: + safe_call(backend.get().af_draw_scatter_3d(self._wnd, X.arr, Y.arr, Z.arr, + marker.value, ct.pointer(_cell))) + else: + safe_call(backend.get().af_draw_scatter_nd(self._wnd, points.arr, marker.value, ct.pointer(_cell))) + + def scatter2(self, points, marker=MARKER.POINT, title=None): + """ + Renders the input array as a 2D Scatter plot. + + Paramters + --------- + + points: af.Array. + A 2 dimensional array containing (X,Y) co-ordinates. + marker: af.MARKER Specifies how the points look title: str. Title used for the plot. """ + assert(points.numdims() == 2) _cell = _Cell(self._r, self._c, title, self._cmap) - safe_call(backend.get().af_draw_scatter(self._wnd, X.arr, Y.arr, - marker.value, ct.pointer(_cell))) + safe_call(backend.get().af_draw_scatter2(self._wnd, points.arr, + marker.value, ct.pointer(_cell))) - def scatter3(self, P, marker=MARKER.POINT, title=None): + def scatter3(self, points, marker=MARKER.POINT, title=None): """ Renders the input array as a 3D Scatter plot. Paramters --------- - P: af.Array. + points: af.Array. A 2 dimensional array containing (X,Y,Z) co-ordinates. + marker: af.MARKER + Specifies how the points look + title: str. Title used for the plot. """ + assert(points.numdims() == 3) _cell = _Cell(self._r, self._c, title, self._cmap) - safe_call(backend.get().af_draw_scatter3(self._wnd, P.arr, + safe_call(backend.get().af_draw_scatter3(self._wnd, points.arr, marker.value, ct.pointer(_cell))) - - def plot(self, X, Y, title=None): + def plot(self, X, Y, Z=None, line = None, title=None): """ - Display a 2D Plot. + Display a 2D or 3D Plot. Paramters --------- X: af.Array. - A 1 dimensional array containing X co-ordinates. + - A 1 dimensional array containing X co-ordinates. + - Not used if line is not None Y: af.Array. - A 1 dimensional array containing Y co-ordinates. + - A 1 dimensional array containing Y co-ordinates. + - Not used if line is not None + + Z: optional: af.Array. default: None. + - A 1 dimensional array containing Z co-ordinates. + - Not used if line is not None + + line: optional: af.Array. default: None. + - A 2 dimensional array of size [n 2]. Each column denotes X and Y co-ordinates for plotting 2D lines. + - A 3 dimensional array of size [n 3]. Each column denotes X, Y, and Z co-ordinates for plotting 3D lines. title: str. Title used for the plot. + + Note + ---- + + The line parameter takes precedence. """ _cell = _Cell(self._r, self._c, title, self._cmap) - safe_call(backend.get().af_draw_plot(self._wnd, X.arr, Y.arr, ct.pointer(_cell))) + if line is None: + if Z is None: + safe_call(backend.get().af_draw_plot_2d(self._wnd, X.arr, Y.arr, ct.pointer(_cell))) + else: + safe_call(backend.get().af_draw_plot_3d(self._wnd, X.arr, Y.arr, Z.arr, ct.pointer(_cell))) + else: + safe_call(backend.get().af_draw_plot_nd(self._wnd, line.arr, ct.pointer(_cell))) - def plot3(self, line, title=None): + def plot2(self, line, title=None): """ - Renders the input array as a 3D line plot. + Display a 2D Plot. Paramters --------- line: af.Array. - A 2 dimensional array containing (X,Y,Z) co-ordinates. + - A 2 dimensional array of size [n 2]. Each column denotes X, and Y co-ordinates for plotting 2D lines. title: str. Title used for the plot. + """ + + assert(line.numdims() == 2) _cell = _Cell(self._r, self._c, title, self._cmap) - safe_call(backend.get().af_draw_plot3(self._wnd, line.arr, ct.pointer(_cell))) + safe_call(backend.get().af_draw_plot_nd(self._wnd, line.arr, ct.pointer(_cell))) + + def plot3(self, X=None, Y=None, Z=None, line=None, title=None): + """ + Display a 3D Plot. + + Paramters + --------- + + line: af.Array. + - A 3 dimensional array of size [n 3]. Each column denotes X, Y, and Z co-ordinates for plotting 3D lines. + + title: str. + Title used for the plot. + """ + + assert(line.numdims() == 3) + _cell = _Cell(self._r, self._c, title, self._cmap) + safe_call(backend.get().af_draw_plot_nd(self._wnd, line.arr, ct.pointer(_cell))) + + def vector_field(self, xpoints, xdirs, ypoints, ydirs, zpoints=None, zdirs=None, + points = None, dirs = None, title=None): + """ + Display a 2D or 3D Vector_Field. + + Paramters + --------- + + xpoints : af.Array. + - A 1 dimensional array containing X co-ordinates. + - Not used if points is not None + + xdirs : af.Array. + - A 1 dimensional array specifying direction at current location. + - Not used if dirs is not None + + ypoints : af.Array. + - A 1 dimensional array containing Y co-ordinates. + - Not used if points is not None + + ydirs : af.Array. + - A 1 dimensional array specifying direction at current location. + - Not used if dirs is not None + + zpoints : optional: af.Array. default: None. + - A 1 dimensional array containing Z co-ordinates. + - Not used if points is not None + + zdirs : optional: af.Array. default: none. + - A 1 dimensional array specifying direction at current location. + - Not used if dirs is not None + + points : optional: af.Array. default: None. + - A 2 dimensional array of size [n 2]. Each column denotes X and Y co-ordinates for plotting 2D lines. + - A 3 dimensional array of size [n 3]. Each column denotes X, Y, and Z co-ordinates for plotting 3D lines. + + dirs : optional: af.Array. default: None. + - A 2 dimensional array of size [n 2]. Each column denotes X and Y directions for plotting 2D lines. + - A 3 dimensional array of size [n 3]. Each column denotes X, Y, and Z directions for plotting 3D lines. + + title : str. + Title used for the plot. + + Note + ---- + + The line parameter takes precedence. + """ + _cell = _Cell(self._r, self._c, title, self._cmap) + if line is None: + if Z is None: + safe_call(backend.get().af_draw_vector_field_2d(self._wnd, + xpoints.arr, ypoints.arr, + xdirs.arr, ydirs.arr, + ct.pointer(_cell))) + else: + safe_call(backend.get().af_draw_vector_field_2d(self._wnd, + xpoints.arr, ypoints.arr, zpoints.arr, + xdirs.arr, ydirs.arr, zdirs.arr, + ct.pointer(_cell))) + else: + safe_call(backend.get().af_draw_plot_nd(self._wnd, points.arr, dirs.arr, ct.pointer(_cell))) def surface(self, x_vals, y_vals, z_vals, title=None): """ @@ -305,6 +450,52 @@ def set_visibility(is_visible): """ safe_call(backend.get().af_set_visibility(self._wnd, is_visible)) + def set_axes_limits(self, xmin, xmax, ymin, ymax, zmin=None, zmax=None, exact=False): + """ + Set axis limits. + + Paramters + --------- + + xmin : af.Array. + - lower limit of the x axis. + + xmax : af.Array. + - upper limit of the x axis. + + ymin : af.Array. + - lower limit of the y axis. + + ymax : af.Array. + - upper limit of the y axis. + + zmin : optional: af.Array. default: None. + - lower limit of the z axis. + + zmax : optional: af.Array. default: None. + - upper limit of the z axis. + + title : str. + Title used for the plot. + + Note + ---- + + The line parameter takes precedence. + """ + _cell = _Cell(self._r, self._c, "", self._cmap) + if (zmin is None or zmax is None): + safe_call(backend.get().af_set_axes_limits_2d(self._wnd, + ct.c_float(xmin), ct.c_float(xmax), + ct.c_float(ymin), ct.c_float(ymax), + exact, ct.pointer(_cell))) + else: + safe_call(backend.get().af_set_axes_limits_2d(self._wnd, + ct.c_float(xmin), ct.c_float(xmax), + ct.c_float(ymin), ct.c_float(ymax), + ct.c_float(zmin), ct.c_float(zmax), + exact, ct.pointer(_cell))) + def __getitem__(self, keys): """ Get access to a specific grid location within the window. From 4b3369f664453c27a79a223dac3432b22bcc35f8 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 23 Sep 2016 16:15:03 -0700 Subject: [PATCH 099/212] Adding get_size_of --- arrayfire/library.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arrayfire/library.py b/arrayfire/library.py index fc76c9fa8..c0541620d 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -671,4 +671,12 @@ def get_device_id(A): safe_call(backend.get().af_get_device_id(ct.pointer(device_id), A.arr)) return device_id +def get_size_of(dtype): + """ + Get the size of the type represented by arrayfire.Dtype + """ + size = ct.c_size_t(0) + safe_call(backend.get().af_get_size_of(ct.pointer(size), dtype.value)) + return size.value + from .util import safe_call From 85465c2fae89da37f4d6f0452383b18ab08f6390 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 23 Sep 2016 17:36:35 -0700 Subject: [PATCH 100/212] Fixing bugs in random and random tests --- arrayfire/__init__.py | 1 + arrayfire/random.py | 20 ++++++++++---------- arrayfire/tests/simple/__init__.py | 1 + arrayfire/tests/simple/random.py | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/arrayfire/__init__.py b/arrayfire/__init__.py index 74d1dca43..c392d24be 100644 --- a/arrayfire/__init__.py +++ b/arrayfire/__init__.py @@ -72,6 +72,7 @@ from .index import * from .interop import * from .timer import * +from .random import * # do not export default modules as part of arrayfire del ct diff --git a/arrayfire/random.py b/arrayfire/random.py index 60148a8da..d95fa9081 100644 --- a/arrayfire/random.py +++ b/arrayfire/random.py @@ -81,7 +81,7 @@ def get_seed(self): safe_call(backend.get().af_random_engine_get_seed(ct.pointer(seed), self.engine)) return seed.value -def randu(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, random_engine=None): +def randu(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, engine=None): """ Create a multi dimensional array containing values from a uniform distribution. @@ -102,8 +102,8 @@ def randu(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, random_engine=None): dtype : optional: af.Dtype. default: af.Dtype.f32. Data type of the array. - random_engine : optional: Random_Engine. default: None. - If random_engine is None, uses a default engine created by arrayfire. + engine : optional: Random_Engine. default: None. + If engine is None, uses a default engine created by arrayfire. Returns ------- @@ -118,14 +118,14 @@ def randu(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, random_engine=None): out = Array() dims = dim4(d0, d1, d2, d3) - if random_engine is None: + if engine is None: safe_call(backend.get().af_randu(ct.pointer(out.arr), 4, ct.pointer(dims), dtype.value)) else: - safe_call(backend.get().af_random_uniform(ct.pointer(out.arr), 4, ct.pointer(dims), random_engine.engine)) + safe_call(backend.get().af_random_uniform(ct.pointer(out.arr), 4, ct.pointer(dims), dtype.value, engine.engine)) return out -def randn(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, random_engine=None): +def randn(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, engine=None): """ Create a multi dimensional array containing values from a normal distribution. @@ -146,8 +146,8 @@ def randn(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, random_engine=None): dtype : optional: af.Dtype. default: af.Dtype.f32. Data type of the array. - random_engine : optional: Random_Engine. default: None. - If random_engine is None, uses a default engine created by arrayfire. + engine : optional: Random_Engine. default: None. + If engine is None, uses a default engine created by arrayfire. Returns ------- @@ -163,10 +163,10 @@ def randn(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, random_engine=None): out = Array() dims = dim4(d0, d1, d2, d3) - if random_engine is None: + if engine is None: safe_call(backend.get().af_randn(ct.pointer(out.arr), 4, ct.pointer(dims), dtype.value)) else: - safe_call(backend.get().af_random_normal(ct.pointer(out.arr), 4, ct.pointer(dims), random_engine.engine)) + safe_call(backend.get().af_random_normal(ct.pointer(out.arr), 4, ct.pointer(dims), dtype.value, engine.engine)) return out diff --git a/arrayfire/tests/simple/__init__.py b/arrayfire/tests/simple/__init__.py index 465197202..0a1588ed8 100644 --- a/arrayfire/tests/simple/__init__.py +++ b/arrayfire/tests/simple/__init__.py @@ -18,4 +18,5 @@ from .lapack import * from .signal import * from .statistics import * +from .random import * from ._util import tests diff --git a/arrayfire/tests/simple/random.py b/arrayfire/tests/simple/random.py index 6b72a910a..544389836 100644 --- a/arrayfire/tests/simple/random.py +++ b/arrayfire/tests/simple/random.py @@ -25,7 +25,7 @@ def simple_random(verbose=False): af.set_seed(1024) assert(af.get_seed() == 1024) - engine = Random_Engine(RANDOM_ENGINE.MERSENNE_GP11213, 100) + engine = af.Random_Engine(af.RANDOM_ENGINE.MERSENNE_GP11213, 100) display_func(af.randu(3, 3, 1, 2, engine=engine)) display_func(af.randu(3, 3, 1, 2, af.Dtype.s32, engine=engine)) From 3637f589ba20297f06f47d7150a7ea6e6d3f3e91 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 23 Sep 2016 17:37:21 -0700 Subject: [PATCH 101/212] Adding functions to create and manipulate sparse matrices --- arrayfire/__init__.py | 1 + arrayfire/sparse.py | 275 +++++++++++++++++++++++++++++ arrayfire/tests/simple/__init__.py | 1 + arrayfire/tests/simple/sparse.py | 28 +++ 4 files changed, 305 insertions(+) create mode 100644 arrayfire/sparse.py create mode 100644 arrayfire/tests/simple/sparse.py diff --git a/arrayfire/__init__.py b/arrayfire/__init__.py index c392d24be..255fbbeeb 100644 --- a/arrayfire/__init__.py +++ b/arrayfire/__init__.py @@ -73,6 +73,7 @@ from .interop import * from .timer import * from .random import * +from .sparse import * # do not export default modules as part of arrayfire del ct diff --git a/arrayfire/sparse.py b/arrayfire/sparse.py new file mode 100644 index 000000000..9a4c30460 --- /dev/null +++ b/arrayfire/sparse.py @@ -0,0 +1,275 @@ +####################################################### +# Copyright (c) 2015, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +""" +Functions to create and manipulate sparse matrices. +""" + +from .library import * +from .array import * +import numbers +from .interop import to_array + +__to_sparse_enum = [STORAGE.DENSE, + STORAGE.CSR, + STORAGE.CSC, + STORAGE.COO] + + +def sparse(values, row_idx, col_idx, nrows, ncols, storage = STORAGE.CSR): + """ + Create a sparse matrix from it's constituent parts. + + Parameters + ---------- + + values : af.Array. + - Contains the non zero elements of the sparse array. + + row_idx : af.Array. + - Contains row indices of the sparse array. + + col_idx : af.Array. + - Contains column indices of the sparse array. + + nrows : int. + - specifies the number of rows in sparse matrix. + + ncols : int. + - specifies the number of columns in sparse matrix. + + storage : optional: arrayfire.STORAGE. default: arrayfire.STORAGE.CSR. + - Can be one of arrayfire.STORAGE.CSR, arrayfire.STORAGE.COO. + + Returns + ------- + + A sparse matrix. + """ + assert(isinstance(values, Array)) + assert(isinstance(row_idx, Array)) + assert(isinstance(col_idx, Array)) + out = Array() + safe_call(backend.get().af_create_sparse_array(ct.pointer(out.arr), c_dim_t(nrows), c_dim_t(ncols), + values.arr, row_idx.arr, col_idx.arr, storage.value)) + return out + +def sparse_from_host(values, row_idx, col_idx, nrows, ncols, storage = STORAGE.CSR): + """ + Create a sparse matrix from it's constituent parts. + + Parameters + ---------- + + values : Any datatype that can be converted to array. + - Contains the non zero elements of the sparse array. + + row_idx : Any datatype that can be converted to array. + - Contains row indices of the sparse array. + + col_idx : Any datatype that can be converted to array. + - Contains column indices of the sparse array. + + nrows : int. + - specifies the number of rows in sparse matrix. + + ncols : int. + - specifies the number of columns in sparse matrix. + + storage : optional: arrayfire.STORAGE. default: arrayfire.STORAGE.CSR. + - Can be one of arrayfire.STORAGE.CSR, arrayfire.STORAGE.COO. + + Returns + ------- + + A sparse matrix. + """ + return sparse(to_array(values), to_array(row_idx), to_array(col_idx), nrows, ncols, storage) + +def sparse_from_dense(dense, storage = STORAGE.CSR): + """ + Create a sparse matrix from a dense matrix. + + Parameters + ---------- + + dense : af.Array. + - A dense matrix. + + storage : optional: arrayfire.STORAGE. default: arrayfire.STORAGE.CSR. + - Can be one of arrayfire.STORAGE.CSR, arrayfire.STORAGE.COO. + + Returns + ------- + + A sparse matrix. + """ + assert(isinstance(dense, Array)) + out = Array() + safe_call(backend.get().af_create_sparse_array_from_dense(ct.pointer(out.arr), dense.arr, storage.value)) + return out + +def sparse_to_dense(sparse): + """ + Create a dense matrix from a sparse matrix. + + Parameters + ---------- + + sparse : af.Array. + - A sparse matrix. + + Returns + ------- + + A dense matrix. + """ + out = Array() + safe_call(backend.get().af_sparse_to_dense(ct.pointer(out.arr), sparse.arr)) + return out + +def sparse_get_info(sparse): + """ + Get the constituent arrays and storage info from a sparse matrix. + + Parameters + ---------- + + sparse : af.Array. + - A sparse matrix. + + Returns + -------- + (values, row_idx, col_idx, storage) where + values : arrayfire.Array containing non zero elements from sparse matrix + row_idx : arrayfire.Array containing the row indices + col_idx : arrayfire.Array containing the column indices + storage : sparse storage + """ + values = Array() + row_idx = Array() + col_idx = Array() + stype = ct.c_int(0) + safe_call(backend.get().af_sparse_get_info(ct.pointer(values.arr), ct.pointer(row_idx.arr), + ct.pointer(col_idx.arr), ct.pointer(stype), + sparse.arr)) + return (values, row_idx, col_idx, __to_sparse_enum[stype.value]) + +def sparse_get_values(sparse): + """ + Get the non zero values from sparse matrix. + + Parameters + ---------- + + sparse : af.Array. + - A sparse matrix. + + Returns + -------- + arrayfire array containing the non zero elements. + + """ + values = Array() + safe_call(backend.get().af_sparse_get_values(ct.pointer(values.arr), sparse.arr)) + return values + +def sparse_get_row_idx(sparse): + """ + Get the row indices from sparse matrix. + + Parameters + ---------- + + sparse : af.Array. + - A sparse matrix. + + Returns + -------- + arrayfire array containing the non zero elements. + + """ + row_idx = Array() + safe_call(backend.get().af_sparse_get_row_idx(ct.pointer(row_idx.arr), sparse.arr)) + return row_idx + +def sparse_get_col_idx(sparse): + """ + Get the column indices from sparse matrix. + + Parameters + ---------- + + sparse : af.Array. + - A sparse matrix. + + Returns + -------- + arrayfire array containing the non zero elements. + + """ + col_idx = Array() + safe_call(backend.get().af_sparse_get_col_idx(ct.pointer(col_idx.arr), sparse.arr)) + return col_idx + +def sparse_get_nnz(sparse): + """ + Get the column indices from sparse matrix. + + Parameters + ---------- + + sparse : af.Array. + - A sparse matrix. + + Returns + -------- + Number of non zero elements in the sparse matrix. + + """ + nnz = c_dim_t(0) + safe_call(backend.get().af_sparse_get_nnz(ct.pointer(nnz), sparse.arr)) + return nnz.value + +def sparse_get_storage(sparse): + """ + Get the column indices from sparse matrix. + + Parameters + ---------- + + sparse : af.Array. + - A sparse matrix. + + Returns + -------- + Number of non zero elements in the sparse matrix. + + """ + storage = ct.c_int(0) + safe_call(backend.get().af_sparse_get_storage(ct.pointer(storage), sparse.arr)) + return __to_sparse_enum[storage.value] + +def sparse_convert_to(sparse, storage): + """ + Convert sparse matrix from one format to another. + + Parameters + ---------- + + storage : arrayfire.STORAGE. + + Returns + ------- + + Sparse matrix converted to the appropriate type. + """ + out = Array() + safe_call(backend.get().af_sparse_convert_to(ct.pointer(out.arr), sparse.arr, storage.value)) + return out diff --git a/arrayfire/tests/simple/__init__.py b/arrayfire/tests/simple/__init__.py index 0a1588ed8..528215ffc 100644 --- a/arrayfire/tests/simple/__init__.py +++ b/arrayfire/tests/simple/__init__.py @@ -19,4 +19,5 @@ from .signal import * from .statistics import * from .random import * +from .sparse import * from ._util import tests diff --git a/arrayfire/tests/simple/sparse.py b/arrayfire/tests/simple/sparse.py new file mode 100644 index 000000000..b756cd5a5 --- /dev/null +++ b/arrayfire/tests/simple/sparse.py @@ -0,0 +1,28 @@ +#!/usr/bin/python +####################################################### +# Copyright (c) 2015, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +import arrayfire as af +from . import _util + +def simple_sparse(verbose=False): + display_func = _util.display_func(verbose) + print_func = _util.print_func(verbose) + + dd = af.randu(5, 5) + ds = dd * (dd > 0.5) + sp = af.sparse_from_dense(ds) + display_func(af.sparse_get_info(sp)) + display_func(af.sparse_get_values(sp)) + display_func(af.sparse_get_row_idx(sp)) + display_func(af.sparse_get_col_idx(sp)) + print_func(af.sparse_get_nnz(sp)) + print_func(af.sparse_get_storage(sp)) + +_util.tests['sparse'] = simple_sparse From a79ccc5e690421de478de4e4777d1b8656a78f1c Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 23 Sep 2016 18:38:19 -0700 Subject: [PATCH 102/212] Changing Tegra K1 badge to Tegra X1 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e83f9901..35c4ee441 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ | Linux | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-linux)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-linux/) | | Windows | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-windows)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-windows/) | | OSX | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-osx)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-osx/) | -| Linux on ARM | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-tegrak1)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-tegrak1/)| +| Linux on ARM | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-tegrax1)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-tegrak1/)| ## Documentation From 5f8dce089579ce05a112b43cfef70696a1d286f6 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sat, 24 Sep 2016 14:38:19 -0700 Subject: [PATCH 103/212] Alias ctypes data types to custom data types --- arrayfire/algorithm.py | 58 ++++++------- arrayfire/arith.py | 12 +-- arrayfire/array.py | 182 ++++++++++++++++++++-------------------- arrayfire/base.py | 2 +- arrayfire/blas.py | 10 +-- arrayfire/cuda.py | 8 +- arrayfire/data.py | 42 +++++----- arrayfire/device.py | 64 +++++++------- arrayfire/features.py | 16 ++-- arrayfire/graphics.py | 74 ++++++++-------- arrayfire/image.py | 106 +++++++++++------------ arrayfire/index.py | 38 ++++----- arrayfire/interop.py | 2 +- arrayfire/lapack.py | 46 +++++----- arrayfire/library.py | 48 +++++++---- arrayfire/opencl.py | 20 ++--- arrayfire/random.py | 40 ++++----- arrayfire/signal.py | 70 ++++++++-------- arrayfire/sparse.py | 26 +++--- arrayfire/statistics.py | 54 ++++++------ arrayfire/util.py | 36 ++++---- arrayfire/vision.py | 42 +++++----- 22 files changed, 506 insertions(+), 490 deletions(-) diff --git a/arrayfire/algorithm.py b/arrayfire/algorithm.py index a219ea663..d57e0ce86 100644 --- a/arrayfire/algorithm.py +++ b/arrayfire/algorithm.py @@ -16,14 +16,14 @@ def _parallel_dim(a, dim, c_func): out = Array() - safe_call(c_func(ct.pointer(out.arr), a.arr, ct.c_int(dim))) + safe_call(c_func(c_pointer(out.arr), a.arr, c_int_t(dim))) return out def _reduce_all(a, c_func): - real = ct.c_double(0) - imag = ct.c_double(0) + real = c_double_t(0) + imag = c_double_t(0) - safe_call(c_func(ct.pointer(real), ct.pointer(imag), a.arr)) + safe_call(c_func(c_pointer(real), c_pointer(imag), a.arr)) real = real.value imag = imag.value @@ -31,14 +31,14 @@ def _reduce_all(a, c_func): def _nan_parallel_dim(a, dim, c_func, nan_val): out = Array() - safe_call(c_func(ct.pointer(out.arr), a.arr, ct.c_int(dim), ct.c_double(nan_val))) + safe_call(c_func(c_pointer(out.arr), a.arr, c_int_t(dim), c_double_t(nan_val))) return out def _nan_reduce_all(a, c_func, nan_val): - real = ct.c_double(0) - imag = ct.c_double(0) + real = c_double_t(0) + imag = c_double_t(0) - safe_call(c_func(ct.pointer(real), ct.pointer(imag), a.arr, ct.c_double(nan_val))) + safe_call(c_func(c_pointer(real), c_pointer(imag), a.arr, c_double_t(nan_val))) real = real.value imag = imag.value @@ -235,13 +235,13 @@ def imin(a, dim=None): if dim is not None: out = Array() idx = Array() - safe_call(backend.get().af_imin(ct.pointer(out.arr), ct.pointer(idx.arr), a.arr, ct.c_int(dim))) + safe_call(backend.get().af_imin(c_pointer(out.arr), c_pointer(idx.arr), a.arr, c_int_t(dim))) return out,idx else: - real = ct.c_double(0) - imag = ct.c_double(0) - idx = ct.c_uint(0) - safe_call(backend.get().af_imin_all(ct.pointer(real), ct.pointer(imag), ct.pointer(idx), a.arr)) + real = c_double_t(0) + imag = c_double_t(0) + idx = c_uint_t(0) + safe_call(backend.get().af_imin_all(c_pointer(real), c_pointer(imag), c_pointer(idx), a.arr)) real = real.value imag = imag.value val = real if imag == 0 else real + imag * 1j @@ -268,13 +268,13 @@ def imax(a, dim=None): if dim is not None: out = Array() idx = Array() - safe_call(backend.get().af_imax(ct.pointer(out.arr), ct.pointer(idx.arr), a.arr, ct.c_int(dim))) + safe_call(backend.get().af_imax(c_pointer(out.arr), c_pointer(idx.arr), a.arr, c_int_t(dim))) return out,idx else: - real = ct.c_double(0) - imag = ct.c_double(0) - idx = ct.c_uint(0) - safe_call(backend.get().af_imax_all(ct.pointer(real), ct.pointer(imag), ct.pointer(idx), a.arr)) + real = c_double_t(0) + imag = c_double_t(0) + idx = c_uint_t(0) + safe_call(backend.get().af_imax_all(c_pointer(real), c_pointer(imag), c_pointer(idx), a.arr)) real = real.value imag = imag.value val = real if imag == 0 else real + imag * 1j @@ -327,7 +327,7 @@ def scan(a, dim=0, op=BINARYOP.ADD, inclusive_scan=True): - will contain scan of input. """ out = Array() - safe_call(backend.get().af_scan(ct.pointer(out.arr), a.arr, dim, op.value, inclusive_scan)) + safe_call(backend.get().af_scan(c_pointer(out.arr), a.arr, dim, op.value, inclusive_scan)) return out def scan_by_key(key, a, dim=0, op=BINARYOP.ADD, inclusive_scan=True): @@ -361,7 +361,7 @@ def scan_by_key(key, a, dim=0, op=BINARYOP.ADD, inclusive_scan=True): - will contain scan of input. """ out = Array() - safe_call(backend.get().af_scan_by_key(ct.pointer(out.arr), key.arr, a.arr, dim, op.value, inclusive_scan)) + safe_call(backend.get().af_scan_by_key(c_pointer(out.arr), key.arr, a.arr, dim, op.value, inclusive_scan)) return out def where(a): @@ -379,7 +379,7 @@ def where(a): Linear indices for non zero elements. """ out = Array() - safe_call(backend.get().af_where(ct.pointer(out.arr), a.arr)) + safe_call(backend.get().af_where(c_pointer(out.arr), a.arr)) return out def diff1(a, dim=0): @@ -441,7 +441,7 @@ def sort(a, dim=0, is_ascending=True): Currently `dim` is only supported for 0. """ out = Array() - safe_call(backend.get().af_sort(ct.pointer(out.arr), a.arr, ct.c_uint(dim), ct.c_bool(is_ascending))) + safe_call(backend.get().af_sort(c_pointer(out.arr), a.arr, c_uint_t(dim), c_bool_t(is_ascending))) return out def sort_index(a, dim=0, is_ascending=True): @@ -469,8 +469,8 @@ def sort_index(a, dim=0, is_ascending=True): """ out = Array() idx = Array() - safe_call(backend.get().af_sort_index(ct.pointer(out.arr), ct.pointer(idx.arr), a.arr, - ct.c_uint(dim), ct.c_bool(is_ascending))) + safe_call(backend.get().af_sort_index(c_pointer(out.arr), c_pointer(idx.arr), a.arr, + c_uint_t(dim), c_bool_t(is_ascending))) return out,idx def sort_by_key(iv, ik, dim=0, is_ascending=True): @@ -500,8 +500,8 @@ def sort_by_key(iv, ik, dim=0, is_ascending=True): """ ov = Array() ok = Array() - safe_call(backend.get().af_sort_by_key(ct.pointer(ov.arr), ct.pointer(ok.arr), - iv.arr, ik.arr, ct.c_uint(dim), ct.c_bool(is_ascending))) + safe_call(backend.get().af_sort_by_key(c_pointer(ov.arr), c_pointer(ok.arr), + iv.arr, ik.arr, c_uint_t(dim), c_bool_t(is_ascending))) return ov,ok def set_unique(a, is_sorted=False): @@ -521,7 +521,7 @@ def set_unique(a, is_sorted=False): an array containing the unique values from `a` """ out = Array() - safe_call(backend.get().af_set_unique(ct.pointer(out.arr), a.arr, ct.c_bool(is_sorted))) + safe_call(backend.get().af_set_unique(c_pointer(out.arr), a.arr, c_bool_t(is_sorted))) return out def set_union(a, b, is_unique=False): @@ -543,7 +543,7 @@ def set_union(a, b, is_unique=False): an array values after performing the union of `a` and `b`. """ out = Array() - safe_call(backend.get().af_set_union(ct.pointer(out.arr), a.arr, b.arr, ct.c_bool(is_unique))) + safe_call(backend.get().af_set_union(c_pointer(out.arr), a.arr, b.arr, c_bool_t(is_unique))) return out def set_intersect(a, b, is_unique=False): @@ -565,5 +565,5 @@ def set_intersect(a, b, is_unique=False): an array values after performing the intersect of `a` and `b`. """ out = Array() - safe_call(backend.get().af_set_intersect(ct.pointer(out.arr), a.arr, b.arr, ct.c_bool(is_unique))) + safe_call(backend.get().af_set_intersect(c_pointer(out.arr), a.arr, b.arr, c_bool_t(is_unique))) return out diff --git a/arrayfire/arith.py b/arrayfire/arith.py index 3b397c4a5..70c2e5471 100644 --- a/arrayfire/arith.py +++ b/arrayfire/arith.py @@ -26,27 +26,27 @@ def _arith_binary_func(lhs, rhs, c_func): raise TypeError("Atleast one input needs to be of type arrayfire.array") elif (is_left_array and is_right_array): - safe_call(c_func(ct.pointer(out.arr), lhs.arr, rhs.arr, _bcast_var.get())) + safe_call(c_func(c_pointer(out.arr), lhs.arr, rhs.arr, _bcast_var.get())) elif (_is_number(rhs)): ldims = dim4_to_tuple(lhs.dims()) rty = implicit_dtype(rhs, lhs.type()) other = Array() other.arr = constant_array(rhs, ldims[0], ldims[1], ldims[2], ldims[3], rty) - safe_call(c_func(ct.pointer(out.arr), lhs.arr, other.arr, _bcast_var.get())) + safe_call(c_func(c_pointer(out.arr), lhs.arr, other.arr, _bcast_var.get())) else: rdims = dim4_to_tuple(rhs.dims()) lty = implicit_dtype(lhs, rhs.type()) other = Array() other.arr = constant_array(lhs, rdims[0], rdims[1], rdims[2], rdims[3], lty) - safe_call(c_func(ct.pointer(out.arr), other.arr, rhs.arr, _bcast_var.get())) + safe_call(c_func(c_pointer(out.arr), other.arr, rhs.arr, _bcast_var.get())) return out def _arith_unary_func(a, c_func): out = Array() - safe_call(c_func(ct.pointer(out.arr), a.arr)) + safe_call(c_func(c_pointer(out.arr), a.arr)) return out def cast(a, dtype): @@ -75,7 +75,7 @@ def cast(a, dtype): array containing the values from `a` after converting to `dtype`. """ out=Array() - safe_call(backend.get().af_cast(ct.pointer(out.arr), a.arr, dtype.value)) + safe_call(backend.get().af_cast(c_pointer(out.arr), a.arr, dtype.value)) return out def minof(lhs, rhs): @@ -160,7 +160,7 @@ def clamp(val, low, high): else: high_arr = high.arr - safe_call(backend.get().af_clamp(ct.pointer(out.arr), val.arr, low_arr, high_arr, _bcast_var.get())) + safe_call(backend.get().af_clamp(c_pointer(out.arr), val.arr, low_arr, high_arr, _bcast_var.get())) return out diff --git a/arrayfire/array.py b/arrayfire/array.py index 4e27af691..d9f78bf4d 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -21,18 +21,18 @@ from .index import _Index4 def _create_array(buf, numdims, idims, dtype, is_device): - out_arr = ct.c_void_p(0) + out_arr = c_void_ptr_t(0) c_dims = dim4(idims[0], idims[1], idims[2], idims[3]) if (not is_device): - safe_call(backend.get().af_create_array(ct.pointer(out_arr), ct.c_void_p(buf), - numdims, ct.pointer(c_dims), dtype.value)) + safe_call(backend.get().af_create_array(c_pointer(out_arr), c_void_ptr_t(buf), + numdims, c_pointer(c_dims), dtype.value)) else: - safe_call(backend.get().af_device_array(ct.pointer(out_arr), ct.c_void_p(buf), - numdims, ct.pointer(c_dims), dtype.value)) + safe_call(backend.get().af_device_array(c_pointer(out_arr), c_void_ptr_t(buf), + numdims, c_pointer(c_dims), dtype.value)) return out_arr def _create_strided_array(buf, numdims, idims, dtype, is_device, offset, strides): - out_arr = ct.c_void_p(0) + out_arr = c_void_ptr_t(0) c_dims = dim4(idims[0], idims[1], idims[2], idims[3]) if offset is None: offset = 0 @@ -46,17 +46,17 @@ def _create_strided_array(buf, numdims, idims, dtype, is_device, offset, strides location = Source.device else: location = Source.host - safe_call(backend.get().af_create_strided_array(ct.pointer(out_arr), ct.c_void_p(buf), - offset, numdims, ct.pointer(c_dims), - ct.pointer(strides), dtype.value, + safe_call(backend.get().af_create_strided_array(c_pointer(out_arr), c_void_ptr_t(buf), + offset, numdims, c_pointer(c_dims), + c_pointer(strides), dtype.value, location.value)) return out_arr def _create_empty_array(numdims, idims, dtype): - out_arr = ct.c_void_p(0) + out_arr = c_void_ptr_t(0) c_dims = dim4(idims[0], idims[1], idims[2], idims[3]) - safe_call(backend.get().af_create_handle(ct.pointer(out_arr), - numdims, ct.pointer(c_dims), dtype.value)) + safe_call(backend.get().af_create_handle(c_pointer(out_arr), + numdims, c_pointer(c_dims), dtype.value)) return out_arr def constant_array(val, d0, d1=None, d2=None, d3=None, dtype=Dtype.f32): @@ -64,35 +64,35 @@ def constant_array(val, d0, d1=None, d2=None, d3=None, dtype=Dtype.f32): Internal function to create a C array. Should not be used externall. """ - if not isinstance(dtype, ct.c_int): + if not isinstance(dtype, c_int_t): if isinstance(dtype, int): - dtype = ct.c_int(dtype) + dtype = c_int_t(dtype) elif isinstance(dtype, Dtype): - dtype = ct.c_int(dtype.value) + dtype = c_int_t(dtype.value) else: raise TypeError("Invalid dtype") - out = ct.c_void_p(0) + out = c_void_ptr_t(0) dims = dim4(d0, d1, d2, d3) if isinstance(val, complex): - c_real = ct.c_double(val.real) - c_imag = ct.c_double(val.imag) + c_real = c_double_t(val.real) + c_imag = c_double_t(val.imag) if (dtype.value != Dtype.c32.value and dtype.value != Dtype.c64.value): dtype = Dtype.c32.value - safe_call(backend.get().af_constant_complex(ct.pointer(out), c_real, c_imag, - 4, ct.pointer(dims), dtype)) + safe_call(backend.get().af_constant_complex(c_pointer(out), c_real, c_imag, + 4, c_pointer(dims), dtype)) elif dtype.value == Dtype.s64.value: - c_val = ct.c_longlong(val.real) - safe_call(backend.get().af_constant_long(ct.pointer(out), c_val, 4, ct.pointer(dims))) + c_val = c_longlong_t(val.real) + safe_call(backend.get().af_constant_long(c_pointer(out), c_val, 4, c_pointer(dims))) elif dtype.value == Dtype.u64.value: - c_val = ct.c_ulonglong(val.real) - safe_call(backend.get().af_constant_ulong(ct.pointer(out), c_val, 4, ct.pointer(dims))) + c_val = c_ulonglong_t(val.real) + safe_call(backend.get().af_constant_ulong(c_pointer(out), c_val, 4, c_pointer(dims))) else: - c_val = ct.c_double(val) - safe_call(backend.get().af_constant(ct.pointer(out), c_val, 4, ct.pointer(dims), dtype)) + c_val = c_double_t(val) + safe_call(backend.get().af_constant(c_pointer(out), c_val, 4, c_pointer(dims), dtype)) return out @@ -109,7 +109,7 @@ def _binary_func(lhs, rhs, c_func): elif not isinstance(rhs, Array): raise TypeError("Invalid parameter to binary function") - safe_call(c_func(ct.pointer(out.arr), lhs.arr, other.arr, _bcast_var.get())) + safe_call(c_func(c_pointer(out.arr), lhs.arr, other.arr, _bcast_var.get())) return out @@ -125,7 +125,7 @@ def _binary_funcr(lhs, rhs, c_func): elif not isinstance(lhs, Array): raise TypeError("Invalid parameter to binary function") - c_func(ct.pointer(out.arr), other.arr, rhs.arr, _bcast_var.get()) + c_func(c_pointer(out.arr), other.arr, rhs.arr, _bcast_var.get()) return out @@ -257,7 +257,7 @@ def transpose(a, conj=False): """ out = Array() - safe_call(backend.get().af_transpose(ct.pointer(out.arr), a.arr, conj)) + safe_call(backend.get().af_transpose(c_pointer(out.arr), a.arr, conj)) return out def transpose_inplace(a, conj=False): @@ -403,7 +403,7 @@ def __init__(self, src=None, dims=(0,), dtype=None, is_device=False, offset=None if src is not None: if (isinstance(src, Array)): - safe_call(backend.get().af_retain_array(ct.pointer(self.arr), src.arr)) + safe_call(backend.get().af_retain_array(c_pointer(self.arr), src.arr)) return host = __import__("array") @@ -417,8 +417,8 @@ def __init__(self, src=None, dims=(0,), dtype=None, is_device=False, offset=None buf,buf_len = tmp.buffer_info() _type_char = tmp.typecode numdims, idims = _get_info(dims, buf_len) - elif isinstance(src, int) or isinstance(src, ct.c_void_p): - buf = src if not isinstance(src, ct.c_void_p) else src.value + elif isinstance(src, int) or isinstance(src, c_void_ptr_t): + buf = src if not isinstance(src, c_void_ptr_t) else src.value numdims, idims = _get_info(dims, buf_len) @@ -476,7 +476,7 @@ def copy(self): An identical copy of self. """ out = Array() - safe_call(backend.get().af_copy_array(ct.pointer(out.arr), self.arr)) + safe_call(backend.get().af_copy_array(c_pointer(out.arr), self.arr)) return out def __del__(self): @@ -503,8 +503,8 @@ def device_ptr(self): - A copy of the memory is done if multiple arrays share the same memory or the array is not the owner of the memory. - In case of a copy the return value points to the newly allocated memory which is now exclusively owned by the array. """ - ptr = ct.c_void_p(0) - backend.get().af_get_device_ptr(ct.pointer(ptr), self.arr) + ptr = c_void_ptr_t(0) + backend.get().af_get_device_ptr(c_pointer(ptr), self.arr) return ptr.value def raw_ptr(self): @@ -524,8 +524,8 @@ def raw_ptr(self): - In particular the JIT compiler will not be aware of the shared arrays. - This results in JITed operations not being immediately visible through the other array. """ - ptr = ct.c_void_p(0) - backend.get().af_get_raw_ptr(ct.pointer(ptr), self.arr) + ptr = c_void_ptr_t(0) + backend.get().af_get_raw_ptr(c_pointer(ptr), self.arr) return ptr.value def offset(self): @@ -538,7 +538,7 @@ def offset(self): The offset in number of elements """ offset = c_dim_t(0) - safe_call(backend.get().af_get_offset(ct.pointer(offset), self.arr)) + safe_call(backend.get().af_get_offset(c_pointer(offset), self.arr)) return offset.value def strides(self): @@ -554,8 +554,8 @@ def strides(self): s1 = c_dim_t(0) s2 = c_dim_t(0) s3 = c_dim_t(0) - safe_call(backend.get().af_get_strides(ct.pointer(s0), ct.pointer(s1), - ct.pointer(s2), ct.pointer(s3), self.arr)) + safe_call(backend.get().af_get_strides(c_pointer(s0), c_pointer(s1), + c_pointer(s2), c_pointer(s3), self.arr)) strides = (s0.value,s1.value,s2.value,s3.value) return strides[:self.numdims()] @@ -564,15 +564,15 @@ def elements(self): Return the number of elements in the array. """ num = c_dim_t(0) - safe_call(backend.get().af_get_elements(ct.pointer(num), self.arr)) + safe_call(backend.get().af_get_elements(c_pointer(num), self.arr)) return num.value def dtype(self): """ Return the data type as a arrayfire.Dtype enum value. """ - dty = ct.c_int(Dtype.f32.value) - safe_call(backend.get().af_get_type(ct.pointer(dty), self.arr)) + dty = c_int_t(Dtype.f32.value) + safe_call(backend.get().af_get_type(c_pointer(dty), self.arr)) return to_dtype[to_typecode[dty.value]] def type(self): @@ -603,8 +603,8 @@ def dims(self): d1 = c_dim_t(0) d2 = c_dim_t(0) d3 = c_dim_t(0) - safe_call(backend.get().af_get_dims(ct.pointer(d0), ct.pointer(d1), - ct.pointer(d2), ct.pointer(d3), self.arr)) + safe_call(backend.get().af_get_dims(c_pointer(d0), c_pointer(d1), + c_pointer(d2), c_pointer(d3), self.arr)) dims = (d0.value,d1.value,d2.value,d3.value) return dims[:self.numdims()] @@ -619,40 +619,40 @@ def numdims(self): """ Return the number of dimensions of the array. """ - nd = ct.c_uint(0) - safe_call(backend.get().af_get_numdims(ct.pointer(nd), self.arr)) + nd = c_uint_t(0) + safe_call(backend.get().af_get_numdims(c_pointer(nd), self.arr)) return nd.value def is_empty(self): """ Check if the array is empty i.e. it has no elements. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_empty(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_empty(c_pointer(res), self.arr)) return res.value def is_scalar(self): """ Check if the array is scalar i.e. it has only one element. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_scalar(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_scalar(c_pointer(res), self.arr)) return res.value def is_row(self): """ Check if the array is a row i.e. it has a shape of (1, cols). """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_row(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_row(c_pointer(res), self.arr)) return res.value def is_column(self): """ Check if the array is a column i.e. it has a shape of (rows, 1). """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_column(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_column(c_pointer(res), self.arr)) return res.value def is_vector(self): @@ -663,96 +663,96 @@ def is_vector(self): - (1, 1, vols) - (1, 1, 1, batch) """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_vector(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_vector(c_pointer(res), self.arr)) return res.value def is_sparse(self): """ Check if the array is a sparse matrix. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_sparse(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_sparse(c_pointer(res), self.arr)) return res.value def is_complex(self): """ Check if the array is of complex type. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_complex(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_complex(c_pointer(res), self.arr)) return res.value def is_real(self): """ Check if the array is not of complex type. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_real(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_real(c_pointer(res), self.arr)) return res.value def is_double(self): """ Check if the array is of double precision floating point type. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_double(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_double(c_pointer(res), self.arr)) return res.value def is_single(self): """ Check if the array is of single precision floating point type. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_single(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_single(c_pointer(res), self.arr)) return res.value def is_real_floating(self): """ Check if the array is real and of floating point type. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_realfloating(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_realfloating(c_pointer(res), self.arr)) return res.value def is_floating(self): """ Check if the array is of floating point type. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_floating(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_floating(c_pointer(res), self.arr)) return res.value def is_integer(self): """ Check if the array is of integer type. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_integer(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_integer(c_pointer(res), self.arr)) return res.value def is_bool(self): """ Check if the array is of type b8. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_bool(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_bool(c_pointer(res), self.arr)) return res.value def is_linear(self): """ Check if all elements of the array are contiguous. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_linear(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_linear(c_pointer(res), self.arr)) return res.value def is_owner(self): """ Check if the array owns the raw pointer or is a derived array. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_owner(ct.pointer(res), self.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_owner(c_pointer(res), self.arr)) return res.value def __add__(self, other): @@ -1033,7 +1033,7 @@ def __getitem__(self, key): inds = _get_indices(key) - safe_call(backend.get().af_index_gen(ct.pointer(out.arr), + safe_call(backend.get().af_index_gen(c_pointer(out.arr), self.arr, c_dim_t(n_dims), inds.pointer)) return out except RuntimeError as e: @@ -1071,10 +1071,10 @@ def __setitem__(self, key, val): other_arr = val.arr del_other = False - out_arr = ct.c_void_p(0) + out_arr = c_void_ptr_t(0) inds = _get_indices(key) - safe_call(backend.get().af_assign_gen(ct.pointer(out_arr), + safe_call(backend.get().af_assign_gen(c_pointer(out_arr), self.arr, c_dim_t(n_dims), inds.pointer, other_arr)) safe_call(backend.get().af_release_array(self.arr)) @@ -1113,7 +1113,7 @@ def to_ctype(self, row_major=False, return_shape=False): tmp = transpose(self) if row_major else self ctype_type = to_c_type[self.type()] * self.elements() res = ctype_type() - safe_call(backend.get().af_get_data_ptr(ct.pointer(res), self.arr)) + safe_call(backend.get().af_get_data_ptr(c_pointer(res), self.arr)) if (return_shape): return res, self.dims() else: @@ -1188,8 +1188,8 @@ def __repr__(self): You can also use af.display(a, pres) to display the contents of the array with better precision. """ - arr_str = ct.c_char_p(0) - safe_call(backend.get().af_array_to_string(ct.pointer(arr_str), "", self.arr, 4, True)) + arr_str = c_char_ptr_t(0) + safe_call(backend.get().af_array_to_string(c_pointer(arr_str), "", self.arr, 4, True)) return 'arrayfire.Array()\nType: %s' % \ (to_typename[self.type()]) + to_str(arr_str) @@ -1200,7 +1200,7 @@ def __array__(self): """ import numpy as np res = np.empty(self.dims(), dtype=np.dtype(to_typecode[self.type()]), order='F') - safe_call(backend.get().af_get_data_ptr(ct.c_void_p(res.ctypes.data), self.arr)) + safe_call(backend.get().af_get_data_ptr(c_void_ptr_t(res.ctypes.data), self.arr)) return res def display(a, precision=4): @@ -1226,7 +1226,7 @@ def display(a, precision=4): pass safe_call(backend.get().af_print_array_gen(name.encode('utf-8'), - a.arr, ct.c_int(precision))) + a.arr, c_int_t(precision))) def save_array(key, a, filename, append=False): """ @@ -1251,8 +1251,8 @@ def save_array(key, a, filename, append=False): index : int The index of the array stored in the file. """ - index = ct.c_int(-1) - safe_call(backend.get().af_save_array(ct.pointer(index), + index = c_int_t(-1) + safe_call(backend.get().af_save_array(c_pointer(index), key.encode('utf-8'), a.arr, filename.encode('utf-8'), @@ -1283,11 +1283,11 @@ def read_array(filename, index=None, key=None): assert((index is not None) or (key is not None)) out = Array() if (index is not None): - safe_call(backend.get().af_read_array_index(ct.pointer(out.arr), + safe_call(backend.get().af_read_array_index(c_pointer(out.arr), filename.encode('utf-8'), index)) elif (key is not None): - safe_call(backend.get().af_read_array_key(ct.pointer(out.arr), + safe_call(backend.get().af_read_array_key(c_pointer(out.arr), filename.encode('utf-8'), key.encode('utf-8'))) diff --git a/arrayfire/base.py b/arrayfire/base.py index 90b220590..ca072fa2c 100644 --- a/arrayfire/base.py +++ b/arrayfire/base.py @@ -19,4 +19,4 @@ class BaseArray(object): Base array class for arrayfire. For internal use only. """ def __init__(self): - self.arr = ct.c_void_p(0) + self.arr = c_void_ptr_t(0) diff --git a/arrayfire/blas.py b/arrayfire/blas.py index a3774f106..4fa7ffad6 100644 --- a/arrayfire/blas.py +++ b/arrayfire/blas.py @@ -53,7 +53,7 @@ def matmul(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE): """ out = Array() - safe_call(backend.get().af_matmul(ct.pointer(out.arr), lhs.arr, rhs.arr, + safe_call(backend.get().af_matmul(c_pointer(out.arr), lhs.arr, rhs.arr, lhs_opts.value, rhs_opts.value)) return out @@ -84,7 +84,7 @@ def matmulTN(lhs, rhs): """ out = Array() - safe_call(backend.get().af_matmul(ct.pointer(out.arr), lhs.arr, rhs.arr, + safe_call(backend.get().af_matmul(c_pointer(out.arr), lhs.arr, rhs.arr, MATPROP.TRANS.value, MATPROP.NONE.value)) return out @@ -115,7 +115,7 @@ def matmulNT(lhs, rhs): """ out = Array() - safe_call(backend.get().af_matmul(ct.pointer(out.arr), lhs.arr, rhs.arr, + safe_call(backend.get().af_matmul(c_pointer(out.arr), lhs.arr, rhs.arr, MATPROP.NONE.value, MATPROP.TRANS.value)) return out @@ -146,7 +146,7 @@ def matmulTT(lhs, rhs): """ out = Array() - safe_call(backend.get().af_matmul(ct.pointer(out.arr), lhs.arr, rhs.arr, + safe_call(backend.get().af_matmul(c_pointer(out.arr), lhs.arr, rhs.arr, MATPROP.TRANS.value, MATPROP.TRANS.value)) return out @@ -187,6 +187,6 @@ def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE): """ out = Array() - safe_call(backend.get().af_dot(ct.pointer(out.arr), lhs.arr, rhs.arr, + safe_call(backend.get().af_dot(c_pointer(out.arr), lhs.arr, rhs.arr, lhs_opts.value, rhs_opts.value)) return out diff --git a/arrayfire/cuda.py b/arrayfire/cuda.py index 4ca7810a7..ea24c0e30 100644 --- a/arrayfire/cuda.py +++ b/arrayfire/cuda.py @@ -35,8 +35,8 @@ def get_stream(idx): if (backend.name() != "cuda"): raise RuntimeError("Invalid backend loaded") - stream = ct.c_void_p(0) - safe_call(backend.get().afcu_get_stream(ct.pointer(stream), idx)) + stream = c_void_ptr_t(0) + safe_call(backend.get().afcu_get_stream(c_pointer(stream), idx)) return stream.value def get_native_id(idx): @@ -61,8 +61,8 @@ def get_native_id(idx): if (backend.name() != "cuda"): raise RuntimeError("Invalid backend loaded") - native = ct.c_int(0) - safe_call(backend.get().afcu_get_native_id(ct.pointer(native), idx)) + native = c_int_t(0) + safe_call(backend.get().afcu_get_native_id(c_pointer(native), idx)) return native.value def set_native_id(idx): diff --git a/arrayfire/data.py b/arrayfire/data.py index 786d64902..0e953f707 100644 --- a/arrayfire/data.py +++ b/arrayfire/data.py @@ -118,7 +118,7 @@ def range(d0, d1=None, d2=None, d3=None, dim=0, dtype=Dtype.f32): out = Array() dims = dim4(d0, d1, d2, d3) - safe_call(backend.get().af_range(ct.pointer(out.arr), 4, ct.pointer(dims), dim, dtype.value)) + safe_call(backend.get().af_range(c_pointer(out.arr), 4, c_pointer(dims), dim, dtype.value)) return out @@ -183,8 +183,8 @@ def iota(d0, d1=None, d2=None, d3=None, dim=-1, tile_dims=None, dtype=Dtype.f32) tdims = dim4(td[0], td[1], td[2], td[3]) - safe_call(backend.get().af_iota(ct.pointer(out.arr), 4, ct.pointer(dims), - 4, ct.pointer(tdims), dtype.value)) + safe_call(backend.get().af_iota(c_pointer(out.arr), 4, c_pointer(dims), + 4, c_pointer(tdims), dtype.value)) return out def identity(d0, d1, d2=None, d3=None, dtype=Dtype.f32): @@ -221,7 +221,7 @@ def identity(d0, d1, d2=None, d3=None, dtype=Dtype.f32): out = Array() dims = dim4(d0, d1, d2, d3) - safe_call(backend.get().af_identity(ct.pointer(out.arr), 4, ct.pointer(dims), dtype.value)) + safe_call(backend.get().af_identity(c_pointer(out.arr), 4, c_pointer(dims), dtype.value)) return out def diag(a, num=0, extract=True): @@ -252,9 +252,9 @@ def diag(a, num=0, extract=True): """ out = Array() if extract: - safe_call(backend.get().af_diag_extract(ct.pointer(out.arr), a.arr, ct.c_int(num))) + safe_call(backend.get().af_diag_extract(c_pointer(out.arr), a.arr, c_int_t(num))) else: - safe_call(backend.get().af_diag_create(ct.pointer(out.arr), a.arr, ct.c_int(num))) + safe_call(backend.get().af_diag_create(c_pointer(out.arr), a.arr, c_int_t(num))) return out def join(dim, first, second, third=None, fourth=None): @@ -317,9 +317,9 @@ def join(dim, first, second, third=None, fourth=None): """ out = Array() if (third is None and fourth is None): - safe_call(backend.get().af_join(ct.pointer(out.arr), dim, first.arr, second.arr)) + safe_call(backend.get().af_join(c_pointer(out.arr), dim, first.arr, second.arr)) else: - c_void_p_4 = ct.c_void_p * 4 + c_void_p_4 = c_void_ptr_t * 4 c_array_vec = c_void_p_4(first.arr, second.arr, 0, 0) num = 2 if third is not None: @@ -329,7 +329,7 @@ def join(dim, first, second, third=None, fourth=None): c_array_vec[num] = fourth.arr num+=1 - safe_call(backend.get().af_join_many(ct.pointer(out.arr), dim, num, ct.pointer(c_array_vec))) + safe_call(backend.get().af_join_many(c_pointer(out.arr), dim, num, c_pointer(c_array_vec))) return out @@ -394,7 +394,7 @@ def tile(a, d0, d1=1, d2=1, d3=1): 0.8224 0.1794 0.0081 0.8224 0.1794 0.0081 """ out = Array() - safe_call(backend.get().af_tile(ct.pointer(out.arr), a.arr, d0, d1, d2, d3)) + safe_call(backend.get().af_tile(c_pointer(out.arr), a.arr, d0, d1, d2, d3)) return out @@ -479,7 +479,7 @@ def reorder(a, d0=1, d1=0, d2=2, d3=3): 0.9276 0.8662 0.3578 0.6263 0.9747 """ out = Array() - safe_call(backend.get().af_reorder(ct.pointer(out.arr), a.arr, d0, d1, d2, d3)) + safe_call(backend.get().af_reorder(c_pointer(out.arr), a.arr, d0, d1, d2, d3)) return out def shift(a, d0, d1=0, d2=0, d3=0): @@ -535,7 +535,7 @@ def shift(a, d0, d1=0, d2=0, d3=0): 0.1437 0.0899 0.7104 """ out = Array() - safe_call(backend.get().af_shift(ct.pointer(out.arr), a.arr, d0, d1, d2, d3)) + safe_call(backend.get().af_shift(c_pointer(out.arr), a.arr, d0, d1, d2, d3)) return out def moddims(a, d0, d1=1, d2=1, d3=1): @@ -569,7 +569,7 @@ def moddims(a, d0, d1=1, d2=1, d3=1): """ out = Array() dims = dim4(d0, d1, d2, d3) - safe_call(backend.get().af_moddims(ct.pointer(out.arr), a.arr, 4, ct.pointer(dims))) + safe_call(backend.get().af_moddims(c_pointer(out.arr), a.arr, 4, c_pointer(dims))) return out def flat(a): @@ -589,7 +589,7 @@ def flat(a): - 1 dimensional array containing all the elements from `a`. """ out = Array() - safe_call(backend.get().af_flat(ct.pointer(out.arr), a.arr)) + safe_call(backend.get().af_flat(c_pointer(out.arr), a.arr)) return out def flip(a, dim=0): @@ -636,7 +636,7 @@ def flip(a, dim=0): """ out = Array() - safe_call(backend.get().af_flip(ct.pointer(out.arr), a.arr, ct.c_int(dim))) + safe_call(backend.get().af_flip(c_pointer(out.arr), a.arr, c_int_t(dim))) return out def lower(a, is_unit_diag=False): @@ -659,7 +659,7 @@ def lower(a, is_unit_diag=False): An array containing the lower triangular elements from `a`. """ out = Array() - safe_call(backend.get().af_lower(ct.pointer(out.arr), a.arr, is_unit_diag)) + safe_call(backend.get().af_lower(c_pointer(out.arr), a.arr, is_unit_diag)) return out def upper(a, is_unit_diag=False): @@ -682,7 +682,7 @@ def upper(a, is_unit_diag=False): An array containing the upper triangular elements from `a`. """ out = Array() - safe_call(backend.get().af_upper(ct.pointer(out.arr), a.arr, is_unit_diag)) + safe_call(backend.get().af_upper(c_pointer(out.arr), a.arr, is_unit_diag)) return out def select(cond, lhs, rhs): @@ -743,12 +743,12 @@ def select(cond, lhs, rhs): raise TypeError("Atleast one input needs to be of type arrayfire.array") elif (is_left_array and is_right_array): - safe_call(backend.get().af_select(ct.pointer(out.arr), cond.arr, lhs.arr, rhs.arr)) + safe_call(backend.get().af_select(c_pointer(out.arr), cond.arr, lhs.arr, rhs.arr)) elif (_is_number(rhs)): - safe_call(backend.get().af_select_scalar_r(ct.pointer(out.arr), cond.arr, lhs.arr, ct.c_double(rhs))) + safe_call(backend.get().af_select_scalar_r(c_pointer(out.arr), cond.arr, lhs.arr, c_double_t(rhs))) else: - safe_call(backend.get().af_select_scalar_l(ct.pointer(out.arr), cond.arr, ct.c_double(lhs), rhs.arr)) + safe_call(backend.get().af_select_scalar_l(c_pointer(out.arr), cond.arr, c_double_t(lhs), rhs.arr)) return out @@ -798,4 +798,4 @@ def replace(lhs, cond, rhs): if (is_right_array): safe_call(backend.get().af_replace(lhs.arr, cond.arr, rhs.arr)) else: - safe_call(backend.get().af_replace_scalar(lhs.arr, cond.arr, ct.c_double(rhs))) + safe_call(backend.get().af_replace_scalar(lhs.arr, cond.arr, c_double_t(rhs))) diff --git a/arrayfire/device.py b/arrayfire/device.py index b13989b65..ad8abd512 100644 --- a/arrayfire/device.py +++ b/arrayfire/device.py @@ -39,14 +39,14 @@ def device_info(): - 'toolkit': The toolkit version for the backend. - 'compute': The compute version of the device. """ - c_char_256 = ct.c_char * 256 + c_char_256 = c_char_t * 256 device_name = c_char_256() backend_name = c_char_256() toolkit = c_char_256() compute = c_char_256() - safe_call(backend.get().af_device_info(ct.pointer(device_name), ct.pointer(backend_name), - ct.pointer(toolkit), ct.pointer(compute))) + safe_call(backend.get().af_device_info(c_pointer(device_name), c_pointer(backend_name), + c_pointer(toolkit), c_pointer(compute))) dev_info = {} dev_info['device'] = to_str(device_name) dev_info['backend'] = to_str(backend_name) @@ -59,16 +59,16 @@ def get_device_count(): """ Returns the number of devices available. """ - c_num = ct.c_int(0) - safe_call(backend.get().af_get_device_count(ct.pointer(c_num))) + c_num = c_int_t(0) + safe_call(backend.get().af_get_device_count(c_pointer(c_num))) return c_num.value def get_device(): """ Returns the id of the current device. """ - c_dev = ct.c_int(0) - safe_call(backend.get().af_get_device(ct.pointer(c_dev))) + c_dev = c_int_t(0) + safe_call(backend.get().af_get_device(c_pointer(c_dev))) return c_dev.value def set_device(num): @@ -146,8 +146,8 @@ def is_dbl_supported(device=None): - False if double precision not supported. """ dev = device if device is not None else get_device() - res = ct.c_bool(False) - safe_call(backend.get().af_get_dbl_support(ct.pointer(res), dev)) + res = c_bool_t(False) + safe_call(backend.get().af_get_dbl_support(c_pointer(res), dev)) return res.value def sync(device=None): @@ -167,11 +167,11 @@ def __eval(*args): if (nargs == 1): safe_call(backend.get().af_eval(args[0].arr)) else: - c_void_p_n = ct.c_void_p * nargs + c_void_p_n = c_void_ptr_t * nargs arrs = c_void_p_n() for n in range(nargs): arrs[n] = args[n].arr - safe_call(backend.get().af_eval_multiple(ct.c_int(nargs), ct.pointer(arrs))) + safe_call(backend.get().af_eval_multiple(c_int_t(nargs), c_pointer(arrs))) return def eval(*args): @@ -241,8 +241,8 @@ def get_manual_eval_flag(): ---- This does not affect the evaluation that occurs when a non JIT function forces the evaluation. """ - res = ct.c_bool(False) - safe_call(backend.get().af_get_manual_eval_flag(ct.pointer(res))) + res = c_bool_t(False) + safe_call(backend.get().af_get_manual_eval_flag(c_pointer(res))) return res.value def device_mem_info(): @@ -262,12 +262,12 @@ def device_mem_info(): - The difference between alloc bytes and lock bytes equals the number of free bytes. """ - alloc_bytes = ct.c_size_t(0) - alloc_buffers = ct.c_size_t(0) - lock_bytes = ct.c_size_t(0) - lock_buffers = ct.c_size_t(0) - safe_call(backend.get().af_device_mem_info(ct.pointer(alloc_bytes), ct.pointer(alloc_buffers), - ct.pointer(lock_bytes), ct.pointer(lock_buffers))) + alloc_bytes = c_size_t(0) + alloc_buffers = c_size_t(0) + lock_bytes = c_size_t(0) + lock_buffers = c_size_t(0) + safe_call(backend.get().af_device_mem_info(c_pointer(alloc_bytes), c_pointer(alloc_buffers), + c_pointer(lock_bytes), c_pointer(lock_buffers))) mem_info = {} mem_info['alloc'] = {'buffers' : alloc_buffers.value, 'bytes' : alloc_bytes.value} mem_info['lock'] = {'buffers' : lock_buffers.value, 'bytes' : lock_bytes.value} @@ -298,8 +298,8 @@ def get_device_ptr(a): - This function enables the user to interoperate arrayfire with other CUDA/OpenCL/C libraries. """ - ptr = ct.c_void_p(0) - safe_call(backend.get().af_get_device_ptr(ct.pointer(ptr), a.arr)) + ptr = c_void_ptr_t(0) + safe_call(backend.get().af_get_device_ptr(c_pointer(ptr), a.arr)) return ptr def lock_device_ptr(a): @@ -338,8 +338,8 @@ def is_locked_array(a): ----------- A bool specifying if the input array is locked. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_locked_array(ct.pointer(res), a.arr)) + res = c_bool_t(False) + safe_call(backend.get().af_is_locked_array(c_pointer(res), a.arr)) return res.value def unlock_device_ptr(a): @@ -366,48 +366,48 @@ def alloc_device(num_bytes): """ Allocate a buffer on the device with specified number of bytes. """ - ptr = ct.c_void_p(0) + ptr = c_void_ptr_t(0) c_num_bytes = c_dim_t(num_bytes) - safe_call(backend.get().af_alloc_device(ct.pointer(ptr), c_num_bytes)) + safe_call(backend.get().af_alloc_device(c_pointer(ptr), c_num_bytes)) return ptr.value def alloc_host(num_bytes): """ Allocate a buffer on the host with specified number of bytes. """ - ptr = ct.c_void_p(0) + ptr = c_void_ptr_t(0) c_num_bytes = c_dim_t(num_bytes) - safe_call(backend.get().af_alloc_host(ct.pointer(ptr), c_num_bytes)) + safe_call(backend.get().af_alloc_host(c_pointer(ptr), c_num_bytes)) return ptr.value def alloc_pinned(num_bytes): """ Allocate a buffer on the host using pinned memory with specified number of bytes. """ - ptr = ct.c_void_p(0) + ptr = c_void_ptr_t(0) c_num_bytes = c_dim_t(num_bytes) - safe_call(backend.get().af_alloc_pinned(ct.pointer(ptr), c_num_bytes)) + safe_call(backend.get().af_alloc_pinned(c_pointer(ptr), c_num_bytes)) return ptr.value def free_device(ptr): """ Free the device memory allocated by alloc_device """ - cptr = ct.c_void_p(ptr) + cptr = c_void_ptr_t(ptr) safe_call(backend.get().af_free_device(cptr)) def free_host(ptr): """ Free the host memory allocated by alloc_host """ - cptr = ct.c_void_p(ptr) + cptr = c_void_ptr_t(ptr) safe_call(backend.get().af_free_host(cptr)) def free_pinned(ptr): """ Free the pinned memory allocated by alloc_pinned """ - cptr = ct.c_void_p(ptr) + cptr = c_void_ptr_t(ptr) safe_call(backend.get().af_free_pinned(cptr)) from .array import Array diff --git a/arrayfire/features.py b/arrayfire/features.py index 6e006afcc..efb24898e 100644 --- a/arrayfire/features.py +++ b/arrayfire/features.py @@ -27,17 +27,17 @@ class Features(object): """ def __init__(self, num=0): - self.feat = ct.c_void_p(0) + self.feat = c_void_ptr_t(0) if num is not None: assert(isinstance(num, numbers.Number)) - safe_call(backend.get().af_create_features(ct.pointer(self.feat), c_dim_t(num))) + safe_call(backend.get().af_create_features(c_pointer(self.feat), c_dim_t(num))) def num_features(self): """ Returns the number of features detected. """ num = c_dim_t(0) - safe_call(backend.get().af_get_features_num(ct.pointer(num), self.feat)) + safe_call(backend.get().af_get_features_num(c_pointer(num), self.feat)) return num def get_xpos(self): @@ -45,7 +45,7 @@ def get_xpos(self): Returns the x-positions of the features detected. """ out = Array() - safe_call(backend.get().af_get_features_xpos(ct.pointer(out.arr), self.feat)) + safe_call(backend.get().af_get_features_xpos(c_pointer(out.arr), self.feat)) return out def get_ypos(self): @@ -53,7 +53,7 @@ def get_ypos(self): Returns the y-positions of the features detected. """ out = Array() - safe_call(backend.get().af_get_features_ypos(ct.pointer(out.arr), self.feat)) + safe_call(backend.get().af_get_features_ypos(c_pointer(out.arr), self.feat)) return out def get_score(self): @@ -61,7 +61,7 @@ def get_score(self): Returns the scores of the features detected. """ out = Array() - safe_call(backend.get().af_get_features_score(ct.pointer(out.arr), self.feat)) + safe_call(backend.get().af_get_features_score(c_pointer(out.arr), self.feat)) return out def get_orientation(self): @@ -69,7 +69,7 @@ def get_orientation(self): Returns the orientations of the features detected. """ out = Array() - safe_call(backend.get().af_get_features_orientation(ct.pointer(out.arr), self.feat)) + safe_call(backend.get().af_get_features_orientation(c_pointer(out.arr), self.feat)) return out def get_size(self): @@ -77,5 +77,5 @@ def get_size(self): Returns the sizes of the features detected. """ out = Array() - safe_call(backend.get().af_get_features_size(ct.pointer(out.arr), self.feat)) + safe_call(backend.get().af_get_features_size(c_pointer(out.arr), self.feat)) return out diff --git a/arrayfire/graphics.py b/arrayfire/graphics.py index 59da8dbf7..3ada18737 100644 --- a/arrayfire/graphics.py +++ b/arrayfire/graphics.py @@ -16,15 +16,15 @@ from .util import _is_number class _Cell(ct.Structure): - _fields_ = [("row", ct.c_int), - ("col", ct.c_int), - ("title", ct.c_char_p), - ("cmap", ct.c_int)] + _fields_ = [("row", c_int_t), + ("col", c_int_t), + ("title", c_char_ptr_t), + ("cmap", c_int_t)] def __init__(self, r, c, title, cmap): self.row = r self.col = c - self.title = title if title is not None else ct.c_char_p() + self.title = title if title is not None else c_char_ptr_t() self.cmap = cmap.value class Window(object): @@ -48,7 +48,7 @@ class Window(object): def __init__(self, width=1280, height=720, title="ArrayFire"): self._r = -1 self._c = -1 - self._wnd = ct.c_void_p(0) + self._wnd = c_void_ptr_t(0) self._cmap = COLORMAP.DEFAULT _width = 1280 if width is None else width @@ -57,9 +57,9 @@ def __init__(self, width=1280, height=720, title="ArrayFire"): _title = _title.encode("ascii") - safe_call(backend.get().af_create_window(ct.pointer(self._wnd), - ct.c_int(_width), ct.c_int(_height), - ct.c_char_p(_title))) + safe_call(backend.get().af_create_window(c_pointer(self._wnd), + c_int_t(_width), c_int_t(_height), + c_char_ptr_t(_title))) def __del__(self): """ @@ -81,7 +81,7 @@ def set_pos(self, x, y): Pixel offset from top """ - safe_call(backend.get().af_set_position(self._wnd, ct.c_int(x), ct.c_int(y))) + safe_call(backend.get().af_set_position(self._wnd, c_int_t(x), c_int_t(y))) def set_title(self, title): """ @@ -138,7 +138,7 @@ def image(self, img, title=None): Title used for the image. """ _cell = _Cell(self._r, self._c, title, self._cmap) - safe_call(backend.get().af_draw_image(self._wnd, img.arr, ct.pointer(_cell))) + safe_call(backend.get().af_draw_image(self._wnd, img.arr, c_pointer(_cell))) def scatter(self, X, Y, Z=None, points=None, marker=MARKER.POINT, title=None): """ @@ -172,12 +172,12 @@ def scatter(self, X, Y, Z=None, points=None, marker=MARKER.POINT, title=None): if points is None: if Z is None: safe_call(backend.get().af_draw_scatter_2d(self._wnd, X.arr, Y.arr, - marker.value, ct.pointer(_cell))) + marker.value, c_pointer(_cell))) else: safe_call(backend.get().af_draw_scatter_3d(self._wnd, X.arr, Y.arr, Z.arr, - marker.value, ct.pointer(_cell))) + marker.value, c_pointer(_cell))) else: - safe_call(backend.get().af_draw_scatter_nd(self._wnd, points.arr, marker.value, ct.pointer(_cell))) + safe_call(backend.get().af_draw_scatter_nd(self._wnd, points.arr, marker.value, c_pointer(_cell))) def scatter2(self, points, marker=MARKER.POINT, title=None): """ @@ -198,7 +198,7 @@ def scatter2(self, points, marker=MARKER.POINT, title=None): assert(points.numdims() == 2) _cell = _Cell(self._r, self._c, title, self._cmap) safe_call(backend.get().af_draw_scatter2(self._wnd, points.arr, - marker.value, ct.pointer(_cell))) + marker.value, c_pointer(_cell))) def scatter3(self, points, marker=MARKER.POINT, title=None): """ @@ -219,7 +219,7 @@ def scatter3(self, points, marker=MARKER.POINT, title=None): assert(points.numdims() == 3) _cell = _Cell(self._r, self._c, title, self._cmap) safe_call(backend.get().af_draw_scatter3(self._wnd, points.arr, - marker.value, ct.pointer(_cell))) + marker.value, c_pointer(_cell))) def plot(self, X, Y, Z=None, line = None, title=None): """ Display a 2D or 3D Plot. @@ -254,11 +254,11 @@ def plot(self, X, Y, Z=None, line = None, title=None): _cell = _Cell(self._r, self._c, title, self._cmap) if line is None: if Z is None: - safe_call(backend.get().af_draw_plot_2d(self._wnd, X.arr, Y.arr, ct.pointer(_cell))) + safe_call(backend.get().af_draw_plot_2d(self._wnd, X.arr, Y.arr, c_pointer(_cell))) else: - safe_call(backend.get().af_draw_plot_3d(self._wnd, X.arr, Y.arr, Z.arr, ct.pointer(_cell))) + safe_call(backend.get().af_draw_plot_3d(self._wnd, X.arr, Y.arr, Z.arr, c_pointer(_cell))) else: - safe_call(backend.get().af_draw_plot_nd(self._wnd, line.arr, ct.pointer(_cell))) + safe_call(backend.get().af_draw_plot_nd(self._wnd, line.arr, c_pointer(_cell))) def plot2(self, line, title=None): """ @@ -277,7 +277,7 @@ def plot2(self, line, title=None): assert(line.numdims() == 2) _cell = _Cell(self._r, self._c, title, self._cmap) - safe_call(backend.get().af_draw_plot_nd(self._wnd, line.arr, ct.pointer(_cell))) + safe_call(backend.get().af_draw_plot_nd(self._wnd, line.arr, c_pointer(_cell))) def plot3(self, X=None, Y=None, Z=None, line=None, title=None): """ @@ -295,7 +295,7 @@ def plot3(self, X=None, Y=None, Z=None, line=None, title=None): assert(line.numdims() == 3) _cell = _Cell(self._r, self._c, title, self._cmap) - safe_call(backend.get().af_draw_plot_nd(self._wnd, line.arr, ct.pointer(_cell))) + safe_call(backend.get().af_draw_plot_nd(self._wnd, line.arr, c_pointer(_cell))) def vector_field(self, xpoints, xdirs, ypoints, ydirs, zpoints=None, zdirs=None, points = None, dirs = None, title=None): @@ -351,14 +351,14 @@ def vector_field(self, xpoints, xdirs, ypoints, ydirs, zpoints=None, zdirs=None, safe_call(backend.get().af_draw_vector_field_2d(self._wnd, xpoints.arr, ypoints.arr, xdirs.arr, ydirs.arr, - ct.pointer(_cell))) + c_pointer(_cell))) else: safe_call(backend.get().af_draw_vector_field_2d(self._wnd, xpoints.arr, ypoints.arr, zpoints.arr, xdirs.arr, ydirs.arr, zdirs.arr, - ct.pointer(_cell))) + c_pointer(_cell))) else: - safe_call(backend.get().af_draw_plot_nd(self._wnd, points.arr, dirs.arr, ct.pointer(_cell))) + safe_call(backend.get().af_draw_plot_nd(self._wnd, points.arr, dirs.arr, c_pointer(_cell))) def surface(self, x_vals, y_vals, z_vals, title=None): """ @@ -382,7 +382,7 @@ def surface(self, x_vals, y_vals, z_vals, title=None): _cell = _Cell(self._r, self._c, title, self._cmap) safe_call(backend.get().af_draw_surface(self._wnd, x_vals.arr, y_vals.arr, z_vals.arr, - ct.pointer(_cell))) + c_pointer(_cell))) def hist(self, X, min_val, max_val, title=None): """ @@ -405,8 +405,8 @@ def hist(self, X, min_val, max_val, title=None): """ _cell = _Cell(self._r, self._c, title, self._cmap) safe_call(backend.get().af_draw_hist(self._wnd, X.arr, - ct.c_double(max_val), ct.c_double(min_val), - ct.pointer(_cell))) + c_double_t(max_val), c_double_t(min_val), + c_pointer(_cell))) def grid(self, rows, cols): """ @@ -422,7 +422,7 @@ def grid(self, rows, cols): Number of columns in the grid. """ - safe_call(backend.get().af_grid(self._wnd, ct.c_int(rows), ct.c_int(cols))) + safe_call(backend.get().af_grid(self._wnd, c_int_t(rows), c_int_t(cols))) def show(self): """ @@ -436,8 +436,8 @@ def close(self): """ Close the window. """ - tmp = ct.c_bool(True) - safe_call(backend.get().af_is_window_closed(ct.pointer(tmp), self._wnd)) + tmp = c_bool_t(True) + safe_call(backend.get().af_is_window_closed(c_pointer(tmp), self._wnd)) return tmp def set_visibility(is_visible): @@ -486,15 +486,15 @@ def set_axes_limits(self, xmin, xmax, ymin, ymax, zmin=None, zmax=None, exact=Fa _cell = _Cell(self._r, self._c, "", self._cmap) if (zmin is None or zmax is None): safe_call(backend.get().af_set_axes_limits_2d(self._wnd, - ct.c_float(xmin), ct.c_float(xmax), - ct.c_float(ymin), ct.c_float(ymax), - exact, ct.pointer(_cell))) + c_float_t(xmin), c_float_t(xmax), + c_float_t(ymin), c_float_t(ymax), + exact, c_pointer(_cell))) else: safe_call(backend.get().af_set_axes_limits_2d(self._wnd, - ct.c_float(xmin), ct.c_float(xmax), - ct.c_float(ymin), ct.c_float(ymax), - ct.c_float(zmin), ct.c_float(zmax), - exact, ct.pointer(_cell))) + c_float_t(xmin), c_float_t(xmax), + c_float_t(ymin), c_float_t(ymax), + c_float_t(zmin), c_float_t(zmax), + exact, c_pointer(_cell))) def __getitem__(self, keys): """ diff --git a/arrayfire/image.py b/arrayfire/image.py index 7ddb6de9a..5fadd991a 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -36,7 +36,7 @@ def gradient(image): """ dx = Array() dy = Array() - safe_call(backend.get().af_gradient(ct.pointer(dx.arr), ct.pointer(dy.arr), image.arr)) + safe_call(backend.get().af_gradient(c_pointer(dx.arr), c_pointer(dy.arr), image.arr)) return dx, dy def load_image(file_name, is_color=False): @@ -59,8 +59,8 @@ def load_image(file_name, is_color=False): """ assert(os.path.isfile(file_name)) image = Array() - safe_call(backend.get().af_load_image(ct.pointer(image.arr), - ct.c_char_p(file_name.encode('ascii')), is_color)) + safe_call(backend.get().af_load_image(c_pointer(image.arr), + c_char_ptr_t(file_name.encode('ascii')), is_color)) return image def save_image(image, file_name): @@ -76,7 +76,7 @@ def save_image(image, file_name): - Full path of the file name on the disk. """ assert(isinstance(file_name, str)) - safe_call(backend.get().af_save_image(ct.c_char_p(file_name.encode('ascii')), image.arr)) + safe_call(backend.get().af_save_image(c_char_ptr_t(file_name.encode('ascii')), image.arr)) return image @@ -97,8 +97,8 @@ def load_image_native(file_name): """ assert(os.path.isfile(file_name)) image = Array() - safe_call(backend.get().af_load_image_native(ct.pointer(image.arr), - ct.c_char_p(file_name.encode('ascii')))) + safe_call(backend.get().af_load_image_native(c_pointer(image.arr), + c_char_ptr_t(file_name.encode('ascii')))) return image def save_image_native(image, file_name): @@ -114,7 +114,7 @@ def save_image_native(image, file_name): - Full path of the file name on the disk. """ assert(isinstance(file_name, str)) - safe_call(backend.get().af_save_image_native(ct.c_char_p(file_name.encode('ascii')), image.arr)) + safe_call(backend.get().af_save_image_native(c_char_ptr_t(file_name.encode('ascii')), image.arr)) return image def resize(image, scale=None, odim0=None, odim1=None, method=INTERP.NEAREST): @@ -160,7 +160,7 @@ def resize(image, scale=None, odim0=None, odim1=None, method=INTERP.NEAREST): odim1 = int(scale * idims[1]) output = Array() - safe_call(backend.get().af_resize(ct.pointer(output.arr), + safe_call(backend.get().af_resize(c_pointer(output.arr), image.arr, c_dim_t(odim0), c_dim_t(odim1), method.value)) @@ -203,7 +203,7 @@ def transform(image, trans_mat, odim0 = 0, odim1 = 0, method=INTERP.NEAREST, is_ """ output = Array() - safe_call(backend.get().af_transform(ct.pointer(output.arr), + safe_call(backend.get().af_transform(c_pointer(output.arr), image.arr, trans_mat.arr, c_dim_t(odim0), c_dim_t(odim1), method.value, is_inverse)) @@ -235,8 +235,8 @@ def rotate(image, theta, is_crop = True, method = INTERP.NEAREST): - Output image after rotating. """ output = Array() - safe_call(backend.get().af_rotate(ct.pointer(output.arr), image.arr, - ct.c_float(theta), is_crop, method.value)) + safe_call(backend.get().af_rotate(c_pointer(output.arr), image.arr, + c_float_t(theta), is_crop, method.value)) return output def translate(image, trans0, trans1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST): @@ -276,7 +276,7 @@ def translate(image, trans0, trans1, odim0 = 0, odim1 = 0, method = INTERP.NEARE """ output = Array() - safe_call(backend.get().af_translate(ct.pointer(output.arr), + safe_call(backend.get().af_translate(c_pointer(output.arr), image.arr, trans0, trans1, c_dim_t(odim0), c_dim_t(odim1), method.value)) return output @@ -318,8 +318,8 @@ def scale(image, scale0, scale1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST): """ output = Array() - safe_call(backend.get().af_scale(ct.pointer(output.arr), - image.arr, ct.c_float(scale0), ct.c_float(scale1), + safe_call(backend.get().af_scale(c_pointer(output.arr), + image.arr, c_float_t(scale0), c_float_t(scale1), c_dim_t(odim0), c_dim_t(odim1), method.value)) return output @@ -363,8 +363,8 @@ def skew(image, skew0, skew1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST, is_ """ output = Array() - safe_call(backend.get().af_skew(ct.pointer(output.arr), - image.arr, ct.c_float(skew0), ct.c_float(skew1), + safe_call(backend.get().af_skew(c_pointer(output.arr), + image.arr, c_float_t(skew0), c_float_t(skew1), c_dim_t(odim0), c_dim_t(odim1), method.value, is_inverse)) @@ -407,9 +407,9 @@ def histogram(image, nbins, min_val = None, max_val = None): max_val = af_max(image) output = Array() - safe_call(backend.get().af_histogram(ct.pointer(output.arr), - image.arr, ct.c_uint(nbins), - ct.c_double(min_val), ct.c_double(max_val))) + safe_call(backend.get().af_histogram(c_pointer(output.arr), + image.arr, c_uint_t(nbins), + c_double_t(min_val), c_double_t(max_val))) return output def hist_equal(image, hist): @@ -433,7 +433,7 @@ def hist_equal(image, hist): """ output = Array() - safe_call(backend.get().af_hist_equal(ct.pointer(output.arr), image.arr, hist.arr)) + safe_call(backend.get().af_hist_equal(c_pointer(output.arr), image.arr, hist.arr)) return output def dilate(image, mask = None): @@ -461,7 +461,7 @@ def dilate(image, mask = None): mask = constant(1, 3, 3, dtype=Dtype.f32) output = Array() - safe_call(backend.get().af_dilate(ct.pointer(output.arr), image.arr, mask.arr)) + safe_call(backend.get().af_dilate(c_pointer(output.arr), image.arr, mask.arr)) return output @@ -490,7 +490,7 @@ def dilate3(volume, mask = None): mask = constant(1, 3, 3, 3, dtype=Dtype.f32) output = Array() - safe_call(backend.get().af_dilate3(ct.pointer(output.arr), volume.arr, mask.arr)) + safe_call(backend.get().af_dilate3(c_pointer(output.arr), volume.arr, mask.arr)) return output @@ -519,7 +519,7 @@ def erode(image, mask = None): mask = constant(1, 3, 3, dtype=Dtype.f32) output = Array() - safe_call(backend.get().af_erode(ct.pointer(output.arr), image.arr, mask.arr)) + safe_call(backend.get().af_erode(c_pointer(output.arr), image.arr, mask.arr)) return output @@ -549,7 +549,7 @@ def erode3(volume, mask = None): mask = constant(1, 3, 3, 3, dtype=Dtype.f32) output = Array() - safe_call(backend.get().af_erode3(ct.pointer(output.arr), volume.arr, mask.arr)) + safe_call(backend.get().af_erode3(c_pointer(output.arr), volume.arr, mask.arr)) return output @@ -580,9 +580,9 @@ def bilateral(image, s_sigma, c_sigma, is_color = False): """ output = Array() - safe_call(backend.get().af_bilateral(ct.pointer(output.arr), - image.arr, ct.c_float(s_sigma), - ct.c_float(c_sigma), is_color)) + safe_call(backend.get().af_bilateral(c_pointer(output.arr), + image.arr, c_float_t(s_sigma), + c_float_t(c_sigma), is_color)) return output def mean_shift(image, s_sigma, c_sigma, n_iter, is_color = False): @@ -615,9 +615,9 @@ def mean_shift(image, s_sigma, c_sigma, n_iter, is_color = False): """ output = Array() - safe_call(backend.get().af_mean_shift(ct.pointer(output.arr), - image.arr, ct.c_float(s_sigma), ct.c_float(c_sigma), - ct.c_uint(n_iter), is_color)) + safe_call(backend.get().af_mean_shift(c_pointer(output.arr), + image.arr, c_float_t(s_sigma), c_float_t(c_sigma), + c_uint_t(n_iter), is_color)) return output def minfilt(image, w_len = 3, w_wid = 3, edge_pad = PAD.ZERO): @@ -647,7 +647,7 @@ def minfilt(image, w_len = 3, w_wid = 3, edge_pad = PAD.ZERO): """ output = Array() - safe_call(backend.get().af_minfilt(ct.pointer(output.arr), + safe_call(backend.get().af_minfilt(c_pointer(output.arr), image.arr, c_dim_t(w_len), c_dim_t(w_wid), edge_pad.value)) return output @@ -679,7 +679,7 @@ def maxfilt(image, w_len = 3, w_wid = 3, edge_pad = PAD.ZERO): """ output = Array() - safe_call(backend.get().af_maxfilt(ct.pointer(output.arr), + safe_call(backend.get().af_maxfilt(c_pointer(output.arr), image.arr, c_dim_t(w_len), c_dim_t(w_wid), edge_pad.value)) return output @@ -707,7 +707,7 @@ def regions(image, conn = CONNECTIVITY.FOUR, out_type = Dtype.f32): """ output = Array() - safe_call(backend.get().af_regions(ct.pointer(output.arr), image.arr, + safe_call(backend.get().af_regions(c_pointer(output.arr), image.arr, conn.value, out_type.value)) return output @@ -734,8 +734,8 @@ def sobel_derivatives(image, w_len=3): """ dx = Array() dy = Array() - safe_call(backend.get().af_sobel_operator(ct.pointer(dx.arr), ct.pointer(dy.arr), - image.arr, ct.c_uint(w_len))) + safe_call(backend.get().af_sobel_operator(c_pointer(dx.arr), c_pointer(dy.arr), + image.arr, c_uint_t(w_len))) return dx,dy def gaussian_kernel(rows, cols, sigma_r = None, sigma_c = None): @@ -775,9 +775,9 @@ def gaussian_kernel(rows, cols, sigma_r = None, sigma_c = None): if (sigma_c is None): sigma_c = 0.25 * cols + 0.75 - safe_call(backend.get().af_gaussian_kernel(ct.pointer(out.arr), - ct.c_int(rows), ct.c_int(cols), - ct.c_double(sigma_r), ct.c_double(sigma_c))) + safe_call(backend.get().af_gaussian_kernel(c_pointer(out.arr), + c_int_t(rows), c_int_t(cols), + c_double_t(sigma_r), c_double_t(sigma_c))) return out def sobel_filter(image, w_len = 3, is_fast = False): @@ -839,8 +839,8 @@ def rgb2gray(image, r_factor = 0.2126, g_factor = 0.7152, b_factor = 0.0722): """ output=Array() - safe_call(backend.get().af_rgb2gray(ct.pointer(output.arr), - image.arr, ct.c_float(r_factor), ct.c_float(g_factor), ct.c_float(b_factor))) + safe_call(backend.get().af_rgb2gray(c_pointer(output.arr), + image.arr, c_float_t(r_factor), c_float_t(g_factor), c_float_t(b_factor))) return output def gray2rgb(image, r_factor = 1.0, g_factor = 1.0, b_factor = 1.0): @@ -871,8 +871,8 @@ def gray2rgb(image, r_factor = 1.0, g_factor = 1.0, b_factor = 1.0): """ output=Array() - safe_call(backend.get().af_gray2rgb(ct.pointer(output.arr), - image.arr, ct.c_float(r_factor), ct.c_float(g_factor), ct.c_float(b_factor))) + safe_call(backend.get().af_gray2rgb(c_pointer(output.arr), + image.arr, c_float_t(r_factor), c_float_t(g_factor), c_float_t(b_factor))) return output def hsv2rgb(image): @@ -893,7 +893,7 @@ def hsv2rgb(image): """ output = Array() - safe_call(backend.get().af_hsv2rgb(ct.pointer(output.arr), image.arr)) + safe_call(backend.get().af_hsv2rgb(c_pointer(output.arr), image.arr)) return output def rgb2hsv(image): @@ -914,7 +914,7 @@ def rgb2hsv(image): """ output = Array() - safe_call(backend.get().af_rgb2hsv(ct.pointer(output.arr), image.arr)) + safe_call(backend.get().af_rgb2hsv(c_pointer(output.arr), image.arr)) return output def color_space(image, to_type, from_type): @@ -940,7 +940,7 @@ def color_space(image, to_type, from_type): """ output = Array() - safe_call(backend.get().af_color_space(ct.pointer(output.arr), image.arr, + safe_call(backend.get().af_color_space(c_pointer(output.arr), image.arr, to_type.value, from_type.value)) return output @@ -1006,7 +1006,7 @@ def unwrap(image, wx, wy, sx, sy, px=0, py=0, is_column=True): """ out = Array() - safe_call(backend.get().af_unwrap(ct.pointer(out.arr), image.arr, + safe_call(backend.get().af_unwrap(c_pointer(out.arr), image.arr, c_dim_t(wx), c_dim_t(wy), c_dim_t(sx), c_dim_t(sy), c_dim_t(px), c_dim_t(py), @@ -1088,7 +1088,7 @@ def wrap(a, ox, oy, wx, wy, sx, sy, px=0, py=0, is_column=True): """ out = Array() - safe_call(backend.get().af_wrap(ct.pointer(out.arr), a.arr, + safe_call(backend.get().af_wrap(c_pointer(out.arr), a.arr, c_dim_t(ox), c_dim_t(oy), c_dim_t(wx), c_dim_t(wy), c_dim_t(sx), c_dim_t(sy), @@ -1112,7 +1112,7 @@ def sat(image): """ out = Array() - safe_call(backend.get().af_sat(ct.pointer(out.arr), image.arr)) + safe_call(backend.get().af_sat(c_pointer(out.arr), image.arr)) return out def ycbcr2rgb(image, standard=YCC_STD.BT_601): @@ -1138,7 +1138,7 @@ def ycbcr2rgb(image, standard=YCC_STD.BT_601): """ out = Array() - safe_call(backend.get().af_ycbcr2rgb(ct.pointer(out.arr), image.arr, standard.value)) + safe_call(backend.get().af_ycbcr2rgb(c_pointer(out.arr), image.arr, standard.value)) return out def rgb2ycbcr(image, standard=YCC_STD.BT_601): @@ -1164,7 +1164,7 @@ def rgb2ycbcr(image, standard=YCC_STD.BT_601): """ out = Array() - safe_call(backend.get().af_rgb2ycbcr(ct.pointer(out.arr), image.arr, standard.value)) + safe_call(backend.get().af_rgb2ycbcr(c_pointer(out.arr), image.arr, standard.value)) return out def moments(image, moment = MOMENT.FIRST_ORDER): @@ -1191,13 +1191,13 @@ def moments(image, moment = MOMENT.FIRST_ORDER): - array containing requested moment(s) of each image """ output = Array() - safe_call(backend.get().af_moments(ct.pointer(output.arr), image.arr, moment.value)) + safe_call(backend.get().af_moments(c_pointer(output.arr), image.arr, moment.value)) return output def is_image_io_available(): """ Function to check if the arrayfire library was built with Image IO support. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_image_io_available(ct.pointer(res))) + res = c_bool_t(False) + safe_call(backend.get().af_is_image_io_available(c_pointer(res))) return res.value diff --git a/arrayfire/index.py b/arrayfire/index.py index a23e2e203..18c68dc35 100644 --- a/arrayfire/index.py +++ b/arrayfire/index.py @@ -39,27 +39,27 @@ class Seq(ct.Structure): S: slice or number. """ - _fields_ = [("begin", ct.c_double), - ("end" , ct.c_double), - ("step" , ct.c_double)] + _fields_ = [("begin", c_double_t), + ("end" , c_double_t), + ("step" , c_double_t)] def __init__ (self, S): - self.begin = ct.c_double( 0) - self.end = ct.c_double(-1) - self.step = ct.c_double( 1) + self.begin = c_double_t( 0) + self.end = c_double_t(-1) + self.step = c_double_t( 1) if _is_number(S): - self.begin = ct.c_double(S) - self.end = ct.c_double(S) + self.begin = c_double_t(S) + self.end = c_double_t(S) elif isinstance(S, slice): if (S.step is not None): - self.step = ct.c_double(S.step) + self.step = c_double_t(S.step) if(S.step < 0): self.begin, self.end = self.end, self.begin if (S.start is not None): - self.begin = ct.c_double(S.start) + self.begin = c_double_t(S.start) if (S.stop is not None): - self.end = ct.c_double(S.stop - math.copysign(1, self.step)) + self.end = c_double_t(S.stop - math.copysign(1, self.step)) else: raise IndexError("Invalid type while indexing arrayfire.array") @@ -146,13 +146,13 @@ def __next__(self): return self.next() class _uidx(ct.Union): - _fields_ = [("arr", ct.c_void_p), + _fields_ = [("arr", c_void_ptr_t), ("seq", Seq)] class Index(ct.Structure): _fields_ = [("idx", _uidx), - ("isSeq", ct.c_bool), - ("isBatch", ct.c_bool)] + ("isSeq", c_bool_t), + ("isBatch", c_bool_t)] """ Container for the index class in arrayfire C library @@ -194,12 +194,12 @@ def __init__ (self, idx): if isinstance(idx, BaseArray): - arr = ct.c_void_p(0) + arr = c_void_ptr_t(0) if (idx.type() == Dtype.b8.value): - safe_call(backend.get().af_where(ct.pointer(arr), idx.arr)) + safe_call(backend.get().af_where(c_pointer(arr), idx.arr)) else: - safe_call(backend.get().af_retain_array(ct.pointer(arr), idx.arr)) + safe_call(backend.get().af_retain_array(c_pointer(arr), idx.arr)) self.idx.arr = arr self.isSeq = False @@ -214,7 +214,7 @@ def __del__(self): # ctypes field variables are automatically # converted to basic C types so we have to # build the void_p from the value again. - arr = ct.c_void_p(self.idx.arr) + arr = c_void_ptr_t(self.idx.arr) backend.get().af_release_array(arr) class _Index4(object): @@ -227,7 +227,7 @@ def __init__(self, idx0, idx1, idx2, idx3): self.idxs = [idx0,idx1,idx2,idx3] @property def pointer(self): - return ct.pointer(self.array) + return c_pointer(self.array) def __getitem__(self, idx): return self.array[idx] diff --git a/arrayfire/interop.py b/arrayfire/interop.py index 4de6d1ebe..e1a5d3b3d 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -53,7 +53,7 @@ def np_to_af_array(np_arr): """ in_shape = np_arr.shape - in_ptr = np_arr.ctypes.data_as(ct.c_void_p) + in_ptr = np_arr.ctypes.data_as(c_void_ptr_t) in_dtype = _nptype_to_aftype[np_arr.dtype.str[1:]] if (np_arr.flags['F_CONTIGUOUS']): diff --git a/arrayfire/lapack.py b/arrayfire/lapack.py index ba2a5212d..05c18732b 100644 --- a/arrayfire/lapack.py +++ b/arrayfire/lapack.py @@ -41,7 +41,7 @@ def lu(A): L = Array() U = Array() P = Array() - safe_call(backend.get().af_lu(ct.pointer(L.arr), ct.pointer(U.arr), ct.pointer(P.arr), A.arr)) + safe_call(backend.get().af_lu(c_pointer(L.arr), c_pointer(U.arr), c_pointer(P.arr), A.arr)) return L,U,P def lu_inplace(A, pivot="lapack"): @@ -68,7 +68,7 @@ def lu_inplace(A, pivot="lapack"): """ P = Array() is_pivot_lapack = False if (pivot == "full") else True - safe_call(backend.get().af_lu_inplace(ct.pointer(P.arr), A.arr, is_pivot_lapack)) + safe_call(backend.get().af_lu_inplace(c_pointer(P.arr), A.arr, is_pivot_lapack)) return P def qr(A): @@ -98,7 +98,7 @@ def qr(A): Q = Array() R = Array() T = Array() - safe_call(backend.get().af_qr(ct.pointer(Q.arr), ct.pointer(R.arr), ct.pointer(T.arr), A.arr)) + safe_call(backend.get().af_qr(c_pointer(Q.arr), c_pointer(R.arr), c_pointer(T.arr), A.arr)) return Q,R,T def qr_inplace(A): @@ -122,7 +122,7 @@ def qr_inplace(A): This function is used to save space only when `R` is required. """ T = Array() - safe_call(backend.get().af_qr_inplace(ct.pointer(T.arr), A.arr)) + safe_call(backend.get().af_qr_inplace(c_pointer(T.arr), A.arr)) return T def cholesky(A, is_upper=True): @@ -151,8 +151,8 @@ def cholesky(A, is_upper=True): """ R = Array() - info = ct.c_int(0) - safe_call(backend.get().af_cholesky(ct.pointer(R.arr), ct.pointer(info), A.arr, is_upper)) + info = c_int_t(0) + safe_call(backend.get().af_cholesky(c_pointer(R.arr), c_pointer(info), A.arr, is_upper)) return R, info.value def cholesky_inplace(A, is_upper=True): @@ -174,8 +174,8 @@ def cholesky_inplace(A, is_upper=True): 0 if decomposition sucessful. """ - info = ct.c_int(0) - safe_call(backend.get().af_cholesky_inplace(ct.pointer(info), A.arr, is_upper)) + info = c_int_t(0) + safe_call(backend.get().af_cholesky_inplace(c_pointer(info), A.arr, is_upper)) return info.value def solve(A, B, options=MATPROP.NONE): @@ -202,7 +202,7 @@ def solve(A, B, options=MATPROP.NONE): """ X = Array() - safe_call(backend.get().af_solve(ct.pointer(X.arr), A.arr, B.arr, options.value)) + safe_call(backend.get().af_solve(c_pointer(X.arr), A.arr, B.arr, options.value)) return X def solve_lu(A, P, B, options=MATPROP.NONE): @@ -230,7 +230,7 @@ def solve_lu(A, P, B, options=MATPROP.NONE): """ X = Array() - safe_call(backend.get().af_solve_lu(ct.pointer(X.arr), A.arr, P.arr, B.arr, options.value)) + safe_call(backend.get().af_solve_lu(c_pointer(X.arr), A.arr, P.arr, B.arr, options.value)) return X def inverse(A, options=MATPROP.NONE): @@ -260,7 +260,7 @@ def inverse(A, options=MATPROP.NONE): """ AI = Array() - safe_call(backend.get().af_inverse(ct.pointer(AI.arr), A.arr, options.value)) + safe_call(backend.get().af_inverse(c_pointer(AI.arr), A.arr, options.value)) return AI def rank(A, tol=1E-5): @@ -282,8 +282,8 @@ def rank(A, tol=1E-5): r: int - Rank of `A` within the given tolerance """ - r = ct.c_uint(0) - safe_call(backend.get().af_rank(ct.pointer(r), A.arr, ct.c_double(tol))) + r = c_uint_t(0) + safe_call(backend.get().af_rank(c_pointer(r), A.arr, c_double_t(tol))) return r.value def det(A): @@ -302,9 +302,9 @@ def det(A): res: scalar - Determinant of the matrix. """ - re = ct.c_double(0) - im = ct.c_double(0) - safe_call(backend.get().af_det(ct.pointer(re), ct.pointer(im), A.arr)) + re = c_double_t(0) + im = c_double_t(0) + safe_call(backend.get().af_det(c_pointer(re), c_pointer(im), A.arr)) re = re.value im = im.value return re if (im == 0) else re + im * 1j @@ -335,9 +335,9 @@ def norm(A, norm_type=NORM.EUCLID, p=1.0, q=1.0): - norm of the input """ - res = ct.c_double(0) - safe_call(backend.get().af_norm(ct.pointer(res), A.arr, norm_type.value, - ct.c_double(p), ct.c_double(q))) + res = c_double_t(0) + safe_call(backend.get().af_norm(c_pointer(res), A.arr, norm_type.value, + c_double_t(p), c_double_t(q))) return res.value def svd(A): @@ -371,7 +371,7 @@ def svd(A): U = Array() S = Array() Vt = Array() - safe_call(backend.get().af_svd(ct.pointer(U.arr), ct.pointer(S.arr), ct.pointer(Vt.arr), A.arr)) + safe_call(backend.get().af_svd(c_pointer(U.arr), c_pointer(S.arr), c_pointer(Vt.arr), A.arr)) return U, S, Vt def svd_inplace(A): @@ -405,7 +405,7 @@ def svd_inplace(A): U = Array() S = Array() Vt = Array() - safe_call(backend.get().af_svd_inplace(ct.pointer(U.arr), ct.pointer(S.arr), ct.pointer(Vt.arr), + safe_call(backend.get().af_svd_inplace(c_pointer(U.arr), c_pointer(S.arr), c_pointer(Vt.arr), A.arr)) return U, S, Vt @@ -413,6 +413,6 @@ def is_lapack_available(): """ Function to check if the arrayfire library was built with lapack support. """ - res = ct.c_bool(False) - safe_call(backend.get().af_is_lapack_available(ct.pointer(res))) + res = c_bool_t(False) + safe_call(backend.get().af_is_lapack_available(c_pointer(res))) return res.value diff --git a/arrayfire/library.py b/arrayfire/library.py index c0541620d..edaa62666 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -14,18 +14,34 @@ import platform import ctypes as ct +c_float_t = ct.c_float +c_double_t = ct.c_double +c_int_t = ct.c_int +c_uint_t = ct.c_uint +c_longlong_t = ct.c_longlong +c_ulonglong_t = ct.c_ulonglong +c_char_t = ct.c_char +c_bool_t = ct.c_bool +c_uchar_t = ct.c_ubyte +c_short_t = ct.c_short +c_ushort_t = ct.c_ushort +c_pointer = ct.pointer +c_void_ptr_t = ct.c_void_p +c_char_ptr_t = ct.c_char_p +c_size_t = ct.c_size_t + # Work around for unexpected architectures if 'c_dim_t_forced' in globals(): global c_dim_t_forced c_dim_t = c_dim_t_forced else: # dim_t is long long by default - c_dim_t = ct.c_longlong + c_dim_t = c_longlong_t # Change to int for 32 bit x86 and amr architectures if (platform.architecture()[0][0:2] == '32' and (platform.machine()[-2:] == '86' or platform.machine()[0:3] == 'arm')): - c_dim_t = ct.c_int + c_dim_t = c_int_t try: from enum import Enum as _Enum @@ -522,7 +538,7 @@ def __init__(self): pass c_dim4 = c_dim_t*4 - out = ct.c_void_p(0) + out = c_void_ptr_t(0) dims = c_dim4(10, 10, 1, 1) # Iterate in reverse order of preference @@ -534,7 +550,7 @@ def __init__(self): __name = 'unified' if name == '' else name clib = ct.CDLL(libname) self.__clibs[__name] = clib - err = clib.af_randu(ct.pointer(out), 4, ct.pointer(dims), Dtype.f32.value) + err = clib.af_randu(c_pointer(out), 4, c_pointer(dims), Dtype.f32.value) if (err == ERR.NONE.value): self.__name = __name clib.af_release_array(out) @@ -610,8 +626,8 @@ def get_backend_id(A): name : str. Backend name """ - backend_id = ct.c_int(BACKEND.CPU.value) - safe_call(backend.get().af_get_backend_id(ct.pointer(backend_id), A.arr)) + backend_id = c_int_t(BACKEND.CPU.value) + safe_call(backend.get().af_get_backend_id(c_pointer(backend_id), A.arr)) return backend.get_name(backend_id.value) def get_backend_count(): @@ -624,8 +640,8 @@ def get_backend_count(): count : int Number of available backends """ - count = ct.c_int(0) - safe_call(backend.get().af_get_backend_count(ct.pointer(count))) + count = c_int_t(0) + safe_call(backend.get().af_get_backend_count(c_pointer(count))) return count.value def get_available_backends(): @@ -638,8 +654,8 @@ def get_available_backends(): names : tuple of strings Names of available backends """ - available = ct.c_int(0) - safe_call(backend.get().af_get_available_backends(ct.pointer(available))) + available = c_int_t(0) + safe_call(backend.get().af_get_available_backends(c_pointer(available))) return backend.parse(int(available.value)) def get_active_backend(): @@ -649,8 +665,8 @@ def get_active_backend(): name : str. Backend name """ - backend_id = ct.c_int(BACKEND.CPU.value) - safe_call(backend.get().af_get_active_backend(ct.pointer(backend_id))) + backend_id = c_int_t(BACKEND.CPU.value) + safe_call(backend.get().af_get_active_backend(c_pointer(backend_id))) return backend.get_name(backend_id.value) def get_device_id(A): @@ -667,16 +683,16 @@ def get_device_id(A): dev : Integer id of the device array was created on """ - device_id = ct.c_int(0) - safe_call(backend.get().af_get_device_id(ct.pointer(device_id), A.arr)) + device_id = c_int_t(0) + safe_call(backend.get().af_get_device_id(c_pointer(device_id), A.arr)) return device_id def get_size_of(dtype): """ Get the size of the type represented by arrayfire.Dtype """ - size = ct.c_size_t(0) - safe_call(backend.get().af_get_size_of(ct.pointer(size), dtype.value)) + size = c_size_t(0) + safe_call(backend.get().af_get_size_of(c_pointer(size), dtype.value)) return size.value from .util import safe_call diff --git a/arrayfire/opencl.py b/arrayfire/opencl.py index d41be1df8..a4a09c92b 100644 --- a/arrayfire/opencl.py +++ b/arrayfire/opencl.py @@ -59,8 +59,8 @@ def get_context(retain=False): if (backend.name() != "opencl"): raise RuntimeError("Invalid backend loaded") - context = ct.c_void_p(0) - safe_call(backend.get().afcl_get_context(ct.pointer(context), retain)) + context = c_void_ptr_t(0) + safe_call(backend.get().afcl_get_context(c_pointer(context), retain)) return context.value def get_queue(retain): @@ -85,8 +85,8 @@ def get_queue(retain): if (backend.name() != "opencl"): raise RuntimeError("Invalid backend loaded") - queue = ct.c_int(0) - safe_call(backend.get().afcl_get_queue(ct.pointer(queue), retain)) + queue = c_int_t(0) + safe_call(backend.get().afcl_get_queue(c_pointer(queue), retain)) return queue.value def get_device_id(): @@ -107,8 +107,8 @@ def get_device_id(): if (backend.name() != "opencl"): raise RuntimeError("Invalid backend loaded") - idx = ct.c_int(0) - safe_call(backend.get().afcl_get_device_id(ct.pointer(idx))) + idx = c_int_t(0) + safe_call(backend.get().afcl_get_device_id(c_pointer(idx))) return idx.value def set_device_id(idx): @@ -204,14 +204,14 @@ def get_device_type(): """ Get opencl device type """ - res = ct.c_int(DEVICE_TYPE.UNKNOWN.value) - safe_call(backend.get().afcl_get_device_type(ct.pointer(res))) + res = c_int_t(DEVICE_TYPE.UNKNOWN.value) + safe_call(backend.get().afcl_get_device_type(c_pointer(res))) return _to_device_type[res.value] def get_platform(): """ Get opencl platform """ - res = ct.c_int(PLATFORM.UNKNOWN.value) - safe_call(backend.get().afcl_get_platform(ct.pointer(res))) + res = c_int_t(PLATFORM.UNKNOWN.value) + safe_call(backend.get().afcl_get_platform(c_pointer(res))) return _to_platform[res.value] diff --git a/arrayfire/random.py b/arrayfire/random.py index d95fa9081..c53579248 100644 --- a/arrayfire/random.py +++ b/arrayfire/random.py @@ -42,8 +42,8 @@ class Random_Engine(object): def __init__(self, engine_type = RANDOM_ENGINE.PHILOX, seed = 0, engine = None): if (engine is None): - self.engine = ct.c_void_p(0) - safe_call(backend.get().af_create_random_engine(ct.pointer(self.engine), engine_type.value, ct.c_longlong(seed))) + self.engine = c_void_ptr_t(0) + safe_call(backend.get().af_create_random_engine(c_pointer(self.engine), engine_type.value, c_longlong_t(seed))) else: self.engine = engine @@ -54,7 +54,7 @@ def set_type(self, engine_type): """ Set the type of the random engine. """ - safe_call(backend.get().af_random_engine_set_type(ct.pointer(self.engine), engine_type.value)) + safe_call(backend.get().af_random_engine_set_type(c_pointer(self.engine), engine_type.value)) def get_type(self): """ @@ -63,22 +63,22 @@ def get_type(self): __to_random_engine_type = [RANDOM_ENGINE.PHILOX_4X32_10, RANDOM_ENGINE.THREEFRY_2X32_16, RANDOM_ENGINE.MERSENNE_GP11213] - rty = ct.c_int(RANDOM_ENGINE.PHILOX.value) - safe_call(backend.get().af_random_engine_get_type(ct.pointer(rty), self.engine)) + rty = c_int_t(RANDOM_ENGINE.PHILOX.value) + safe_call(backend.get().af_random_engine_get_type(c_pointer(rty), self.engine)) return __to_random_engine_type[rty] def set_seed(self, seed): """ Set the seed for the random engine. """ - safe_call(backend.get().af_random_engine_set_seed(ct.pointer(self.engine), ct.c_longlong(seed))) + safe_call(backend.get().af_random_engine_set_seed(c_pointer(self.engine), c_longlong_t(seed))) def get_seed(self): """ Get the seed for the random engine. """ - seed = ct.c_longlong(0) - safe_call(backend.get().af_random_engine_get_seed(ct.pointer(seed), self.engine)) + seed = c_longlong_t(0) + safe_call(backend.get().af_random_engine_get_seed(c_pointer(seed), self.engine)) return seed.value def randu(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, engine=None): @@ -119,9 +119,9 @@ def randu(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, engine=None): dims = dim4(d0, d1, d2, d3) if engine is None: - safe_call(backend.get().af_randu(ct.pointer(out.arr), 4, ct.pointer(dims), dtype.value)) + safe_call(backend.get().af_randu(c_pointer(out.arr), 4, c_pointer(dims), dtype.value)) else: - safe_call(backend.get().af_random_uniform(ct.pointer(out.arr), 4, ct.pointer(dims), dtype.value, engine.engine)) + safe_call(backend.get().af_random_uniform(c_pointer(out.arr), 4, c_pointer(dims), dtype.value, engine.engine)) return out @@ -164,9 +164,9 @@ def randn(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, engine=None): dims = dim4(d0, d1, d2, d3) if engine is None: - safe_call(backend.get().af_randn(ct.pointer(out.arr), 4, ct.pointer(dims), dtype.value)) + safe_call(backend.get().af_randn(c_pointer(out.arr), 4, c_pointer(dims), dtype.value)) else: - safe_call(backend.get().af_random_normal(ct.pointer(out.arr), 4, ct.pointer(dims), dtype.value, engine.engine)) + safe_call(backend.get().af_random_normal(c_pointer(out.arr), 4, c_pointer(dims), dtype.value, engine.engine)) return out @@ -179,7 +179,7 @@ def set_seed(seed=0): seed: int. Seed for the random number generator """ - safe_call(backend.get().af_set_seed(ct.c_ulonglong(seed))) + safe_call(backend.get().af_set_seed(c_ulonglong_t(seed))) def get_seed(): """ @@ -190,8 +190,8 @@ def get_seed(): seed: int. Seed for the random number generator """ - seed = ct.c_ulonglong(0) - safe_call(backend.get().af_get_seed(ct.pointer(seed))) + seed = c_ulonglong_t(0) + safe_call(backend.get().af_get_seed(c_pointer(seed))) return seed.value def set_default_random_engine_type(engine_type): @@ -214,7 +214,7 @@ def set_default_random_engine_type(engine_type): This only affects randu and randn when a random engine is not specified. """ - safe_call(backend.get().af_set_default_random_engine_type(ct.pointer(self.engine), engine_type.value)) + safe_call(backend.get().af_set_default_random_engine_type(c_pointer(self.engine), engine_type.value)) def get_default_random_engine(): """ @@ -225,8 +225,8 @@ def get_default_random_engine(): The default random engine used by randu and randn """ - engine = ct.c_void_p(0) - default_engine = ct.c_void_p(0) - safe_call(backend.get().af_get_default_random_engine(ct.pointer(default_engine))) - safe_call(backend.get().af_retain_random_engine(ct.pointer(engine), default_engine)) + engine = c_void_ptr_t(0) + default_engine = c_void_ptr_t(0) + safe_call(backend.get().af_get_default_random_engine(c_pointer(default_engine))) + safe_call(backend.get().af_retain_random_engine(c_pointer(engine), default_engine)) return Random_Engine(engine=engine) diff --git a/arrayfire/signal.py b/arrayfire/signal.py index 363ed248c..4ddea26c6 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -48,8 +48,8 @@ def approx1(signal, pos0, method=INTERP.LINEAR, off_grid=0.0): """ output = Array() - safe_call(backend.get().af_approx1(ct.pointer(output.arr), signal.arr, pos0.arr, - method.value, ct.c_double(off_grid))) + safe_call(backend.get().af_approx1(c_pointer(output.arr), signal.arr, pos0.arr, + method.value, c_double_t(off_grid))) return output def approx2(signal, pos0, pos1, method=INTERP.LINEAR, off_grid=0.0): @@ -90,8 +90,8 @@ def approx2(signal, pos0, pos1, method=INTERP.LINEAR, off_grid=0.0): """ output = Array() - safe_call(backend.get().af_approx2(ct.pointer(output.arr), signal.arr, - pos0.arr, pos1.arr, method.value, ct.c_double(off_grid))) + safe_call(backend.get().af_approx2(c_pointer(output.arr), signal.arr, + pos0.arr, pos1.arr, method.value, c_double_t(off_grid))) return output def fft(signal, dim0 = None , scale = None): @@ -127,7 +127,7 @@ def fft(signal, dim0 = None , scale = None): scale = 1.0 output = Array() - safe_call(backend.get().af_fft(ct.pointer(output.arr), signal.arr, ct.c_double(scale), c_dim_t(dim0))) + safe_call(backend.get().af_fft(c_pointer(output.arr), signal.arr, c_double_t(scale), c_dim_t(dim0))) return output def fft2(signal, dim0 = None, dim1 = None , scale = None): @@ -169,7 +169,7 @@ def fft2(signal, dim0 = None, dim1 = None , scale = None): scale = 1.0 output = Array() - safe_call(backend.get().af_fft2(ct.pointer(output.arr), signal.arr, ct.c_double(scale), + safe_call(backend.get().af_fft2(c_pointer(output.arr), signal.arr, c_double_t(scale), c_dim_t(dim0), c_dim_t(dim1))) return output @@ -219,7 +219,7 @@ def fft3(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): scale = 1.0 output = Array() - safe_call(backend.get().af_fft3(ct.pointer(output.arr), signal.arr, ct.c_double(scale), + safe_call(backend.get().af_fft3(c_pointer(output.arr), signal.arr, c_double_t(scale), c_dim_t(dim0), c_dim_t(dim1), c_dim_t(dim2))) return output @@ -261,7 +261,7 @@ def ifft(signal, dim0 = None , scale = None): scale = 1.0/float(dim0) output = Array() - safe_call(backend.get().af_ifft(ct.pointer(output.arr), signal.arr, ct.c_double(scale), c_dim_t(dim0))) + safe_call(backend.get().af_ifft(c_pointer(output.arr), signal.arr, c_double_t(scale), c_dim_t(dim0))) return output def ifft2(signal, dim0 = None, dim1 = None , scale = None): @@ -311,7 +311,7 @@ def ifft2(signal, dim0 = None, dim1 = None , scale = None): scale = 1.0/float(dim0 * dim1) output = Array() - safe_call(backend.get().af_ifft2(ct.pointer(output.arr), signal.arr, ct.c_double(scale), + safe_call(backend.get().af_ifft2(c_pointer(output.arr), signal.arr, c_double_t(scale), c_dim_t(dim0), c_dim_t(dim1))) return output @@ -369,7 +369,7 @@ def ifft3(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): scale = 1.0 / float(dim0 * dim1 * dim2) output = Array() - safe_call(backend.get().af_ifft3(ct.pointer(output.arr), signal.arr, ct.c_double(scale), + safe_call(backend.get().af_ifft3(c_pointer(output.arr), signal.arr, c_double_t(scale), c_dim_t(dim0), c_dim_t(dim1), c_dim_t(dim2))) return output @@ -392,7 +392,7 @@ def fft_inplace(signal, scale = None): if scale is None: scale = 1.0 - safe_call(backend.get().af_fft_inplace(signal.arr, ct.c_double(scale))) + safe_call(backend.get().af_fft_inplace(signal.arr, c_double_t(scale))) def fft2_inplace(signal, scale = None): """ @@ -413,7 +413,7 @@ def fft2_inplace(signal, scale = None): if scale is None: scale = 1.0 - safe_call(backend.get().af_fft2_inplace(signal.arr, ct.c_double(scale))) + safe_call(backend.get().af_fft2_inplace(signal.arr, c_double_t(scale))) def fft3_inplace(signal, scale = None): """ @@ -434,7 +434,7 @@ def fft3_inplace(signal, scale = None): scale = 1.0 output = Array() - safe_call(backend.get().af_fft3_inplace(signal.arr, ct.c_double(scale))) + safe_call(backend.get().af_fft3_inplace(signal.arr, c_double_t(scale))) def ifft_inplace(signal, scale = None): """ @@ -455,7 +455,7 @@ def ifft_inplace(signal, scale = None): dim0 = signal.dims()[0] scale = 1.0/float(dim0) - safe_call(backend.get().af_ifft_inplace(signal.arr, ct.c_double(scale))) + safe_call(backend.get().af_ifft_inplace(signal.arr, c_double_t(scale))) def ifft2_inplace(signal, scale = None): """ @@ -479,7 +479,7 @@ def ifft2_inplace(signal, scale = None): dim1 = dims[1] scale = 1.0/float(dim0 * dim1) - safe_call(backend.get().af_ifft2_inplace(signal.arr, ct.c_double(scale))) + safe_call(backend.get().af_ifft2_inplace(signal.arr, c_double_t(scale))) def ifft3_inplace(signal, scale = None): """ @@ -504,7 +504,7 @@ def ifft3_inplace(signal, scale = None): dim2 = dims[2] scale = 1.0 / float(dim0 * dim1 * dim2) - safe_call(backend.get().af_ifft3_inplace(signal.arr, ct.c_double(scale))) + safe_call(backend.get().af_ifft3_inplace(signal.arr, c_double_t(scale))) def fft_r2c(signal, dim0 = None , scale = None): """ @@ -539,7 +539,7 @@ def fft_r2c(signal, dim0 = None , scale = None): scale = 1.0 output = Array() - safe_call(backend.get().af_fft_r2c(ct.pointer(output.arr), signal.arr, ct.c_double(scale), c_dim_t(dim0))) + safe_call(backend.get().af_fft_r2c(c_pointer(output.arr), signal.arr, c_double_t(scale), c_dim_t(dim0))) return output def fft2_r2c(signal, dim0 = None, dim1 = None , scale = None): @@ -581,7 +581,7 @@ def fft2_r2c(signal, dim0 = None, dim1 = None , scale = None): scale = 1.0 output = Array() - safe_call(backend.get().af_fft2_r2c(ct.pointer(output.arr), signal.arr, ct.c_double(scale), + safe_call(backend.get().af_fft2_r2c(c_pointer(output.arr), signal.arr, c_double_t(scale), c_dim_t(dim0), c_dim_t(dim1))) return output @@ -631,7 +631,7 @@ def fft3_r2c(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): scale = 1.0 output = Array() - safe_call(backend.get().af_fft3_r2c(ct.pointer(output.arr), signal.arr, ct.c_double(scale), + safe_call(backend.get().af_fft3_r2c(c_pointer(output.arr), signal.arr, c_double_t(scale), c_dim_t(dim0), c_dim_t(dim1), c_dim_t(dim2))) return output @@ -669,7 +669,7 @@ def fft_c2r(signal, is_odd = False, scale = None): scale = 1.0/float(dim0) output = Array() - safe_call(backend.get().af_fft_c2r(ct.pointer(output.arr), signal.arr, ct.c_double(scale), is_odd)) + safe_call(backend.get().af_fft_c2r(c_pointer(output.arr), signal.arr, c_double_t(scale), is_odd)) return output def fft2_c2r(signal, is_odd = False, scale = None): @@ -704,7 +704,7 @@ def fft2_c2r(signal, is_odd = False, scale = None): scale = 1.0/float(dim0 * dim1) output = Array() - safe_call(backend.get().af_fft2_c2r(ct.pointer(output.arr), signal.arr, ct.c_double(scale), is_odd)) + safe_call(backend.get().af_fft2_c2r(c_pointer(output.arr), signal.arr, c_double_t(scale), is_odd)) return output def fft3_c2r(signal, is_odd = False, scale = None): @@ -740,7 +740,7 @@ def fft3_c2r(signal, is_odd = False, scale = None): scale = 1.0/float(dim0 * dim1 * dim2) output = Array() - safe_call(backend.get().af_fft3_c2r(ct.pointer(output.arr), signal.arr, ct.c_double(scale), is_odd)) + safe_call(backend.get().af_fft3_c2r(c_pointer(output.arr), signal.arr, c_double_t(scale), is_odd)) return output @@ -871,7 +871,7 @@ def convolve1(signal, kernel, conv_mode = CONV_MODE.DEFAULT, conv_domain = CONV_ """ output = Array() - safe_call(backend.get().af_convolve1(ct.pointer(output.arr), signal.arr, kernel.arr, + safe_call(backend.get().af_convolve1(c_pointer(output.arr), signal.arr, kernel.arr, conv_mode.value, conv_domain.value)) return output @@ -919,7 +919,7 @@ def convolve2(signal, kernel, conv_mode = CONV_MODE.DEFAULT, conv_domain = CONV_ """ output = Array() - safe_call(backend.get().af_convolve2(ct.pointer(output.arr), signal.arr, kernel.arr, + safe_call(backend.get().af_convolve2(c_pointer(output.arr), signal.arr, kernel.arr, conv_mode.value, conv_domain.value)) return output @@ -949,7 +949,7 @@ def convolve2_separable(col_kernel, row_kernel, signal, conv_mode = CONV_MODE.DE - Output of 2D sepearable convolution. """ output = Array() - safe_call(backend.get().af_convolve2_sep(ct.pointer(output.arr), + safe_call(backend.get().af_convolve2_sep(c_pointer(output.arr), col_kernel.arr, row_kernel.arr,signal.arr, conv_mode.value)) return output @@ -996,7 +996,7 @@ def convolve3(signal, kernel, conv_mode = CONV_MODE.DEFAULT, conv_domain = CONV_ """ output = Array() - safe_call(backend.get().af_convolve3(ct.pointer(output.arr), signal.arr, kernel.arr, + safe_call(backend.get().af_convolve3(c_pointer(output.arr), signal.arr, kernel.arr, conv_mode.value, conv_domain.value)) return output @@ -1083,7 +1083,7 @@ def fft_convolve1(signal, kernel, conv_mode = CONV_MODE.DEFAULT): """ output = Array() - safe_call(backend.get().af_fft_convolve1(ct.pointer(output.arr), signal.arr, kernel.arr, + safe_call(backend.get().af_fft_convolve1(c_pointer(output.arr), signal.arr, kernel.arr, conv_mode.value)) return output @@ -1127,7 +1127,7 @@ def fft_convolve2(signal, kernel, conv_mode = CONV_MODE.DEFAULT): """ output = Array() - safe_call(backend.get().af_fft_convolve2(ct.pointer(output.arr), signal.arr, kernel.arr, + safe_call(backend.get().af_fft_convolve2(c_pointer(output.arr), signal.arr, kernel.arr, conv_mode.value)) return output @@ -1169,7 +1169,7 @@ def fft_convolve3(signal, kernel, conv_mode = CONV_MODE.DEFAULT): """ output = Array() - safe_call(backend.get().af_fft_convolve3(ct.pointer(output.arr), signal.arr, kernel.arr, + safe_call(backend.get().af_fft_convolve3(c_pointer(output.arr), signal.arr, kernel.arr, conv_mode.value)) return output @@ -1235,7 +1235,7 @@ def fir(B, X): """ Y = Array() - safe_call(backend.get().af_fir(ct.pointer(Y.arr), B.arr, X.arr)) + safe_call(backend.get().af_fir(c_pointer(Y.arr), B.arr, X.arr)) return Y def iir(B, A, X): @@ -1262,7 +1262,7 @@ def iir(B, A, X): """ Y = Array() - safe_call(backend.get().af_iir(ct.pointer(Y.arr), B.arr, A.arr, X.arr)) + safe_call(backend.get().af_iir(c_pointer(Y.arr), B.arr, A.arr, X.arr)) return Y def medfilt(signal, w0 = 3, w1 = 3, edge_pad = PAD.ZERO): @@ -1292,7 +1292,7 @@ def medfilt(signal, w0 = 3, w1 = 3, edge_pad = PAD.ZERO): """ output = Array() - safe_call(backend.get().af_medfilt(ct.pointer(output.arr), + safe_call(backend.get().af_medfilt(c_pointer(output.arr), signal.arr, c_dim_t(w0), c_dim_t(w1), edge_pad.value)) return output @@ -1321,7 +1321,7 @@ def medfilt1(signal, length = 3, edge_pad = PAD.ZERO): """ output = Array() - safe_call(backend.get().af_medfilt1(ct.pointer(output.arr), signal.arr, c_dim_t(length), edge_pad.value)) + safe_call(backend.get().af_medfilt1(c_pointer(output.arr), signal.arr, c_dim_t(length), edge_pad.value)) return output def medfilt2(signal, w0 = 3, w1 = 3, edge_pad = PAD.ZERO): @@ -1351,7 +1351,7 @@ def medfilt2(signal, w0 = 3, w1 = 3, edge_pad = PAD.ZERO): """ output = Array() - safe_call(backend.get().af_medfilt2(ct.pointer(output.arr), + safe_call(backend.get().af_medfilt2(c_pointer(output.arr), signal.arr, c_dim_t(w0), c_dim_t(w1), edge_pad.value)) return output @@ -1366,4 +1366,4 @@ def set_fft_plan_cache_size(cache_size): cache_size : scalar the number of plans that shall be cached """ - safe_call(backend.get().af_set_fft_plan_cache_size(ct.c_size_t(cache_size))) + safe_call(backend.get().af_set_fft_plan_cache_size(c_size_t(cache_size))) diff --git a/arrayfire/sparse.py b/arrayfire/sparse.py index 9a4c30460..82eed1706 100644 --- a/arrayfire/sparse.py +++ b/arrayfire/sparse.py @@ -56,7 +56,7 @@ def sparse(values, row_idx, col_idx, nrows, ncols, storage = STORAGE.CSR): assert(isinstance(row_idx, Array)) assert(isinstance(col_idx, Array)) out = Array() - safe_call(backend.get().af_create_sparse_array(ct.pointer(out.arr), c_dim_t(nrows), c_dim_t(ncols), + safe_call(backend.get().af_create_sparse_array(c_pointer(out.arr), c_dim_t(nrows), c_dim_t(ncols), values.arr, row_idx.arr, col_idx.arr, storage.value)) return out @@ -112,7 +112,7 @@ def sparse_from_dense(dense, storage = STORAGE.CSR): """ assert(isinstance(dense, Array)) out = Array() - safe_call(backend.get().af_create_sparse_array_from_dense(ct.pointer(out.arr), dense.arr, storage.value)) + safe_call(backend.get().af_create_sparse_array_from_dense(c_pointer(out.arr), dense.arr, storage.value)) return out def sparse_to_dense(sparse): @@ -131,7 +131,7 @@ def sparse_to_dense(sparse): A dense matrix. """ out = Array() - safe_call(backend.get().af_sparse_to_dense(ct.pointer(out.arr), sparse.arr)) + safe_call(backend.get().af_sparse_to_dense(c_pointer(out.arr), sparse.arr)) return out def sparse_get_info(sparse): @@ -155,9 +155,9 @@ def sparse_get_info(sparse): values = Array() row_idx = Array() col_idx = Array() - stype = ct.c_int(0) - safe_call(backend.get().af_sparse_get_info(ct.pointer(values.arr), ct.pointer(row_idx.arr), - ct.pointer(col_idx.arr), ct.pointer(stype), + stype = c_int_t(0) + safe_call(backend.get().af_sparse_get_info(c_pointer(values.arr), c_pointer(row_idx.arr), + c_pointer(col_idx.arr), c_pointer(stype), sparse.arr)) return (values, row_idx, col_idx, __to_sparse_enum[stype.value]) @@ -177,7 +177,7 @@ def sparse_get_values(sparse): """ values = Array() - safe_call(backend.get().af_sparse_get_values(ct.pointer(values.arr), sparse.arr)) + safe_call(backend.get().af_sparse_get_values(c_pointer(values.arr), sparse.arr)) return values def sparse_get_row_idx(sparse): @@ -196,7 +196,7 @@ def sparse_get_row_idx(sparse): """ row_idx = Array() - safe_call(backend.get().af_sparse_get_row_idx(ct.pointer(row_idx.arr), sparse.arr)) + safe_call(backend.get().af_sparse_get_row_idx(c_pointer(row_idx.arr), sparse.arr)) return row_idx def sparse_get_col_idx(sparse): @@ -215,7 +215,7 @@ def sparse_get_col_idx(sparse): """ col_idx = Array() - safe_call(backend.get().af_sparse_get_col_idx(ct.pointer(col_idx.arr), sparse.arr)) + safe_call(backend.get().af_sparse_get_col_idx(c_pointer(col_idx.arr), sparse.arr)) return col_idx def sparse_get_nnz(sparse): @@ -234,7 +234,7 @@ def sparse_get_nnz(sparse): """ nnz = c_dim_t(0) - safe_call(backend.get().af_sparse_get_nnz(ct.pointer(nnz), sparse.arr)) + safe_call(backend.get().af_sparse_get_nnz(c_pointer(nnz), sparse.arr)) return nnz.value def sparse_get_storage(sparse): @@ -252,8 +252,8 @@ def sparse_get_storage(sparse): Number of non zero elements in the sparse matrix. """ - storage = ct.c_int(0) - safe_call(backend.get().af_sparse_get_storage(ct.pointer(storage), sparse.arr)) + storage = c_int_t(0) + safe_call(backend.get().af_sparse_get_storage(c_pointer(storage), sparse.arr)) return __to_sparse_enum[storage.value] def sparse_convert_to(sparse, storage): @@ -271,5 +271,5 @@ def sparse_convert_to(sparse, storage): Sparse matrix converted to the appropriate type. """ out = Array() - safe_call(backend.get().af_sparse_convert_to(ct.pointer(out.arr), sparse.arr, storage.value)) + safe_call(backend.get().af_sparse_convert_to(c_pointer(out.arr), sparse.arr, storage.value)) return out diff --git a/arrayfire/statistics.py b/arrayfire/statistics.py index d95336944..e8abaea12 100644 --- a/arrayfire/statistics.py +++ b/arrayfire/statistics.py @@ -19,19 +19,19 @@ def mean(a, weights=None, dim=None): out = Array() if weights is None: - safe_call(backend.get().af_mean(ct.pointer(out.arr), a.arr, ct.c_int(dim))) + safe_call(backend.get().af_mean(c_pointer(out.arr), a.arr, c_int_t(dim))) else: - safe_call(backend.get().af_mean_weighted(ct.pointer(out.arr), a.arr, weights.arr, ct.c_int(dim))) + safe_call(backend.get().af_mean_weighted(c_pointer(out.arr), a.arr, weights.arr, c_int_t(dim))) return out else: - real = ct.c_double(0) - imag = ct.c_double(0) + real = c_double_t(0) + imag = c_double_t(0) if weights is None: - safe_call(backend.get().af_mean_all(ct.pointer(real), ct.pointer(imag), a.arr)) + safe_call(backend.get().af_mean_all(c_pointer(real), c_pointer(imag), a.arr)) else: - safe_call(backend.get().af_mean_all_weighted(ct.pointer(real), ct.pointer(imag), a.arr, weights.arr)) + safe_call(backend.get().af_mean_all_weighted(c_pointer(real), c_pointer(imag), a.arr, weights.arr)) real = real.value imag = imag.value @@ -43,19 +43,19 @@ def var(a, isbiased=False, weights=None, dim=None): out = Array() if weights is None: - safe_call(backend.get().af_var(ct.pointer(out.arr), a.arr, isbiased, ct.c_int(dim))) + safe_call(backend.get().af_var(c_pointer(out.arr), a.arr, isbiased, c_int_t(dim))) else: - safe_call(backend.get().af_var_weighted(ct.pointer(out.arr), a.arr, weights.arr, ct.c_int(dim))) + safe_call(backend.get().af_var_weighted(c_pointer(out.arr), a.arr, weights.arr, c_int_t(dim))) return out else: - real = ct.c_double(0) - imag = ct.c_double(0) + real = c_double_t(0) + imag = c_double_t(0) if weights is None: - safe_call(backend.get().af_var_all(ct.pointer(real), ct.pointer(imag), a.arr, isbiased)) + safe_call(backend.get().af_var_all(c_pointer(real), c_pointer(imag), a.arr, isbiased)) else: - safe_call(backend.get().af_var_all_weighted(ct.pointer(real), ct.pointer(imag), a.arr, weights.arr)) + safe_call(backend.get().af_var_all_weighted(c_pointer(real), c_pointer(imag), a.arr, weights.arr)) real = real.value imag = imag.value @@ -65,12 +65,12 @@ def var(a, isbiased=False, weights=None, dim=None): def stdev(a, dim=None): if dim is not None: out = Array() - safe_call(backend.get().af_stdev(ct.pointer(out.arr), a.arr, ct.c_int(dim))) + safe_call(backend.get().af_stdev(c_pointer(out.arr), a.arr, c_int_t(dim))) return out else: - real = ct.c_double(0) - imag = ct.c_double(0) - safe_call(backend.get().af_stdev_all(ct.pointer(real), ct.pointer(imag), a.arr)) + real = c_double_t(0) + imag = c_double_t(0) + safe_call(backend.get().af_stdev_all(c_pointer(real), c_pointer(imag), a.arr)) real = real.value imag = imag.value return real if imag == 0 else real + imag * 1j @@ -78,12 +78,12 @@ def stdev(a, dim=None): def cov(a, isbiased=False, dim=None): if dim is not None: out = Array() - safe_call(backend.get().af_cov(ct.pointer(out.arr), a.arr, isbiased, ct.c_int(dim))) + safe_call(backend.get().af_cov(c_pointer(out.arr), a.arr, isbiased, c_int_t(dim))) return out else: - real = ct.c_double(0) - imag = ct.c_double(0) - safe_call(backend.get().af_cov_all(ct.pointer(real), ct.pointer(imag), a.arr, isbiased)) + real = c_double_t(0) + imag = c_double_t(0) + safe_call(backend.get().af_cov_all(c_pointer(real), c_pointer(imag), a.arr, isbiased)) real = real.value imag = imag.value return real if imag == 0 else real + imag * 1j @@ -91,20 +91,20 @@ def cov(a, isbiased=False, dim=None): def median(a, dim=None): if dim is not None: out = Array() - safe_call(backend.get().af_median(ct.pointer(out.arr), a.arr, ct.c_int(dim))) + safe_call(backend.get().af_median(c_pointer(out.arr), a.arr, c_int_t(dim))) return out else: - real = ct.c_double(0) - imag = ct.c_double(0) - safe_call(backend.get().af_median_all(ct.pointer(real), ct.pointer(imag), a.arr)) + real = c_double_t(0) + imag = c_double_t(0) + safe_call(backend.get().af_median_all(c_pointer(real), c_pointer(imag), a.arr)) real = real.value imag = imag.value return real if imag == 0 else real + imag * 1j def corrcoef(x, y): - real = ct.c_double(0) - imag = ct.c_double(0) - safe_call(backend.get().af_corrcoef(ct.pointer(real), ct.pointer(imag), x.arr, y.arr)) + real = c_double_t(0) + imag = c_double_t(0) + safe_call(backend.get().af_corrcoef(c_pointer(real), c_pointer(imag), x.arr, y.arr)) real = real.value imag = imag.value return real if imag == 0 else real + imag * 1j diff --git a/arrayfire/util.py b/arrayfire/util.py index 35cc5a8f8..709bd7811 100644 --- a/arrayfire/util.py +++ b/arrayfire/util.py @@ -73,19 +73,19 @@ def to_str(c_str): def safe_call(af_error): if (af_error != ERR.NONE.value): - err_str = ct.c_char_p(0) + err_str = c_char_ptr_t(0) err_len = c_dim_t(0) - backend.get().af_get_last_error(ct.pointer(err_str), ct.pointer(err_len)) + backend.get().af_get_last_error(c_pointer(err_str), c_pointer(err_len)) raise RuntimeError(to_str(err_str)) def get_version(): """ Function to get the version of arrayfire. """ - major=ct.c_int(0) - minor=ct.c_int(0) - patch=ct.c_int(0) - safe_call(backend.get().af_get_version(ct.pointer(major), ct.pointer(minor), ct.pointer(patch))) + major=c_int_t(0) + minor=c_int_t(0) + patch=c_int_t(0) + safe_call(backend.get().af_get_version(c_pointer(major), c_pointer(minor), c_pointer(patch))) return major.value,minor.value,patch.value def get_reversion(): @@ -120,18 +120,18 @@ def get_reversion(): Dtype.c32.value : 'F', Dtype.c64.value : 'D'} -to_c_type = {Dtype.f32.value : ct.c_float, - Dtype.f64.value : ct.c_double, - Dtype.b8.value : ct.c_char, - Dtype.u8.value : ct.c_ubyte, - Dtype.s16.value : ct.c_short, - Dtype.u16.value : ct.c_ushort, - Dtype.s32.value : ct.c_int, - Dtype.u32.value : ct.c_uint, - Dtype.s64.value : ct.c_longlong, - Dtype.u64.value : ct.c_ulonglong, - Dtype.c32.value : ct.c_float * 2, - Dtype.c64.value : ct.c_double * 2} +to_c_type = {Dtype.f32.value : c_float_t, + Dtype.f64.value : c_double_t, + Dtype.b8.value : c_char_t, + Dtype.u8.value : c_uchar_t, + Dtype.s16.value : c_short_t, + Dtype.u16.value : c_ushort_t, + Dtype.s32.value : c_int_t, + Dtype.u32.value : c_uint_t, + Dtype.s64.value : c_longlong_t, + Dtype.u64.value : c_ulonglong_t, + Dtype.c32.value : c_float_t * 2, + Dtype.c64.value : c_double_t * 2} to_typename = {Dtype.f32.value : 'float', Dtype.f64.value : 'double', diff --git a/arrayfire/vision.py b/arrayfire/vision.py index 9598a6b5f..2e5edacee 100644 --- a/arrayfire/vision.py +++ b/arrayfire/vision.py @@ -47,9 +47,9 @@ def fast(image, threshold=20.0, arc_length=9, non_max=True, feature_ratio=0.05, """ out = Features() - safe_call(backend.get().af_fast(ct.pointer(out.feat), - image.arr, ct.c_float(threshold), ct.c_uint(arc_length), non_max, - ct.c_float(feature_ratio), ct.c_uint(edge))) + safe_call(backend.get().af_fast(c_pointer(out.feat), + image.arr, c_float_t(threshold), c_uint_t(arc_length), non_max, + c_float_t(feature_ratio), c_uint_t(edge))) return out def harris(image, max_corners=500, min_response=1E5, sigma=1.0, block_size=0, k_thr=0.04): @@ -91,9 +91,9 @@ def harris(image, max_corners=500, min_response=1E5, sigma=1.0, block_size=0, k_ """ out = Features() - safe_call(backend.get().af_harris(ct.pointer(out.feat), - image.arr, ct.c_uint(max_corners), ct.c_float(min_response), - ct.c_float(sigma), ct.c_uint(block_size), ct.c_float(k_thr))) + safe_call(backend.get().af_harris(c_pointer(out.feat), + image.arr, c_uint_t(max_corners), c_float_t(min_response), + c_float_t(sigma), c_uint_t(block_size), c_float_t(k_thr))) return out def orb(image, threshold=20.0, max_features=400, scale = 1.5, num_levels = 4, blur_image = False): @@ -131,9 +131,9 @@ def orb(image, threshold=20.0, max_features=400, scale = 1.5, num_levels = 4, bl """ feat = Features() desc = Array() - safe_call(backend.get().af_orb(ct.pointer(feat.feat), ct.pointer(desc.arr), - ct.c_float(threshold), ct.c_uint(max_features), - ct.c_float(scale), ct.c_uint(num_levels), blur_image)) + safe_call(backend.get().af_orb(c_pointer(feat.feat), c_pointer(desc.arr), + c_float_t(threshold), c_uint_t(max_features), + c_float_t(scale), c_uint_t(num_levels), blur_image)) return feat, desc def hamming_matcher(query, database, dim = 0, num_nearest = 1): @@ -164,7 +164,7 @@ def hamming_matcher(query, database, dim = 0, num_nearest = 1): """ index = Array() dist = Array() - safe_call(backend.get().af_hamming_matcher(ct.pointer(idx.arr), ct.pointer(dist.arr), + safe_call(backend.get().af_hamming_matcher(c_pointer(idx.arr), c_pointer(dist.arr), query.arr, database.arr, c_dim_t(dim), c_dim_t(num_nearest))) return index, dist @@ -200,7 +200,7 @@ def nearest_neighbour(query, database, dim = 0, num_nearest = 1, match_type=MATC """ index = Array() dist = Array() - safe_call(backend.get().af_nearest_neighbour(ct.pointer(idx.arr), ct.pointer(dist.arr), + safe_call(backend.get().af_nearest_neighbour(c_pointer(idx.arr), c_pointer(dist.arr), query.arr, database.arr, c_dim_t(dim), c_dim_t(num_nearest), match_type.value)) @@ -229,7 +229,7 @@ def match_template(image, template, match_type = MATCH.SAD): """ out = Array() - safe_call(backend.get().af_match_template(ct.pointer(out.arr), + safe_call(backend.get().af_match_template(c_pointer(out.arr), image.arr, template.arr, match_type.value)) return out @@ -266,10 +266,10 @@ def susan(image, radius=3, diff_thr=32, geom_thr=10, feature_ratio=0.05, edge=3) """ out = Features() - safe_call(backend.get().af_susan(ct.pointer(out.feat), - image.arr, ct.c_uint(radius), ct.c_float(diff_thr), - ct.c_float(geom_thr), ct.c_float(feature_ratio), - ct.c_uint(edge))) + safe_call(backend.get().af_susan(c_pointer(out.feat), + image.arr, c_uint_t(radius), c_float_t(diff_thr), + c_float_t(geom_thr), c_float_t(feature_ratio), + c_uint_t(edge))) return out def dog(image, radius1, radius2): @@ -301,7 +301,7 @@ def dog(image, radius1, radius2): """ out = Array() - safe_call(backend.get().af_dog(ct.pointer(out.arr), + safe_call(backend.get().af_dog(c_pointer(out.arr), image.arr, radius1, radius2)) return out @@ -345,7 +345,7 @@ def sift(image, num_layers=3, contrast_threshold=0.04, edge_threshold=10.0, init feat = Features() desc = Array() - safe_call(af_sift(ct.pointer(feat), ct.pointer(desc), + safe_call(af_sift(c_pointer(feat), c_pointer(desc), image.arr, num_layers, contrast_threshold, edge_threshold, initial_sigma, double_input, intensity_scale, feature_ratio)) @@ -391,7 +391,7 @@ def gloh(image, num_layers=3, contrast_threshold=0.04, edge_threshold=10.0, init feat = Features() desc = Array() - safe_call(af_gloh(ct.pointer(feat), ct.pointer(desc), + safe_call(af_gloh(c_pointer(feat), c_pointer(desc), image.arr, num_layers, contrast_threshold, edge_threshold, initial_sigma, double_input, intensity_scale, feature_ratio)) @@ -433,8 +433,8 @@ def homography(x_src, y_src, x_dst, y_dst, htype = HOMOGRAPHY.RANSAC, """ H = Array() - inliers = ct.c_int(0) - safe_call(backend.get().af_homography(ct.pointer(H), ct.pointer(inliers), + inliers = c_int_t(0) + safe_call(backend.get().af_homography(c_pointer(H), c_pointer(inliers), x_src.arr, y_src.arr, x_dst.arr, y_dst.arr, htype.value, ransac_threshold, iters, out_type.value)) return (H, inliers) From 64fb62ef1a610e0ab5ca2130f480353769a9871d Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sat, 24 Sep 2016 20:38:38 -0700 Subject: [PATCH 104/212] Cleaning up Index --- arrayfire/array.py | 5 +---- arrayfire/index.py | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index d9f78bf4d..17c17f274 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -178,10 +178,7 @@ def _get_info(dims, buf_len): def _get_indices(key): - - S = Index(slice(None)) - inds = _Index4(S, S, S, S) - + inds = _Index4() if isinstance(key, tuple): n_idx = len(key) for n in range(n_idx): diff --git a/arrayfire/index.py b/arrayfire/index.py index 18c68dc35..093a88336 100644 --- a/arrayfire/index.py +++ b/arrayfire/index.py @@ -59,7 +59,20 @@ def __init__ (self, S): if (S.start is not None): self.begin = c_double_t(S.start) if (S.stop is not None): - self.end = c_double_t(S.stop - math.copysign(1, self.step)) + self.end = c_double_t(S.stop) + + # handle special cases + if self.begin >= 0 and self.end >=0 and self.end <= self.begin and self.step >= 0: + self.begin = 1 + self.end = 1 + self.step = 1 + elif self.begin < 0 and self.end < 0 and self.end >= self.begin and self.step <= 0: + self.begin = -2 + self.end = -2 + self.step = -1 + + if (S.stop is not None): + self.end = self.end - math.copysign(1, self.step) else: raise IndexError("Invalid type while indexing arrayfire.array") @@ -217,14 +230,15 @@ def __del__(self): arr = c_void_ptr_t(self.idx.arr) backend.get().af_release_array(arr) +_span = Index(slice(None)) class _Index4(object): - def __init__(self, idx0, idx1, idx2, idx3): + def __init__(self): index_vec = Index * 4 - self.array = index_vec(idx0, idx1, idx2, idx3) + self.array = index_vec(_span, _span, _span, _span) # Do not lose those idx as self.array keeps # no reference to them. Otherwise the destructor # is prematurely called - self.idxs = [idx0,idx1,idx2,idx3] + self.idxs = [_span, _span, _span, _span] @property def pointer(self): return c_pointer(self.array) From 300c7d0a8a6e65a6c9692508005d03d83d794945 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sat, 24 Sep 2016 20:40:03 -0700 Subject: [PATCH 105/212] Changing setup.py and README.md --- README.md | 6 ++++++ setup.py | 3 +-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 35c4ee441..311523c67 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,12 @@ python setup.py install Please follow [these instructions](https://github.com/arrayfire/arrayfire-python/wiki) to ensure the arrayfire-python can find the arrayfire libraries. +To run arrayfire tests, you can run the following command from command line. + +``` +python -m arrayfire.tests +``` + ## Acknowledgements The ArrayFire library is written by developers at [ArrayFire](http://arrayfire.com) LLC diff --git a/setup.py b/setup.py index d229aa831..ab1d2eae8 100644 --- a/setup.py +++ b/setup.py @@ -14,11 +14,10 @@ #TODO: #1) Look for af libraries during setup -#2) Include test suite setup( author="Pavan Yalamanchili", - author_email="pavan@arrayfire.com", + author_email="contact@pavanky.com", name="arrayfire", version="3.4.0", description="Python bindings for ArrayFire", From 48d1ffbee65147991b2f6c7c4c9fa3f6a40e81f2 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 25 Sep 2016 00:51:55 -0700 Subject: [PATCH 106/212] Changing sparse* functions to create_sparse* --- arrayfire/sparse.py | 10 +++++----- arrayfire/tests/simple/sparse.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arrayfire/sparse.py b/arrayfire/sparse.py index 82eed1706..830b2c7bc 100644 --- a/arrayfire/sparse.py +++ b/arrayfire/sparse.py @@ -22,7 +22,7 @@ STORAGE.COO] -def sparse(values, row_idx, col_idx, nrows, ncols, storage = STORAGE.CSR): +def create_sparse(values, row_idx, col_idx, nrows, ncols, storage = STORAGE.CSR): """ Create a sparse matrix from it's constituent parts. @@ -60,7 +60,7 @@ def sparse(values, row_idx, col_idx, nrows, ncols, storage = STORAGE.CSR): values.arr, row_idx.arr, col_idx.arr, storage.value)) return out -def sparse_from_host(values, row_idx, col_idx, nrows, ncols, storage = STORAGE.CSR): +def create_sparse_from_host(values, row_idx, col_idx, nrows, ncols, storage = STORAGE.CSR): """ Create a sparse matrix from it's constituent parts. @@ -90,9 +90,9 @@ def sparse_from_host(values, row_idx, col_idx, nrows, ncols, storage = STORAGE.C A sparse matrix. """ - return sparse(to_array(values), to_array(row_idx), to_array(col_idx), nrows, ncols, storage) + return create_sparse(to_array(values), to_array(row_idx), to_array(col_idx), nrows, ncols, storage) -def sparse_from_dense(dense, storage = STORAGE.CSR): +def create_sparse_from_dense(dense, storage = STORAGE.CSR): """ Create a sparse matrix from a dense matrix. @@ -115,7 +115,7 @@ def sparse_from_dense(dense, storage = STORAGE.CSR): safe_call(backend.get().af_create_sparse_array_from_dense(c_pointer(out.arr), dense.arr, storage.value)) return out -def sparse_to_dense(sparse): +def create_sparse_to_dense(sparse): """ Create a dense matrix from a sparse matrix. diff --git a/arrayfire/tests/simple/sparse.py b/arrayfire/tests/simple/sparse.py index b756cd5a5..89315dfb1 100644 --- a/arrayfire/tests/simple/sparse.py +++ b/arrayfire/tests/simple/sparse.py @@ -17,7 +17,7 @@ def simple_sparse(verbose=False): dd = af.randu(5, 5) ds = dd * (dd > 0.5) - sp = af.sparse_from_dense(ds) + sp = af.create_sparse_from_dense(ds) display_func(af.sparse_get_info(sp)) display_func(af.sparse_get_values(sp)) display_func(af.sparse_get_row_idx(sp)) From 3f1d3ab951aaabbc636738d8bf00119d6325bb84 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 25 Sep 2016 01:13:00 -0700 Subject: [PATCH 107/212] Updating changes to reflect new documentation --- __af_version__.py | 4 ++-- arrayfire/array.py | 2 ++ arrayfire/lapack.py | 1 + arrayfire/random.py | 4 ++-- arrayfire/sparse.py | 4 ++-- docs/arrayfire.random.rst | 7 +++++++ docs/arrayfire.rst | 4 +++- docs/arrayfire.sparse.rst | 7 +++++++ 8 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 docs/arrayfire.random.rst create mode 100644 docs/arrayfire.sparse.rst diff --git a/__af_version__.py b/__af_version__.py index 72e423a40..828a50d33 100644 --- a/__af_version__.py +++ b/__af_version__.py @@ -9,6 +9,6 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -version = "3.3" -release = "20160624" +version = "3.4" +release = "20160925" full_version = version + "." + release diff --git a/arrayfire/array.py b/arrayfire/array.py index 17c17f274..57f557485 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -305,6 +305,7 @@ class Array(BaseArray): - 'L' for unsigned 64 bit integer - 'F' for 32 bit complex number - 'D' for 64 bit complex number + - if arrayfire.Dtype, must be one of the following: - Dtype.f32 for float - Dtype.f64 for double @@ -318,6 +319,7 @@ class Array(BaseArray): - Dtype.u64 for unsigned 64 bit integer - Dtype.c32 for 32 bit complex number - Dtype.c64 for 64 bit complex number + - if None, Dtype.f32 is assumed Attributes diff --git a/arrayfire/lapack.py b/arrayfire/lapack.py index 05c18732b..e6ffd5cb7 100644 --- a/arrayfire/lapack.py +++ b/arrayfire/lapack.py @@ -142,6 +142,7 @@ def cholesky(A, is_upper=True): (R,info): tuple of af.Array, int. - R - triangular matrix. - info - 0 if decomposition sucessful. + Note ---- diff --git a/arrayfire/random.py b/arrayfire/random.py index c53579248..179833db8 100644 --- a/arrayfire/random.py +++ b/arrayfire/random.py @@ -186,7 +186,7 @@ def get_seed(): Get the seed for the random number generator. Returns - ---------- + ------- seed: int. Seed for the random number generator """ @@ -221,7 +221,7 @@ def get_default_random_engine(): Get the default random engine Returns - ------ + ------- The default random engine used by randu and randn """ diff --git a/arrayfire/sparse.py b/arrayfire/sparse.py index 830b2c7bc..b261bdbd8 100644 --- a/arrayfire/sparse.py +++ b/arrayfire/sparse.py @@ -115,7 +115,7 @@ def create_sparse_from_dense(dense, storage = STORAGE.CSR): safe_call(backend.get().af_create_sparse_array_from_dense(c_pointer(out.arr), dense.arr, storage.value)) return out -def create_sparse_to_dense(sparse): +def convert_sparse_to_dense(sparse): """ Create a dense matrix from a sparse matrix. @@ -256,7 +256,7 @@ def sparse_get_storage(sparse): safe_call(backend.get().af_sparse_get_storage(c_pointer(storage), sparse.arr)) return __to_sparse_enum[storage.value] -def sparse_convert_to(sparse, storage): +def convert_sparse(sparse, storage): """ Convert sparse matrix from one format to another. diff --git a/docs/arrayfire.random.rst b/docs/arrayfire.random.rst new file mode 100644 index 000000000..33c86f96b --- /dev/null +++ b/docs/arrayfire.random.rst @@ -0,0 +1,7 @@ +arrayfire.random module +========================= + +.. automodule:: arrayfire.random + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.rst b/docs/arrayfire.rst index 2ccfd3b41..2951fcb3b 100644 --- a/docs/arrayfire.rst +++ b/docs/arrayfire.rst @@ -6,7 +6,7 @@ Introduction .. automodule:: arrayfire - Submodules +Submodules ---------- .. autosummary:: @@ -27,6 +27,8 @@ Introduction arrayfire.lapack arrayfire.library arrayfire.opencl + arrayfire.random + arrayfire.sparse arrayfire.signal arrayfire.statistics arrayfire.timer diff --git a/docs/arrayfire.sparse.rst b/docs/arrayfire.sparse.rst new file mode 100644 index 000000000..cc087885d --- /dev/null +++ b/docs/arrayfire.sparse.rst @@ -0,0 +1,7 @@ +arrayfire.sparse module +========================= + +.. automodule:: arrayfire.sparse + :members: + :undoc-members: + :show-inheritance: From a9fec068ef3c9a8eef6d84044eb842e762290a73 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 25 Sep 2016 01:18:12 -0700 Subject: [PATCH 108/212] Workaround for upstream bug --- arrayfire/tests/simple/algorithm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/arrayfire/tests/simple/algorithm.py b/arrayfire/tests/simple/algorithm.py index 75ab814d4..5528da3b0 100644 --- a/arrayfire/tests/simple/algorithm.py +++ b/arrayfire/tests/simple/algorithm.py @@ -17,6 +17,7 @@ def simple_algorithm(verbose = False): a = af.randu(3, 3) k = af.constant(1, 3, 3, dtype=af.Dtype.u32) + af.eval(k) print_func(af.sum(a), af.product(a), af.min(a), af.max(a), af.count(a), af.any_true(a), af.all_true(a)) From 17e9179efa14066920af1eec27637570c324eaaa Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 25 Sep 2016 01:18:37 -0700 Subject: [PATCH 109/212] Updating Changelog --- CHANGELOG.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a55a2bd6b..c1548715e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,57 @@ +### v3.4.20160925 +- Feature parity with ArrayFire 3.4 libs + + - [Sparse matrix support](http://arrayfire.org/arrayfire-python/arrayfire.sparse.html#module-arrayfire.sparse) + - `create_sparse` + - `create_sparse_from_dense` + - `create_sparse_from_host` + - `convert_sparse_to_dense` + - `convert_sparse` + - `sparse_get_info` + - `sparse_get_nnz` + - `sparse_get_values` + - `sparse_get_row_idx` + - `sparse_get_col_idx` + - `sparse_get_storage` + + - [Random Engine support](http://arrayfire.org/arrayfire-python/arrayfire.random.html#module-arrayfire.random) + - Three new random engines, `RANDOM_ENGINE.PHILOX`, `RANDOM_ENGINE.THREEFRY`, and `RANDOM_ENGINE.MERSENNE`. + - `randu` and `randn` now accept an additional engine parameter. + - `set_default_random_engine_type` + - `get_default_random_engine` + + - New functions + - [`scan`](http://arrayfire.org/arrayfire-python/arrayfire.algorithm.html?arrayfire.algorithm.scan#arrayfire.algorithm.scan) + - [`scan_by_key`](http://arrayfire.org/arrayfire-python/arrayfire.algorithm.html?arrayfire.algorithm.scan#arrayfire.algorithm.scan_by_key) + - [`clamp`](http://arrayfire.org/arrayfire-python/arrayfire.arith.html?arrayfire.arith.clamp#arrayfire.arith.clamp) + - [`medfilt1`](http://arrayfire.org/arrayfire-python/arrayfire.signal.html#arrayfire.signal.medfilt1) + - [`medfilt2`](http://arrayfire.org/arrayfire-python/arrayfire.signal.html#arrayfire.signal.medfilt2) + - [`moments`](http://arrayfire.org/arrayfire-python/arrayfire.image.html#arrayfire.image.moments) + - [`get_size_of`](http://arrayfire.org/arrayfire-python/arrayfire.library.html#arrayfire.library.get_size_of) + - [`get_manual_eval_flag`](http://arrayfire.org/arrayfire-python/arrayfire.device.html#arrayfire.device.get_manual_eval_flag) + - [`set_manual_eval_flag`](http://arrayfire.org/arrayfire-python/arrayfire.device.html#arrayfire.device.set_manual_eval_flag) + + - Behavior changes + - [`eval`](http://arrayfire.org/arrayfire-python/arrayfire.device.html#arrayfire.device.eval) now supports fusing kernels. + + - Graphics updates + - [`plot`](http://arrayfire.org/arrayfire-python/arrayfire.graphics.html#arrayfire.graphics.Window.plot) updated to take new parameters. + - [`plot2`](http://arrayfire.org/arrayfire-python/arrayfire.graphics.html#arrayfire.graphics.Window.plot2) added. + - [`scatter`](http://arrayfire.org/arrayfire-python/arrayfire.graphics.html#arrayfire.graphics.Window.scatter) updated to take new parameters. + - [`scatter2`](http://arrayfire.org/arrayfire-python/arrayfire.graphics.html#arrayfire.graphics.Window.scatter2) added. + - [`vector_field`](http://arrayfire.org/arrayfire-python/arrayfire.graphics.html#arrayfire.graphics.Window.vector_field) added. + - [`set_axes_limits`](http://arrayfire.org/arrayfire-python/arrayfire.graphics.html#arrayfire.graphics.Window.set_axes_limits) added. + +- Bug fixes + + - ArrayFire now has higher priority when numpy for mixed operations. [1](https://github.com/arrayfire/arrayfire-python/issues/69) [2](https://github.com/arrayfire/arrayfire-python/pull/71) + - Numpy interoperability issues on Widnows. [1](https://github.com/arrayfire/arrayfire-python/issues/92) + - Switch to a working backend by default. [1](https://github.com/arrayfire/arrayfire-python/issues/90) + - Fixed incorrect behavior for Hermitian transpose and QR. [1](https://github.com/arrayfire/arrayfire-python/issues/91) + - `array[0:0]` now returns empty arrays. [1](https://github.com/arrayfire/arrayfire-python/issues/26) + +- Further Improvements from upstream can be read in the [arrayfire release notes](https://github.com/arrayfire/arrayfire/blob/master/docs/pages/release_notes.md). + ### v3.3.20160624 - Adding 16 bit integer support - Adding support for sphinx documentation From 7935ed9d157720d97d68c7eedc8b3e9e8be203a0 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 25 Sep 2016 01:45:45 -0700 Subject: [PATCH 110/212] Fixing bug in graphics documentation --- arrayfire/graphics.py | 44 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/arrayfire/graphics.py b/arrayfire/graphics.py index 3ada18737..4e378aaf5 100644 --- a/arrayfire/graphics.py +++ b/arrayfire/graphics.py @@ -127,8 +127,8 @@ def image(self, img, title=None): """ Display an arrayfire array as an image. - Paramters - --------- + Parameters + ---------- img: af.Array. A 2 dimensional array for single channel image. @@ -144,8 +144,8 @@ def scatter(self, X, Y, Z=None, points=None, marker=MARKER.POINT, title=None): """ Renders input arrays as 2D or 3D scatter plot. - Paramters - --------- + Parameters + ---------- X: af.Array. A 1 dimensional array containing X co-ordinates. @@ -183,8 +183,8 @@ def scatter2(self, points, marker=MARKER.POINT, title=None): """ Renders the input array as a 2D Scatter plot. - Paramters - --------- + Parameters + ---------- points: af.Array. A 2 dimensional array containing (X,Y) co-ordinates. @@ -204,8 +204,8 @@ def scatter3(self, points, marker=MARKER.POINT, title=None): """ Renders the input array as a 3D Scatter plot. - Paramters - --------- + Parameters + ---------- points: af.Array. A 2 dimensional array containing (X,Y,Z) co-ordinates. @@ -224,8 +224,8 @@ def plot(self, X, Y, Z=None, line = None, title=None): """ Display a 2D or 3D Plot. - Paramters - --------- + Parameters + ---------- X: af.Array. - A 1 dimensional array containing X co-ordinates. @@ -264,8 +264,8 @@ def plot2(self, line, title=None): """ Display a 2D Plot. - Paramters - --------- + Parameters + ---------- line: af.Array. - A 2 dimensional array of size [n 2]. Each column denotes X, and Y co-ordinates for plotting 2D lines. @@ -283,8 +283,8 @@ def plot3(self, X=None, Y=None, Z=None, line=None, title=None): """ Display a 3D Plot. - Paramters - --------- + Parameters + ---------- line: af.Array. - A 3 dimensional array of size [n 3]. Each column denotes X, Y, and Z co-ordinates for plotting 3D lines. @@ -302,8 +302,8 @@ def vector_field(self, xpoints, xdirs, ypoints, ydirs, zpoints=None, zdirs=None, """ Display a 2D or 3D Vector_Field. - Paramters - --------- + Parameters + ---------- xpoints : af.Array. - A 1 dimensional array containing X co-ordinates. @@ -364,8 +364,8 @@ def surface(self, x_vals, y_vals, z_vals, title=None): """ Renders the input array as a 3D surface plot. - Paramters - --------- + Parameters + ---------- x_vals: af.Array. A 1 dimensional array containing X co-ordinates. @@ -388,8 +388,8 @@ def hist(self, X, min_val, max_val, title=None): """ Display a histogram Plot. - Paramters - --------- + Parameters + ---------- X: af.Array. A 1 dimensional array containing the histogram. @@ -454,8 +454,8 @@ def set_axes_limits(self, xmin, xmax, ymin, ymax, zmin=None, zmax=None, exact=Fa """ Set axis limits. - Paramters - --------- + Parameters + ---------- xmin : af.Array. - lower limit of the x axis. From 7cec9c804460bfda6f2052c07bf0a7b1f7d59959 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 25 Sep 2016 01:47:49 -0700 Subject: [PATCH 111/212] Updating release version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ab1d2eae8..aac101f8c 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ author="Pavan Yalamanchili", author_email="contact@pavanky.com", name="arrayfire", - version="3.4.0", + version="3.4.20160925", description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From cafc208b9b0d6b5cd9219da628692ef8ee0f92cb Mon Sep 17 00:00:00 2001 From: ZacDiggum Date: Tue, 11 Oct 2016 19:27:47 +0200 Subject: [PATCH 112/212] Update interop.py (#103) * Update interop.py add numpy u16 dtype * Add files via upload * added numpy u16 and s16 dtypes --- arrayfire/interop.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/arrayfire/interop.py b/arrayfire/interop.py index e1a5d3b3d..e4cd3561d 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -27,18 +27,19 @@ AF_NUMPY_FOUND=True - _nptype_to_aftype = {'f4' : Dtype.f32, + _nptype_to_aftype = {'b1' : Dtype.b8, + 'u1' : Dtype.u8, + 'u2' : Dtype.u16, + 'i2' : Dtype.s16, + 's4' : Dtype.u32, + 'i4' : Dtype.s32, + 'f4' : Dtype.f32, + 'c8' : Dtype.c32, + 's8' : Dtype.u64, + 'i8' : Dtype.s64, 'f8' : Dtype.f64, - 'b1' : Dtype.b8, - 'u1' : Dtype.u8, - 'i4' : Dtype.s32, - 's4' : Dtype.u32, - 'i8' : Dtype.s64, - 's8' : Dtype.u64, - 'c8' : Dtype.c32, 'c16' : Dtype.c64} - def np_to_af_array(np_arr): """ Convert numpy.ndarray to arrayfire.Array. From 2cab1e7e93a31a2cee7be48529ca0a190841116e Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sat, 26 Nov 2016 17:56:43 -0800 Subject: [PATCH 113/212] BUGFIX: Do not call af_create_handle for empty arrays All the internal functions initialize an empty array first and use the internal pointer to get the output af_array. However this was not releasing the handle originally created. This created a memory leak easily fixed by not creating a handle when the array is empty. --- arrayfire/array.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 57f557485..d9674dbc6 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -54,6 +54,9 @@ def _create_strided_array(buf, numdims, idims, dtype, is_device, offset, strides def _create_empty_array(numdims, idims, dtype): out_arr = c_void_ptr_t(0) + + if numdims == 0: return out_arr + c_dims = dim4(idims[0], idims[1], idims[2], idims[3]) safe_call(backend.get().af_create_handle(c_pointer(out_arr), numdims, c_pointer(c_dims), dtype.value)) @@ -382,7 +385,7 @@ class Array(BaseArray): # arrayfire's __radd__() instead of numpy's __add__() __array_priority__ = 30 - def __init__(self, src=None, dims=(0,), dtype=None, is_device=False, offset=None, strides=None): + def __init__(self, src=None, dims=None, dtype=None, is_device=False, offset=None, strides=None): super(Array, self).__init__() @@ -449,10 +452,12 @@ def __init__(self, src=None, dims=(0,), dtype=None, is_device=False, offset=None if type_char is None: type_char = 'f' - numdims = len(dims) + numdims = len(dims) if dims else 0 + idims = [1] * 4 for n in range(numdims): idims[n] = dims[n] + self.arr = _create_empty_array(numdims, idims, to_dtype[type_char]) def as_type(self, ty): From 239d97b09cffc2543c7863d71fe94f590c7cc125 Mon Sep 17 00:00:00 2001 From: ZacDiggum Date: Tue, 11 Oct 2016 19:27:47 +0200 Subject: [PATCH 114/212] Update interop.py (#103) * Update interop.py add numpy u16 dtype * Add files via upload * added numpy u16 and s16 dtypes --- arrayfire/interop.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/arrayfire/interop.py b/arrayfire/interop.py index e1a5d3b3d..e4cd3561d 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -27,18 +27,19 @@ AF_NUMPY_FOUND=True - _nptype_to_aftype = {'f4' : Dtype.f32, + _nptype_to_aftype = {'b1' : Dtype.b8, + 'u1' : Dtype.u8, + 'u2' : Dtype.u16, + 'i2' : Dtype.s16, + 's4' : Dtype.u32, + 'i4' : Dtype.s32, + 'f4' : Dtype.f32, + 'c8' : Dtype.c32, + 's8' : Dtype.u64, + 'i8' : Dtype.s64, 'f8' : Dtype.f64, - 'b1' : Dtype.b8, - 'u1' : Dtype.u8, - 'i4' : Dtype.s32, - 's4' : Dtype.u32, - 'i8' : Dtype.s64, - 's8' : Dtype.u64, - 'c8' : Dtype.c32, 'c16' : Dtype.c64} - def np_to_af_array(np_arr): """ Convert numpy.ndarray to arrayfire.Array. From 996043141981669fe6ad381a1ed13caa249b71e4 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sat, 26 Nov 2016 18:05:12 -0800 Subject: [PATCH 115/212] BUGFIX: Fixing _get_info when dims is None --- arrayfire/array.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index d9674dbc6..d665169ae 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -163,19 +163,18 @@ def _slice_to_length(key, dim): def _get_info(dims, buf_len): elements = 1 - numdims = len(dims) - idims = [1]*4 - - for i in range(numdims): - elements *= dims[i] - idims[i] = dims[i] - - if (elements == 0): - if (buf_len != 0): - idims = [buf_len, 1, 1, 1] - numdims = 1 - else: - raise RuntimeError("Invalid size") + numdims = 0 + if dims: + numdims = len(dims) + idims = [1]*4 + for i in range(numdims): + elements *= dims[i] + idims[i] = dims[i] + elif (buf_len != 0): + idims = [buf_len, 1, 1, 1] + numdims = 1 + else: + raise RuntimeError("Invalid size") return numdims, idims From 02efc475922a324760103a000ec76bfc5bf9bba7 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sat, 26 Nov 2016 18:16:03 -0800 Subject: [PATCH 116/212] Updating version number and changelog --- CHANGELOG.md | 4 ++++ setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1548715e..4e662a254 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### v3.3.20161126 +- Fixing memory leak in array creation. +- Supporting 16 bit integer types in interop. + ### v3.4.20160925 - Feature parity with ArrayFire 3.4 libs diff --git a/setup.py b/setup.py index aac101f8c..83fcb221b 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ author="Pavan Yalamanchili", author_email="contact@pavanky.com", name="arrayfire", - version="3.4.20160925", + version="3.4.20161126", description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From a6843559e1fb5af62ad51d6008df4ceafa0f899b Mon Sep 17 00:00:00 2001 From: Marek Wojciechowski Date: Tue, 3 Jan 2017 13:48:22 +0100 Subject: [PATCH 117/212] Update monte_carlo_pi.py (#108) calc_pi_numpy returned integer value, it returns float now. --- examples/benchmarks/monte_carlo_pi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/benchmarks/monte_carlo_pi.py b/examples/benchmarks/monte_carlo_pi.py index f3198d4e7..2703069c2 100755 --- a/examples/benchmarks/monte_carlo_pi.py +++ b/examples/benchmarks/monte_carlo_pi.py @@ -38,7 +38,7 @@ def calc_pi_numpy(samples): np.random.seed(1) x = np.random.rand(samples).astype(np.float32) y = np.random.rand(samples).astype(np.float32) - return 4 * np.sum(in_circle(x, y)) / samples + return 4. * np.sum(in_circle(x, y)) / samples def calc_pi_host(samples): count = sum(1 for k in frange(samples) if in_circle(random(), random())) From 58b928a42ffb4631729b0f2b15da1cc84ad250a3 Mon Sep 17 00:00:00 2001 From: Marek Wojciechowski Date: Wed, 4 Jan 2017 18:22:43 +0100 Subject: [PATCH 118/212] Add conjugate gradient benchmark. Tests dense and sparse arrayfire behavior against numpy and scipy solutions. Works in float32 presision. --- examples/benchmarks/bench_cg.py | 200 ++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 examples/benchmarks/bench_cg.py diff --git a/examples/benchmarks/bench_cg.py b/examples/benchmarks/bench_cg.py new file mode 100644 index 000000000..2f0bb25d6 --- /dev/null +++ b/examples/benchmarks/bench_cg.py @@ -0,0 +1,200 @@ +#!/usr/bin/python + +####################################################### +# Copyright (c) 2015, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + + +import sys +from time import time +import arrayfire as af + +try: + import numpy as np +except: + np = None + +try: + from scipy import sparse as sp + from scipy.sparse import linalg +except: + sp = None + + +def to_numpy(A): + return np.asarray(A.to_list(), dtype=np.float32) + + +def to_sparse(A): + return af.sparse.create_sparse_from_dense(A) + + +def to_scipy_sparse(spA, fmt='csr'): + vals = np.asarray(af.sparse.sparse_get_values(spA).to_list(), + dtype = np.float32) + rows = np.asarray(af.sparse.sparse_get_row_idx(spA).to_list(), + dtype = np.int) + cols = np.asarray(af.sparse.sparse_get_col_idx(spA).to_list(), + dtype = np.int) + return sp.csr_matrix((vals, cols, rows), dtype=np.float32) + + +def setup_input(n, sparsity=7): + T = af.randu(n, n, dtype=af.Dtype.f32) + A = af.floor(T*1000) + A = A * ((A % sparsity) == 0) / 1000 + A = A.T + A + n*af.identity(n, n, dtype=af.Dtype.f32) + x0 = af.randu(n, dtype=af.Dtype.f32) + b = af.matmul(A, x0) + # printing + # nnz = af.sum((A != 0)) + # print "Sparsity of A: %2.2f %%" %(100*nnz/n**2,) + return A, b, x0 + + +def input_info(A, Asp): + m, n = A.dims() + nnz = af.sum((A != 0)) + print(" matrix size: %i x %i" %(m, n)) + print(" matrix sparsity: %2.2f %%" %(100*nnz/n**2,)) + print(" dense matrix memory usage: ") + print(" sparse matrix memory usage: ") + + +def calc_arrayfire(A, b, x0, maxiter=10): + x = af.constant(0, b.dims()[0], dtype=af.Dtype.f32) + r = b - af.matmul(A, x) + p = r + for i in range(maxiter): + Ap = af.matmul(A, p) + alpha_num = af.dot(r, r) + alpha_den = af.dot(p, Ap) + alpha = alpha_num/alpha_den + r -= af.tile(alpha, Ap.dims()[0]) * Ap + x += af.tile(alpha, Ap.dims()[0]) * p + beta_num = af.dot(r, r) + beta = beta_num/alpha_num + p = r + af.tile(beta, p.dims()[0]) * p + res = x0 - x + return x, af.dot(res, res) + + +def calc_numpy(A, b, x0, maxiter=10): + x = np.zeros(len(b), dtype=np.float32) + r = b - np.dot(A, x) + p = r.copy() + for i in range(maxiter): + Ap = np.dot(A, p) + alpha_num = np.dot(r, r) + alpha_den = np.dot(p, Ap) + alpha = alpha_num/alpha_den + r -= alpha * Ap + x += alpha * p + beta_num = np.dot(r, r) + beta = beta_num/alpha_num + p = r + beta * p + res = x0 - x + return x, np.dot(res, res) + + +def calc_scipy_sparse(A, b, x0, maxiter=10): + x = np.zeros(len(b), dtype=np.float32) + r = b - A*x + p = r.copy() + for i in range(maxiter): + Ap = A*p + alpha_num = np.dot(r, r) + alpha_den = np.dot(p, Ap) + alpha = alpha_num/alpha_den + r -= alpha * Ap + x += alpha * p + beta_num = np.dot(r, r) + beta = beta_num/alpha_num + p = r + beta * p + res = x0 - x + return x, np.dot(res, res) + + +def calc_scipy_sparse_linalg_cg(A, b, x0, maxiter=10): + x = np.zeros(len(b), dtype=np.float32) + x, _ = linalg.cg(A, b, x, tol=0., maxiter=maxiter) + res = x0 - x + return x, np.dot(res, res) + + +def timeit(calc, iters, args): + t0 = time() + for i in range(iters): + calc(*args) + dt = time() - t0 + return 1000*dt/iters # ms + + +def test(): + print("\nTesting benchmark functions...") + A, b, x0 = setup_input(50) # dense A + Asp = to_sparse(A) + x1, _ = calc_arrayfire(A, b, x0) + x2, _ = calc_arrayfire(Asp, b, x0) + if af.sum(af.abs(x1 - x2)/x2 > 1e-6): + raise ValueError("arrayfire test failed") + if np: + An = to_numpy(A) + bn = to_numpy(b) + x0n = to_numpy(x0) + x3, _ = calc_numpy(An, bn, x0n) + if not np.allclose(x3, x1.to_list()): + raise ValueError("numpy test failed") + if sp: + Asc = to_scipy_sparse(Asp) + x4, _ = calc_scipy_sparse(Asc, bn, x0n) + if not np.allclose(x4, x1.to_list()): + raise ValueError("scipy.sparse test failed") + x5, _ = calc_scipy_sparse_linalg_cg(Asc, bn, x0n) + if not np.allclose(x5, x1.to_list()): + raise ValueError("scipy.sparse.linalg.cg test failed") + print(" all tests passed...") + + +def bench(n=4*1024, sparsity=7, maxiter=10, iters=10): + # generate data + print("\nGenerating benchmark data for n = %i ..." %n) + A, b, x0 = setup_input(n, sparsity) # dense A + Asp = to_sparse(A) # sparse A + input_info(A, Asp) + # make benchmarks + print("Benchmarking CG solver for n = %i ..." %n) + t1 = timeit(calc_arrayfire, iters, args=(A, b, x0, maxiter)) + print(" arrayfire - dense: %f ms" %t1) + t2 = timeit(calc_arrayfire, iters, args=(Asp, b, x0, maxiter)) + print(" arrayfire - sparse: %f ms" %t2) + if np: + An = to_numpy(A) + bn = to_numpy(b) + x0n = to_numpy(x0) + t3 = timeit(calc_numpy, iters, args=(An, bn, x0n, maxiter)) + print(" numpy - dense: %f ms" %t3) + if sp: + Asc = to_scipy_sparse(Asp) + t4 = timeit(calc_scipy_sparse, iters, args=(Asc, bn, x0n, maxiter)) + print(" scipy - sparse: %f ms" %t4) + t5 = timeit(calc_scipy_sparse_linalg_cg, iters, args=(Asc, bn, x0n, maxiter)) + print(" scipy - sparse.linalg.cg: %f ms" %t5) + +if __name__ == "__main__": + #af.set_backend('cpu', unsafe=True) + + if (len(sys.argv) > 1): + af.set_device(int(sys.argv[1])) + + af.info() + + test() + + for n in (128, 256, 512, 1024, 2048, 4096): + bench(n) From 320f9fc2982459c614b02703ed158876b8d534b7 Mon Sep 17 00:00:00 2001 From: Ghislain Antony Vaillant Date: Mon, 9 Jan 2017 18:06:44 +0000 Subject: [PATCH 119/212] Create MANIFEST.in (#110) In addition to the arrayfire Python module, the tarball generated with `sdist` now contains the docs, examples, changelog, readme and licensing terms. This is desirable for downstream packaging by Linux distributions, which usually source Python packages from PyPI instead of the upstream repository. --- MANIFEST.in | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..88db0a145 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +recursive-include docs * +recursive-include examples * +include CHANGELOG.md LICENSE README.md From 10757d1ddda256dcb07409531bd886e6c8ed41e0 Mon Sep 17 00:00:00 2001 From: unbornchikken Date: Mon, 16 Jan 2017 21:51:14 +0100 Subject: [PATCH 120/212] lookup + faster not --- arrayfire/array.py | 4 +++- arrayfire/data.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index d665169ae..6f91d1339 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -1008,7 +1008,9 @@ def __invert__(self): """ Return ~self """ - return self == 0 + out = Array() + safe_call(backend.get().af_not(c_pointer(out.arr), self.arr)) + self = out def __nonzero__(self): return self != 0 diff --git a/arrayfire/data.py b/arrayfire/data.py index 0e953f707..40afe1724 100644 --- a/arrayfire/data.py +++ b/arrayfire/data.py @@ -799,3 +799,46 @@ def replace(lhs, cond, rhs): safe_call(backend.get().af_replace(lhs.arr, cond.arr, rhs.arr)) else: safe_call(backend.get().af_replace_scalar(lhs.arr, cond.arr, c_double_t(rhs))) + +def lookup(a, idx, dim=0): + """ + Lookup the values of input array based on index. + + Parameters + ---------- + + a : af.Array. + Multi dimensional array. + + idx : is lookup indices + + dim : optional: int. default: 0. + Specifies the dimension for indexing + + Returns + ------- + + out : af.Array + An array containing values at locations specified by 'idx' + + Examples + --------- + + >>> import arrayfire as af + >>> a = af.randu(3, 3) + >>> af.display(a) + [3 3 1 1] + 0.7269 0.3569 0.3341 + 0.7104 0.1437 0.0899 + 0.5201 0.4563 0.5363 + + >>> idx = af.array([1, 2]) + >>> o = af.lookup() + [2 1 1 1] + 0.7269 0.3569 0.3341 + 0.7104 0.1437 0.0899 + + """ + out = Array() + safe_call(backend.get().af_lookup(c_pointer(out.arr), a.arr, idx.arr, c_int_t(dim))) + return out From 4237ffb26a5886e4d5418087ad0b905f3c048de4 Mon Sep 17 00:00:00 2001 From: unbornchikken Date: Tue, 17 Jan 2017 14:56:54 +0100 Subject: [PATCH 121/212] minor fixes --- arrayfire/array.py | 1 + arrayfire/data.py | 26 +++++++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 6f91d1339..4a8c42f57 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -1011,6 +1011,7 @@ def __invert__(self): out = Array() safe_call(backend.get().af_not(c_pointer(out.arr), self.arr)) self = out + return self def __nonzero__(self): return self != 0 diff --git a/arrayfire/data.py b/arrayfire/data.py index 40afe1724..73f516073 100644 --- a/arrayfire/data.py +++ b/arrayfire/data.py @@ -825,19 +825,23 @@ def lookup(a, idx, dim=0): --------- >>> import arrayfire as af - >>> a = af.randu(3, 3) - >>> af.display(a) - [3 3 1 1] - 0.7269 0.3569 0.3341 - 0.7104 0.1437 0.0899 - 0.5201 0.4563 0.5363 + >>> arr = af.Array([1,0,3,4,5,6], (2,3)) + >>> af.display(arr) + [2 3 1 1] + 1.0000 3.0000 5.0000 + 0.0000 4.0000 6.0000 - >>> idx = af.array([1, 2]) - >>> o = af.lookup() - [2 1 1 1] - 0.7269 0.3569 0.3341 - 0.7104 0.1437 0.0899 + >>> idx = af.array([0, 2]) + >>> af.lookup(arr, idx, 1) + [2 2 1 1] + 1.0000 5.0000 + 0.0000 6.0000 + >>> idx = af.array([0]) + >>> af.lookup(arr, idx, 0) + [2 1 1 1] + 0.0000 + 2.0000 """ out = Array() safe_call(backend.get().af_lookup(c_pointer(out.arr), a.arr, idx.arr, c_int_t(dim))) From 7465f508d539f7ae3c163221feac4b5b859f45c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Mez=C5=91?= Date: Tue, 17 Jan 2017 19:50:54 +0200 Subject: [PATCH 122/212] fix lapack test: prevent opencl mapping of the same resource (#114) --- arrayfire/tests/simple/lapack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrayfire/tests/simple/lapack.py b/arrayfire/tests/simple/lapack.py index 8ff59c2b5..e3c3dbbb2 100644 --- a/arrayfire/tests/simple/lapack.py +++ b/arrayfire/tests/simple/lapack.py @@ -39,7 +39,7 @@ def simple_lapack(verbose=False): display_func(a) a = af.randu(5, 5) - a = af.matmulTN(a, a) + 10 * af.identity(5,5) + a = af.matmulTN(a, a.copy()) + 10 * af.identity(5,5) R,info = af.cholesky(a) display_func(R) From 0b29c3ad03f7d50c032cb13ea85ebad139a59054 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 17 Jan 2017 09:55:52 -0800 Subject: [PATCH 123/212] Fixing typos in hamming_matcher and nearest_neighbour --- arrayfire/vision.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arrayfire/vision.py b/arrayfire/vision.py index 2e5edacee..bd4eeccac 100644 --- a/arrayfire/vision.py +++ b/arrayfire/vision.py @@ -164,7 +164,7 @@ def hamming_matcher(query, database, dim = 0, num_nearest = 1): """ index = Array() dist = Array() - safe_call(backend.get().af_hamming_matcher(c_pointer(idx.arr), c_pointer(dist.arr), + safe_call(backend.get().af_hamming_matcher(c_pointer(index.arr), c_pointer(dist.arr), query.arr, database.arr, c_dim_t(dim), c_dim_t(num_nearest))) return index, dist @@ -200,7 +200,7 @@ def nearest_neighbour(query, database, dim = 0, num_nearest = 1, match_type=MATC """ index = Array() dist = Array() - safe_call(backend.get().af_nearest_neighbour(c_pointer(idx.arr), c_pointer(dist.arr), + safe_call(backend.get().af_nearest_neighbour(c_pointer(index.arr), c_pointer(dist.arr), query.arr, database.arr, c_dim_t(dim), c_dim_t(num_nearest), match_type.value)) From 1078dd0de6075c2a273d7a581bb53c613cf1f037 Mon Sep 17 00:00:00 2001 From: ajflood Date: Wed, 18 Jan 2017 13:17:33 -0600 Subject: [PATCH 124/212] approx1 off_grid Error In the singal.py, for arrayfire.approx1, I found that the off_grid format should be float not double. Therefore I changed it and it now works as expected. Sorry if this is not proper procedure for fixing bugs, this is my first time reporting bugs on using github. --- arrayfire/signal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arrayfire/signal.py b/arrayfire/signal.py index 4ddea26c6..f3783728f 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -49,7 +49,7 @@ def approx1(signal, pos0, method=INTERP.LINEAR, off_grid=0.0): """ output = Array() safe_call(backend.get().af_approx1(c_pointer(output.arr), signal.arr, pos0.arr, - method.value, c_double_t(off_grid))) + method.value, c_float_t(off_grid))) return output def approx2(signal, pos0, pos1, method=INTERP.LINEAR, off_grid=0.0): @@ -91,7 +91,7 @@ def approx2(signal, pos0, pos1, method=INTERP.LINEAR, off_grid=0.0): """ output = Array() safe_call(backend.get().af_approx2(c_pointer(output.arr), signal.arr, - pos0.arr, pos1.arr, method.value, c_double_t(off_grid))) + pos0.arr, pos1.arr, method.value, c_float_t(off_grid))) return output def fft(signal, dim0 = None , scale = None): From b643f55b49e4b947f4f94093af05852d3faf672d Mon Sep 17 00:00:00 2001 From: unbornchikken Date: Mon, 23 Jan 2017 22:02:16 +0100 Subject: [PATCH 125/212] * `__repr__` made IDE friendly * `to_string()` added to have a method for getting the full string representation * memory leak after calling `af_array_to_string` fixed --- .gitignore | 4 ++++ arrayfire/array.py | 25 ++++++++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index ba7466050..aa7bb5f1d 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,7 @@ docs/_build/ # PyBuilder target/ + +# IDE +.idea +.vscode diff --git a/arrayfire/array.py b/arrayfire/array.py index 4a8c42f57..6d00a3204 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -1185,9 +1185,9 @@ def to_list(self, row_major=False): ct_array, shape = self.to_ctype(row_major, True) return _ctype_to_lists(ct_array, len(shape) - 1, shape) - def __repr__(self): + def to_string(self): """ - Displays the meta data and contents of the arrayfire array. + Converts the arrayfire array to string showing its meta data and contents. Note ---- @@ -1195,10 +1195,25 @@ def __repr__(self): """ arr_str = c_char_ptr_t(0) - safe_call(backend.get().af_array_to_string(c_pointer(arr_str), "", self.arr, 4, True)) + be = backend.get() + safe_call(be.af_array_to_string(c_pointer(arr_str), "", self.arr, 4, True)) + py_str = to_str(arr_str) + safe_call(be.af_free_host(arr_str)) + + return 'arrayfire.Array()\nType: {}\nDims: {}\nData: {}' \ + .format(to_typename[self.type()], str(self.dims()), py_str) + + def __repr__(self): + """ + Displays the meta data of the arrayfire array. + + Note + ---- + You can use af.display(a, pres) to display the contents of the array. + """ - return 'arrayfire.Array()\nType: %s' % \ - (to_typename[self.type()]) + to_str(arr_str) + return 'arrayfire.Array()\nType: {}\nDims: {}' \ + .format(to_typename[self.type()], str(self.dims())) def __array__(self): """ From 2ef52f01eea11d1d01e23a6e2c2323f86beca0e1 Mon Sep 17 00:00:00 2001 From: unbornchikken Date: Tue, 31 Jan 2017 22:20:56 +0100 Subject: [PATCH 126/212] get/set_display_dims_limit --- arrayfire/array.py | 63 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 6d00a3204..e2c23294c 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -12,6 +12,7 @@ """ import inspect +import os from .library import * from .util import * from .util import _is_number @@ -20,6 +21,63 @@ from .index import * from .index import _Index4 +_is_running_in_py_charm = "PYCHARM_HOSTED" in os.environ + +_display_dims_limit = None + +def set_display_dims_limit(*dims): + """ + Sets the dimension limit after which array's data won't get + presented to the result of str(arr). + + Default is None, which means there is no limit. + + Parameters + ---------- + *dims : dimension limit args + + Example + ------- + set_display_dims_limit(10, 10, 10, 10) + + """ + global _display_dims_limit + _display_dims_limit = dims + +def get_display_dims_limit(): + """ + Gets the dimension limit after which array's data won't get + presented to the result of str(arr). + + Default is None, which means there is no limit. + + Returns + ----------- + - tuple of the current limit + - None is there is no limit + + Example + ------- + get_display_dims_limit() + # None + set_display_dims_limit(10, 10, 10, 10) + get_display_dims_limit() + # (10, 10, 10, 10) + + """ + return _display_dims_limit + +def _in_display_dims_limit(dims): + if _is_running_in_py_charm: + return False + print(_display_dims_limit) + if _display_dims_limit is not None: + min_dim_len = min(len(_display_dims_limit), len(dims)) + for i in range(min_dim_len): + if dims[i] > _display_dims_limit[i]: + return False + return True + def _create_array(buf, numdims, idims, dtype, is_device): out_arr = c_void_ptr_t(0) c_dims = dim4(idims[0], idims[1], idims[2], idims[3]) @@ -1185,7 +1243,7 @@ def to_list(self, row_major=False): ct_array, shape = self.to_ctype(row_major, True) return _ctype_to_lists(ct_array, len(shape) - 1, shape) - def to_string(self): + def __str__(self): """ Converts the arrayfire array to string showing its meta data and contents. @@ -1194,6 +1252,9 @@ def to_string(self): You can also use af.display(a, pres) to display the contents of the array with better precision. """ + if not _in_display_dims_limit(self.dims()): + return self.__repr__(); + arr_str = c_char_ptr_t(0) be = backend.get() safe_call(be.af_array_to_string(c_pointer(arr_str), "", self.arr, 4, True)) From 9a463cdb7bae4abe6ff8a44710cf37d3c6c496f9 Mon Sep 17 00:00:00 2001 From: unbornchikken Date: Tue, 31 Jan 2017 22:24:54 +0100 Subject: [PATCH 127/212] semicolon removed --- arrayfire/array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index e2c23294c..73510d48b 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -1253,7 +1253,7 @@ def __str__(self): """ if not _in_display_dims_limit(self.dims()): - return self.__repr__(); + return self.__repr__() arr_str = c_char_ptr_t(0) be = backend.get() From 64a306642a2143279b959b20a79a9058ffe31640 Mon Sep 17 00:00:00 2001 From: unbornchikken Date: Wed, 8 Feb 2017 21:21:34 +0100 Subject: [PATCH 128/212] more fixes and improvements --- arrayfire/array.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 73510d48b..643711253 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -70,10 +70,12 @@ def get_display_dims_limit(): def _in_display_dims_limit(dims): if _is_running_in_py_charm: return False - print(_display_dims_limit) if _display_dims_limit is not None: - min_dim_len = min(len(_display_dims_limit), len(dims)) - for i in range(min_dim_len): + limit_len = len(_display_dims_limit) + len = len(dims) + if len > limit_len: + return False + for i in range(len): if dims[i] > _display_dims_limit[i]: return False return True @@ -1253,16 +1255,9 @@ def __str__(self): """ if not _in_display_dims_limit(self.dims()): - return self.__repr__() + return self._get_metadata_str() - arr_str = c_char_ptr_t(0) - be = backend.get() - safe_call(be.af_array_to_string(c_pointer(arr_str), "", self.arr, 4, True)) - py_str = to_str(arr_str) - safe_call(be.af_free_host(arr_str)) - - return 'arrayfire.Array()\nType: {}\nDims: {}\nData: {}' \ - .format(to_typename[self.type()], str(self.dims()), py_str) + return self._get_metadata_str(dims=False) + self._as_str() def __repr__(self): """ @@ -1273,8 +1268,19 @@ def __repr__(self): You can use af.display(a, pres) to display the contents of the array. """ - return 'arrayfire.Array()\nType: {}\nDims: {}' \ - .format(to_typename[self.type()], str(self.dims())) + return self._get_metadata_str() + + def _get_metadata_str(self, dims=True): + return 'arrayfire.Array()\nType: {}\n{}' \ + .format(to_typename[self.type()], 'Dims: {}'.format(str(self.dims())) if dims else '') + + def _as_str(self): + arr_str = c_char_ptr_t(0) + be = backend.get() + safe_call(be.af_array_to_string(c_pointer(arr_str), "", self.arr, 4, True)) + py_str = to_str(arr_str) + safe_call(be.af_free_host(arr_str)) + return py_str def __array__(self): """ From ced607ba69d2fd8594a90fa0f1bb2c337d4981f7 Mon Sep 17 00:00:00 2001 From: unbornchikken Date: Wed, 8 Feb 2017 21:23:54 +0100 Subject: [PATCH 129/212] variable naming fixed --- arrayfire/array.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 643711253..beb7a0076 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -72,10 +72,10 @@ def _in_display_dims_limit(dims): return False if _display_dims_limit is not None: limit_len = len(_display_dims_limit) - len = len(dims) - if len > limit_len: + dim_len = len(dims) + if dim_len > limit_len: return False - for i in range(len): + for i in range(dim_len): if dims[i] > _display_dims_limit[i]: return False return True From ff7a6897a08bb70b12c2d94c918b2b833d4b98d0 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 21 Feb 2017 23:34:16 -0800 Subject: [PATCH 130/212] cleaning up interop code and adding tests --- arrayfire/interop.py | 160 +++++++++++++++-------------- arrayfire/opencl.py | 34 +++++- arrayfire/tests/simple/__init__.py | 1 + arrayfire/tests/simple/interop.py | 98 ++++++++++++++++++ 4 files changed, 214 insertions(+), 79 deletions(-) create mode 100644 arrayfire/tests/simple/interop.py diff --git a/arrayfire/interop.py b/arrayfire/interop.py index e4cd3561d..d837fb945 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -10,16 +10,54 @@ """ Interop with other python packages. -This module provides interoperability with the following python packages. +This module provides helper functions to copy data to arrayfire from the following modules: + + 1. numpy - numpy.ndarray + 2. pycuda - pycuda.gpuarray + 3. pyopencl - pyopencl.array - 1. numpy - 2. pycuda - 3. pyopencl """ from .array import * from .device import * + +def _fc_to_af_array(in_ptr, in_shape, in_dtype, is_device=False, copy = True): + """ + Fortran Contiguous to af array + """ + res = Array(in_ptr, in_shape, in_dtype, is_device=is_device) + + if is_device: + lock_array(res) + pass + + return res.copy() if copy else res + +def _cc_to_af_array(in_ptr, ndim, in_shape, in_dtype, is_device=False, copy = True): + """ + C Contiguous to af array + """ + if ndim == 1: + return _fc_to_af_array(in_ptr, in_shape, in_dtype, is_device, copy) + elif ndim == 2: + shape = (in_shape[1], in_shape[0]) + res = Array(in_ptr, shape, in_dtype, is_device=is_device) + if is_device: lock_array(res) + return reorder(res, 1, 0) + elif ndim == 3: + shape = (in_shape[2], in_shape[1], in_shape[0]) + res = Array(in_ptr, shape, in_dtype, is_device=is_device) + if is_device: lock_array(res) + return reorder(res, 2, 1, 0) + elif ndim == 4: + shape = (in_shape[3], in_shape[2], in_shape[1], in_shape[0]) + res = Array(in_ptr, shape, in_dtype, is_device=is_device) + if is_device: lock_array(res) + return reorder(res, 3, 2, 1, 0) + else: + raise RuntimeError("Unsupported ndim") + try: import numpy as np from numpy import ndarray as NumpyArray @@ -40,7 +78,7 @@ 'f8' : Dtype.f64, 'c16' : Dtype.c64} - def np_to_af_array(np_arr): + def np_to_af_array(np_arr, copy=True): """ Convert numpy.ndarray to arrayfire.Array. @@ -48,6 +86,10 @@ def np_to_af_array(np_arr): ---------- np_arr : numpy.ndarray() + copy : Bool specifying if array is to be copied. + Default is true. + Can only be False if array is fortran contiguous. + Returns --------- af_arr : arrayfire.Array() @@ -57,27 +99,15 @@ def np_to_af_array(np_arr): in_ptr = np_arr.ctypes.data_as(c_void_ptr_t) in_dtype = _nptype_to_aftype[np_arr.dtype.str[1:]] + if not copy: + raise RuntimeError("Copy can not be False for numpy arrays") + if (np_arr.flags['F_CONTIGUOUS']): - return Array(in_ptr, in_shape, in_dtype) + return _fc_to_af_array(in_ptr, in_shape, in_dtype) elif (np_arr.flags['C_CONTIGUOUS']): - if np_arr.ndim == 1: - return Array(in_ptr, in_shape, in_dtype) - elif np_arr.ndim == 2: - shape = (in_shape[1], in_shape[0]) - res = Array(in_ptr, shape, in_dtype) - return reorder(res, 1, 0) - elif np_arr.ndim == 3: - shape = (in_shape[2], in_shape[1], in_shape[0]) - res = Array(in_ptr, shape, in_dtype) - return reorder(res, 2, 1, 0) - elif np_arr.ndim == 4: - shape = (in_shape[3], in_shape[2], in_shape[1], in_shape[0]) - res = Array(in_ptr, shape, in_dtype) - return reorder(res, 3, 2, 1, 0) - else: - raise RuntimeError("Unsupported ndim") + return _cc_to_af_array(in_ptr, np_arr.ndim, in_shape, in_dtype) else: - return np_to_af_array(np.asfortranarray(np_arr)) + return np_to_af_array(np_arr.copy()) from_ndarray = np_to_af_array except: @@ -88,7 +118,7 @@ def np_to_af_array(np_arr): from pycuda.gpuarray import GPUArray as CudaArray AF_PYCUDA_FOUND=True - def pycuda_to_af_array(pycu_arr): + def pycuda_to_af_array(pycu_arr, copy=True): """ Convert pycuda.gpuarray to arrayfire.Array @@ -96,6 +126,10 @@ def pycuda_to_af_array(pycu_arr): ----------- pycu_arr : pycuda.GPUArray() + copy : Bool specifying if array is to be copied. + Default is true. + Can only be False if array is fortran contiguous. + Returns ---------- af_arr : arrayfire.Array() @@ -109,31 +143,13 @@ def pycuda_to_af_array(pycu_arr): in_shape = pycu_arr.shape in_dtype = pycu_arr.dtype.char + if not copy and not pycu_arr.flags.f_contiguous: + raise RuntimeError("Copy can only be False when arr.flags.f_contiguous is True") + if (pycu_arr.flags.f_contiguous): - res = Array(in_ptr, in_shape, in_dtype, is_device=True) - lock_array(res) - res = res.copy() - return res + return _fc_to_af_array(in_ptr, in_shape, in_dtype, True, copy) elif (pycu_arr.flags.c_contiguous): - if pycu_arr.ndim == 1: - return Array(in_ptr, in_shape, in_dtype, is_device=True) - elif pycu_arr.ndim == 2: - shape = (in_shape[1], in_shape[0]) - res = Array(in_ptr, shape, in_dtype, is_device=True) - lock_array(res) - return reorder(res, 1, 0) - elif pycu_arr.ndim == 3: - shape = (in_shape[2], in_shape[1], in_shape[0]) - res = Array(in_ptr, shape, in_dtype, is_device=True) - lock_array(res) - return reorder(res, 2, 1, 0) - elif pycu_arr.ndim == 4: - shape = (in_shape[3], in_shape[2], in_shape[1], in_shape[0]) - res = Array(in_ptr, shape, in_dtype, is_device=True) - lock_array(res) - return reorder(res, 3, 2, 1, 0) - else: - raise RuntimeError("Unsupported ndim") + return _cc_to_af_array(in_ptr, pycu_arr.ndim, in_shape, in_dtype, True, copy) else: return pycuda_to_af_array(pycu_arr.copy()) except: @@ -147,7 +163,7 @@ def pycuda_to_af_array(pycu_arr): from .opencl import get_context as _get_context AF_PYOPENCL_FOUND=True - def pyopencl_to_af_array(pycl_arr): + def pyopencl_to_af_array(pycl_arr, copy=True): """ Convert pyopencl.gpuarray to arrayfire.Array @@ -155,6 +171,10 @@ def pyopencl_to_af_array(pycl_arr): ----------- pycl_arr : pyopencl.Array() + copy : Bool specifying if array is to be copied. + Default is true. + Can only be False if array is fortran contiguous. + Returns ---------- af_arr : arrayfire.Array() @@ -179,44 +199,31 @@ def pyopencl_to_af_array(pycl_arr): if (dev_idx == None or ctx_idx == None or dev_idx != dev or ctx_idx != ctx): + print("Adding context and queue") _add_device_context(dev, ctx, que) _set_device_context(dev, ctx) + info() in_ptr = pycl_arr.base_data.int_ptr in_shape = pycl_arr.shape in_dtype = pycl_arr.dtype.char + if not copy and not pycl_arr.flags.f_contiguous: + raise RuntimeError("Copy can only be False when arr.flags.f_contiguous is True") + + print("Copying array") + print(pycl_arr.base_data.int_ptr) if (pycl_arr.flags.f_contiguous): - res = Array(in_ptr, in_shape, in_dtype, is_device=True) - lock_array(res) - return res + return _fc_to_af_array(in_ptr, in_shape, in_dtype, True, copy) elif (pycl_arr.flags.c_contiguous): - if pycl_arr.ndim == 1: - return Array(in_ptr, in_shape, in_dtype, is_device=True) - elif pycl_arr.ndim == 2: - shape = (in_shape[1], in_shape[0]) - res = Array(in_ptr, shape, in_dtype, is_device=True) - lock_array(res) - return reorder(res, 1, 0) - elif pycl_arr.ndim == 3: - shape = (in_shape[2], in_shape[1], in_shape[0]) - res = Array(in_ptr, shape, in_dtype, is_device=True) - lock_array(res) - return reorder(res, 2, 1, 0) - elif pycl_arr.ndim == 4: - shape = (in_shape[3], in_shape[2], in_shape[1], in_shape[0]) - res = Array(in_ptr, shape, in_dtype, is_device=True) - lock_array(res) - return reorder(res, 3, 2, 1, 0) - else: - raise RuntimeError("Unsupported ndim") + return _cc_to_af_array(in_ptr, pycl_arr.ndim, in_shape, in_dtype, True, copy) else: return pyopencl_to_af_array(pycl_arr.copy()) except: AF_PYOPENCL_FOUND=False -def to_array(in_array): +def to_array(in_array, copy = True): """ Helper function to convert input from a different module to af.Array @@ -226,16 +233,19 @@ def to_array(in_array): in_array : array like object Can be one of numpy.ndarray, pycuda.GPUArray, pyopencl.Array, array.array, list + copy : Bool specifying if array is to be copied. + Default is true. + Can only be False if array is fortran contiguous. + Returns -------------- af.Array of same dimensions as input after copying the data from the input - """ if AF_NUMPY_FOUND and isinstance(in_array, NumpyArray): - return np_to_af_array(in_array) + return np_to_af_array(in_array, copy) if AF_PYCUDA_FOUND and isinstance(in_array, CudaArray): - return pycuda_to_af_array(in_array) + return pycuda_to_af_array(in_array, copy) if AF_PYOPENCL_FOUND and isinstance(in_array, OpenclArray): - return pyopencl_to_af_array(in_array) + return pyopencl_to_af_array(in_array, copy) return Array(src=in_array) diff --git a/arrayfire/opencl.py b/arrayfire/opencl.py index a4a09c92b..266e1095a 100644 --- a/arrayfire/opencl.py +++ b/arrayfire/opencl.py @@ -54,7 +54,7 @@ def get_context(retain=False): import ctypes as ct from .util import safe_call as safe_call - from .library import backend as backend + from .library import backend if (backend.name() != "opencl"): raise RuntimeError("Invalid backend loaded") @@ -80,7 +80,7 @@ def get_queue(retain): import ctypes as ct from .util import safe_call as safe_call - from .library import backend as backend + from .library import backend if (backend.name() != "opencl"): raise RuntimeError("Invalid backend loaded") @@ -102,7 +102,7 @@ def get_device_id(): import ctypes as ct from .util import safe_call as safe_call - from .library import backend as backend + from .library import backend if (backend.name() != "opencl"): raise RuntimeError("Invalid backend loaded") @@ -124,7 +124,7 @@ def set_device_id(idx): import ctypes as ct from .util import safe_call as safe_call - from .library import backend as backend + from .library import backend if (backend.name() != "opencl"): raise RuntimeError("Invalid backend loaded") @@ -146,6 +146,10 @@ def add_device_context(dev, ctx, que): que : cl_command_queue """ + import ctypes as ct + from .util import safe_call as safe_call + from .library import backend + if (backend.name() != "opencl"): raise RuntimeError("Invalid backend loaded") @@ -163,6 +167,10 @@ def set_device_context(dev, ctx): ctx : cl_context """ + import ctypes as ct + from .util import safe_call as safe_call + from .library import backend + if (backend.name() != "opencl"): raise RuntimeError("Invalid backend loaded") @@ -180,6 +188,10 @@ def delete_device_context(dev, ctx): ctx : cl_context """ + import ctypes as ct + from .util import safe_call as safe_call + from .library import backend + if (backend.name() != "opencl"): raise RuntimeError("Invalid backend loaded") @@ -204,6 +216,13 @@ def get_device_type(): """ Get opencl device type """ + import ctypes as ct + from .util import safe_call as safe_call + from .library import backend + + if (backend.name() != "opencl"): + raise RuntimeError("Invalid backend loaded") + res = c_int_t(DEVICE_TYPE.UNKNOWN.value) safe_call(backend.get().afcl_get_device_type(c_pointer(res))) return _to_device_type[res.value] @@ -212,6 +231,13 @@ def get_platform(): """ Get opencl platform """ + import ctypes as ct + from .util import safe_call as safe_call + from .library import backend + + if (backend.name() != "opencl"): + raise RuntimeError("Invalid backend loaded") + res = c_int_t(PLATFORM.UNKNOWN.value) safe_call(backend.get().afcl_get_platform(c_pointer(res))) return _to_platform[res.value] diff --git a/arrayfire/tests/simple/__init__.py b/arrayfire/tests/simple/__init__.py index 528215ffc..26ed88961 100644 --- a/arrayfire/tests/simple/__init__.py +++ b/arrayfire/tests/simple/__init__.py @@ -15,6 +15,7 @@ from .device import * from .image import * from .index import * +from .interop import * from .lapack import * from .signal import * from .statistics import * diff --git a/arrayfire/tests/simple/interop.py b/arrayfire/tests/simple/interop.py new file mode 100644 index 000000000..6e8bd5877 --- /dev/null +++ b/arrayfire/tests/simple/interop.py @@ -0,0 +1,98 @@ +#!/usr/bin/python +####################################################### +# Copyright (c) 2015, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +import arrayfire as af +from . import _util + +def simple_interop(verbose = False): + if af.AF_NUMPY_FOUND: + import numpy as np + n = np.random.random((5,)) + a = af.to_array(n) + n2 = np.array(a) + assert((n==n2).all()) + + n = np.random.random((5,3)) + a = af.to_array(n) + n2 = np.array(a) + assert((n==n2).all()) + + n = np.random.random((5,3,2)) + a = af.to_array(n) + n2 = np.array(a) + assert((n==n2).all()) + + n = np.random.random((5,3,2, 2)) + a = af.to_array(n) + n2 = np.array(a) + assert((n==n2).all()) + + if af.AF_PYCUDA_FOUND and af.get_active_backend() == 'cuda': + import pycuda.autoinit + import pycuda.gpuarray as cudaArray + n = np.random.random((5,)) + c = cudaArray.to_gpu(n) + a = af.to_array(c) + n2 = np.array(a) + assert((n==n2).all()) + + n = np.random.random((5,3)) + c = cudaArray.to_gpu(n) + a = af.to_array(c) + n2 = np.array(a) + assert((n==n2).all()) + + n = np.random.random((5,3,2)) + c = cudaArray.to_gpu(n) + a = af.to_array(c) + n2 = np.array(a) + assert((n==n2).all()) + + n = np.random.random((5,3,2,2)) + c = cudaArray.to_gpu(n) + a = af.to_array(c) + n2 = np.array(a) + assert((n==n2).all()) + + if af.AF_PYOPENCL_FOUND and af.backend.name() == 'opencl': + # This needs fixing upstream + # https://github.com/arrayfire/arrayfire/issues/1728 + + # import pyopencl as cl + # import pyopencl.array as clArray + # ctx = cl.create_some_context() + # queue = cl.CommandQueue(ctx) + + # n = np.random.random((5,)) + # c = cl.array.to_device(queue, n) + # a = af.to_array(c) + # n2 = np.array(a) + # assert((n==n2).all()) + + # n = np.random.random((5,3)) + # c = cl.array.to_device(queue, n) + # a = af.to_array(c) + # n2 = np.array(a) + # assert((n==n2).all()) + + # n = np.random.random((5,3,2)) + # c = cl.array.to_device(queue, n) + # a = af.to_array(c) + # n2 = np.array(a) + # assert((n==n2).all()) + + # n = np.random.random((5,3,2,2)) + # c = cl.array.to_device(queue, n) + # a = af.to_array(c) + # n2 = np.array(a) + # assert((n==n2).all()) + pass + +_util.tests['interop'] = simple_interop From 3cf70d8ee8e2c61111ffea21fc3e0681ef22c32d Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 22 Feb 2017 00:23:10 -0800 Subject: [PATCH 131/212] Adding functions to copy from numba to arrayfire --- arrayfire/interop.py | 81 +++++++++++++++++++++++++------ arrayfire/tests/simple/interop.py | 29 +++++++++++ 2 files changed, 95 insertions(+), 15 deletions(-) diff --git a/arrayfire/interop.py b/arrayfire/interop.py index d837fb945..0d400e64b 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -15,6 +15,7 @@ 1. numpy - numpy.ndarray 2. pycuda - pycuda.gpuarray 3. pyopencl - pyopencl.array + 4. numba - numba.cuda.cudadrv.devicearray.DeviceNDArray """ @@ -58,6 +59,20 @@ def _cc_to_af_array(in_ptr, ndim, in_shape, in_dtype, is_device=False, copy = Tr else: raise RuntimeError("Unsupported ndim") + +_nptype_to_aftype = {'b1' : Dtype.b8, + 'u1' : Dtype.u8, + 'u2' : Dtype.u16, + 'i2' : Dtype.s16, + 's4' : Dtype.u32, + 'i4' : Dtype.s32, + 'f4' : Dtype.f32, + 'c8' : Dtype.c32, + 's8' : Dtype.u64, + 'i8' : Dtype.s64, + 'f8' : Dtype.f64, + 'c16' : Dtype.c64} + try: import numpy as np from numpy import ndarray as NumpyArray @@ -65,19 +80,6 @@ def _cc_to_af_array(in_ptr, ndim, in_shape, in_dtype, is_device=False, copy = Tr AF_NUMPY_FOUND=True - _nptype_to_aftype = {'b1' : Dtype.b8, - 'u1' : Dtype.u8, - 'u2' : Dtype.u16, - 'i2' : Dtype.s16, - 's4' : Dtype.u32, - 'i4' : Dtype.s32, - 'f4' : Dtype.f32, - 'c8' : Dtype.c32, - 's8' : Dtype.u64, - 'i8' : Dtype.s64, - 'f8' : Dtype.f64, - 'c16' : Dtype.c64} - def np_to_af_array(np_arr, copy=True): """ Convert numpy.ndarray to arrayfire.Array. @@ -222,6 +224,48 @@ def pyopencl_to_af_array(pycl_arr, copy=True): except: AF_PYOPENCL_FOUND=False +try: + import numba + from numba import cuda + NumbaCudaArray = cuda.cudadrv.devicearray.DeviceNDArray + AF_NUMBA_FOUND=True + + def numba_to_af_array(nb_arr, copy=True): + """ + Convert numba.gpuarray to arrayfire.Array + + Parameters + ----------- + nb_arr : numba.cuda.cudadrv.devicearray.DeviceNDArray() + + copy : Bool specifying if array is to be copied. + Default is true. + Can only be False if array is fortran contiguous. + + Returns + ---------- + af_arr : arrayfire.Array() + + Note + ---------- + The input array is copied to af.Array + """ + + in_ptr = nb_arr.device_ctypes_pointer.value + in_shape = nb_arr.shape + in_dtype = _nptype_to_aftype[nb_arr.dtype.str[1:]] + + if not copy and not nb_arr.flags.f_contiguous: + raise RuntimeError("Copy can only be False when arr.flags.f_contiguous is True") + + if (nb_arr.is_f_contiguous()): + return _fc_to_af_array(in_ptr, in_shape, in_dtype, True, copy) + elif (nb_arr.is_c_contiguous()): + return _cc_to_af_array(in_ptr, nb_arr.ndim, in_shape, in_dtype, True, copy) + else: + return numba_to_af_array(nb_arr.copy()) +except: + AF_NUMBA_FOUND=False def to_array(in_array, copy = True): """ @@ -231,8 +275,13 @@ def to_array(in_array, copy = True): ------------- in_array : array like object - Can be one of numpy.ndarray, pycuda.GPUArray, pyopencl.Array, array.array, list - + Can be one of the following: + - numpy.ndarray + - pycuda.GPUArray + - pyopencl.Array + - numba.cuda.cudadrv.devicearray.DeviceNDArray + - array.array + - list copy : Bool specifying if array is to be copied. Default is true. Can only be False if array is fortran contiguous. @@ -248,4 +297,6 @@ def to_array(in_array, copy = True): return pycuda_to_af_array(in_array, copy) if AF_PYOPENCL_FOUND and isinstance(in_array, OpenclArray): return pyopencl_to_af_array(in_array, copy) + if AF_NUMBA_FOUND and isinstance(in_array, NumbaCudaArray): + return numba_to_af_array(in_array, copy) return Array(src=in_array) diff --git a/arrayfire/tests/simple/interop.py b/arrayfire/tests/simple/interop.py index 6e8bd5877..145e1039a 100644 --- a/arrayfire/tests/simple/interop.py +++ b/arrayfire/tests/simple/interop.py @@ -95,4 +95,33 @@ def simple_interop(verbose = False): # assert((n==n2).all()) pass + if af.AF_NUMBA_FOUND and af.get_active_backend() == 'cuda': + + import numba + from numba import cuda + + n = np.random.random((5,)) + c = cuda.to_device(n) + a = af.to_array(c) + n2 = np.array(a) + assert((n==n2).all()) + + n = np.random.random((5,3)) + c = cuda.to_device(n) + a = af.to_array(c) + n2 = np.array(a) + assert((n==n2).all()) + + n = np.random.random((5,3,2)) + c = cuda.to_device(n) + a = af.to_array(c) + n2 = np.array(a) + assert((n==n2).all()) + + n = np.random.random((5,3,2,2)) + c = cuda.to_device(n) + a = af.to_array(c) + n2 = np.array(a) + assert((n==n2).all()) + _util.tests['interop'] = simple_interop From 583dd22c51bcbc6094fbc390188ca466f6dd6ae1 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 22 Feb 2017 00:44:25 -0800 Subject: [PATCH 132/212] Updating changelog and setup.py --- CHANGELOG.md | 8 ++++++++ setup.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e662a254..be0419e53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +### v3.3.20160222 +- Bugfix: Fixes typo in `approx1`. +- Bugfix: Fixes typo in `hamming_matcher` and `nearest_neighbour`. +- Bugfix: Added necessary copy and lock mechanisms in interop.py. +- Example / Benchmark: New conjugate gradient benchmark. +- Feature: Added support to create arrayfire arrays from numba. +- Behavior change: af.print() only prints full arrays for smaller sizes. + ### v3.3.20161126 - Fixing memory leak in array creation. - Supporting 16 bit integer types in interop. diff --git a/setup.py b/setup.py index 454891590..6d11b14af 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ author="Pavan Yalamanchili", author_email="contact@pavanky.com", name="arrayfire", - version="3.5.0", + version="3.4.20170222", description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From 1bebf3aadf09bbfc2982e1fc685fe509f41817ce Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Wed, 22 Feb 2017 00:51:44 -0800 Subject: [PATCH 133/212] Fixing typo in CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be0419e53..e3538a0c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### v3.3.20160222 +### v3.3.20170222 - Bugfix: Fixes typo in `approx1`. - Bugfix: Fixes typo in `hamming_matcher` and `nearest_neighbour`. - Bugfix: Added necessary copy and lock mechanisms in interop.py. From c169b17a06afb3e7b88a3b1bd9ab302310ebb5ad Mon Sep 17 00:00:00 2001 From: Johnnie Gray Date: Wed, 1 Mar 2017 18:28:48 +0000 Subject: [PATCH 134/212] abstract out arrayfire and forge major versions from library setup This fixes #131, where arrayfire-python attempted to load the non-existant libforge.so.3 --- arrayfire/library.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index edaa62666..970f7870f 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -30,6 +30,10 @@ c_char_ptr_t = ct.c_char_p c_size_t = ct.c_size_t + +AF_VER_MAJOR = '3' +FORGE_VER_MAJOR = '0' + # Work around for unexpected architectures if 'c_dim_t_forced' in globals(): global c_dim_t_forced @@ -409,6 +413,8 @@ class STORAGE(_Enum): CSC = _Enum_Type(2) COO = _Enum_Type(3) +_VER_MAJOR_PLACEHOLDER = "__VER_MAJOR__" + def _setup(): import platform import os @@ -446,7 +452,7 @@ def _setup(): ct.windll.kernel32.SetErrorMode(0x0001 | 0x0002) if AF_SEARCH_PATH is None: - AF_SEARCH_PATH="C:/Program Files/ArrayFire/v3/" + AF_SEARCH_PATH="C:/Program Files/ArrayFire/v" + AF_VER_MAJOR +"/" if CUDA_PATH is not None: CUDA_FOUND = os.path.isdir(CUDA_PATH + '/bin') and os.path.isdir(CUDA_PATH + '/nvvm/bin/') @@ -455,7 +461,7 @@ def _setup(): ## OSX specific setup pre = 'lib' - post = '.3.dylib' + post = '.' + _VER_MAJOR_PLACEHOLDER + '.dylib' if AF_SEARCH_PATH is None: AF_SEARCH_PATH='/usr/local/' @@ -467,10 +473,10 @@ def _setup(): elif platform_name == 'Linux': pre = 'lib' - post = '.so.3' + post = '.so.' + _VER_MAJOR_PLACEHOLDER if AF_SEARCH_PATH is None: - AF_SEARCH_PATH='/opt/arrayfire-3/' + AF_SEARCH_PATH='/opt/arrayfire-' + AF_VER_MAJOR + '/' if CUDA_PATH is None: CUDA_PATH='/usr/local/cuda/' @@ -489,8 +495,9 @@ def _setup(): class _clibrary(object): - def __libname(self, name, head='af'): - libname = self.__pre + head + name + self.__post + def __libname(self, name, head='af', ver_major=AF_VER_MAJOR): + post = self.__post.replace(_VER_MAJOR_PLACEHOLDER, ver_major) + libname = self.__pre + head + name + post libname_full = self.AF_PATH + '/lib/' + libname return (libname, libname_full) @@ -530,7 +537,7 @@ def __init__(self): 'opencl' : 4} # Try to pre-load forge library if it exists - libnames = self.__libname('forge', '') + libnames = self.__libname('forge', head='', ver_major=FORGE_VER_MAJOR) for libname in libnames: try: ct.cdll.LoadLibrary(libname) From 038f9266a3031e47516e24e10037c3227791e267 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Thu, 25 May 2017 00:28:03 -0400 Subject: [PATCH 135/212] Do not use bare except: clauses https://docs.python.org/2/howto/doanddont.html#except Signed-off-by: Anders Kaseorg --- arrayfire/__init__.py | 2 +- arrayfire/array.py | 2 +- arrayfire/interop.py | 20 ++++++++++++-------- arrayfire/library.py | 10 +++++----- arrayfire/tests/simple/_util.py | 2 +- examples/benchmarks/bench_blas.py | 2 +- examples/benchmarks/bench_cg.py | 4 ++-- examples/benchmarks/bench_fft.py | 2 +- examples/benchmarks/monte_carlo_pi.py | 2 +- 9 files changed, 25 insertions(+), 21 deletions(-) diff --git a/arrayfire/__init__.py b/arrayfire/__init__.py index 255fbbeeb..538085bb3 100644 --- a/arrayfire/__init__.py +++ b/arrayfire/__init__.py @@ -50,7 +50,7 @@ try: import pycuda.autoinit -except: +except ImportError: pass from .library import * diff --git a/arrayfire/array.py b/arrayfire/array.py index beb7a0076..7c8ddd4f1 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -1310,7 +1310,7 @@ def display(a, precision=4): st = expr[0].find('(') + 1 en = expr[0].rfind(')') name = expr[0][st:en] - except: + except IndexError: pass safe_call(backend.get().af_print_array_gen(name.encode('utf-8'), diff --git a/arrayfire/interop.py b/arrayfire/interop.py index 0d400e64b..a93fbe5ae 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -75,6 +75,9 @@ def _cc_to_af_array(in_ptr, ndim, in_shape, in_dtype, is_device=False, copy = Tr try: import numpy as np +except ImportError: + AF_NUMPY_FOUND=False +else: from numpy import ndarray as NumpyArray from .data import reorder @@ -112,11 +115,12 @@ def np_to_af_array(np_arr, copy=True): return np_to_af_array(np_arr.copy()) from_ndarray = np_to_af_array -except: - AF_NUMPY_FOUND=False try: import pycuda.gpuarray +except ImportError: + AF_PYCUDA_FOUND=False +else: from pycuda.gpuarray import GPUArray as CudaArray AF_PYCUDA_FOUND=True @@ -154,11 +158,12 @@ def pycuda_to_af_array(pycu_arr, copy=True): return _cc_to_af_array(in_ptr, pycu_arr.ndim, in_shape, in_dtype, True, copy) else: return pycuda_to_af_array(pycu_arr.copy()) -except: - AF_PYCUDA_FOUND=False try: from pyopencl.array import Array as OpenclArray +except ImportError: + AF_PYOPENCL_FOUND=False +else: from .opencl import add_device_context as _add_device_context from .opencl import set_device_context as _set_device_context from .opencl import get_device_id as _get_device_id @@ -221,11 +226,12 @@ def pyopencl_to_af_array(pycl_arr, copy=True): return _cc_to_af_array(in_ptr, pycl_arr.ndim, in_shape, in_dtype, True, copy) else: return pyopencl_to_af_array(pycl_arr.copy()) -except: - AF_PYOPENCL_FOUND=False try: import numba +except ImportError: + AF_NUMBA_FOUND=False +else: from numba import cuda NumbaCudaArray = cuda.cudadrv.devicearray.DeviceNDArray AF_NUMBA_FOUND=True @@ -264,8 +270,6 @@ def numba_to_af_array(nb_arr, copy=True): return _cc_to_af_array(in_ptr, nb_arr.ndim, in_shape, in_dtype, True, copy) else: return numba_to_af_array(nb_arr.copy()) -except: - AF_NUMBA_FOUND=False def to_array(in_array, copy = True): """ diff --git a/arrayfire/library.py b/arrayfire/library.py index edaa62666..6c1108a34 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -47,7 +47,7 @@ from enum import Enum as _Enum def _Enum_Type(v): return v -except: +except ImportError: class _MetaEnum(type): def __init__(cls, name, bases, attrs): for attrname, attrvalue in attrs.iteritems(): @@ -417,7 +417,7 @@ def _setup(): try: AF_PATH = os.environ['AF_PATH'] - except: + except KeyError: AF_PATH = None pass @@ -425,7 +425,7 @@ def _setup(): try: CUDA_PATH = os.environ['CUDA_PATH'] - except: + except KeyError: CUDA_PATH= None pass @@ -534,7 +534,7 @@ def __init__(self): for libname in libnames: try: ct.cdll.LoadLibrary(libname) - except: + except OSError: pass c_dim4 = c_dim_t*4 @@ -555,7 +555,7 @@ def __init__(self): self.__name = __name clib.af_release_array(out) break; - except: + except OSError: pass if (self.__name is None): diff --git a/arrayfire/tests/simple/_util.py b/arrayfire/tests/simple/_util.py index 4b38e9c4d..cda7c84a8 100644 --- a/arrayfire/tests/simple/_util.py +++ b/arrayfire/tests/simple/_util.py @@ -24,7 +24,7 @@ def run(self, name_list=None, verbose=False): self.print_log = '' try: test = self[key] - except: + except KeyError: print(self.print_str % (key, "NOTFOUND")) continue diff --git a/examples/benchmarks/bench_blas.py b/examples/benchmarks/bench_blas.py index aaf4eb1de..21b776869 100644 --- a/examples/benchmarks/bench_blas.py +++ b/examples/benchmarks/bench_blas.py @@ -16,7 +16,7 @@ try: import numpy as np -except: +except ImportError: np = None diff --git a/examples/benchmarks/bench_cg.py b/examples/benchmarks/bench_cg.py index 2f0bb25d6..8a74f25a9 100644 --- a/examples/benchmarks/bench_cg.py +++ b/examples/benchmarks/bench_cg.py @@ -16,13 +16,13 @@ try: import numpy as np -except: +except ImportError: np = None try: from scipy import sparse as sp from scipy.sparse import linalg -except: +except ImportError: sp = None diff --git a/examples/benchmarks/bench_fft.py b/examples/benchmarks/bench_fft.py index 9a2d283ed..4d9a3d7b1 100644 --- a/examples/benchmarks/bench_fft.py +++ b/examples/benchmarks/bench_fft.py @@ -16,7 +16,7 @@ try: import numpy as np -except: +except ImportError: np = None diff --git a/examples/benchmarks/monte_carlo_pi.py b/examples/benchmarks/monte_carlo_pi.py index 2703069c2..440c01594 100755 --- a/examples/benchmarks/monte_carlo_pi.py +++ b/examples/benchmarks/monte_carlo_pi.py @@ -16,7 +16,7 @@ try: import numpy as np -except: +except ImportError: np = None #alias range / xrange because xrange is faster than range in python2 From fda4427e67dcdc289dcc986f149d4639eb7ff1ca Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 25 May 2017 10:49:22 -0700 Subject: [PATCH 136/212] Fixing bug in sort_by_key parameters --- arrayfire/algorithm.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arrayfire/algorithm.py b/arrayfire/algorithm.py index d57e0ce86..36b5d79b8 100644 --- a/arrayfire/algorithm.py +++ b/arrayfire/algorithm.py @@ -473,16 +473,16 @@ def sort_index(a, dim=0, is_ascending=True): c_uint_t(dim), c_bool_t(is_ascending))) return out,idx -def sort_by_key(iv, ik, dim=0, is_ascending=True): +def sort_by_key(ik, iv, dim=0, is_ascending=True): """ Sort an array based on specified keys Parameters ---------- - iv : af.Array - An Array containing the values ik : af.Array An Array containing the keys + iv : af.Array + An Array containing the values dim: optional: int. default: 0 Dimension along which sort is to be performed. is_ascending: optional: bool. default: True @@ -490,9 +490,9 @@ def sort_by_key(iv, ik, dim=0, is_ascending=True): Returns ------- - (ov, ok): tuple of af.Array - `ov` contains the values from `iv` after sorting them based on `ik` + (ok, ov): tuple of af.Array `ok` contains the values from `ik` in sorted order + `ov` contains the values from `iv` after sorting them based on `ik` Note ------- @@ -500,8 +500,8 @@ def sort_by_key(iv, ik, dim=0, is_ascending=True): """ ov = Array() ok = Array() - safe_call(backend.get().af_sort_by_key(c_pointer(ov.arr), c_pointer(ok.arr), - iv.arr, ik.arr, c_uint_t(dim), c_bool_t(is_ascending))) + safe_call(backend.get().af_sort_by_key(c_pointer(ok.arr), c_pointer(ov.arr), + ik.arr, iv.arr, c_uint_t(dim), c_bool_t(is_ascending))) return ov,ok def set_unique(a, is_sorted=False): From 37e93ecd0cf5e1b59d6797d8add334edab7df8d5 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 2 Jul 2017 23:26:42 -0700 Subject: [PATCH 137/212] Add functios to query and print memory - print_mem_info - Array.allocated --- arrayfire/array.py | 8 ++++++++ arrayfire/device.py | 46 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index 7c8ddd4f1..d1c6d084e 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -630,6 +630,14 @@ def elements(self): safe_call(backend.get().af_get_elements(c_pointer(num), self.arr)) return num.value + def allocated(self): + """ + Returns the number of bytes allocated by the memory manager for the array. + """ + num = c_size_t(0) + safe_call(backend.get().af_get_allocated_bytes(c_pointer(num), self.arr)) + return num.value + def dtype(self): """ Return the data type as a arrayfire.Dtype enum value. diff --git a/arrayfire/device.py b/arrayfire/device.py index ad8abd512..84594f2b3 100644 --- a/arrayfire/device.py +++ b/arrayfire/device.py @@ -273,6 +273,52 @@ def device_mem_info(): mem_info['lock'] = {'buffers' : lock_buffers.value, 'bytes' : lock_bytes.value} return mem_info +def print_mem_info(title = "Memory Info", device_id = None): + """ + Prints the memory used for the specified device. + + Parameters + ---------- + title: optional. Default: "Memory Info" + - Title to display before printing the memory info. + device_id: optional. Default: None + - Specifies the device for which the memory info should be displayed. + - If None, uses the current device. + + Examples + -------- + + >>> a = af.randu(5,5) + >>> af.print_mem_info() + Memory Info + --------------------------------------------------------- + | POINTER | SIZE | AF LOCK | USER LOCK | + --------------------------------------------------------- + | 0x706400000 | 1 KB | Yes | No | + --------------------------------------------------------- + >>> b = af.randu(5,5) + >>> af.print_mem_info() + Memory Info + --------------------------------------------------------- + | POINTER | SIZE | AF LOCK | USER LOCK | + --------------------------------------------------------- + | 0x706400400 | 1 KB | Yes | No | + | 0x706400000 | 1 KB | Yes | No | + --------------------------------------------------------- + >>> a = af.randu(1000,1000) + >>> af.print_mem_info() + Memory Info + --------------------------------------------------------- + | POINTER | SIZE | AF LOCK | USER LOCK | + --------------------------------------------------------- + | 0x706500000 | 3.815 MB | Yes | No | + | 0x706400400 | 1 KB | Yes | No | + | 0x706400000 | 1 KB | No | No | + --------------------------------------------------------- + """ + device_id = device_id if device_id else get_device() + safe_call(backend.get().af_print_mem_info(title.encode('utf-8'), device_id)) + def device_gc(): """ Ask the garbage collector to free all unlocked memory From d81fccf7abda754f0f632d425edcc80c37e96445 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 17 Jul 2017 23:40:12 -0700 Subject: [PATCH 138/212] FEAT: Adding array.scalar() --- arrayfire/array.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index d1c6d084e..7d60dee0a 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -1253,6 +1253,19 @@ def to_list(self, row_major=False): ct_array, shape = self.to_ctype(row_major, True) return _ctype_to_lists(ct_array, len(shape) - 1, shape) + def scalar(self): + """ + Return the first element of the array + """ + + if (self.arr.value == 0): + raise RuntimeError("Can not call to_ctype on empty array") + + ctype_type = to_c_type[self.type()] + res = ctype_type() + safe_call(backend.get().af_get_scalar(c_pointer(res), self.arr)) + return res.value + def __str__(self): """ Converts the arrayfire array to string showing its meta data and contents. From e02252eb1467ce6036235ccc1f292c62f8250bc3 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 18 Jul 2017 01:00:14 -0700 Subject: [PATCH 139/212] FEAT: Adding canny edge detector --- arrayfire/image.py | 41 +++++++++++++++++++++++++++++++++++++++++ arrayfire/library.py | 7 +++++++ 2 files changed, 48 insertions(+) diff --git a/arrayfire/image.py b/arrayfire/image.py index 5fadd991a..11cbe2560 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -1194,6 +1194,47 @@ def moments(image, moment = MOMENT.FIRST_ORDER): safe_call(backend.get().af_moments(c_pointer(output.arr), image.arr, moment.value)) return output +def canny(image, + low_threshold, high_threshold = None, + treshold_type = CANNY_THRESHOLD.MANUAL, + sobel_window = 3, is_fast = False): + """ + Canny edge detector. + + Parameters + ---------- + image : af.Array + - A 2 D arrayfire array representing an image + + threshold_type : optional: af.CANNY_THRESHOLD. default: af.CANNY_THRESHOLD.MANUAL. + Can be one of: + - af.CANNY_THRESHOLD.MANUAL + - af.CANNY_THRESHOLD.AUTO_OTSU + + low_threshold : required: float. + Specifies the % of maximum in gradient image if threshold_type is MANUAL. + Specifies the % of auto dervied high value if threshold_type is AUTO_OTSU. + + high_threshold : optional: float. default: None + Specifies the % of maximum in gradient image if threshold_type is MANUAL. + Ignored if threshold_type is AUTO_OTSU + + sobel_window : optional: int. default: 3 + Specifies the size of sobel kernel when computing the gradient image. + + Returns + -------- + + out : af.Array + - A binary image containing the edges + + """ + output = Array() + safe_call(backend.get().af_canny(c_pointer(output.arr), threshold_type.value, + low_threshold, high_threshold and high_threshold.value or 0, + c_uint(sobel_window), c_bool(is_fast))) + return output + def is_image_io_available(): """ Function to check if the arrayfire library was built with Image IO support. diff --git a/arrayfire/library.py b/arrayfire/library.py index 9a8e50307..eeca414a8 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -413,6 +413,13 @@ class STORAGE(_Enum): CSC = _Enum_Type(2) COO = _Enum_Type(3) +class CANNY_THRESHOLD(_Enum): + """ + Canny Edge Threshold types + """ + MANUAL = _Enum_Type(0) + AUTO_OTSU = _Enum_Type(1) + _VER_MAJOR_PLACEHOLDER = "__VER_MAJOR__" def _setup(): From 2775b51005d6bacaf12e765e44695b461c6953ac Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 18 Jul 2017 01:07:30 -0700 Subject: [PATCH 140/212] FEAT: Adding support for dot --- arrayfire/blas.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/arrayfire/blas.py b/arrayfire/blas.py index 4fa7ffad6..f0e9dfdc6 100644 --- a/arrayfire/blas.py +++ b/arrayfire/blas.py @@ -150,7 +150,7 @@ def matmulTT(lhs, rhs): MATPROP.TRANS.value, MATPROP.TRANS.value)) return out -def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE): +def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE, return_scalar = False): """ Dot product of two input vectors. @@ -173,10 +173,13 @@ def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE): - af.MATPROP.NONE - If no op should be done on `rhs`. - No other options are currently supported. + return_scalar: optional: bool. default: False. + - When set to true, the input arrays are flattened and the output is a scalar + Returns ------- - out : af.Array + out : af.Array or scalar Output of dot product of `lhs` and `rhs`. Note @@ -186,7 +189,16 @@ def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE): - Batches are not supported. """ - out = Array() - safe_call(backend.get().af_dot(c_pointer(out.arr), lhs.arr, rhs.arr, - lhs_opts.value, rhs_opts.value)) - return out + if return_scalar: + real = c_double_t(0) + imag = c_double_t(0) + safe_call(backend.get().af_dot_all(c_pointer(real), c_pointer(imag), + lhs.arr, rhs.arr, lhs_opts.value, rhs_opts.value)) + real = real.value + imag = imag.value + return real if imag == 0 else real + imag * 1j + else: + out = Array() + safe_call(backend.get().af_dot(c_pointer(out.arr), lhs.arr, rhs.arr, + lhs_opts.value, rhs_opts.value)) + return out From 4703097fd3053ce4d1d1343cbfb6c5606237971b Mon Sep 17 00:00:00 2001 From: Johnnie Gray Date: Wed, 1 Mar 2017 18:28:48 +0000 Subject: [PATCH 141/212] abstract out arrayfire and forge major versions from library setup This fixes #131, where arrayfire-python attempted to load the non-existant libforge.so.3 --- arrayfire/library.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index edaa62666..970f7870f 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -30,6 +30,10 @@ c_char_ptr_t = ct.c_char_p c_size_t = ct.c_size_t + +AF_VER_MAJOR = '3' +FORGE_VER_MAJOR = '0' + # Work around for unexpected architectures if 'c_dim_t_forced' in globals(): global c_dim_t_forced @@ -409,6 +413,8 @@ class STORAGE(_Enum): CSC = _Enum_Type(2) COO = _Enum_Type(3) +_VER_MAJOR_PLACEHOLDER = "__VER_MAJOR__" + def _setup(): import platform import os @@ -446,7 +452,7 @@ def _setup(): ct.windll.kernel32.SetErrorMode(0x0001 | 0x0002) if AF_SEARCH_PATH is None: - AF_SEARCH_PATH="C:/Program Files/ArrayFire/v3/" + AF_SEARCH_PATH="C:/Program Files/ArrayFire/v" + AF_VER_MAJOR +"/" if CUDA_PATH is not None: CUDA_FOUND = os.path.isdir(CUDA_PATH + '/bin') and os.path.isdir(CUDA_PATH + '/nvvm/bin/') @@ -455,7 +461,7 @@ def _setup(): ## OSX specific setup pre = 'lib' - post = '.3.dylib' + post = '.' + _VER_MAJOR_PLACEHOLDER + '.dylib' if AF_SEARCH_PATH is None: AF_SEARCH_PATH='/usr/local/' @@ -467,10 +473,10 @@ def _setup(): elif platform_name == 'Linux': pre = 'lib' - post = '.so.3' + post = '.so.' + _VER_MAJOR_PLACEHOLDER if AF_SEARCH_PATH is None: - AF_SEARCH_PATH='/opt/arrayfire-3/' + AF_SEARCH_PATH='/opt/arrayfire-' + AF_VER_MAJOR + '/' if CUDA_PATH is None: CUDA_PATH='/usr/local/cuda/' @@ -489,8 +495,9 @@ def _setup(): class _clibrary(object): - def __libname(self, name, head='af'): - libname = self.__pre + head + name + self.__post + def __libname(self, name, head='af', ver_major=AF_VER_MAJOR): + post = self.__post.replace(_VER_MAJOR_PLACEHOLDER, ver_major) + libname = self.__pre + head + name + post libname_full = self.AF_PATH + '/lib/' + libname return (libname, libname_full) @@ -530,7 +537,7 @@ def __init__(self): 'opencl' : 4} # Try to pre-load forge library if it exists - libnames = self.__libname('forge', '') + libnames = self.__libname('forge', head='', ver_major=FORGE_VER_MAJOR) for libname in libnames: try: ct.cdll.LoadLibrary(libname) From 4f82bf4efcdcac6436bf1365f126cd9f4df841e3 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Thu, 25 May 2017 00:28:03 -0400 Subject: [PATCH 142/212] Do not use bare except: clauses https://docs.python.org/2/howto/doanddont.html#except Signed-off-by: Anders Kaseorg --- arrayfire/__init__.py | 2 +- arrayfire/array.py | 2 +- arrayfire/interop.py | 20 ++++++++++++-------- arrayfire/library.py | 10 +++++----- arrayfire/tests/simple/_util.py | 2 +- examples/benchmarks/bench_blas.py | 2 +- examples/benchmarks/bench_cg.py | 4 ++-- examples/benchmarks/bench_fft.py | 2 +- examples/benchmarks/monte_carlo_pi.py | 2 +- 9 files changed, 25 insertions(+), 21 deletions(-) diff --git a/arrayfire/__init__.py b/arrayfire/__init__.py index 255fbbeeb..538085bb3 100644 --- a/arrayfire/__init__.py +++ b/arrayfire/__init__.py @@ -50,7 +50,7 @@ try: import pycuda.autoinit -except: +except ImportError: pass from .library import * diff --git a/arrayfire/array.py b/arrayfire/array.py index beb7a0076..7c8ddd4f1 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -1310,7 +1310,7 @@ def display(a, precision=4): st = expr[0].find('(') + 1 en = expr[0].rfind(')') name = expr[0][st:en] - except: + except IndexError: pass safe_call(backend.get().af_print_array_gen(name.encode('utf-8'), diff --git a/arrayfire/interop.py b/arrayfire/interop.py index 0d400e64b..a93fbe5ae 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -75,6 +75,9 @@ def _cc_to_af_array(in_ptr, ndim, in_shape, in_dtype, is_device=False, copy = Tr try: import numpy as np +except ImportError: + AF_NUMPY_FOUND=False +else: from numpy import ndarray as NumpyArray from .data import reorder @@ -112,11 +115,12 @@ def np_to_af_array(np_arr, copy=True): return np_to_af_array(np_arr.copy()) from_ndarray = np_to_af_array -except: - AF_NUMPY_FOUND=False try: import pycuda.gpuarray +except ImportError: + AF_PYCUDA_FOUND=False +else: from pycuda.gpuarray import GPUArray as CudaArray AF_PYCUDA_FOUND=True @@ -154,11 +158,12 @@ def pycuda_to_af_array(pycu_arr, copy=True): return _cc_to_af_array(in_ptr, pycu_arr.ndim, in_shape, in_dtype, True, copy) else: return pycuda_to_af_array(pycu_arr.copy()) -except: - AF_PYCUDA_FOUND=False try: from pyopencl.array import Array as OpenclArray +except ImportError: + AF_PYOPENCL_FOUND=False +else: from .opencl import add_device_context as _add_device_context from .opencl import set_device_context as _set_device_context from .opencl import get_device_id as _get_device_id @@ -221,11 +226,12 @@ def pyopencl_to_af_array(pycl_arr, copy=True): return _cc_to_af_array(in_ptr, pycl_arr.ndim, in_shape, in_dtype, True, copy) else: return pyopencl_to_af_array(pycl_arr.copy()) -except: - AF_PYOPENCL_FOUND=False try: import numba +except ImportError: + AF_NUMBA_FOUND=False +else: from numba import cuda NumbaCudaArray = cuda.cudadrv.devicearray.DeviceNDArray AF_NUMBA_FOUND=True @@ -264,8 +270,6 @@ def numba_to_af_array(nb_arr, copy=True): return _cc_to_af_array(in_ptr, nb_arr.ndim, in_shape, in_dtype, True, copy) else: return numba_to_af_array(nb_arr.copy()) -except: - AF_NUMBA_FOUND=False def to_array(in_array, copy = True): """ diff --git a/arrayfire/library.py b/arrayfire/library.py index 970f7870f..9a8e50307 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -51,7 +51,7 @@ from enum import Enum as _Enum def _Enum_Type(v): return v -except: +except ImportError: class _MetaEnum(type): def __init__(cls, name, bases, attrs): for attrname, attrvalue in attrs.iteritems(): @@ -423,7 +423,7 @@ def _setup(): try: AF_PATH = os.environ['AF_PATH'] - except: + except KeyError: AF_PATH = None pass @@ -431,7 +431,7 @@ def _setup(): try: CUDA_PATH = os.environ['CUDA_PATH'] - except: + except KeyError: CUDA_PATH= None pass @@ -541,7 +541,7 @@ def __init__(self): for libname in libnames: try: ct.cdll.LoadLibrary(libname) - except: + except OSError: pass c_dim4 = c_dim_t*4 @@ -562,7 +562,7 @@ def __init__(self): self.__name = __name clib.af_release_array(out) break; - except: + except OSError: pass if (self.__name is None): diff --git a/arrayfire/tests/simple/_util.py b/arrayfire/tests/simple/_util.py index 4b38e9c4d..cda7c84a8 100644 --- a/arrayfire/tests/simple/_util.py +++ b/arrayfire/tests/simple/_util.py @@ -24,7 +24,7 @@ def run(self, name_list=None, verbose=False): self.print_log = '' try: test = self[key] - except: + except KeyError: print(self.print_str % (key, "NOTFOUND")) continue diff --git a/examples/benchmarks/bench_blas.py b/examples/benchmarks/bench_blas.py index aaf4eb1de..21b776869 100644 --- a/examples/benchmarks/bench_blas.py +++ b/examples/benchmarks/bench_blas.py @@ -16,7 +16,7 @@ try: import numpy as np -except: +except ImportError: np = None diff --git a/examples/benchmarks/bench_cg.py b/examples/benchmarks/bench_cg.py index 2f0bb25d6..8a74f25a9 100644 --- a/examples/benchmarks/bench_cg.py +++ b/examples/benchmarks/bench_cg.py @@ -16,13 +16,13 @@ try: import numpy as np -except: +except ImportError: np = None try: from scipy import sparse as sp from scipy.sparse import linalg -except: +except ImportError: sp = None diff --git a/examples/benchmarks/bench_fft.py b/examples/benchmarks/bench_fft.py index 9a2d283ed..4d9a3d7b1 100644 --- a/examples/benchmarks/bench_fft.py +++ b/examples/benchmarks/bench_fft.py @@ -16,7 +16,7 @@ try: import numpy as np -except: +except ImportError: np = None diff --git a/examples/benchmarks/monte_carlo_pi.py b/examples/benchmarks/monte_carlo_pi.py index 2703069c2..440c01594 100755 --- a/examples/benchmarks/monte_carlo_pi.py +++ b/examples/benchmarks/monte_carlo_pi.py @@ -16,7 +16,7 @@ try: import numpy as np -except: +except ImportError: np = None #alias range / xrange because xrange is faster than range in python2 From 364175889ffebc97ec1bd442383b71c221d26685 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 25 May 2017 10:49:22 -0700 Subject: [PATCH 143/212] Fixing bug in sort_by_key parameters --- arrayfire/algorithm.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arrayfire/algorithm.py b/arrayfire/algorithm.py index d57e0ce86..36b5d79b8 100644 --- a/arrayfire/algorithm.py +++ b/arrayfire/algorithm.py @@ -473,16 +473,16 @@ def sort_index(a, dim=0, is_ascending=True): c_uint_t(dim), c_bool_t(is_ascending))) return out,idx -def sort_by_key(iv, ik, dim=0, is_ascending=True): +def sort_by_key(ik, iv, dim=0, is_ascending=True): """ Sort an array based on specified keys Parameters ---------- - iv : af.Array - An Array containing the values ik : af.Array An Array containing the keys + iv : af.Array + An Array containing the values dim: optional: int. default: 0 Dimension along which sort is to be performed. is_ascending: optional: bool. default: True @@ -490,9 +490,9 @@ def sort_by_key(iv, ik, dim=0, is_ascending=True): Returns ------- - (ov, ok): tuple of af.Array - `ov` contains the values from `iv` after sorting them based on `ik` + (ok, ov): tuple of af.Array `ok` contains the values from `ik` in sorted order + `ov` contains the values from `iv` after sorting them based on `ik` Note ------- @@ -500,8 +500,8 @@ def sort_by_key(iv, ik, dim=0, is_ascending=True): """ ov = Array() ok = Array() - safe_call(backend.get().af_sort_by_key(c_pointer(ov.arr), c_pointer(ok.arr), - iv.arr, ik.arr, c_uint_t(dim), c_bool_t(is_ascending))) + safe_call(backend.get().af_sort_by_key(c_pointer(ok.arr), c_pointer(ov.arr), + ik.arr, iv.arr, c_uint_t(dim), c_bool_t(is_ascending))) return ov,ok def set_unique(a, is_sorted=False): From 15af43161d1fa109b1f45fa623339791fa3c3026 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 2 Jul 2017 23:26:42 -0700 Subject: [PATCH 144/212] Add functios to query and print memory - print_mem_info - Array.allocated --- arrayfire/array.py | 8 ++++++++ arrayfire/device.py | 46 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index 7c8ddd4f1..d1c6d084e 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -630,6 +630,14 @@ def elements(self): safe_call(backend.get().af_get_elements(c_pointer(num), self.arr)) return num.value + def allocated(self): + """ + Returns the number of bytes allocated by the memory manager for the array. + """ + num = c_size_t(0) + safe_call(backend.get().af_get_allocated_bytes(c_pointer(num), self.arr)) + return num.value + def dtype(self): """ Return the data type as a arrayfire.Dtype enum value. diff --git a/arrayfire/device.py b/arrayfire/device.py index ad8abd512..84594f2b3 100644 --- a/arrayfire/device.py +++ b/arrayfire/device.py @@ -273,6 +273,52 @@ def device_mem_info(): mem_info['lock'] = {'buffers' : lock_buffers.value, 'bytes' : lock_bytes.value} return mem_info +def print_mem_info(title = "Memory Info", device_id = None): + """ + Prints the memory used for the specified device. + + Parameters + ---------- + title: optional. Default: "Memory Info" + - Title to display before printing the memory info. + device_id: optional. Default: None + - Specifies the device for which the memory info should be displayed. + - If None, uses the current device. + + Examples + -------- + + >>> a = af.randu(5,5) + >>> af.print_mem_info() + Memory Info + --------------------------------------------------------- + | POINTER | SIZE | AF LOCK | USER LOCK | + --------------------------------------------------------- + | 0x706400000 | 1 KB | Yes | No | + --------------------------------------------------------- + >>> b = af.randu(5,5) + >>> af.print_mem_info() + Memory Info + --------------------------------------------------------- + | POINTER | SIZE | AF LOCK | USER LOCK | + --------------------------------------------------------- + | 0x706400400 | 1 KB | Yes | No | + | 0x706400000 | 1 KB | Yes | No | + --------------------------------------------------------- + >>> a = af.randu(1000,1000) + >>> af.print_mem_info() + Memory Info + --------------------------------------------------------- + | POINTER | SIZE | AF LOCK | USER LOCK | + --------------------------------------------------------- + | 0x706500000 | 3.815 MB | Yes | No | + | 0x706400400 | 1 KB | Yes | No | + | 0x706400000 | 1 KB | No | No | + --------------------------------------------------------- + """ + device_id = device_id if device_id else get_device() + safe_call(backend.get().af_print_mem_info(title.encode('utf-8'), device_id)) + def device_gc(): """ Ask the garbage collector to free all unlocked memory From 8e84d604142af99e94c20fe8c8c688287a75b882 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Mon, 17 Jul 2017 23:40:12 -0700 Subject: [PATCH 145/212] FEAT: Adding array.scalar() --- arrayfire/array.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index d1c6d084e..7d60dee0a 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -1253,6 +1253,19 @@ def to_list(self, row_major=False): ct_array, shape = self.to_ctype(row_major, True) return _ctype_to_lists(ct_array, len(shape) - 1, shape) + def scalar(self): + """ + Return the first element of the array + """ + + if (self.arr.value == 0): + raise RuntimeError("Can not call to_ctype on empty array") + + ctype_type = to_c_type[self.type()] + res = ctype_type() + safe_call(backend.get().af_get_scalar(c_pointer(res), self.arr)) + return res.value + def __str__(self): """ Converts the arrayfire array to string showing its meta data and contents. From 8bf7c014777bb34d9e23f04e580f683b0acc0623 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 18 Jul 2017 01:00:14 -0700 Subject: [PATCH 146/212] FEAT: Adding canny edge detector --- arrayfire/image.py | 41 +++++++++++++++++++++++++++++++++++++++++ arrayfire/library.py | 7 +++++++ 2 files changed, 48 insertions(+) diff --git a/arrayfire/image.py b/arrayfire/image.py index 5fadd991a..11cbe2560 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -1194,6 +1194,47 @@ def moments(image, moment = MOMENT.FIRST_ORDER): safe_call(backend.get().af_moments(c_pointer(output.arr), image.arr, moment.value)) return output +def canny(image, + low_threshold, high_threshold = None, + treshold_type = CANNY_THRESHOLD.MANUAL, + sobel_window = 3, is_fast = False): + """ + Canny edge detector. + + Parameters + ---------- + image : af.Array + - A 2 D arrayfire array representing an image + + threshold_type : optional: af.CANNY_THRESHOLD. default: af.CANNY_THRESHOLD.MANUAL. + Can be one of: + - af.CANNY_THRESHOLD.MANUAL + - af.CANNY_THRESHOLD.AUTO_OTSU + + low_threshold : required: float. + Specifies the % of maximum in gradient image if threshold_type is MANUAL. + Specifies the % of auto dervied high value if threshold_type is AUTO_OTSU. + + high_threshold : optional: float. default: None + Specifies the % of maximum in gradient image if threshold_type is MANUAL. + Ignored if threshold_type is AUTO_OTSU + + sobel_window : optional: int. default: 3 + Specifies the size of sobel kernel when computing the gradient image. + + Returns + -------- + + out : af.Array + - A binary image containing the edges + + """ + output = Array() + safe_call(backend.get().af_canny(c_pointer(output.arr), threshold_type.value, + low_threshold, high_threshold and high_threshold.value or 0, + c_uint(sobel_window), c_bool(is_fast))) + return output + def is_image_io_available(): """ Function to check if the arrayfire library was built with Image IO support. diff --git a/arrayfire/library.py b/arrayfire/library.py index 9a8e50307..eeca414a8 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -413,6 +413,13 @@ class STORAGE(_Enum): CSC = _Enum_Type(2) COO = _Enum_Type(3) +class CANNY_THRESHOLD(_Enum): + """ + Canny Edge Threshold types + """ + MANUAL = _Enum_Type(0) + AUTO_OTSU = _Enum_Type(1) + _VER_MAJOR_PLACEHOLDER = "__VER_MAJOR__" def _setup(): From 7bf28b7d08b559e1f301556af0cfd24e699d8f08 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 18 Jul 2017 01:07:30 -0700 Subject: [PATCH 147/212] FEAT: Adding support for dot --- arrayfire/blas.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/arrayfire/blas.py b/arrayfire/blas.py index 4fa7ffad6..f0e9dfdc6 100644 --- a/arrayfire/blas.py +++ b/arrayfire/blas.py @@ -150,7 +150,7 @@ def matmulTT(lhs, rhs): MATPROP.TRANS.value, MATPROP.TRANS.value)) return out -def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE): +def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE, return_scalar = False): """ Dot product of two input vectors. @@ -173,10 +173,13 @@ def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE): - af.MATPROP.NONE - If no op should be done on `rhs`. - No other options are currently supported. + return_scalar: optional: bool. default: False. + - When set to true, the input arrays are flattened and the output is a scalar + Returns ------- - out : af.Array + out : af.Array or scalar Output of dot product of `lhs` and `rhs`. Note @@ -186,7 +189,16 @@ def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE): - Batches are not supported. """ - out = Array() - safe_call(backend.get().af_dot(c_pointer(out.arr), lhs.arr, rhs.arr, - lhs_opts.value, rhs_opts.value)) - return out + if return_scalar: + real = c_double_t(0) + imag = c_double_t(0) + safe_call(backend.get().af_dot_all(c_pointer(real), c_pointer(imag), + lhs.arr, rhs.arr, lhs_opts.value, rhs_opts.value)) + real = real.value + imag = imag.value + return real if imag == 0 else real + imag * 1j + else: + out = Array() + safe_call(backend.get().af_dot(c_pointer(out.arr), lhs.arr, rhs.arr, + lhs_opts.value, rhs_opts.value)) + return out From de788f91ab186425559b93ed19d0ec0413000576 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 18 Jul 2017 01:09:40 -0700 Subject: [PATCH 148/212] Updating version number to 3.5.20170718 and Changelog --- CHANGELOG.md | 22 ++++++++++++++++++++-- __af_version__.py | 4 ++-- setup.py | 2 +- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3538a0c5..7db11996c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,22 @@ -### v3.3.20170222 +### v3.5.20170718 +- Feature parity with ArrayFire 3.5. + - `canny`: Canny Edge detector + - `Array.scalar`: Return the first element of the array + - `dot`: Now support option to return scalar + - `print_mem_info`: Prints memory being used / locked by arrayfire memory manager. + - `Array.allocated`: Returs the amount of memory allocated for the given buffer. + - `set_fft_plan_cache_size`: Sets the size of the fft plan cache. + +- Bug Fixes: + - `sort_by_key` had key and value flipped in documentation. + +- Improvements and bugfixes from upstream include: + - CUDA backend uses nvrtc instead of nvvm + - Performance improvements to arrayfire.reorder + - Faster unified backend + - You can find more information at arrayfire's [release notes](https://github.com/arrayfire/arrayfire/blob/v3.5.0/docs/pages/release_notes.md) + +### v3.4.20170222 - Bugfix: Fixes typo in `approx1`. - Bugfix: Fixes typo in `hamming_matcher` and `nearest_neighbour`. - Bugfix: Added necessary copy and lock mechanisms in interop.py. @@ -6,7 +24,7 @@ - Feature: Added support to create arrayfire arrays from numba. - Behavior change: af.print() only prints full arrays for smaller sizes. -### v3.3.20161126 +### v3.4.20161126 - Fixing memory leak in array creation. - Supporting 16 bit integer types in interop. diff --git a/__af_version__.py b/__af_version__.py index 828a50d33..9b8a5f40c 100644 --- a/__af_version__.py +++ b/__af_version__.py @@ -9,6 +9,6 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -version = "3.4" -release = "20160925" +version = "3.5" +release = "20170718" full_version = version + "." + release diff --git a/setup.py b/setup.py index 6d11b14af..46f16135d 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ author="Pavan Yalamanchili", author_email="contact@pavanky.com", name="arrayfire", - version="3.4.20170222", + version="3.5.20170718", description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From 92542a01bdb06a4db7551d1d1a85ddd253909d80 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Tue, 18 Jul 2017 01:53:02 -0700 Subject: [PATCH 149/212] Updating version to 3.6.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 46f16135d..528353709 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ author="Pavan Yalamanchili", author_email="contact@pavanky.com", name="arrayfire", - version="3.5.20170718", + version="3.6.0", description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From d7d25e8e04b3f944626edbae1ac38c9d1eb044c3 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 21 Jul 2017 00:24:55 -0700 Subject: [PATCH 150/212] Fix bug in Canny --- arrayfire/image.py | 13 +++++++++---- arrayfire/tests/simple/image.py | 3 +++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/arrayfire/image.py b/arrayfire/image.py index 11cbe2560..020e1444d 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -1196,7 +1196,7 @@ def moments(image, moment = MOMENT.FIRST_ORDER): def canny(image, low_threshold, high_threshold = None, - treshold_type = CANNY_THRESHOLD.MANUAL, + threshold_type = CANNY_THRESHOLD.MANUAL, sobel_window = 3, is_fast = False): """ Canny edge detector. @@ -1230,9 +1230,14 @@ def canny(image, """ output = Array() - safe_call(backend.get().af_canny(c_pointer(output.arr), threshold_type.value, - low_threshold, high_threshold and high_threshold.value or 0, - c_uint(sobel_window), c_bool(is_fast))) + if threshold_type.value == CANNY_THRESHOLD.MANUAL.value: + assert(high_threshold is not None) + + high_threshold = high_threshold if high_threshold else 0 + safe_call(backend.get().af_canny(c_pointer(output.arr), image.arr, + c_int_t(threshold_type.value), + c_float_t(low_threshold), c_float_t(high_threshold), + c_uint_t(sobel_window), c_bool_t(is_fast))) return output def is_image_io_available(): diff --git a/arrayfire/tests/simple/image.py b/arrayfire/tests/simple/image.py index 209013a2e..04a344c93 100644 --- a/arrayfire/tests/simple/image.py +++ b/arrayfire/tests/simple/image.py @@ -78,4 +78,7 @@ def simple_image(verbose = False): display_func(af.rgb2ycbcr(a)) display_func(af.ycbcr2rgb(a)) + a = af.randu(10, 10) + b = af.canny(a, low_threshold = 0.2, high_threshold = 0.8) + _util.tests['image'] = simple_image From 978479183fa0f95b698f1556262ff53969c81498 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 21 Jul 2017 00:26:44 -0700 Subject: [PATCH 151/212] Updating changelog and revision number --- CHANGELOG.md | 3 +++ setup.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7db11996c..55938cc8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### v3.5.20170721 +- Bug fixes for canny edge detection + ### v3.5.20170718 - Feature parity with ArrayFire 3.5. - `canny`: Canny Edge detector diff --git a/setup.py b/setup.py index 46f16135d..c2187a877 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ author="Pavan Yalamanchili", author_email="contact@pavanky.com", name="arrayfire", - version="3.5.20170718", + version="3.5.20170721", description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From a80efe926f4633a9c37eb85e99099ab22f037548 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Fri, 21 Jul 2017 00:24:55 -0700 Subject: [PATCH 152/212] Fix bug in Canny --- arrayfire/image.py | 13 +++++++++---- arrayfire/tests/simple/image.py | 3 +++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/arrayfire/image.py b/arrayfire/image.py index 11cbe2560..020e1444d 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -1196,7 +1196,7 @@ def moments(image, moment = MOMENT.FIRST_ORDER): def canny(image, low_threshold, high_threshold = None, - treshold_type = CANNY_THRESHOLD.MANUAL, + threshold_type = CANNY_THRESHOLD.MANUAL, sobel_window = 3, is_fast = False): """ Canny edge detector. @@ -1230,9 +1230,14 @@ def canny(image, """ output = Array() - safe_call(backend.get().af_canny(c_pointer(output.arr), threshold_type.value, - low_threshold, high_threshold and high_threshold.value or 0, - c_uint(sobel_window), c_bool(is_fast))) + if threshold_type.value == CANNY_THRESHOLD.MANUAL.value: + assert(high_threshold is not None) + + high_threshold = high_threshold if high_threshold else 0 + safe_call(backend.get().af_canny(c_pointer(output.arr), image.arr, + c_int_t(threshold_type.value), + c_float_t(low_threshold), c_float_t(high_threshold), + c_uint_t(sobel_window), c_bool_t(is_fast))) return output def is_image_io_available(): diff --git a/arrayfire/tests/simple/image.py b/arrayfire/tests/simple/image.py index 209013a2e..04a344c93 100644 --- a/arrayfire/tests/simple/image.py +++ b/arrayfire/tests/simple/image.py @@ -78,4 +78,7 @@ def simple_image(verbose = False): display_func(af.rgb2ycbcr(a)) display_func(af.ycbcr2rgb(a)) + a = af.randu(10, 10) + b = af.canny(a, low_threshold = 0.2, high_threshold = 0.8) + _util.tests['image'] = simple_image From 0188f8b1d8b2c6c6a9ef5236d7de5f9dadf97553 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 17 Aug 2017 00:24:18 -0700 Subject: [PATCH 153/212] Fixing forge major version. Adding verbose options. --- arrayfire/library.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index eeca414a8..3566ac461 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -13,6 +13,8 @@ import platform import ctypes as ct +import traceback +import os c_float_t = ct.c_float c_double_t = ct.c_double @@ -32,7 +34,7 @@ AF_VER_MAJOR = '3' -FORGE_VER_MAJOR = '0' +FORGE_VER_MAJOR = '1' # Work around for unexpected architectures if 'c_dim_t_forced' in globals(): @@ -424,7 +426,6 @@ class CANNY_THRESHOLD(_Enum): def _setup(): import platform - import os platform_name = platform.system() @@ -545,10 +546,23 @@ def __init__(self): # Try to pre-load forge library if it exists libnames = self.__libname('forge', head='', ver_major=FORGE_VER_MAJOR) + + try: + VERBOSE_LOADS = os.environ['AF_VERBOSE_LOADS'] == '1' + except KeyError: + VERBOSE_LOADS = False + pass + for libname in libnames: try: ct.cdll.LoadLibrary(libname) + if VERBOSE_LOADS: + print('Loaded ' + libname) + break except OSError: + if VERBOSE_LOADS: + traceback.print_exc() + print('Unable to load ' + libname) pass c_dim4 = c_dim_t*4 @@ -568,8 +582,13 @@ def __init__(self): if (err == ERR.NONE.value): self.__name = __name clib.af_release_array(out) - break; + if VERBOSE_LOADS: + print('Loaded ' + libname) + break; except OSError: + if VERBOSE_LOADS: + traceback.print_exc() + print('Unable to load ' + libname) pass if (self.__name is None): From 38f9fd8aad48af9c46e1eaa2180c57f55413b65e Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 17 Aug 2017 00:28:20 -0700 Subject: [PATCH 154/212] Updating version and changelog --- CHANGELOG.md | 3 +++ setup.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55938cc8f..1278c87aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### v3.5.20170721 +- Bug fixes when using v3.5 of arrayfire libs + graphics + ### v3.5.20170721 - Bug fixes for canny edge detection diff --git a/setup.py b/setup.py index c2187a877..0e74aa2d0 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ author="Pavan Yalamanchili", author_email="contact@pavanky.com", name="arrayfire", - version="3.5.20170721", + version="3.5.20170817", description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From f139d8cea9e36f54a01c8035e05c9e7a139b9b5a Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 17 Aug 2017 00:24:18 -0700 Subject: [PATCH 155/212] Fixing forge major version. Adding verbose options. --- arrayfire/library.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index eeca414a8..3566ac461 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -13,6 +13,8 @@ import platform import ctypes as ct +import traceback +import os c_float_t = ct.c_float c_double_t = ct.c_double @@ -32,7 +34,7 @@ AF_VER_MAJOR = '3' -FORGE_VER_MAJOR = '0' +FORGE_VER_MAJOR = '1' # Work around for unexpected architectures if 'c_dim_t_forced' in globals(): @@ -424,7 +426,6 @@ class CANNY_THRESHOLD(_Enum): def _setup(): import platform - import os platform_name = platform.system() @@ -545,10 +546,23 @@ def __init__(self): # Try to pre-load forge library if it exists libnames = self.__libname('forge', head='', ver_major=FORGE_VER_MAJOR) + + try: + VERBOSE_LOADS = os.environ['AF_VERBOSE_LOADS'] == '1' + except KeyError: + VERBOSE_LOADS = False + pass + for libname in libnames: try: ct.cdll.LoadLibrary(libname) + if VERBOSE_LOADS: + print('Loaded ' + libname) + break except OSError: + if VERBOSE_LOADS: + traceback.print_exc() + print('Unable to load ' + libname) pass c_dim4 = c_dim_t*4 @@ -568,8 +582,13 @@ def __init__(self): if (err == ERR.NONE.value): self.__name = __name clib.af_release_array(out) - break; + if VERBOSE_LOADS: + print('Loaded ' + libname) + break; except OSError: + if VERBOSE_LOADS: + traceback.print_exc() + print('Unable to load ' + libname) pass if (self.__name is None): From ee1109499ff2de55a32a959103d778674438fb3a Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 17 Aug 2017 08:35:35 -0700 Subject: [PATCH 156/212] Adding links to slack and google groups --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 311523c67..430a87e25 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,11 @@ To run arrayfire tests, you can run the following command from command line. python -m arrayfire.tests ``` +## Communication + +* [Slack Chat](https://join.slack.com/t/arrayfire-org/shared_invite/MjI1ODQ4NjI1MTM4LTE1MDI1NTgzOTctNzdjZmYyYWIwNA) +* [Google Groups](https://groups.google.com/forum/#!forum/arrayfire-users) + ## Acknowledgements The ArrayFire library is written by developers at [ArrayFire](http://arrayfire.com) LLC From 8367e53ababc02503fc224e4db5c2c5870d26e61 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Thu, 17 Aug 2017 09:58:00 -0700 Subject: [PATCH 157/212] Updatign slack invite link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 430a87e25..ad170f0f5 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ python -m arrayfire.tests ## Communication -* [Slack Chat](https://join.slack.com/t/arrayfire-org/shared_invite/MjI1ODQ4NjI1MTM4LTE1MDI1NTgzOTctNzdjZmYyYWIwNA) +* [Slack Chat](https://join.slack.com/t/arrayfire-org/shared_invite/MjI4MjIzMDMzMTczLTE1MDI5ODg4NzYtN2QwNGE3ODA5OQ) * [Google Groups](https://groups.google.com/forum/#!forum/arrayfire-users) ## Acknowledgements From e2ba101bd6f6bec1ec52fdc42fbcebf1d9d814e8 Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 17 Sep 2017 19:02:08 -0700 Subject: [PATCH 158/212] FEAT: Adding function to copy to existing ndarray --- arrayfire/array.py | 56 +++++++++++++++++++++++++++++-- arrayfire/data.py | 1 - arrayfire/tests/simple/interop.py | 14 +++++++- 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 7d60dee0a..febacc8f5 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -296,7 +296,6 @@ def _get_assign_dims(key, idims): else: raise IndexError("Invalid type while assigning to arrayfire.array") - def transpose(a, conj=False): """ Perform the transpose on an input. @@ -504,7 +503,9 @@ def __init__(self, src=None, dims=None, dtype=None, is_device=False, offset=None if(offset is None and strides is None): self.arr = _create_array(buf, numdims, idims, to_dtype[_type_char], is_device) else: - self.arr = _create_strided_array(buf, numdims, idims, to_dtype[_type_char], is_device, offset, strides) + self.arr = _create_strided_array(buf, numdims, idims, + to_dtype[_type_char], + is_device, offset, strides) else: @@ -1159,6 +1160,19 @@ def __setitem__(self, key, val): except RuntimeError as e: raise IndexError(str(e)) + def _reorder(self): + """ + Returns a reordered array to help interoperate with row major formats. + """ + ndims = self.numdims() + if (ndims == 1): + return self + + rdims = tuple(reversed(range(ndims))) + tuple(range(ndims, 4)) + out = Array() + safe_call(backend.get().af_reorder(c_pointer(out.arr), self.arr, *rdims)) + return out + def to_ctype(self, row_major=False, return_shape=False): """ Return the data as a ctype C array after copying to host memory @@ -1312,6 +1326,44 @@ def __array__(self): safe_call(backend.get().af_get_data_ptr(c_void_ptr_t(res.ctypes.data), self.arr)) return res + def to_ndarray(self, output=None): + """ + Parameters + ----------- + output: optional: numpy. default: None + + Returns + ---------- + If output is None: Constructs a numpy.array from arrayfire.Array + If output is not None: copies content of af.array into numpy array. + + Note + ------ + + - An exception is thrown when output is not None and it is not contiguous. + - When output is None, The returned array is in fortran contiguous order. + """ + if output is None: + return self.__array__() + + if (output.dtype != to_typecode[self.type()]): + raise TypeError("Output is not the same type as the array") + + if (output.size != self.elements()): + raise RuntimeError("Output size does not match that of input") + + flags = output.flags + tmp = None + if flags['F_CONTIGUOUS']: + tmp = self + elif flags['C_CONTIGUOUS']: + tmp = self._reorder() + else: + raise RuntimeError("When output is not None, it must be contiguous") + + safe_call(backend.get().af_get_data_ptr(c_void_ptr_t(output.ctypes.data), tmp.arr)) + return output + def display(a, precision=4): """ Displays the contents of an array. diff --git a/arrayfire/data.py b/arrayfire/data.py index 73f516073..d9ad19e48 100644 --- a/arrayfire/data.py +++ b/arrayfire/data.py @@ -397,7 +397,6 @@ def tile(a, d0, d1=1, d2=1, d3=1): safe_call(backend.get().af_tile(c_pointer(out.arr), a.arr, d0, d1, d2, d3)) return out - def reorder(a, d0=1, d1=0, d2=2, d3=3): """ Reorder the dimensions of the input. diff --git a/arrayfire/tests/simple/interop.py b/arrayfire/tests/simple/interop.py index 145e1039a..ee924c6fa 100644 --- a/arrayfire/tests/simple/interop.py +++ b/arrayfire/tests/simple/interop.py @@ -18,21 +18,33 @@ def simple_interop(verbose = False): a = af.to_array(n) n2 = np.array(a) assert((n==n2).all()) + n2[:] = 0 + a.to_ndarray(n2) + assert((n==n2).all()) n = np.random.random((5,3)) a = af.to_array(n) n2 = np.array(a) assert((n==n2).all()) + n2[:] = 0 + a.to_ndarray(n2) + assert((n==n2).all()) n = np.random.random((5,3,2)) a = af.to_array(n) n2 = np.array(a) assert((n==n2).all()) + n2[:] = 0 + a.to_ndarray(n2) + assert((n==n2).all()) - n = np.random.random((5,3,2, 2)) + n = np.random.random((5,3,2,2)) a = af.to_array(n) n2 = np.array(a) assert((n==n2).all()) + n2[:] = 0 + a.to_ndarray(n2) + assert((n==n2).all()) if af.AF_PYCUDA_FOUND and af.get_active_backend() == 'cuda': import pycuda.autoinit From 0216e82105f3086a055a5343dd5546736492112b Mon Sep 17 00:00:00 2001 From: Pavan Yalamanchili Date: Sun, 17 Sep 2017 19:02:38 -0700 Subject: [PATCH 159/212] BUGFIX / PERF: Fixing bugs in interop functions. - Call arr._reorder instead of transpose when using row major. - Disable additional copies when is_device is false --- arrayfire/array.py | 4 +++- arrayfire/interop.py | 25 ++++++------------------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index febacc8f5..a8aabe656 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -1198,9 +1198,11 @@ def to_ctype(self, row_major=False, return_shape=False): if (self.arr.value == 0): raise RuntimeError("Can not call to_ctype on empty array") - tmp = transpose(self) if row_major else self + tmp = self._reorder() if (row_major) else self + ctype_type = to_c_type[self.type()] * self.elements() res = ctype_type() + safe_call(backend.get().af_get_data_ptr(c_pointer(res), self.arr)) if (return_shape): return res, self.dims() diff --git a/arrayfire/interop.py b/arrayfire/interop.py index a93fbe5ae..f2b9a1f68 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -29,10 +29,10 @@ def _fc_to_af_array(in_ptr, in_shape, in_dtype, is_device=False, copy = True): """ res = Array(in_ptr, in_shape, in_dtype, is_device=is_device) - if is_device: - lock_array(res) - pass + if not is_device: + return res + lock_array(res) return res.copy() if copy else res def _cc_to_af_array(in_ptr, ndim, in_shape, in_dtype, is_device=False, copy = True): @@ -41,24 +41,11 @@ def _cc_to_af_array(in_ptr, ndim, in_shape, in_dtype, is_device=False, copy = Tr """ if ndim == 1: return _fc_to_af_array(in_ptr, in_shape, in_dtype, is_device, copy) - elif ndim == 2: - shape = (in_shape[1], in_shape[0]) - res = Array(in_ptr, shape, in_dtype, is_device=is_device) - if is_device: lock_array(res) - return reorder(res, 1, 0) - elif ndim == 3: - shape = (in_shape[2], in_shape[1], in_shape[0]) - res = Array(in_ptr, shape, in_dtype, is_device=is_device) - if is_device: lock_array(res) - return reorder(res, 2, 1, 0) - elif ndim == 4: - shape = (in_shape[3], in_shape[2], in_shape[1], in_shape[0]) + else: + shape = tuple(reversed(in_shape)) res = Array(in_ptr, shape, in_dtype, is_device=is_device) if is_device: lock_array(res) - return reorder(res, 3, 2, 1, 0) - else: - raise RuntimeError("Unsupported ndim") - + return res._reorder() _nptype_to_aftype = {'b1' : Dtype.b8, 'u1' : Dtype.u8, From d270ed2e176ac1d8ac9f2cd9b9e53afbc5a3c400 Mon Sep 17 00:00:00 2001 From: Shyam Sundar Sankaran Date: Tue, 26 Sep 2017 14:19:03 +0530 Subject: [PATCH 160/212] Added interp1d --- arrayfire/signal.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/arrayfire/signal.py b/arrayfire/signal.py index f3783728f..a0218aee2 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -94,6 +94,40 @@ def approx2(signal, pos0, pos1, method=INTERP.LINEAR, off_grid=0.0): pos0.arr, pos1.arr, method.value, c_float_t(off_grid))) return output +def interp1d(x_interpolated, x_input, signal_input, method=INTERP.LINEAR, off_grid=0.0): + """ + One-dimensional linear interpolation.Interpolation is performed along axis 0. + + Parameters + ---------- + + x : af.Array + The x-coordinates of the interpolated values. The interpolation function + is queried at these set of points. + + x : af.Array + The x-coordinates of the data points + + signal_input: af.Array + Input signal array(uniform data) + + method: optional: af.INTERP. default: af.INTERP.LINEAR. + Interpolation method. + + off_grid: optional: scalar. default: 0.0. + The value used for positions outside the range. + + Returns + ------- + + output: af.Array + Values calculated at interpolation points. + """ + dx = sum(x_input[1, 0, 0, 0] - x_input[0, 0, 0, 0]) + pos0 = (x_interpolated - sum(x_input[0, 0, 0, 0]))/dx + + return approx1(signal_input, pos0, method, off_grid) + def fft(signal, dim0 = None , scale = None): """ Fast Fourier Transform: 1D From 7a680de2d6a00419868793691ca70a6826c9e046 Mon Sep 17 00:00:00 2001 From: Shyam Sundar Sankaran Date: Tue, 26 Sep 2017 16:51:44 +0530 Subject: [PATCH 161/212] Added interp2d --- arrayfire/signal.py | 63 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/arrayfire/signal.py b/arrayfire/signal.py index a0218aee2..134bebf99 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -96,20 +96,21 @@ def approx2(signal, pos0, pos1, method=INTERP.LINEAR, off_grid=0.0): def interp1d(x_interpolated, x_input, signal_input, method=INTERP.LINEAR, off_grid=0.0): """ - One-dimensional linear interpolation.Interpolation is performed along axis 0. + One-dimensional linear interpolation.Interpolation is performed along axis 0 + of the input array. Parameters ---------- - x : af.Array - The x-coordinates of the interpolated values. The interpolation function - is queried at these set of points. + x_interpolated : af.Array + The x-coordinates of the interpolation points. The interpolation + function is queried at these set of points. x : af.Array - The x-coordinates of the data points + The x-coordinates of the input data points signal_input: af.Array - Input signal array(uniform data) + Input signal array (signal = f(x)) method: optional: af.INTERP. default: af.INTERP.LINEAR. Interpolation method. @@ -128,6 +129,56 @@ def interp1d(x_interpolated, x_input, signal_input, method=INTERP.LINEAR, off_gr return approx1(signal_input, pos0, method, off_grid) + +def interp2d(x_interpolated, x_input, y_interpolated, y_input, + signal_input, method=INTERP.LINEAR, off_grid=0.0 + ): + """ + Two-dimensional linear interpolation.Interpolation is performed along axes 0 and 1 + of the input array. + + Parameters + ---------- + + x_interpolated : af.Array + The x-coordinates of the interpolation points. The interpolation + function is queried at these set of points. + + x : af.Array + The x-coordinates of the input data points. The convention followed is that + the x-coordinates vary along axis 0 + + y_interpolated : af.Array + The y-coordinates of the interpolation points. The interpolation + function is queried at these set of points. + + y : af.Array + The y-coordinates of the input data points. The convention followed is that + the y-coordinates vary along axis 1 + + signal_input: af.Array + Input signal array (signal = f(x, y)) + + method: optional: af.INTERP. default: af.INTERP.LINEAR. + Interpolation method. + + off_grid: optional: scalar. default: 0.0. + The value used for positions outside the range. + + Returns + ------- + + output: af.Array + Values calculated at interpolation points. + """ + dx = sum(x_input[1, 0, 0, 0] - x_input[0, 0, 0, 0]) + dy = sum(y_input[0, 1, 0, 0] - y_input[0, 0, 0, 0]) + + pos0 = (x_interpolated - sum(x_input[0, 0, 0, 0]))/dx + pos1 = (y_interpolated - sum(y_input[0, 0, 0, 0]))/dy + + return approx2(signal_input, pos0, pos1, method, off_grid) + def fft(signal, dim0 = None , scale = None): """ Fast Fourier Transform: 1D From 84b2f2f93ce5f4f20feb788934bebb7c220cc940 Mon Sep 17 00:00:00 2001 From: Shyam Sundar Sankaran Date: Wed, 27 Sep 2017 13:14:09 +0530 Subject: [PATCH 162/212] Implemented interp functionality into approx1/2 --- arrayfire/signal.py | 146 +++++++++---------------------- arrayfire/tests/simple/signal.py | 21 +++-- 2 files changed, 52 insertions(+), 115 deletions(-) diff --git a/arrayfire/signal.py b/arrayfire/signal.py index 134bebf99..e4b272083 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -13,90 +13,23 @@ from .library import * from .array import * +from .bcast import broadcast -def approx1(signal, pos0, method=INTERP.LINEAR, off_grid=0.0): - """ - Interpolate along a single dimension. - - Parameters - ---------- - - signal: af.Array - A 1 dimensional signal or batch of 1 dimensional signals. +@broadcast +def _scale_pos_axis0(x_curr, x_orig): + x0 = x_orig[0, 0, 0, 0] + dx = x_orig[1, 0, 0, 0] - x0 + return((x_curr - x0) / dx) - pos0 : af.Array - Locations of the interpolation points. +@broadcast +def _scale_pos_axis1(y_curr, y_orig): + y0 = y_orig[0, 0, 0, 0] + dy = y_orig[0, 1, 0, 0] - y0 + return((y_curr - y0) / dy) - method: optional: af.INTERP. default: af.INTERP.LINEAR. - Interpolation method. - - off_grid: optional: scalar. default: 0.0. - The value used for positions outside the range. - - Returns - ------- - - output: af.Array - Values calculated at interpolation points. - - Note - ----- - - The initial measurements are assumed to have taken place at equal steps between [0, N - 1], - where N is the length of the first dimension of `signal`. - - - """ - output = Array() - safe_call(backend.get().af_approx1(c_pointer(output.arr), signal.arr, pos0.arr, - method.value, c_float_t(off_grid))) - return output - -def approx2(signal, pos0, pos1, method=INTERP.LINEAR, off_grid=0.0): +def approx1(x_interpolated, x_input, signal_input, method=INTERP.LINEAR, off_grid=0.0): """ - Interpolate along a two dimension. - - Parameters - ---------- - - signal: af.Array - A 2 dimensional signal or batch of 2 dimensional signals. - - pos0 : af.Array - Locations of the interpolation points along the first dimension. - - pos1 : af.Array - Locations of the interpolation points along the second dimension. - - method: optional: af.INTERP. default: af.INTERP.LINEAR. - Interpolation method. - - off_grid: optional: scalar. default: 0.0. - The value used for positions outside the range. - - Returns - ------- - - output: af.Array - Values calculated at interpolation points. - - Note - ----- - - The initial measurements are assumed to have taken place at equal steps between [(0,0) - [M - 1, N - 1]] - where M is the length of the first dimension of `signal`, - and N is the length of the second dimension of `signal`. - - - """ - output = Array() - safe_call(backend.get().af_approx2(c_pointer(output.arr), signal.arr, - pos0.arr, pos1.arr, method.value, c_float_t(off_grid))) - return output - -def interp1d(x_interpolated, x_input, signal_input, method=INTERP.LINEAR, off_grid=0.0): - """ - One-dimensional linear interpolation.Interpolation is performed along axis 0 + Interpolate along a single dimension.Interpolation is performed along axis 0 of the input array. Parameters @@ -106,17 +39,18 @@ def interp1d(x_interpolated, x_input, signal_input, method=INTERP.LINEAR, off_gr The x-coordinates of the interpolation points. The interpolation function is queried at these set of points. - x : af.Array - The x-coordinates of the input data points + x_input : af.Array + The x-coordinates of the input data points signal_input: af.Array Input signal array (signal = f(x)) + method: optional: af.INTERP. default: af.INTERP.LINEAR. Interpolation method. off_grid: optional: scalar. default: 0.0. - The value used for positions outside the range. + The value used for positions outside the range. Returns ------- @@ -124,17 +58,17 @@ def interp1d(x_interpolated, x_input, signal_input, method=INTERP.LINEAR, off_gr output: af.Array Values calculated at interpolation points. """ - dx = sum(x_input[1, 0, 0, 0] - x_input[0, 0, 0, 0]) - pos0 = (x_interpolated - sum(x_input[0, 0, 0, 0]))/dx - - return approx1(signal_input, pos0, method, off_grid) - + output = Array() + pos0 = _scale_pos_axis0(x_interpolated, x_input) + safe_call(backend.get().af_approx1(c_pointer(output.arr), signal_input.arr, pos0.arr, + method.value, c_float_t(off_grid))) + return output -def interp2d(x_interpolated, x_input, y_interpolated, y_input, - signal_input, method=INTERP.LINEAR, off_grid=0.0 - ): +def approx2(x_interpolated, x_input, y_interpolated, y_input, signal_input, + method=INTERP.LINEAR, off_grid=0.0 + ): """ - Two-dimensional linear interpolation.Interpolation is performed along axes 0 and 1 + Interpolate along a two dimension.Interpolation is performed along axes 0 and 1 of the input array. Parameters @@ -144,17 +78,17 @@ def interp2d(x_interpolated, x_input, y_interpolated, y_input, The x-coordinates of the interpolation points. The interpolation function is queried at these set of points. - x : af.Array - The x-coordinates of the input data points. The convention followed is that - the x-coordinates vary along axis 0 + x_input : af.Array + The x-coordinates of the input data points. The convention followed is that + the x-coordinates vary along axis 0 y_interpolated : af.Array The y-coordinates of the interpolation points. The interpolation function is queried at these set of points. - y : af.Array - The y-coordinates of the input data points. The convention followed is that - the y-coordinates vary along axis 1 + y_input : af.Array + The y-coordinates of the input data points. The convention followed is that + the y-coordinates vary along axis 1 signal_input: af.Array Input signal array (signal = f(x, y)) @@ -163,21 +97,21 @@ def interp2d(x_interpolated, x_input, y_interpolated, y_input, Interpolation method. off_grid: optional: scalar. default: 0.0. - The value used for positions outside the range. + The value used for positions outside the range. Returns ------- output: af.Array Values calculated at interpolation points. - """ - dx = sum(x_input[1, 0, 0, 0] - x_input[0, 0, 0, 0]) - dy = sum(y_input[0, 1, 0, 0] - y_input[0, 0, 0, 0]) - - pos0 = (x_interpolated - sum(x_input[0, 0, 0, 0]))/dx - pos1 = (y_interpolated - sum(y_input[0, 0, 0, 0]))/dy - return approx2(signal_input, pos0, pos1, method, off_grid) + """ + output = Array() + pos0 = _scale_pos_axis0(x_interpolated, x_input) + pos1 = _scale_pos_axis1(y_interpolated, y_input) + safe_call(backend.get().af_approx2(c_pointer(output.arr), signal_input.arr, + pos0.arr, pos1.arr, method.value, c_float_t(off_grid))) + return output def fft(signal, dim0 = None , scale = None): """ diff --git a/arrayfire/tests/simple/signal.py b/arrayfire/tests/simple/signal.py index 817685c5a..a99f499e2 100644 --- a/arrayfire/tests/simple/signal.py +++ b/arrayfire/tests/simple/signal.py @@ -15,15 +15,18 @@ def simple_signal(verbose=False): display_func = _util.display_func(verbose) print_func = _util.print_func(verbose) - a = af.randu(10, 1) - pos0 = af.randu(10) * 10 - display_func(af.approx1(a, pos0)) - - a = af.randu(3, 3) - pos0 = af.randu(3, 3) * 10 - pos1 = af.randu(3, 3) * 10 - - display_func(af.approx2(a, pos0, pos1)) + signal = af.randu(10) + x_new = af.randu(10) + x_orig = af.randu(10) + display_func(af.approx1(x_new, x_orig, signal)) + + signal = af.randu(3, 3) + x_new = af.randu(3, 3) + x_orig = af.randu(3, 3) + y_new = af.randu(3, 3) + y_orig = af.randu(3, 3) + + display_func(af.approx2(x_new, x_orig, y_new, y_orig, signal)) a = af.randu(8, 1) display_func(a) From 7709bb3308c08a11b4168e7795596a79982197bd Mon Sep 17 00:00:00 2001 From: Shyam Sundar Sankaran Date: Thu, 28 Sep 2017 12:07:02 +0530 Subject: [PATCH 163/212] Made changes to retain earlier approx1 behaviour as well --- arrayfire/signal.py | 80 ++++++++++++++++++++++---------- arrayfire/tests/simple/signal.py | 4 +- 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/arrayfire/signal.py b/arrayfire/signal.py index e4b272083..a0c90e410 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -27,7 +27,7 @@ def _scale_pos_axis1(y_curr, y_orig): dy = y_orig[0, 1, 0, 0] - y0 return((y_curr - y0) / dy) -def approx1(x_interpolated, x_input, signal_input, method=INTERP.LINEAR, off_grid=0.0): +def approx1(signal, x_interpolated, method=INTERP.LINEAR, off_grid=0.0, x_input = None): """ Interpolate along a single dimension.Interpolation is performed along axis 0 of the input array. @@ -35,37 +35,49 @@ def approx1(x_interpolated, x_input, signal_input, method=INTERP.LINEAR, off_gri Parameters ---------- + signal: af.Array + Input signal array (signal = f(x)) + x_interpolated : af.Array The x-coordinates of the interpolation points. The interpolation function is queried at these set of points. - x_input : af.Array - The x-coordinates of the input data points - - signal_input: af.Array - Input signal array (signal = f(x)) - - method: optional: af.INTERP. default: af.INTERP.LINEAR. Interpolation method. off_grid: optional: scalar. default: 0.0. The value used for positions outside the range. + x_input : af.Array + The x-coordinates of the input data points + Returns ------- output: af.Array Values calculated at interpolation points. + + + Note + ----- + This holds applicable when x_input isn't provided: + The initial measurements are assumed to have taken place at equal steps between [0, N - 1], + where N is the length of the first dimension of `signal`. """ + output = Array() - pos0 = _scale_pos_axis0(x_interpolated, x_input) - safe_call(backend.get().af_approx1(c_pointer(output.arr), signal_input.arr, pos0.arr, + + if(x_input is not None): + pos0 = _scale_pos_axis0(x_interpolated, x_input) + else: + pos0 = x_interpolated + + safe_call(backend.get().af_approx1(c_pointer(output.arr), signal.arr, pos0.arr, method.value, c_float_t(off_grid))) return output -def approx2(x_interpolated, x_input, y_interpolated, y_input, signal_input, - method=INTERP.LINEAR, off_grid=0.0 +def approx2(signal, x_interpolated, y_interpolated, + method=INTERP.LINEAR, off_grid=0.0, x_input = None, y_input = None ): """ Interpolate along a two dimension.Interpolation is performed along axes 0 and 1 @@ -74,42 +86,60 @@ def approx2(x_interpolated, x_input, y_interpolated, y_input, signal_input, Parameters ---------- + signal: af.Array + Input signal array (signal = f(x, y)) + x_interpolated : af.Array The x-coordinates of the interpolation points. The interpolation function is queried at these set of points. - x_input : af.Array - The x-coordinates of the input data points. The convention followed is that - the x-coordinates vary along axis 0 y_interpolated : af.Array The y-coordinates of the interpolation points. The interpolation function is queried at these set of points. - y_input : af.Array - The y-coordinates of the input data points. The convention followed is that - the y-coordinates vary along axis 1 - - signal_input: af.Array - Input signal array (signal = f(x, y)) - method: optional: af.INTERP. default: af.INTERP.LINEAR. Interpolation method. off_grid: optional: scalar. default: 0.0. The value used for positions outside the range. + x_input : af.Array + The x-coordinates of the input data points. The convention followed is that + the x-coordinates vary along axis 0 + + y_input : af.Array + The y-coordinates of the input data points. The convention followed is that + the y-coordinates vary along axis 1 + Returns ------- output: af.Array Values calculated at interpolation points. + Note + ----- + This holds applicable when x_input/y_input isn't provided: + + The initial measurements are assumed to have taken place at equal steps between [(0,0) - [M - 1, N - 1]] + where M is the length of the first dimension of `signal`, + and N is the length of the second dimension of `signal`. """ + output = Array() - pos0 = _scale_pos_axis0(x_interpolated, x_input) - pos1 = _scale_pos_axis1(y_interpolated, y_input) - safe_call(backend.get().af_approx2(c_pointer(output.arr), signal_input.arr, + + if(x_input is not None): + pos0 = _scale_pos_axis0(x_interpolated, x_input) + else: + pos0 = x_interpolated + + if(y_input is not None): + pos1 = _scale_pos_axis1(y_interpolated, y_input) + else: + pos1 = y_interpolated + + safe_call(backend.get().af_approx2(c_pointer(output.arr), signal.arr, pos0.arr, pos1.arr, method.value, c_float_t(off_grid))) return output diff --git a/arrayfire/tests/simple/signal.py b/arrayfire/tests/simple/signal.py index a99f499e2..030ae046e 100644 --- a/arrayfire/tests/simple/signal.py +++ b/arrayfire/tests/simple/signal.py @@ -18,7 +18,7 @@ def simple_signal(verbose=False): signal = af.randu(10) x_new = af.randu(10) x_orig = af.randu(10) - display_func(af.approx1(x_new, x_orig, signal)) + display_func(af.approx1(signal, x_new, x_input = x_orig)) signal = af.randu(3, 3) x_new = af.randu(3, 3) @@ -26,7 +26,7 @@ def simple_signal(verbose=False): y_new = af.randu(3, 3) y_orig = af.randu(3, 3) - display_func(af.approx2(x_new, x_orig, y_new, y_orig, signal)) + display_func(af.approx2(signal, x_new, y_new, x_input = x_orig, y_input = y_orig)) a = af.randu(8, 1) display_func(a) From 718b8fc1f69f6c926fd4a665bebd42b634241e12 Mon Sep 17 00:00:00 2001 From: Shyam Sundar Sankaran Date: Fri, 29 Sep 2017 16:53:17 +0530 Subject: [PATCH 164/212] Shortened variable names --- arrayfire/signal.py | 58 ++++++++++++++++---------------- arrayfire/tests/simple/signal.py | 4 +-- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/arrayfire/signal.py b/arrayfire/signal.py index a0c90e410..ca27d21c2 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -27,7 +27,7 @@ def _scale_pos_axis1(y_curr, y_orig): dy = y_orig[0, 1, 0, 0] - y0 return((y_curr - y0) / dy) -def approx1(signal, x_interpolated, method=INTERP.LINEAR, off_grid=0.0, x_input = None): +def approx1(signal, x, method=INTERP.LINEAR, off_grid=0.0, xp = None): """ Interpolate along a single dimension.Interpolation is performed along axis 0 of the input array. @@ -38,9 +38,9 @@ def approx1(signal, x_interpolated, method=INTERP.LINEAR, off_grid=0.0, x_input signal: af.Array Input signal array (signal = f(x)) - x_interpolated : af.Array - The x-coordinates of the interpolation points. The interpolation - function is queried at these set of points. + x: af.Array + The x-coordinates of the interpolation points. The interpolation + function is queried at these set of points. method: optional: af.INTERP. default: af.INTERP.LINEAR. Interpolation method. @@ -48,8 +48,8 @@ def approx1(signal, x_interpolated, method=INTERP.LINEAR, off_grid=0.0, x_input off_grid: optional: scalar. default: 0.0. The value used for positions outside the range. - x_input : af.Array - The x-coordinates of the input data points + xp : af.Array + The x-coordinates of the input data points Returns ------- @@ -67,17 +67,17 @@ def approx1(signal, x_interpolated, method=INTERP.LINEAR, off_grid=0.0, x_input output = Array() - if(x_input is not None): - pos0 = _scale_pos_axis0(x_interpolated, x_input) + if(xp is not None): + pos0 = _scale_pos_axis0(x, xp) else: - pos0 = x_interpolated + pos0 = x safe_call(backend.get().af_approx1(c_pointer(output.arr), signal.arr, pos0.arr, method.value, c_float_t(off_grid))) return output -def approx2(signal, x_interpolated, y_interpolated, - method=INTERP.LINEAR, off_grid=0.0, x_input = None, y_input = None +def approx2(signal, x, y, + method=INTERP.LINEAR, off_grid=0.0, xp = None, yp = None ): """ Interpolate along a two dimension.Interpolation is performed along axes 0 and 1 @@ -89,14 +89,14 @@ def approx2(signal, x_interpolated, y_interpolated, signal: af.Array Input signal array (signal = f(x, y)) - x_interpolated : af.Array - The x-coordinates of the interpolation points. The interpolation - function is queried at these set of points. + x : af.Array + The x-coordinates of the interpolation points. The interpolation + function is queried at these set of points. - y_interpolated : af.Array - The y-coordinates of the interpolation points. The interpolation - function is queried at these set of points. + y : af.Array + The y-coordinates of the interpolation points. The interpolation + function is queried at these set of points. method: optional: af.INTERP. default: af.INTERP.LINEAR. Interpolation method. @@ -104,13 +104,13 @@ def approx2(signal, x_interpolated, y_interpolated, off_grid: optional: scalar. default: 0.0. The value used for positions outside the range. - x_input : af.Array - The x-coordinates of the input data points. The convention followed is that - the x-coordinates vary along axis 0 + xp : af.Array + The x-coordinates of the input data points. The convention followed is that + the x-coordinates vary along axis 0 - y_input : af.Array - The y-coordinates of the input data points. The convention followed is that - the y-coordinates vary along axis 1 + yp : af.Array + The y-coordinates of the input data points. The convention followed is that + the y-coordinates vary along axis 1 Returns ------- @@ -129,15 +129,15 @@ def approx2(signal, x_interpolated, y_interpolated, output = Array() - if(x_input is not None): - pos0 = _scale_pos_axis0(x_interpolated, x_input) + if(xp is not None): + pos0 = _scale_pos_axis0(x, xp) else: - pos0 = x_interpolated + pos0 = x - if(y_input is not None): - pos1 = _scale_pos_axis1(y_interpolated, y_input) + if(yp is not None): + pos1 = _scale_pos_axis1(y, yp) else: - pos1 = y_interpolated + pos1 = y safe_call(backend.get().af_approx2(c_pointer(output.arr), signal.arr, pos0.arr, pos1.arr, method.value, c_float_t(off_grid))) diff --git a/arrayfire/tests/simple/signal.py b/arrayfire/tests/simple/signal.py index 030ae046e..fa8036dc2 100644 --- a/arrayfire/tests/simple/signal.py +++ b/arrayfire/tests/simple/signal.py @@ -18,7 +18,7 @@ def simple_signal(verbose=False): signal = af.randu(10) x_new = af.randu(10) x_orig = af.randu(10) - display_func(af.approx1(signal, x_new, x_input = x_orig)) + display_func(af.approx1(signal, x_new, xp = x_orig)) signal = af.randu(3, 3) x_new = af.randu(3, 3) @@ -26,7 +26,7 @@ def simple_signal(verbose=False): y_new = af.randu(3, 3) y_orig = af.randu(3, 3) - display_func(af.approx2(signal, x_new, y_new, x_input = x_orig, y_input = y_orig)) + display_func(af.approx2(signal, x_new, y_new, xp = x_orig, yp = y_orig)) a = af.randu(8, 1) display_func(a) From 98e39b38ca1a287c7505c3ad950fa3e742ee4133 Mon Sep 17 00:00:00 2001 From: Tomer Diament Date: Wed, 29 Nov 2017 16:41:03 +0200 Subject: [PATCH 165/212] fix af_sift call --- arrayfire/vision.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arrayfire/vision.py b/arrayfire/vision.py index bd4eeccac..796dec9de 100644 --- a/arrayfire/vision.py +++ b/arrayfire/vision.py @@ -345,9 +345,9 @@ def sift(image, num_layers=3, contrast_threshold=0.04, edge_threshold=10.0, init feat = Features() desc = Array() - safe_call(af_sift(c_pointer(feat), c_pointer(desc), - image.arr, num_layers, contrast_threshold, edge_threshold, - initial_sigma, double_input, intensity_scale, feature_ratio)) + safe_call(backend.get().af_sift(c_pointer(feat.feat), c_pointer(desc.arr), + image.arr, num_layers, c_float_t(contrast_threshold), c_float_t(edge_threshold), + c_float_t(initial_sigma), double_input, c_float_t(intensity_scale), c_float_t(feature_ratio))) return (feat, desc) From a9031fb5e0db371bc88c958f0b8d43efd7fe8f45 Mon Sep 17 00:00:00 2001 From: Tomer Diament Date: Mon, 25 Dec 2017 10:20:56 +0200 Subject: [PATCH 166/212] vision.py fixes * fix af_sift call * fix vision.gloh call * fix vision.orb call * call af_release_features on features __del__ --- arrayfire/features.py | 8 ++++++++ arrayfire/vision.py | 10 ++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/arrayfire/features.py b/arrayfire/features.py index efb24898e..2f76a97eb 100644 --- a/arrayfire/features.py +++ b/arrayfire/features.py @@ -32,6 +32,14 @@ def __init__(self, num=0): assert(isinstance(num, numbers.Number)) safe_call(backend.get().af_create_features(c_pointer(self.feat), c_dim_t(num))) + def __del__(self): + """ + Release features' memory + """ + if self.feat: + backend.get().af_release_features(self.feat) + self.feat = None + def num_features(self): """ Returns the number of features detected. diff --git a/arrayfire/vision.py b/arrayfire/vision.py index 796dec9de..49cdc8fd8 100644 --- a/arrayfire/vision.py +++ b/arrayfire/vision.py @@ -131,7 +131,7 @@ def orb(image, threshold=20.0, max_features=400, scale = 1.5, num_levels = 4, bl """ feat = Features() desc = Array() - safe_call(backend.get().af_orb(c_pointer(feat.feat), c_pointer(desc.arr), + safe_call(backend.get().af_orb(c_pointer(feat.feat), c_pointer(desc.arr), image.arr, c_float_t(threshold), c_uint_t(max_features), c_float_t(scale), c_uint_t(num_levels), blur_image)) return feat, desc @@ -391,9 +391,11 @@ def gloh(image, num_layers=3, contrast_threshold=0.04, edge_threshold=10.0, init feat = Features() desc = Array() - safe_call(af_gloh(c_pointer(feat), c_pointer(desc), - image.arr, num_layers, contrast_threshold, edge_threshold, - initial_sigma, double_input, intensity_scale, feature_ratio)) + safe_call(backend.get().af_gloh(c_pointer(feat.feat), c_pointer(desc.arr), + image.arr, num_layers, c_float_t(contrast_threshold), + c_float_t(edge_threshold), c_float_t(initial_sigma), + double_input, c_float_t(intensity_scale), + c_float_t(feature_ratio))) return (feat, desc) From 6c9a4dbaf358ad41a9c8f77f435eb2fbecc45dcf Mon Sep 17 00:00:00 2001 From: Shyam Sundar Sankaran Date: Tue, 9 Jan 2018 22:56:02 +0530 Subject: [PATCH 167/212] Added len() method --- arrayfire/array.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index a8aabe656..76afece01 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -631,6 +631,9 @@ def elements(self): safe_call(backend.get().af_get_elements(c_pointer(num), self.arr)) return num.value + def __len__(self): + return(self.elements()) + def allocated(self): """ Returns the number of bytes allocated by the memory manager for the array. From a9100392c2717d40ae92d23bc3d7aee2d02eb602 Mon Sep 17 00:00:00 2001 From: Matus Krajnak Date: Fri, 13 Apr 2018 14:41:01 +1000 Subject: [PATCH 168/212] Update arith.py Add missing python code for modulus function af.mod() --- arrayfire/arith.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arrayfire/arith.py b/arrayfire/arith.py index 70c2e5471..4c40597d3 100644 --- a/arrayfire/arith.py +++ b/arrayfire/arith.py @@ -164,6 +164,26 @@ def clamp(val, low, high): return out +def mod(lhs, rhs): + """ + Find the modulus. + Parameters + ---------- + lhs : af.Array or scalar + Multi dimensional arrayfire array or a scalar number. + rhs : af.Array or scalar + Multi dimensional arrayfire array or a scalar number. + Returns + -------- + out : af.Array + Contains the moduli after dividing each value of lhs` with those in `rhs`. + Note + ------- + - Atleast one of `lhs` and `rhs` needs to be af.Array. + - If `lhs` and `rhs` are both af.Array, they must be of same size. + """ + return _arith_binary_func(lhs, rhs, backend.get().af_mod) + def rem(lhs, rhs): """ Find the remainder. From 3d3fdab4b7a5f41bff735b80d7e62f6958d62bc9 Mon Sep 17 00:00:00 2001 From: Shyam Sundar Sankaran Date: Wed, 8 Aug 2018 21:27:28 +0530 Subject: [PATCH 169/212] Change to documentation of af.sign --- arrayfire/arith.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrayfire/arith.py b/arrayfire/arith.py index 4c40597d3..b0d945f05 100644 --- a/arrayfire/arith.py +++ b/arrayfire/arith.py @@ -252,7 +252,7 @@ def sign(a): Returns -------- out : af.Array - array containing -1 for negative values, 1 otherwise. + array containing 1 for negative values, 0 otherwise. """ return _arith_unary_func(a, backend.get().af_sign) From 0ec6da39baef87f5ca3bfd1e0aa978c7b48c6ef8 Mon Sep 17 00:00:00 2001 From: Miguel Lloreda Date: Wed, 10 Oct 2018 08:08:39 -0500 Subject: [PATCH 170/212] Improved helloworld example to match C++ lib. --- examples/helloworld/helloworld.py | 53 ++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/examples/helloworld/helloworld.py b/examples/helloworld/helloworld.py index 37ef89500..2d76cf3ea 100755 --- a/examples/helloworld/helloworld.py +++ b/examples/helloworld/helloworld.py @@ -11,14 +11,51 @@ import arrayfire as af -# Display backend information -af.info() +try: + # Display backend information + af.info() -# Generate a uniform random array with a size of 5 elements -a = af.randu(5, 1) + print("Create a 5-by-3 matrix of random floats on the GPU\n") + A = af.randu(5, 3, 1, 1, af.Dtype.f32) + af.display(A) -# Print a and its minimum value -print(a) + print("Element-wise arithmetic\n") + B = af.sin(A) + 1.5 + af.display(B) -# Print min and max values of a -print("Minimum, Maximum: ", af.min(a), af.max(a)) + print("Negate the first three elements of second column\n") + B[0:3, 1] = B[0:3, 1] * -1 + af.display(B) + + print("Fourier transform the result\n"); + C = af.fft(B); + af.display(C); + + print("Grab last row\n"); + c = C[-1,:]; + af.display(c); + + print("Scan Test\n"); + r = af.constant(2, 16, 4, 1, 1); + af.display(r); + + print("Scan\n"); + S = af.scan(r, 0, af.BINARYOP.MUL); + af.display(S); + + print("Create 2-by-3 matrix from host data\n"); + d = [ 1, 2, 3, 4, 5, 6 ] + D = af.Array(d, (2, 3)) + af.display(D) + + print("Copy last column onto first\n"); + D[:,0] = D[:, -1] + af.display(D); + + print("Sort A and print sorted array and corresponding indices\n"); + [sorted_vals, sorted_idxs] = af.sort_index(A); + af.display(A) + af.display(sorted_vals) + af.display(sorted_idxs) +except Exception as e: + print("Error: " + str(e)) From 24ec3fbcfedf655fef20d13bfd37ce88c2977914 Mon Sep 17 00:00:00 2001 From: Miguel Lloreda Date: Wed, 10 Oct 2018 22:28:06 -0500 Subject: [PATCH 171/212] Add anisotropic_diffusion() API Added anisotropic_diffusion() support from v3.6.0 --- arrayfire/image.py | 41 +++++++++++++++++++++++++++++++++ arrayfire/library.py | 16 +++++++++++++ arrayfire/tests/simple/image.py | 2 ++ 3 files changed, 59 insertions(+) diff --git a/arrayfire/image.py b/arrayfire/image.py index 020e1444d..92c8d088b 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -1240,6 +1240,47 @@ def canny(image, c_uint_t(sobel_window), c_bool_t(is_fast))) return output +def anisotropic_diffusion(image, time_step, conductance, iterations, flux_function_type = FLUX.QUADRATIC, diffusion_kind = DIFFUSION.GRAD): + """ + Anisotropic smoothing filter. + + Parameters + ---------- + image: af.Array + The input image. + + time_step: scalar. + The time step used in solving the diffusion equation. + + conductance: + Controls conductance sensitivity in diffusion equation. + + iterations: + Number of times the diffusion step is performed. + + flux_function_type: + Type of flux function to be used. Available flux functions: + - Quadratic (af.FLUX.QUADRATIC) + - Exponential (af.FLUX.EXPONENTIAL) + + diffusion_kind: + Type of diffusion equatoin to be used. Available diffusion equations: + - Gradient diffusion equation (af.DIFFUSION.GRAD) + - Modified curvature diffusion equation (af.DIFFUSION.MCDE) + + Returns + ------- + out: af.Array + Anisotropically-smoothed output image. + + """ + out = Array() + safe_call(backend.get(). + af_anisotropic_diffusion(c_pointer(out.arr), image.arr, + c_float_t(time_step), c_float_t(conductance), c_uint_t(iterations), + flux_function_type.value, diffusion_kind.value)) + return out + def is_image_io_available(): """ Function to check if the arrayfire library was built with Image IO support. diff --git a/arrayfire/library.py b/arrayfire/library.py index 3566ac461..694f1dd3a 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -422,6 +422,22 @@ class CANNY_THRESHOLD(_Enum): MANUAL = _Enum_Type(0) AUTO_OTSU = _Enum_Type(1) +class FLUX(_Enum): + """ + Flux functions + """ + DEFAULT = _Enum_Type(0) + QUADRATIC = _Enum_Type(1) + EXPONENTIAL = _Enum_Type(2) + +class DIFFUSION(_Enum): + """ + Diffusion equations + """ + DEFAULT = _Enum_Type(0) + GRAD = _Enum_Type(1) + MCDE = _Enum_Type(2) + _VER_MAJOR_PLACEHOLDER = "__VER_MAJOR__" def _setup(): diff --git a/arrayfire/tests/simple/image.py b/arrayfire/tests/simple/image.py index 04a344c93..9c7887ebb 100644 --- a/arrayfire/tests/simple/image.py +++ b/arrayfire/tests/simple/image.py @@ -81,4 +81,6 @@ def simple_image(verbose = False): a = af.randu(10, 10) b = af.canny(a, low_threshold = 0.2, high_threshold = 0.8) + display_func(af.anisotropic_diffusion(a, 0.125, 1.0, 64, af.FLUX.QUADRATIC, af.DIFFUSION.GRAD)) + _util.tests['image'] = simple_image From 548b3216e80ba60a1fbe25b059b12cf010f1766e Mon Sep 17 00:00:00 2001 From: Miguel Lloreda Date: Tue, 9 Oct 2018 19:18:53 -0500 Subject: [PATCH 172/212] Added topk() support from v3.6.0. --- arrayfire/library.py | 8 ++++++ arrayfire/statistics.py | 37 ++++++++++++++++++++++++++++ arrayfire/tests/simple/statistics.py | 9 +++++++ 3 files changed, 54 insertions(+) diff --git a/arrayfire/library.py b/arrayfire/library.py index 694f1dd3a..0bdc2eeb9 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -438,6 +438,14 @@ class DIFFUSION(_Enum): GRAD = _Enum_Type(1) MCDE = _Enum_Type(2) +class TOPK(_Enum): + """ + Top-K ordering + """ + DEFAULT = _Enum_Type(0) + MIN = _Enum_Type(1) + MAX = _Enum_Type(2) + _VER_MAJOR_PLACEHOLDER = "__VER_MAJOR__" def _setup(): diff --git a/arrayfire/statistics.py b/arrayfire/statistics.py index e8abaea12..1e2548339 100644 --- a/arrayfire/statistics.py +++ b/arrayfire/statistics.py @@ -108,3 +108,40 @@ def corrcoef(x, y): real = real.value imag = imag.value return real if imag == 0 else real + imag * 1j + +def topk(data, k, dim=0, order=TOPK.DEFAULT): + """ + Return top k elements along a single dimension. + + Parameters + ---------- + + data: af.Array + Input array to return k elements from. + + k: scalar. default: 0 + The number of elements to return from input array. + + dim: optional: scalar. default: 0 + The dimension along which the top k elements are + extracted. Note: at the moment, topk() only supports the + extraction of values along the first dimension. + + order: optional: af.TOPK. default: af.TOPK.DEFAULT + The ordering of k extracted elements. Defaults to top k max values. + + Returns + ------- + + values: af.Array + Top k elements from input array. + indices: af.Array + Corresponding index array to top k elements. + """ + + values = Array() + indices = Array() + + safe_call(backend.get().af_topk(c_pointer(values.arr), c_pointer(indices.arr), data.arr, k, c_int_t(dim), order.value)) + + return values,indices diff --git a/arrayfire/tests/simple/statistics.py b/arrayfire/tests/simple/statistics.py index 2b9099849..d7d5a63d4 100644 --- a/arrayfire/tests/simple/statistics.py +++ b/arrayfire/tests/simple/statistics.py @@ -44,4 +44,13 @@ def simple_statistics(verbose=False): print_func(af.corrcoef(a, b)) + data = af.iota(5, 3) + k = 3 + dim = 0 + order = af.TOPK.DEFAULT # defaults to af.TOPK.MAX + assert(dim == 0) # topk currently supports first dim only + values,indices = af.topk(data, k, dim, order) + display_func(values) + display_func(indices) + _util.tests['statistics'] = simple_statistics From 6137a6f25f1407238b78e5aab7c93fd1eb0a1274 Mon Sep 17 00:00:00 2001 From: Miguel Lloreda Date: Wed, 10 Oct 2018 21:04:44 -0500 Subject: [PATCH 173/212] Documented statistics API. --- arrayfire/statistics.py | 117 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/arrayfire/statistics.py b/arrayfire/statistics.py index 1e2548339..e6b4effd0 100644 --- a/arrayfire/statistics.py +++ b/arrayfire/statistics.py @@ -15,6 +15,27 @@ from .array import * def mean(a, weights=None, dim=None): + """ + Calculate mean along a given dimension. + + Parameters + ---------- + a: af.Array + The input array. + + weights: optional: af.Array. default: None. + Array to calculate the weighted mean. Must match size of the + input array. + + dim: optional: int. default: None. + The dimension for which to obtain the mean from input data. + + Returns + ------- + output: af.Array + Array containing the mean of the input array along a given + dimension. + """ if dim is not None: out = Array() @@ -39,6 +60,31 @@ def mean(a, weights=None, dim=None): return real if imag == 0 else real + imag * 1j def var(a, isbiased=False, weights=None, dim=None): + """ + Calculate variance along a given dimension. + + Parameters + ---------- + a: af.Array + The input array. + + isbiased: optional: Boolean. default: False. + Boolean denoting population variance (false) or sample + variance (true). + + weights: optional: af.Array. default: None. + Array to calculate for the weighted mean. Must match size of + the input array. + + dim: optional: int. default: None. + The dimension for which to obtain the variance from input data. + + Returns + ------- + output: af.Array + Array containing the variance of the input array along a given + dimension. + """ if dim is not None: out = Array() @@ -63,6 +109,24 @@ def var(a, isbiased=False, weights=None, dim=None): return real if imag == 0 else real + imag * 1j def stdev(a, dim=None): + """ + Calculate standard deviation along a given dimension. + + Parameters + ---------- + a: af.Array + The input array. + + dim: optional: int. default: None. + The dimension for which to obtain the standard deviation from + input data. + + Returns + ------- + output: af.Array + Array containing the standard deviation of the input array + along a given dimension. + """ if dim is not None: out = Array() safe_call(backend.get().af_stdev(c_pointer(out.arr), a.arr, c_int_t(dim))) @@ -76,6 +140,26 @@ def stdev(a, dim=None): return real if imag == 0 else real + imag * 1j def cov(a, isbiased=False, dim=None): + """ + Calculate covariance along a given dimension. + + Parameters + ---------- + a: af.Array + The input array. + + isbiased: optional: Boolean. default: False. + Boolean denoting whether biased estimate should be taken. + + dim: optional: int. default: None. + The dimension for which to obtain the covariance from input data. + + Returns + ------- + output: af.Array + Array containing the covariance of the input array along a + given dimension. + """ if dim is not None: out = Array() safe_call(backend.get().af_cov(c_pointer(out.arr), a.arr, isbiased, c_int_t(dim))) @@ -89,6 +173,23 @@ def cov(a, isbiased=False, dim=None): return real if imag == 0 else real + imag * 1j def median(a, dim=None): + """ + Calculate median along a given dimension. + + Parameters + ---------- + a: af.Array + The input array. + + dim: optional: int. default: None. + The dimension for which to obtain the median from input data. + + Returns + ------- + output: af.Array + Array containing the median of the input array along a + given dimension. + """ if dim is not None: out = Array() safe_call(backend.get().af_median(c_pointer(out.arr), a.arr, c_int_t(dim))) @@ -102,6 +203,22 @@ def median(a, dim=None): return real if imag == 0 else real + imag * 1j def corrcoef(x, y): + """ + Calculate the correlation coefficient of the input arrays. + + Parameters + ---------- + x: af.Array + The first input array. + + y: af.Array + The second input array. + + Returns + ------- + output: af.Array + Array containing the correlation coefficient of the input arrays. + """ real = c_double_t(0) imag = c_double_t(0) safe_call(backend.get().af_corrcoef(c_pointer(real), c_pointer(imag), x.arr, y.arr)) From c9cac8c6f3d72b386910b007ebbf765ead2daa3f Mon Sep 17 00:00:00 2001 From: Miguel Lloreda Date: Wed, 17 Oct 2018 13:23:46 -0500 Subject: [PATCH 174/212] Updating release version number to 3.6.20181017. --- CHANGELOG.md | 13 +++++++++++++ README.md | 8 -------- setup.py | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1278c87aa..77ddf3024 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +### v3.6.20181017 +- Feature parity with ArrayFire v3.6. Refer to the [release notes](https://github.com/arrayfire/arrayfire/blob/master/docs/pages/release_notes.md) for more information regarding upstream library improvements in v3.6. + - `anisotropic_diffusion()`: Anisotropic diffusion filter. + - `topk()`: Returns top-K elements given an array. +- Bug fixes: + - Fixed `sift()` and `gloh()`, which were improperly calling the library. +- Enhancements: + - Added `len()` method, which returns `array.elements()`. +- Documentation: + - Documented statistics API. + - Corrected `sign()` documentation. + - Modified `helloworld` example to match C++ lib. + ### v3.5.20170721 - Bug fixes when using v3.5 of arrayfire libs + graphics diff --git a/README.md b/README.md index ad170f0f5..2d3f8c05a 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,6 @@ [ArrayFire](https://github.com/arrayfire/arrayfire) is a high performance library for parallel computing with an easy-to-use API. It enables users to write scientific computing code that is portable across CUDA, OpenCL and CPU devices. This project provides Python bindings for the ArrayFire library. -## Status -| OS | Tests | -|:-------:|:-------:| -| Linux | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-linux)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-linux/) | -| Windows | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-windows)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-windows/) | -| OSX | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-osx)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-osx/) | -| Linux on ARM | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/python-tegrax1)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/python-tegrak1/)| - ## Documentation Documentation for this project can be found [over here](http://arrayfire.org/arrayfire-python/). diff --git a/setup.py b/setup.py index 528353709..92900cc90 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ author="Pavan Yalamanchili", author_email="contact@pavanky.com", name="arrayfire", - version="3.6.0", + version="3.6.20181017", description="Python bindings for ArrayFire", license="BSD", url="http://arrayfire.com", From 988f432b287421f7075e24258bb33472aabc807b Mon Sep 17 00:00:00 2001 From: Miguel Lloreda Date: Mon, 22 Oct 2018 09:13:58 -0500 Subject: [PATCH 175/212] Fixed issue with create_sparse_from_host - (issue #189). Casted row and column index arrays to be of s32 type prior to passing in to lib call. Previously failing due to failing assertions. --- arrayfire/sparse.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arrayfire/sparse.py b/arrayfire/sparse.py index b261bdbd8..91b8f7a23 100644 --- a/arrayfire/sparse.py +++ b/arrayfire/sparse.py @@ -90,7 +90,10 @@ def create_sparse_from_host(values, row_idx, col_idx, nrows, ncols, storage = ST A sparse matrix. """ - return create_sparse(to_array(values), to_array(row_idx), to_array(col_idx), nrows, ncols, storage) + return create_sparse(to_array(values), + to_array(row_idx).as_type(Dtype.s32), + to_array(col_idx).as_type(Dtype.s32), + nrows, ncols, storage) def create_sparse_from_dense(dense, storage = STORAGE.CSR): """ From 9cea077468b5ca15751ca25f6dd23a3e7265a55e Mon Sep 17 00:00:00 2001 From: Umar Arshad Date: Sun, 23 Dec 2018 23:25:03 -0500 Subject: [PATCH 176/212] Workaround failure in bench_cg. Evaluate x array early --- examples/benchmarks/bench_cg.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/benchmarks/bench_cg.py b/examples/benchmarks/bench_cg.py index 8a74f25a9..33c5b856c 100644 --- a/examples/benchmarks/bench_cg.py +++ b/examples/benchmarks/bench_cg.py @@ -80,6 +80,7 @@ def calc_arrayfire(A, b, x0, maxiter=10): beta_num = af.dot(r, r) beta = beta_num/alpha_num p = r + af.tile(beta, p.dims()[0]) * p + af.eval(x) res = x0 - x return x, af.dot(res, res) @@ -137,11 +138,11 @@ def timeit(calc, iters, args): def test(): print("\nTesting benchmark functions...") - A, b, x0 = setup_input(50) # dense A + A, b, x0 = setup_input(n=50, sparsity=7) # dense A Asp = to_sparse(A) x1, _ = calc_arrayfire(A, b, x0) x2, _ = calc_arrayfire(Asp, b, x0) - if af.sum(af.abs(x1 - x2)/x2 > 1e-6): + if af.sum(af.abs(x1 - x2)/x2 > 1e-5): raise ValueError("arrayfire test failed") if np: An = to_numpy(A) @@ -162,11 +163,13 @@ def test(): def bench(n=4*1024, sparsity=7, maxiter=10, iters=10): + # generate data print("\nGenerating benchmark data for n = %i ..." %n) A, b, x0 = setup_input(n, sparsity) # dense A Asp = to_sparse(A) # sparse A input_info(A, Asp) + # make benchmarks print("Benchmarking CG solver for n = %i ..." %n) t1 = timeit(calc_arrayfire, iters, args=(A, b, x0, maxiter)) @@ -192,9 +195,8 @@ def bench(n=4*1024, sparsity=7, maxiter=10, iters=10): if (len(sys.argv) > 1): af.set_device(int(sys.argv[1])) - af.info() - + af.info() test() - + for n in (128, 256, 512, 1024, 2048, 4096): bench(n) From 2a48a39f0cb936af3d6e8de96b55fccd14cabba2 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Tue, 20 Aug 2019 01:43:30 -0700 Subject: [PATCH 177/212] Fix a documentation issue --- arrayfire/array.py | 1 + 1 file changed, 1 insertion(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index 76afece01..801cd502b 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -563,6 +563,7 @@ def device_ptr(self): Note ---- - This can be used to integrate with custom C code and / or PyCUDA or PyOpenCL. + - Implies `af.device.lock_array()`. The device pointer of `a` is not freed by memory manager until `unlock_device_ptr()` is called. - No other arrays will share the same device pointer. - A copy of the memory is done if multiple arrays share the same memory or the array is not the owner of the memory. - In case of a copy the return value points to the newly allocated memory which is now exclusively owned by the array. From 632cb8f102f4aea2b534bf8b42e53906214c7120 Mon Sep 17 00:00:00 2001 From: Anton Chernyatevich Date: Wed, 4 Sep 2019 03:47:55 +0300 Subject: [PATCH 178/212] Move tests to root dir. Minor setup refactoring --- arrayfire/tests/simple/__init__.py | 24 ------- arrayfire/tests/simple_tests.py | 27 ------- setup.cfg | 27 +++++++ setup.py | 19 ++--- {arrayfire/tests => tests}/__init__.py | 2 + {arrayfire/tests => tests}/__main__.py | 23 +++--- tests/simple/__init__.py | 44 ++++++++++++ {arrayfire/tests => tests}/simple/_util.py | 23 +++--- .../tests => tests}/simple/algorithm.py | 35 ++++----- {arrayfire/tests => tests}/simple/arith.py | 34 ++++----- .../tests => tests}/simple/array_test.py | 20 +++--- {arrayfire/tests => tests}/simple/blas.py | 23 +++--- {arrayfire/tests => tests}/simple/data.py | 28 ++++---- {arrayfire/tests => tests}/simple/device.py | 22 +++--- {arrayfire/tests => tests}/simple/image.py | 25 ++++--- {arrayfire/tests => tests}/simple/index.py | 46 ++++++------ {arrayfire/tests => tests}/simple/interop.py | 71 ++++++++++--------- {arrayfire/tests => tests}/simple/lapack.py | 31 ++++---- {arrayfire/tests => tests}/simple/random.py | 9 ++- {arrayfire/tests => tests}/simple/signal.py | 20 +++--- {arrayfire/tests => tests}/simple/sparse.py | 10 ++- .../tests => tests}/simple/statistics.py | 16 +++-- 22 files changed, 322 insertions(+), 257 deletions(-) delete mode 100644 arrayfire/tests/simple/__init__.py delete mode 100755 arrayfire/tests/simple_tests.py create mode 100644 setup.cfg rename {arrayfire/tests => tests}/__init__.py (93%) rename {arrayfire/tests => tests}/__main__.py (75%) create mode 100644 tests/simple/__init__.py rename {arrayfire/tests => tests}/simple/_util.py (88%) rename {arrayfire/tests => tests}/simple/algorithm.py (74%) rename {arrayfire/tests => tests}/simple/arith.py (89%) rename {arrayfire/tests => tests}/simple/array_test.py (88%) rename {arrayfire/tests => tests}/simple/blas.py (56%) rename {arrayfire/tests => tests}/simple/data.py (72%) rename {arrayfire/tests => tests}/simple/device.py (79%) rename {arrayfire/tests => tests}/simple/image.py (84%) rename {arrayfire/tests => tests}/simple/index.py (69%) rename {arrayfire/tests => tests}/simple/interop.py (68%) rename {arrayfire/tests => tests}/simple/lapack.py (78%) rename {arrayfire/tests => tests}/simple/random.py (91%) rename {arrayfire/tests => tests}/simple/signal.py (89%) rename {arrayfire/tests => tests}/simple/sparse.py (88%) rename {arrayfire/tests => tests}/simple/statistics.py (82%) diff --git a/arrayfire/tests/simple/__init__.py b/arrayfire/tests/simple/__init__.py deleted file mode 100644 index 26ed88961..000000000 --- a/arrayfire/tests/simple/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -####################################################### -# Copyright (c) 2015, ArrayFire -# All rights reserved. -# -# This file is distributed under 3-clause BSD license. -# The complete license agreement can be obtained at: -# http://arrayfire.com/licenses/BSD-3-Clause -######################################################## - -from .algorithm import * -from .arith import * -from .array_test import * -from .blas import * -from .data import * -from .device import * -from .image import * -from .index import * -from .interop import * -from .lapack import * -from .signal import * -from .statistics import * -from .random import * -from .sparse import * -from ._util import tests diff --git a/arrayfire/tests/simple_tests.py b/arrayfire/tests/simple_tests.py deleted file mode 100755 index 603ae9f37..000000000 --- a/arrayfire/tests/simple_tests.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/python - -####################################################### -# Copyright (c) 2015, ArrayFire -# All rights reserved. -# -# This file is distributed under 3-clause BSD license. -# The complete license agreement can be obtained at: -# http://arrayfire.com/licenses/BSD-3-Clause -######################################################## - -from __future__ import absolute_import - -from . import simple -import sys - -if __name__ == "__main__": - verbose = False - - if len(sys.argv) > 1: - verbose = int(sys.argv[1]) - - test_list = None - if len(sys.argv) > 2: - test_list = sys.argv[2:] - - simple.tests.run(test_list, verbose) diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 000000000..6b0fb031d --- /dev/null +++ b/setup.cfg @@ -0,0 +1,27 @@ +[metadata] +name = arrayfire +version = 3.6.20181017 +description = Python bindings for ArrayFire +licence = BSD +long_description = file: README.md +maintainer = Pavan Yalamanchili +maintainer_email = contact@pavanky.com +url = http://arrayfire.com +classifiers = + Programming Language :: Python + Programming Language :: Python :: 2.7 + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.6 + +[options] +packages = find: + +[options.packages.find] +exclude = + examples + tests + +[flake8] +application-import-names = arrayfire +import-order-style = pep8 +max-line-length = 119 diff --git a/setup.py b/setup.py index 92900cc90..e4d485c30 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### # Copyright (c) 2015, ArrayFire @@ -9,19 +9,8 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -from setuptools import setup, find_packages -#from __af_version__ import full_version +# TODO: Look for af libraries during setup -#TODO: -#1) Look for af libraries during setup +from setuptools import setup -setup( - author="Pavan Yalamanchili", - author_email="contact@pavanky.com", - name="arrayfire", - version="3.6.20181017", - description="Python bindings for ArrayFire", - license="BSD", - url="http://arrayfire.com", - packages=find_packages() -) +setup() diff --git a/arrayfire/tests/__init__.py b/tests/__init__.py similarity index 93% rename from arrayfire/tests/__init__.py rename to tests/__init__.py index be7669881..24e9ac759 100644 --- a/arrayfire/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. diff --git a/arrayfire/tests/__main__.py b/tests/__main__.py similarity index 75% rename from arrayfire/tests/__main__.py rename to tests/__main__.py index 468396566..6bed94278 100644 --- a/arrayfire/tests/__main__.py +++ b/tests/__main__.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -10,35 +12,38 @@ from __future__ import absolute_import import sys -from .simple_tests import * + +from . import simple tests = {} tests['simple'] = simple.tests + def assert_valid(name, name_list, name_str): is_valid = any([name == val for val in name_list]) - if not is_valid: - err_str = "The first argument needs to be a %s name\n" % name_str - err_str += "List of supported %ss: %s" % (name_str, str(list(name_list))) - raise RuntimeError(err_str) + if is_valid: + return + err_str = "The first argument needs to be a %s name\n" % name_str + err_str += "List of supported %ss: %s" % (name_str, str(list(name_list))) + raise RuntimeError(err_str) -if __name__ == "__main__": +if __name__ == "__main__": module_name = None num_args = len(sys.argv) - if (num_args > 1): + if num_args > 1: module_name = sys.argv[1].lower() assert_valid(sys.argv[1].lower(), tests.keys(), "module") - if (module_name is None): + if module_name is None: for name in tests: tests[name].run() else: test = tests[module_name] test_list = None - if (num_args > 2): + if num_args > 2: test_list = sys.argv[2:] for test_name in test_list: assert_valid(test_name.lower(), test.keys(), "test") diff --git a/tests/simple/__init__.py b/tests/simple/__init__.py new file mode 100644 index 000000000..4950136e3 --- /dev/null +++ b/tests/simple/__init__.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +####################################################### +# Copyright (c) 2015, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +from ._util import tests +from .algorithm import simple_algorithm +from .arith import simple_arith +from .array_test import simple_array +from .blas import simple_blas +from .data import simple_data +from .device import simple_device +from .image import simple_image +from .index import simple_index +from .interop import simple_interop +from .lapack import simple_lapack +from .random import simple_random +from .signal import simple_signal +from .sparse import simple_sparse +from .statistics import simple_statistics + +__all__ = [ + "tests", + "simple_algorithm", + "simple_arith", + "simple_array", + "simple_blas", + "simple_data", + "simple_device", + "simple_image", + "simple_index", + "simple_interop", + "simple_lapack", + "simple_random", + "simple_signal", + "simple_sparse", + "simple_statistics" +] diff --git a/arrayfire/tests/simple/_util.py b/tests/simple/_util.py similarity index 88% rename from arrayfire/tests/simple/_util.py rename to tests/simple/_util.py index cda7c84a8..2275cf2fc 100644 --- a/arrayfire/tests/simple/_util.py +++ b/tests/simple/_util.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -6,13 +8,13 @@ # The complete license agreement can be obtained at: # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -import traceback + import logging -import arrayfire as af import sys +import traceback -class _simple_test_dict(dict): +class _simple_test_dict(dict): def __init__(self): self.print_str = "Simple %16s: %s" self.failed = False @@ -21,7 +23,7 @@ def __init__(self): def run(self, name_list=None, verbose=False): test_list = name_list if name_list is not None else self.keys() for key in test_list: - self.print_log = '' + self.print_log = "" try: test = self[key] except KeyError: @@ -31,27 +33,30 @@ def run(self, name_list=None, verbose=False): try: test(verbose) print(self.print_str % (key, "PASSED")) - except Exception as e: + except Exception: print(self.print_str % (key, "FAILED")) self.failed = True - if (not verbose): + if not verbose: print(tests.print_log) logging.error(traceback.format_exc()) - if (self.failed): + if self.failed: sys.exit(1) + tests = _simple_test_dict() + def print_func(verbose): def print_func_impl(*args): - _print_log = '' + _print_log = "" for arg in args: _print_log += str(arg) + '\n' - if (verbose): + if verbose: print(_print_log) tests.print_log += _print_log return print_func_impl + def display_func(verbose): return print_func(verbose) diff --git a/arrayfire/tests/simple/algorithm.py b/tests/simple/algorithm.py similarity index 74% rename from arrayfire/tests/simple/algorithm.py rename to tests/simple/algorithm.py index 5528da3b0..5b40d6916 100644 --- a/arrayfire/tests/simple/algorithm.py +++ b/tests/simple/algorithm.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -9,18 +10,19 @@ ######################################################## import arrayfire as af + from . import _util -def simple_algorithm(verbose = False): + +def simple_algorithm(verbose=False): display_func = _util.display_func(verbose) - print_func = _util.print_func(verbose) + print_func = _util.print_func(verbose) a = af.randu(3, 3) k = af.constant(1, 3, 3, dtype=af.Dtype.u32) af.eval(k) - print_func(af.sum(a), af.product(a), af.min(a), af.max(a), - af.count(a), af.any_true(a), af.all_true(a)) + print_func(af.sum(a), af.product(a), af.min(a), af.max(a), af.count(a), af.any_true(a), af.all_true(a)) display_func(af.sum(a, 0)) display_func(af.sum(a, 1)) @@ -58,27 +60,27 @@ def simple_algorithm(verbose = False): b = (a > 0.1) * a c = (a > 0.4) * a d = b / c - print_func(af.sum(d)); - print_func(af.sum(d, nan_val=0.0)); - display_func(af.sum(d, dim=0, nan_val=0.0)); + print_func(af.sum(d)) + print_func(af.sum(d, nan_val=0.0)) + display_func(af.sum(d, dim=0, nan_val=0.0)) - val,idx = af.sort_index(a, is_ascending=True) + val, idx = af.sort_index(a, is_ascending=True) display_func(val) display_func(idx) - val,idx = af.sort_index(a, is_ascending=False) + val, idx = af.sort_index(a, is_ascending=False) display_func(val) display_func(idx) - b = af.randu(3,3) - keys,vals = af.sort_by_key(a, b, is_ascending=True) + b = af.randu(3, 3) + keys, vals = af.sort_by_key(a, b, is_ascending=True) display_func(keys) display_func(vals) - keys,vals = af.sort_by_key(a, b, is_ascending=False) + keys, vals = af.sort_by_key(a, b, is_ascending=False) display_func(keys) display_func(vals) - c = af.randu(5,1) - d = af.randu(5,1) + c = af.randu(5, 1) + d = af.randu(5, 1) cc = af.set_unique(c, is_sorted=False) dd = af.set_unique(af.sort(d), is_sorted=True) display_func(cc) @@ -90,4 +92,5 @@ def simple_algorithm(verbose = False): display_func(af.set_intersect(cc, cc, is_unique=True)) display_func(af.set_intersect(cc, cc, is_unique=False)) -_util.tests['algorithm'] = simple_algorithm + +_util.tests["algorithm"] = simple_algorithm diff --git a/arrayfire/tests/simple/arith.py b/tests/simple/arith.py similarity index 89% rename from arrayfire/tests/simple/arith.py rename to tests/simple/arith.py index 84c291aec..306b93fff 100644 --- a/arrayfire/tests/simple/arith.py +++ b/tests/simple/arith.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -9,13 +10,14 @@ ######################################################## import arrayfire as af + from . import _util -def simple_arith(verbose = False): + +def simple_arith(verbose=False): display_func = _util.display_func(verbose) - print_func = _util.print_func(verbose) - a = af.randu(3,3) + a = af.randu(3, 3) b = af.constant(4, 3, 3) display_func(a) display_func(b) @@ -29,7 +31,6 @@ def simple_arith(verbose = False): display_func(a + 2) display_func(3 + a) - c = a - b d = a d -= b @@ -99,7 +100,7 @@ def simple_arith(verbose = False): display_func(a == 0.5) display_func(0.5 == a) - a = af.randu(3,3,dtype=af.Dtype.u32) + a = af.randu(3, 3, dtype=af.Dtype.u32) b = af.constant(4, 3, 3, dtype=af.Dtype.u32) display_func(a & b) @@ -132,17 +133,17 @@ def simple_arith(verbose = False): display_func(a) display_func(af.cast(a, af.Dtype.c32)) - display_func(af.maxof(a,b)) - display_func(af.minof(a,b)) + display_func(af.maxof(a, b)) + display_func(af.minof(a, b)) display_func(af.clamp(a, 0, 1)) display_func(af.clamp(a, 0, b)) display_func(af.clamp(a, b, 1)) - display_func(af.rem(a,b)) + display_func(af.rem(a, b)) - a = af.randu(3,3) - 0.5 - b = af.randu(3,3) - 0.5 + a = af.randu(3, 3) - 0.5 + b = af.randu(3, 3) - 0.5 display_func(af.abs(a)) display_func(af.arg(a)) @@ -161,7 +162,7 @@ def simple_arith(verbose = False): display_func(af.atan2(a, b)) c = af.cplx(a) - d = af.cplx(a,b) + d = af.cplx(a, b) display_func(c) display_func(d) display_func(af.real(d)) @@ -193,8 +194,8 @@ def simple_arith(verbose = False): display_func(af.sqrt(a)) display_func(af.cbrt(a)) - a = af.round(5 * af.randu(3,3) - 1) - b = af.round(5 * af.randu(3,3) - 1) + a = af.round(5 * af.randu(3, 3) - 1) + b = af.round(5 * af.randu(3, 3) - 1) display_func(af.factorial(a)) display_func(af.tgamma(a)) @@ -205,7 +206,7 @@ def simple_arith(verbose = False): a = af.randu(5, 1) b = af.randu(1, 5) - c = af.broadcast(lambda x,y: x+y, a, b) + c = af.broadcast(lambda x, y: x+y, a, b) display_func(a) display_func(b) display_func(c) @@ -216,4 +217,5 @@ def test_add(aa, bb): display_func(test_add(a, b)) -_util.tests['arith'] = simple_arith + +_util.tests["arith"] = simple_arith diff --git a/arrayfire/tests/simple/array_test.py b/tests/simple/array_test.py similarity index 88% rename from arrayfire/tests/simple/array_test.py rename to tests/simple/array_test.py index 0c6ab5262..b2a787940 100644 --- a/arrayfire/tests/simple/array_test.py +++ b/tests/simple/array_test.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -8,13 +9,16 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -import arrayfire as af import array as host + +import arrayfire as af + from . import _util + def simple_array(verbose=False): display_func = _util.display_func(verbose) - print_func = _util.print_func(verbose) + print_func = _util.print_func(verbose) a = af.Array([1, 2, 3]) display_func(a) @@ -30,15 +34,14 @@ def simple_array(verbose=False): print_func(a.is_complex(), a.is_real(), a.is_double(), a.is_single()) print_func(a.is_real_floating(), a.is_floating(), a.is_integer(), a.is_bool()) - - a = af.Array(host.array('i', [4, 5, 6])) + a = af.Array(host.array("i", [4, 5, 6])) display_func(a) print_func(a.elements(), a.type(), a.dims(), a.numdims()) print_func(a.is_empty(), a.is_scalar(), a.is_column(), a.is_row()) print_func(a.is_complex(), a.is_real(), a.is_double(), a.is_single()) print_func(a.is_real_floating(), a.is_floating(), a.is_integer(), a.is_bool()) - a = af.Array(host.array('I', [7, 8, 9] * 3), (3,3)) + a = af.Array(host.array("I", [7, 8, 9] * 3), (3, 3)) display_func(a) print_func(a.elements(), a.type(), a.dims(), a.numdims()) print_func(a.is_empty(), a.is_scalar(), a.is_column(), a.is_row()) @@ -49,7 +52,7 @@ def simple_array(verbose=False): for n in range(a.elements()): print_func(c[n]) - c,s = a.to_ctype(True, True) + c, s = a.to_ctype(True, True) for n in range(a.elements()): print_func(c[n]) print_func(s) @@ -62,4 +65,5 @@ def simple_array(verbose=False): print_func(a.is_sparse()) -_util.tests['array'] = simple_array + +_util.tests["array"] = simple_array diff --git a/arrayfire/tests/simple/blas.py b/tests/simple/blas.py similarity index 56% rename from arrayfire/tests/simple/blas.py rename to tests/simple/blas.py index fd58d18d9..f04049a93 100644 --- a/arrayfire/tests/simple/blas.py +++ b/tests/simple/blas.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -9,19 +10,21 @@ ######################################################## import arrayfire as af + from . import _util + def simple_blas(verbose=False): display_func = _util.display_func(verbose) - print_func = _util.print_func(verbose) - a = af.randu(5,5) - b = af.randu(5,5) + a = af.randu(5, 5) + b = af.randu(5, 5) + + display_func(af.matmul(a, b)) + display_func(af.matmul(a, b, af.MATPROP.TRANS)) + display_func(af.matmul(a, b, af.MATPROP.NONE, af.MATPROP.TRANS)) - display_func(af.matmul(a,b)) - display_func(af.matmul(a,b,af.MATPROP.TRANS)) - display_func(af.matmul(a,b,af.MATPROP.NONE, af.MATPROP.TRANS)) + b = af.randu(5, 1) + display_func(af.dot(b, b)) - b = af.randu(5,1) - display_func(af.dot(b,b)) -_util.tests['blas'] = simple_blas +_util.tests["blas"] = simple_blas diff --git a/arrayfire/tests/simple/data.py b/tests/simple/data.py similarity index 72% rename from arrayfire/tests/simple/data.py rename to tests/simple/data.py index 86b900baf..d80f9e125 100644 --- a/arrayfire/tests/simple/data.py +++ b/tests/simple/data.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -9,20 +10,21 @@ ######################################################## import arrayfire as af + from . import _util + def simple_data(verbose=False): display_func = _util.display_func(verbose) - print_func = _util.print_func(verbose) - display_func(af.constant(100, 3,3, dtype=af.Dtype.f32)) - display_func(af.constant(25, 3,3, dtype=af.Dtype.c32)) - display_func(af.constant(2**50, 3,3, dtype=af.Dtype.s64)) - display_func(af.constant(2+3j, 3,3)) - display_func(af.constant(3+5j, 3,3, dtype=af.Dtype.c32)) + display_func(af.constant(100, 3, 3, dtype=af.Dtype.f32)) + display_func(af.constant(25, 3, 3, dtype=af.Dtype.c32)) + display_func(af.constant(2**50, 3, 3, dtype=af.Dtype.s64)) + display_func(af.constant(2+3j, 3, 3)) + display_func(af.constant(3+5j, 3, 3, dtype=af.Dtype.c32)) display_func(af.range(3, 3)) - display_func(af.iota(3, 3, tile_dims=(2,2))) + display_func(af.iota(3, 3, tile_dims=(2, 2))) display_func(af.identity(3, 3, 1, 2, af.Dtype.b8)) display_func(af.identity(3, 3, dtype=af.Dtype.c32)) @@ -35,15 +37,14 @@ def simple_data(verbose=False): display_func(b) display_func(c) - display_func(af.diag(b, extract = False)) - display_func(af.diag(c, 1, extract = False)) + display_func(af.diag(b, extract=False)) + display_func(af.diag(c, 1, extract=False)) display_func(af.join(0, a, a)) display_func(af.join(1, a, a, a)) display_func(af.tile(a, 2, 2)) - display_func(af.reorder(a, 1, 0)) display_func(af.shift(a, -1, 1)) @@ -61,7 +62,7 @@ def simple_data(verbose=False): display_func(af.upper(a, False)) display_func(af.upper(a, True)) - a = af.randu(5,5) + a = af.randu(5, 5) display_func(af.transpose(a)) af.transpose_inplace(a) display_func(a) @@ -71,4 +72,5 @@ def simple_data(verbose=False): af.replace(a, a > 0.3, -0.3) display_func(a) -_util.tests['data'] = simple_data + +_util.tests["data"] = simple_data diff --git a/arrayfire/tests/simple/device.py b/tests/simple/device.py similarity index 79% rename from arrayfire/tests/simple/device.py rename to tests/simple/device.py index 279fa3168..f677c5e2a 100644 --- a/arrayfire/tests/simple/device.py +++ b/tests/simple/device.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -9,11 +10,13 @@ ######################################################## import arrayfire as af + from . import _util + def simple_device(verbose=False): display_func = _util.display_func(verbose) - print_func = _util.print_func(verbose) + print_func = _util.print_func(verbose) print_func(af.device_info()) print_func(af.get_device_count()) print_func(af.is_dbl_supported()) @@ -35,19 +38,19 @@ def simple_device(verbose=False): a = af.randu(100, 100) af.sync(dev) mem_info = af.device_mem_info() - assert(mem_info['alloc']['buffers'] == 1 + mem_info_old['alloc']['buffers']) - assert(mem_info[ 'lock']['buffers'] == 1 + mem_info_old[ 'lock']['buffers']) + assert(mem_info["alloc"]["buffers"] == 1 + mem_info_old["alloc"]["buffers"]) + assert(mem_info["lock"]["buffers"] == 1 + mem_info_old["lock"]["buffers"]) af.set_device(curr_dev) - a = af.randu(10,10) + a = af.randu(10, 10) display_func(a) dev_ptr = af.get_device_ptr(a) print_func(dev_ptr) b = af.Array(src=dev_ptr, dims=a.dims(), dtype=a.dtype(), is_device=True) display_func(b) - c = af.randu(10,10) + c = af.randu(10, 10) af.lock_array(c) af.unlock_array(c) @@ -64,10 +67,11 @@ def simple_device(verbose=False): print_func(d) print_func(af.set_manual_eval_flag(True)) - assert(af.get_manual_eval_flag() == True) + assert(af.get_manual_eval_flag()) print_func(af.set_manual_eval_flag(False)) - assert(af.get_manual_eval_flag() == False) + assert(not af.get_manual_eval_flag()) display_func(af.is_locked_array(a)) -_util.tests['device'] = simple_device + +_util.tests["device"] = simple_device diff --git a/arrayfire/tests/simple/image.py b/tests/simple/image.py similarity index 84% rename from arrayfire/tests/simple/image.py rename to tests/simple/image.py index 9c7887ebb..1489e94dc 100644 --- a/arrayfire/tests/simple/image.py +++ b/tests/simple/image.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -9,23 +10,24 @@ ######################################################## import arrayfire as af + from . import _util -def simple_image(verbose = False): + +def simple_image(verbose=False): display_func = _util.display_func(verbose) - print_func = _util.print_func(verbose) a = 10 * af.randu(6, 6) - a3 = 10 * af.randu(5,5,3) + a3 = 10 * af.randu(5, 5, 3) - dx,dy = af.gradient(a) + dx, dy = af.gradient(a) display_func(dx) display_func(dy) display_func(af.resize(a, scale=0.5)) display_func(af.resize(a, odim0=8, odim1=8)) - t = af.randu(3,2) + t = af.randu(3, 2) display_func(af.transform(a, t)) display_func(af.rotate(a, 3.14)) display_func(af.translate(a, 1, 1)) @@ -50,7 +52,7 @@ def simple_image(verbose = False): display_func(af.regions(af.round(a) > 3)) - dx,dy = af.sobel_derivatives(a) + dx, dy = af.sobel_derivatives(a) display_func(dx) display_func(dy) display_func(af.sobel_filter(a)) @@ -66,7 +68,7 @@ def simple_image(verbose = False): display_func(af.color_space(a, af.CSPACE.RGB, af.CSPACE.GRAY)) - a = af.randu(6,6) + a = af.randu(6, 6) b = af.unwrap(a, 2, 2, 2, 2) c = af.wrap(b, 6, 6, 2, 2, 2, 2) display_func(a) @@ -74,13 +76,14 @@ def simple_image(verbose = False): display_func(c) display_func(af.sat(a)) - a = af.randu(10,10,3) + a = af.randu(10, 10, 3) display_func(af.rgb2ycbcr(a)) display_func(af.ycbcr2rgb(a)) a = af.randu(10, 10) - b = af.canny(a, low_threshold = 0.2, high_threshold = 0.8) + b = af.canny(a, low_threshold=0.2, high_threshold=0.8) display_func(af.anisotropic_diffusion(a, 0.125, 1.0, 64, af.FLUX.QUADRATIC, af.DIFFUSION.GRAD)) -_util.tests['image'] = simple_image + +_util.tests["image"] = simple_image diff --git a/arrayfire/tests/simple/index.py b/tests/simple/index.py similarity index 69% rename from arrayfire/tests/simple/index.py rename to tests/simple/index.py index 7ebde6eb3..a0b0cc757 100644 --- a/arrayfire/tests/simple/index.py +++ b/tests/simple/index.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -7,14 +8,17 @@ # The complete license agreement can be obtained at: # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## + +import array as host + import arrayfire as af from arrayfire import ParallelRange -import array as host + from . import _util + def simple_index(verbose=False): display_func = _util.display_func(verbose) - print_func = _util.print_func(verbose) a = af.randu(5, 5) display_func(a) b = af.Array(a) @@ -22,16 +26,16 @@ def simple_index(verbose=False): c = a.copy() display_func(c) - display_func(a[0,0]) + display_func(a[0, 0]) display_func(a[0]) display_func(a[:]) - display_func(a[:,:]) - display_func(a[0:3,]) - display_func(a[-2:-1,-1]) + display_func(a[:, :]) + display_func(a[0:3, ]) + display_func(a[-2:-1, -1]) display_func(a[0:5]) display_func(a[0:5:2]) - idx = af.Array(host.array('i', [0, 3, 2])) + idx = af.Array(host.array("i", [0, 3, 2])) display_func(idx) aa = a[idx] display_func(aa) @@ -40,42 +44,42 @@ def simple_index(verbose=False): display_func(a) a[0] = af.randu(1, 5) display_func(a) - a[:] = af.randu(5,5) + a[:] = af.randu(5, 5) display_func(a) - a[:,-1] = af.randu(5,1) + a[:, -1] = af.randu(5, 1) display_func(a) a[0:5:2] = af.randu(3, 5) display_func(a) - a[idx, idx] = af.randu(3,3) + a[idx, idx] = af.randu(3, 3) display_func(a) - - a = af.randu(5,1) - b = af.randu(5,1) + a = af.randu(5, 1) + b = af.randu(5, 1) display_func(a) display_func(b) - for ii in ParallelRange(1,3): + for ii in ParallelRange(1, 3): a[ii] = b[ii] display_func(a) - for ii in ParallelRange(2,5): + for ii in ParallelRange(2, 5): b[ii] = 2 display_func(b) - a = af.randu(3,2) + a = af.randu(3, 2) rows = af.constant(0, 1, dtype=af.Dtype.s32) - b = a[:,rows] + b = a[:, rows] display_func(b) for r in rows: display_func(r) - display_func(b[:,r]) + display_func(b[:, r]) a = af.randu(3) c = af.randu(3) - b = af.constant(1,3,dtype=af.Dtype.b8) + b = af.constant(1, 3, dtype=af.Dtype.b8) display_func(a) a[b] = c display_func(a) -_util.tests['index'] = simple_index + +_util.tests["index"] = simple_index diff --git a/arrayfire/tests/simple/interop.py b/tests/simple/interop.py similarity index 68% rename from arrayfire/tests/simple/interop.py rename to tests/simple/interop.py index ee924c6fa..f07e6a770 100644 --- a/arrayfire/tests/simple/interop.py +++ b/tests/simple/interop.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -9,72 +10,73 @@ ######################################################## import arrayfire as af + from . import _util -def simple_interop(verbose = False): + +def simple_interop(verbose=False): if af.AF_NUMPY_FOUND: import numpy as np n = np.random.random((5,)) a = af.to_array(n) n2 = np.array(a) - assert((n==n2).all()) + assert((n == n2).all()) n2[:] = 0 a.to_ndarray(n2) - assert((n==n2).all()) + assert((n == n2).all()) - n = np.random.random((5,3)) + n = np.random.random((5, 3)) a = af.to_array(n) n2 = np.array(a) - assert((n==n2).all()) + assert((n == n2).all()) n2[:] = 0 a.to_ndarray(n2) - assert((n==n2).all()) + assert((n == n2).all()) - n = np.random.random((5,3,2)) + n = np.random.random((5, 3, 2)) a = af.to_array(n) n2 = np.array(a) - assert((n==n2).all()) + assert((n == n2).all()) n2[:] = 0 a.to_ndarray(n2) - assert((n==n2).all()) + assert((n == n2).all()) - n = np.random.random((5,3,2,2)) + n = np.random.random((5, 3, 2, 2)) a = af.to_array(n) n2 = np.array(a) - assert((n==n2).all()) + assert((n == n2).all()) n2[:] = 0 a.to_ndarray(n2) - assert((n==n2).all()) + assert((n == n2).all()) - if af.AF_PYCUDA_FOUND and af.get_active_backend() == 'cuda': - import pycuda.autoinit + if af.AF_PYCUDA_FOUND and af.get_active_backend() == "cuda": import pycuda.gpuarray as cudaArray n = np.random.random((5,)) c = cudaArray.to_gpu(n) a = af.to_array(c) n2 = np.array(a) - assert((n==n2).all()) + assert((n == n2).all()) - n = np.random.random((5,3)) + n = np.random.random((5, 3)) c = cudaArray.to_gpu(n) a = af.to_array(c) n2 = np.array(a) - assert((n==n2).all()) + assert((n == n2).all()) - n = np.random.random((5,3,2)) + n = np.random.random((5, 3, 2)) c = cudaArray.to_gpu(n) a = af.to_array(c) n2 = np.array(a) - assert((n==n2).all()) + assert((n == n2).all()) - n = np.random.random((5,3,2,2)) + n = np.random.random((5, 3, 2, 2)) c = cudaArray.to_gpu(n) a = af.to_array(c) n2 = np.array(a) - assert((n==n2).all()) + assert((n == n2).all()) - if af.AF_PYOPENCL_FOUND and af.backend.name() == 'opencl': - # This needs fixing upstream + if af.AF_PYOPENCL_FOUND and af.backend.name() == "opencl": + # TODO: This needs fixing upstream # https://github.com/arrayfire/arrayfire/issues/1728 # import pyopencl as cl @@ -107,33 +109,32 @@ def simple_interop(verbose = False): # assert((n==n2).all()) pass - if af.AF_NUMBA_FOUND and af.get_active_backend() == 'cuda': - - import numba + if af.AF_NUMBA_FOUND and af.get_active_backend() == "cuda": from numba import cuda n = np.random.random((5,)) c = cuda.to_device(n) a = af.to_array(c) n2 = np.array(a) - assert((n==n2).all()) + assert((n == n2).all()) - n = np.random.random((5,3)) + n = np.random.random((5, 3)) c = cuda.to_device(n) a = af.to_array(c) n2 = np.array(a) - assert((n==n2).all()) + assert((n == n2).all()) - n = np.random.random((5,3,2)) + n = np.random.random((5, 3, 2)) c = cuda.to_device(n) a = af.to_array(c) n2 = np.array(a) - assert((n==n2).all()) + assert((n == n2).all()) - n = np.random.random((5,3,2,2)) + n = np.random.random((5, 3, 2, 2)) c = cuda.to_device(n) a = af.to_array(c) n2 = np.array(a) - assert((n==n2).all()) + assert((n == n2).all()) + -_util.tests['interop'] = simple_interop +_util.tests["interop"] = simple_interop diff --git a/arrayfire/tests/simple/lapack.py b/tests/simple/lapack.py similarity index 78% rename from arrayfire/tests/simple/lapack.py rename to tests/simple/lapack.py index e3c3dbbb2..e27fb6bc0 100644 --- a/arrayfire/tests/simple/lapack.py +++ b/tests/simple/lapack.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -7,15 +8,18 @@ # The complete license agreement can be obtained at: # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## + import arrayfire as af + from . import _util + def simple_lapack(verbose=False): display_func = _util.display_func(verbose) - print_func = _util.print_func(verbose) - a = af.randu(5,5) + print_func = _util.print_func(verbose) + a = af.randu(5, 5) - l,u,p = af.lu(a) + l, u, p = af.lu(a) display_func(l) display_func(u) @@ -26,9 +30,9 @@ def simple_lapack(verbose=False): display_func(a) display_func(p) - a = af.randu(5,3) + a = af.randu(5, 3) - q,r,t = af.qr(a) + q, r, t = af.qr(a) display_func(q) display_func(r) @@ -39,16 +43,16 @@ def simple_lapack(verbose=False): display_func(a) a = af.randu(5, 5) - a = af.matmulTN(a, a.copy()) + 10 * af.identity(5,5) + a = af.matmulTN(a, a.copy()) + 10 * af.identity(5, 5) - R,info = af.cholesky(a) + R, info = af.cholesky(a) display_func(R) print_func(info) af.cholesky_inplace(a) display_func(a) - a = af.randu(5,5) + a = af.randu(5, 5) ai = af.inverse(a) display_func(a) @@ -74,11 +78,12 @@ def simple_lapack(verbose=False): print_func(af.norm(a, af.NORM.MATRIX_INF)) print_func(af.norm(a, af.NORM.MATRIX_L_PQ, 1, 1)) - a = af.randu(10,10) + a = af.randu(10, 10) display_func(a) - u,s,vt = af.svd(a) + u, s, vt = af.svd(a) display_func(af.matmul(af.matmul(u, af.diag(s, 0, False)), vt)) - u,s,vt = af.svd_inplace(a) + u, s, vt = af.svd_inplace(a) display_func(af.matmul(af.matmul(u, af.diag(s, 0, False)), vt)) -_util.tests['lapack'] = simple_lapack + +_util.tests["lapack"] = simple_lapack diff --git a/arrayfire/tests/simple/random.py b/tests/simple/random.py similarity index 91% rename from arrayfire/tests/simple/random.py rename to tests/simple/random.py index 544389836..5152cb4e0 100644 --- a/arrayfire/tests/simple/random.py +++ b/tests/simple/random.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -9,11 +10,12 @@ ######################################################## import arrayfire as af + from . import _util + def simple_random(verbose=False): display_func = _util.display_func(verbose) - print_func = _util.print_func(verbose) display_func(af.randu(3, 3, 1, 2)) display_func(af.randu(3, 3, 1, 2, af.Dtype.b8)) @@ -35,4 +37,5 @@ def simple_random(verbose=False): engine.set_seed(100) assert(engine.get_seed() == 100) -_util.tests['random'] = simple_random + +_util.tests["random"] = simple_random diff --git a/arrayfire/tests/simple/signal.py b/tests/simple/signal.py similarity index 89% rename from arrayfire/tests/simple/signal.py rename to tests/simple/signal.py index fa8036dc2..d92526488 100644 --- a/arrayfire/tests/simple/signal.py +++ b/tests/simple/signal.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -9,24 +10,25 @@ ######################################################## import arrayfire as af + from . import _util + def simple_signal(verbose=False): display_func = _util.display_func(verbose) - print_func = _util.print_func(verbose) signal = af.randu(10) - x_new = af.randu(10) + x_new = af.randu(10) x_orig = af.randu(10) - display_func(af.approx1(signal, x_new, xp = x_orig)) + display_func(af.approx1(signal, x_new, xp=x_orig)) signal = af.randu(3, 3) - x_new = af.randu(3, 3) + x_new = af.randu(3, 3) x_orig = af.randu(3, 3) - y_new = af.randu(3, 3) + y_new = af.randu(3, 3) y_orig = af.randu(3, 3) - display_func(af.approx2(signal, x_new, y_new, xp = x_orig, yp = y_orig)) + display_func(af.approx2(signal, x_new, y_new, xp=x_orig, yp=y_orig)) a = af.randu(8, 1) display_func(a) @@ -106,7 +108,6 @@ def simple_signal(verbose=False): display_func(af.convolve(a, b)) display_func(af.fft_convolve(a, b)) - b = af.randu(3, 1) x = af.randu(10, 1) a = af.randu(2, 1) @@ -117,4 +118,5 @@ def simple_signal(verbose=False): display_func(af.medfilt2(a)) display_func(af.medfilt(a)) -_util.tests['signal'] = simple_signal + +_util.tests["signal"] = simple_signal diff --git a/arrayfire/tests/simple/sparse.py b/tests/simple/sparse.py similarity index 88% rename from arrayfire/tests/simple/sparse.py rename to tests/simple/sparse.py index 89315dfb1..bda87dfb7 100644 --- a/arrayfire/tests/simple/sparse.py +++ b/tests/simple/sparse.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -9,11 +10,13 @@ ######################################################## import arrayfire as af + from . import _util + def simple_sparse(verbose=False): display_func = _util.display_func(verbose) - print_func = _util.print_func(verbose) + print_func = _util.print_func(verbose) dd = af.randu(5, 5) ds = dd * (dd > 0.5) @@ -25,4 +28,5 @@ def simple_sparse(verbose=False): print_func(af.sparse_get_nnz(sp)) print_func(af.sparse_get_storage(sp)) -_util.tests['sparse'] = simple_sparse + +_util.tests["sparse"] = simple_sparse diff --git a/arrayfire/tests/simple/statistics.py b/tests/simple/statistics.py similarity index 82% rename from arrayfire/tests/simple/statistics.py rename to tests/simple/statistics.py index d7d5a63d4..2815af335 100644 --- a/arrayfire/tests/simple/statistics.py +++ b/tests/simple/statistics.py @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python + ####################################################### # Copyright (c) 2015, ArrayFire # All rights reserved. @@ -9,11 +10,13 @@ ######################################################## import arrayfire as af + from . import _util + def simple_statistics(verbose=False): display_func = _util.display_func(verbose) - print_func = _util.print_func(verbose) + print_func = _util.print_func(verbose) a = af.randu(5, 5) b = af.randu(5, 5) @@ -47,10 +50,11 @@ def simple_statistics(verbose=False): data = af.iota(5, 3) k = 3 dim = 0 - order = af.TOPK.DEFAULT # defaults to af.TOPK.MAX - assert(dim == 0) # topk currently supports first dim only - values,indices = af.topk(data, k, dim, order) + order = af.TOPK.DEFAULT # defaults to af.TOPK.MAX + assert(dim == 0) # topk currently supports first dim only + values, indices = af.topk(data, k, dim, order) display_func(values) display_func(indices) -_util.tests['statistics'] = simple_statistics + +_util.tests["statistics"] = simple_statistics From 1bd0de5f42f239bb4d1c06bfaec9b72456056ccc Mon Sep 17 00:00:00 2001 From: Anton Chernyatevich Date: Thu, 26 Sep 2019 16:29:23 +0300 Subject: [PATCH 179/212] Fix tests dir creation after package installation --- setup.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.cfg b/setup.cfg index 6b0fb031d..0e02078f1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -17,6 +17,7 @@ classifiers = packages = find: [options.packages.find] +include = arrayfire exclude = examples tests From ec86afa8d4a7e445207b34b94ea8acb13814d377 Mon Sep 17 00:00:00 2001 From: syurkevi Date: Mon, 9 Mar 2020 02:57:28 -0400 Subject: [PATCH 180/212] Add 3.7 features to python wrapper (#221) * adds af_pad to python wrapper * adds meanvar to python wrapper * adds inverse square root to python wrapper * adds pinverse to python wrapper * adds NN convolve and gradient functions to wrapper * adds reduce by key to python wrapper missing convolve gradient function * adds confidenceCC to python wrapper * adds fp16 support to python wrapper * update version * remove stray print statements * adds axes_label_format to python wrapper, removes mistakenly copied code --- __af_version__.py | 4 +- arrayfire/__init__.py | 1 + arrayfire/algorithm.py | 190 +++++++++++++++++++++++++++++++++++++ arrayfire/arith.py | 20 ++++ arrayfire/array.py | 8 ++ arrayfire/data.py | 52 ++++++++++ arrayfire/device.py | 19 ++++ arrayfire/graphics.py | 28 ++++++ arrayfire/image.py | 43 +++++++++ arrayfire/lapack.py | 33 +++++++ arrayfire/library.py | 21 ++++ arrayfire/ml.py | 74 +++++++++++++++ arrayfire/signal.py | 50 ++++++++++ arrayfire/statistics.py | 42 ++++++++ arrayfire/util.py | 12 ++- setup.cfg | 2 +- tests/simple/algorithm.py | 24 +++++ tests/simple/arith.py | 1 + tests/simple/data.py | 1 + tests/simple/image.py | 3 + tests/simple/lapack.py | 3 + tests/simple/signal.py | 5 + tests/simple/statistics.py | 7 ++ 23 files changed, 636 insertions(+), 7 deletions(-) create mode 100644 arrayfire/ml.py diff --git a/__af_version__.py b/__af_version__.py index 9b8a5f40c..dfa78b826 100644 --- a/__af_version__.py +++ b/__af_version__.py @@ -9,6 +9,6 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -version = "3.5" -release = "20170718" +version = "3.7" +release = "20200213" full_version = version + "." + release diff --git a/arrayfire/__init__.py b/arrayfire/__init__.py index 538085bb3..5cb009951 100644 --- a/arrayfire/__init__.py +++ b/arrayfire/__init__.py @@ -74,6 +74,7 @@ from .timer import * from .random import * from .sparse import * +from .ml import * # do not export default modules as part of arrayfire del ct diff --git a/arrayfire/algorithm.py b/arrayfire/algorithm.py index 36b5d79b8..d5adbcce5 100644 --- a/arrayfire/algorithm.py +++ b/arrayfire/algorithm.py @@ -44,6 +44,31 @@ def _nan_reduce_all(a, c_func, nan_val): imag = imag.value return real if imag == 0 else real + imag * 1j +def _FNSD(dim, dims): + if dim >= 0: + return int(dim) + + fnsd = 0 + for i, d in enumerate(dims): + if d > 1: + fnsd = i + break + return int(fnsd) + +def _rbk_dim(keys, vals, dim, c_func): + keys_out = Array() + vals_out = Array() + rdim = _FNSD(dim, vals.dims()) + safe_call(c_func(c_pointer(keys_out.arr), c_pointer(vals_out.arr), keys.arr, vals.arr, c_int_t(rdim))) + return keys_out, vals_out + +def _nan_rbk_dim(a, dim, c_func, nan_val): + keys_out = Array() + vals_out = Array() + rdim = _FNSD(dim, vals.dims()) + safe_call(c_func(c_pointer(keys_out.arr), c_pointer(vals_out.arr), keys.arr, vals.arr, c_int_t(rdim), c_double_t(nan_val))) + return keys_out, vals_out + def sum(a, dim=None, nan_val=None): """ Calculate the sum of all the elements along a specified dimension. @@ -74,6 +99,34 @@ def sum(a, dim=None, nan_val=None): else: return _reduce_all(a, backend.get().af_sum_all) + +def sumByKey(keys, vals, dim=-1, nan_val=None): + """ + Calculate the sum of elements along a specified dimension according to a key. + + Parameters + ---------- + keys : af.Array + One dimensional arrayfire array with reduction keys. + vals : af.Array + Multi dimensional arrayfire array that will be reduced. + dim: optional: int. default: -1 + Dimension along which the sum will occur. + nan_val: optional: scalar. default: None + The value that replaces NaN in the array + + Returns + ------- + keys: af.Array or scalar number + The reduced keys of all elements in `vals` along dimension `dim`. + values: af.Array or scalar number + The sum of all elements in `vals` along dimension `dim` according to keys + """ + if (nan_val is not None): + return _nan_rbk_dim(keys, vals, dim, backend.get().af_sum_by_key_nan, nan_val) + else: + return _rbk_dim(keys, vals, dim, backend.get().af_sum_by_key) + def product(a, dim=None, nan_val=None): """ Calculate the product of all the elements along a specified dimension. @@ -104,6 +157,33 @@ def product(a, dim=None, nan_val=None): else: return _reduce_all(a, backend.get().af_product_all) +def productByKey(keys, vals, dim=-1, nan_val=None): + """ + Calculate the product of elements along a specified dimension according to a key. + + Parameters + ---------- + keys : af.Array + One dimensional arrayfire array with reduction keys. + vals : af.Array + Multi dimensional arrayfire array that will be reduced. + dim: optional: int. default: -1 + Dimension along which the product will occur. + nan_val: optional: scalar. default: None + The value that replaces NaN in the array + + Returns + ------- + keys: af.Array or scalar number + The reduced keys of all elements in `vals` along dimension `dim`. + values: af.Array or scalar number + The product of all elements in `vals` along dimension `dim` according to keys + """ + if (nan_val is not None): + return _nan_rbk_dim(keys, vals, dim, backend.get().af_product_by_key_nan, nan_val) + else: + return _rbk_dim(keys, vals, dim, backend.get().af_product_by_key) + def min(a, dim=None): """ Find the minimum value of all the elements along a specified dimension. @@ -126,6 +206,28 @@ def min(a, dim=None): else: return _reduce_all(a, backend.get().af_min_all) +def minByKey(keys, vals, dim=-1): + """ + Calculate the min of elements along a specified dimension according to a key. + + Parameters + ---------- + keys : af.Array + One dimensional arrayfire array with reduction keys. + vals : af.Array + Multi dimensional arrayfire array that will be reduced. + dim: optional: int. default: -1 + Dimension along which the min will occur. + + Returns + ------- + keys: af.Array or scalar number + The reduced keys of all elements in `vals` along dimension `dim`. + values: af.Array or scalar number + The min of all elements in `vals` along dimension `dim` according to keys + """ + return _rbk_dim(keys, vals, dim, backend.get().af_min_by_key) + def max(a, dim=None): """ Find the maximum value of all the elements along a specified dimension. @@ -148,6 +250,28 @@ def max(a, dim=None): else: return _reduce_all(a, backend.get().af_max_all) +def maxByKey(keys, vals, dim=-1): + """ + Calculate the max of elements along a specified dimension according to a key. + + Parameters + ---------- + keys : af.Array + One dimensional arrayfire array with reduction keys. + vals : af.Array + Multi dimensional arrayfire array that will be reduced. + dim: optional: int. default: -1 + Dimension along which the max will occur. + + Returns + ------- + keys: af.Array or scalar number + The reduced keys of all elements in `vals` along dimension `dim`. + values: af.Array or scalar number + The max of all elements in `vals` along dimension `dim` according to keys. + """ + return _rbk_dim(keys, vals, dim, backend.get().af_max_by_key) + def all_true(a, dim=None): """ Check if all the elements along a specified dimension are true. @@ -170,6 +294,28 @@ def all_true(a, dim=None): else: return _reduce_all(a, backend.get().af_all_true_all) +def allTrueByKey(keys, vals, dim=-1): + """ + Calculate if all elements are true along a specified dimension according to a key. + + Parameters + ---------- + keys : af.Array + One dimensional arrayfire array with reduction keys. + vals : af.Array + Multi dimensional arrayfire array that will be reduced. + dim: optional: int. default: -1 + Dimension along which the all true check will occur. + + Returns + ------- + keys: af.Array or scalar number + The reduced keys of all true check in `vals` along dimension `dim`. + values: af.Array or scalar number + Booleans denoting if all elements are true in `vals` along dimension `dim` according to keys + """ + return _rbk_dim(keys, vals, dim, backend.get().af_all_true_by_key) + def any_true(a, dim=None): """ Check if any the elements along a specified dimension are true. @@ -192,6 +338,28 @@ def any_true(a, dim=None): else: return _reduce_all(a, backend.get().af_any_true_all) +def anyTrueByKey(keys, vals, dim=-1): + """ + Calculate if any elements are true along a specified dimension according to a key. + + Parameters + ---------- + keys : af.Array + One dimensional arrayfire array with reduction keys. + vals : af.Array + Multi dimensional arrayfire array that will be reduced. + dim: optional: int. default: -1 + Dimension along which the any true check will occur. + + Returns + ------- + keys: af.Array or scalar number + The reduced keys of any true check in `vals` along dimension `dim`. + values: af.Array or scalar number + Booleans denoting if any elements are true in `vals` along dimension `dim` according to keys. + """ + return _rbk_dim(keys, vals, dim, backend.get().af_any_true_by_key) + def count(a, dim=None): """ Count the number of non zero elements in an array along a specified dimension. @@ -214,6 +382,28 @@ def count(a, dim=None): else: return _reduce_all(a, backend.get().af_count_all) +def countByKey(keys, vals, dim=-1): + """ + Counts non-zero elements along a specified dimension according to a key. + + Parameters + ---------- + keys : af.Array + One dimensional arrayfire array with reduction keys. + vals : af.Array + Multi dimensional arrayfire array that will be reduced. + dim: optional: int. default: -1 + Dimension along which to count elements. + + Returns + ------- + keys: af.Array or scalar number + The reduced keys of count in `vals` along dimension `dim`. + values: af.Array or scalar number + Count of non-zero elements in `vals` along dimension `dim` according to keys. + """ + return _rbk_dim(keys, vals, dim, backend.get().af_count_by_key) + def imin(a, dim=None): """ Find the value and location of the minimum value along a specified dimension diff --git a/arrayfire/arith.py b/arrayfire/arith.py index b0d945f05..e4dc2fdfd 100644 --- a/arrayfire/arith.py +++ b/arrayfire/arith.py @@ -958,6 +958,26 @@ def sqrt(a): """ return _arith_unary_func(a, backend.get().af_sqrt) +def rsqrt(a): + """ + Reciprocal or inverse square root of each element in the array. + + Parameters + ---------- + a : af.Array + Multi dimensional arrayfire array. + + Returns + -------- + out : af.Array + array containing the inverse square root of each value from `a`. + + Note + ------- + `a` must not be complex. + """ + return _arith_unary_func(a, backend.get().af_rsqrt) + def cbrt(a): """ Cube root of each element in the array. diff --git a/arrayfire/array.py b/arrayfire/array.py index 801cd502b..289ef4699 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -783,6 +783,14 @@ def is_single(self): safe_call(backend.get().af_is_single(c_pointer(res), self.arr)) return res.value + def is_half(self): + """ + Check if the array is of half floating point type (fp16). + """ + res = c_bool_t(False) + safe_call(backend.get().af_is_half(c_pointer(res), self.arr)) + return res.value + def is_real_floating(self): """ Check if the array is real and of floating point type. diff --git a/arrayfire/data.py b/arrayfire/data.py index d9ad19e48..1fbe17a53 100644 --- a/arrayfire/data.py +++ b/arrayfire/data.py @@ -799,6 +799,58 @@ def replace(lhs, cond, rhs): else: safe_call(backend.get().af_replace_scalar(lhs.arr, cond.arr, c_double_t(rhs))) +def pad(a, beginPadding, endPadding, padFillType = PAD.ZERO): + """ + Pad an array + + This function will pad an array with the specified border size. + Newly padded values can be filled in several different ways. + + Parameters + ---------- + + a: af.Array + A multi dimensional input arrayfire array. + + beginPadding: tuple of ints. default: (0, 0, 0, 0). + + endPadding: tuple of ints. default: (0, 0, 0, 0). + + padFillType: optional af.PAD default: af.PAD.ZERO + specifies type of values to fill padded border with + + Returns + ------- + output: af.Array + A padded array + + Examples + --------- + >>> import arrayfire as af + >>> a = af.randu(3,3) + >>> af.display(a) + [3 3 1 1] + 0.4107 0.1794 0.3775 + 0.8224 0.4198 0.3027 + 0.9518 0.0081 0.6456 + + >>> padded = af.pad(a, (1, 1), (1, 1), af.ZERO) + >>> af.display(padded) + [5 5 1 1] + 0.0000 0.0000 0.0000 0.0000 0.0000 + 0.0000 0.4107 0.1794 0.3775 0.0000 + 0.0000 0.8224 0.4198 0.3027 0.0000 + 0.0000 0.9518 0.0081 0.6456 0.0000 + 0.0000 0.0000 0.0000 0.0000 0.0000 + """ + out = Array() + begin_dims = dim4(beginPadding[0], beginPadding[1], beginPadding[2], beginPadding[3]) + end_dims = dim4(endPadding[0], endPadding[1], endPadding[2], endPadding[3]) + + safe_call(backend.get().af_pad(c_pointer(out.arr), a.arr, 4, c_pointer(begin_dims), 4, c_pointer(end_dims), padFillType.value)) + return out + + def lookup(a, idx, dim=0): """ Lookup the values of input array based on index. diff --git a/arrayfire/device.py b/arrayfire/device.py index 84594f2b3..53f302db5 100644 --- a/arrayfire/device.py +++ b/arrayfire/device.py @@ -150,6 +150,25 @@ def is_dbl_supported(device=None): safe_call(backend.get().af_get_dbl_support(c_pointer(res), dev)) return res.value +def is_half_supported(device=None): + """ + Check if half precision is supported on specified device. + + Parameters + ----------- + device: optional: int. default: None. + id of the desired device. + + Returns + -------- + - True if half precision supported. + - False if half precision not supported. + """ + dev = device if device is not None else get_device() + res = c_bool_t(False) + safe_call(backend.get().af_get_half_support(c_pointer(res), dev)) + return res.value + def sync(device=None): """ Block until all the functions on the device have completed execution. diff --git a/arrayfire/graphics.py b/arrayfire/graphics.py index 4e378aaf5..70881f42c 100644 --- a/arrayfire/graphics.py +++ b/arrayfire/graphics.py @@ -496,6 +496,34 @@ def set_axes_limits(self, xmin, xmax, ymin, ymax, zmin=None, zmax=None, exact=Fa c_float_t(zmin), c_float_t(zmax), exact, c_pointer(_cell))) + def set_axes_label_format(self, xformat="4.1%f", yformat="4.1%f", zformat="4.1%f"): + """ + Set axis limits. + + Parameters + ---------- + + xformat : str. + default: "4.1%f". + is a printf-style format specifier for x-axis + yformat : str. + default: "4.1%f". + is a printf-style format specifier for y-axis + zformat : str. + default: "4.1%f". + is a printf-style format specifier for z-axis + + """ + _cell = _Cell(self._r, self._c, None, self._cmap) + xformat = xformat.encode("ascii") + yformat = yformat.encode("ascii") + zformat = zformat.encode("ascii") + safe_call(backend.get().af_set_axes_label_format(self._wnd, + c_char_ptr_t(xformat), + c_char_ptr_t(yformat), + c_char_ptr_t(zformat), + c_pointer(_cell))) + def __getitem__(self, keys): """ Get access to a specific grid location within the window. diff --git a/arrayfire/image.py b/arrayfire/image.py index 92c8d088b..2fdce0aef 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -711,6 +711,49 @@ def regions(image, conn = CONNECTIVITY.FOUR, out_type = Dtype.f32): conn.value, out_type.value)) return output +def confidenceCC(image, seedx, seedy, radius, multiplier, iters, segmented_value): + """ + Find the confidence connected components in the image. + + Parameters + ---------- + image : af.Array + - A 2 D arrayfire array representing an image. + Expects non-integral type + + seedx : af.Array + - An array with x-coordinates of seed points + + seedy : af.Array + - An array with y-coordinates of seed points + + radius : scalar + - The neighborhood region to be considered around + each seed point + + multiplier : scalar + - Controls the threshold range computed from + the mean and variance of seed point neighborhoods + + iters : scalar + - is number of iterations + + segmented_value : scalar + - the value to which output array valid + pixels are set to. + + Returns + --------- + + output : af.Array + - Output array with resulting connected components + + """ + output = Array() + safe_call(backend.get().af_confidence_cc(c_pointer(output.arr), image.arr, seedx.arr, seedy.arr, + c_uint_t(radius), c_uint_t(multiplier), c_int_t(iters), c_double_t(segmented_value))) + return output + def sobel_derivatives(image, w_len=3): """ Find the sobel derivatives of the image. diff --git a/arrayfire/lapack.py b/arrayfire/lapack.py index e6ffd5cb7..97ad92c7a 100644 --- a/arrayfire/lapack.py +++ b/arrayfire/lapack.py @@ -264,6 +264,39 @@ def inverse(A, options=MATPROP.NONE): safe_call(backend.get().af_inverse(c_pointer(AI.arr), A.arr, options.value)) return AI +def pinverse(A, tol=1E-6, options=MATPROP.NONE): + """ + Find pseudo-inverse(Moore-Penrose) of a matrix. + + Parameters + ---------- + + A: af.Array + - A 2 dimensional arrayfire input matrix array + + tol: optional: scalar. default: 1E-6. + - Tolerance for calculating rank + + options: optional: af.MATPROP. default: af.MATPROP.NONE. + - Currently needs to be `af.MATPROP.NONE`. + - Additional options may speed up computation in the future + + Returns + ------- + + AI: af.Array + - A 2 dimensional array that is the pseudo-inverse of `A` + + Note + ---- + + This function is not supported in GFOR + + """ + AI = Array() + safe_call(backend.get().af_pinverse(c_pointer(AI.arr), A.arr, c_double_t(tol), options.value)) + return AI + def rank(A, tol=1E-5): """ Rank of a matrix. diff --git a/arrayfire/library.py b/arrayfire/library.py index 0bdc2eeb9..915ca950a 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -97,6 +97,7 @@ class ERR(_Enum): # 400-499 Errors for missing hardware features NO_DBL = _Enum_Type(401) NO_GFX = _Enum_Type(402) + NO_HALF = _Enum_Type(403) # 500-599 Errors specific to the heterogeneous API LOAD_LIB = _Enum_Type(501) @@ -123,6 +124,7 @@ class Dtype(_Enum): u64 = _Enum_Type(9) s16 = _Enum_Type(10) u16 = _Enum_Type(11) + f16 = _Enum_Type(12) class Source(_Enum): """ @@ -152,6 +154,8 @@ class PAD(_Enum): """ ZERO = _Enum_Type(0) SYM = _Enum_Type(1) + CLAMP_TO_EDGE = _Enum_Type(2) + PERIODIC = _Enum_Type(3) class CONNECTIVITY(_Enum): """ @@ -175,6 +179,15 @@ class CONV_DOMAIN(_Enum): SPATIAL = _Enum_Type(1) FREQ = _Enum_Type(2) +class CONV_GRADIENT(_Enum): + """ + Convolution gradient type + """ + DEFAULT = _Enum_Type(0) + FILTER = _Enum_Type(1) + DATA = _Enum_Type(2) + BIAS = _Enum_Type(3) + class MATCH(_Enum): """ Match type @@ -446,6 +459,14 @@ class TOPK(_Enum): MIN = _Enum_Type(1) MAX = _Enum_Type(2) +class VARIANCE(_Enum): + """ + Variance bias type + """ + DEFAULT = _Enum_Type(0) + SAMPLE = _Enum_Type(1) + POPULATION = _Enum_Type(2) + _VER_MAJOR_PLACEHOLDER = "__VER_MAJOR__" def _setup(): diff --git a/arrayfire/ml.py b/arrayfire/ml.py new file mode 100644 index 000000000..9140cc278 --- /dev/null +++ b/arrayfire/ml.py @@ -0,0 +1,74 @@ +####################################################### +# Copyright (c) 2020, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +""" +Machine learning functions + - Pool 2D, ND, maxpooling, minpooling, meanpooling + - Forward and backward convolution passes +""" + +from .library import * +from .array import * + +def convolve2GradientNN(incoming_gradient, original_signal, original_kernel, convolved_output, stride = (1, 1), padding = (0, 0), dilation = (1, 1), gradType = CONV_GRADIENT.DEFAULT): + """ + This version of convolution is consistent with the machine learning + formulation that will spatially convolve a filter on 2-dimensions against a + signal. Multiple signals and filters can be batched against each other. + Furthermore, the signals and filters can be multi-dimensional however their + dimensions must match. + + Example: + Signals with dimensions: d0 x d1 x d2 x Ns + Filters with dimensions: d0 x d1 x d2 x Nf + + Resulting Convolution: d0 x d1 x Nf x Ns + + Parameters + ----------- + + signal: af.Array + - A 2 dimensional signal or batch of 2 dimensional signals. + + kernel: af.Array + - A 2 dimensional kernel or batch of 2 dimensional kernels. + + stride: tuple of ints. default: (1, 1). + - Specifies how much to stride along each dimension + + padding: tuple of ints. default: (0, 0). + - Specifies signal padding along each dimension + + dilation: tuple of ints. default: (1, 1). + - Specifies how much to dilate kernel along each dimension before convolution + + Returns + -------- + + output: af.Array + - Gradient wrt/requested gradient type + + """ + output = Array() + stride_dim = dim4(stride[0], stride[1]) + padding_dim = dim4(padding[0], padding[1]) + dilation_dim = dim4(dilation[0], dilation[1]) + + safe_call(backend.get().af_convolve2_gradient_nn( + c_pointer(output.arr), + incoming_gradient.arr, + original_signal.arr, + original_kernel.arr, + convolved_output.arr, + 2, c_pointer(stride_dim), + 2, c_pointer(padding_dim), + 2, c_pointer(dilation_dim), + gradType.value)) + return output + diff --git a/arrayfire/signal.py b/arrayfire/signal.py index ca27d21c2..1fa6c424d 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -972,6 +972,56 @@ def convolve2(signal, kernel, conv_mode = CONV_MODE.DEFAULT, conv_domain = CONV_ conv_mode.value, conv_domain.value)) return output +def convolve2NN(signal, kernel, stride = (1, 1), padding = (0, 0), dilation = (1, 1)): + """ + This version of convolution is consistent with the machine learning + formulation that will spatially convolve a filter on 2-dimensions against a + signal. Multiple signals and filters can be batched against each other. + Furthermore, the signals and filters can be multi-dimensional however their + dimensions must match. + + Example: + Signals with dimensions: d0 x d1 x d2 x Ns + Filters with dimensions: d0 x d1 x d2 x Nf + + Resulting Convolution: d0 x d1 x Nf x Ns + + Parameters + ----------- + + signal: af.Array + - A 2 dimensional signal or batch of 2 dimensional signals. + + kernel: af.Array + - A 2 dimensional kernel or batch of 2 dimensional kernels. + + stride: tuple of ints. default: (1, 1). + - Specifies how much to stride along each dimension + + padding: tuple of ints. default: (0, 0). + - Specifies signal padding along each dimension + + dilation: tuple of ints. default: (1, 1). + - Specifies how much to dilate kernel along each dimension before convolution + + Returns + -------- + + output: af.Array + - Convolved 2D array. + + """ + output = Array() + stride_dim = dim4(stride[0], stride[1]) + padding_dim = dim4(padding[0], padding[1]) + dilation_dim = dim4(dilation[0], dilation[1]) + + safe_call(backend.get().af_convolve2_nn(c_pointer(output.arr), signal.arr, kernel.arr, + 2, c_pointer(stride_dim), + 2, c_pointer(padding_dim), + 2, c_pointer(dilation_dim))) + return output + def convolve2_separable(col_kernel, row_kernel, signal, conv_mode = CONV_MODE.DEFAULT): """ Convolution: 2D separable convolution diff --git a/arrayfire/statistics.py b/arrayfire/statistics.py index e6b4effd0..f47f3a48d 100644 --- a/arrayfire/statistics.py +++ b/arrayfire/statistics.py @@ -108,6 +108,48 @@ def var(a, isbiased=False, weights=None, dim=None): return real if imag == 0 else real + imag * 1j +def meanvar(a, weights=None, bias=VARIANCE.DEFAULT, dim=-1): + """ + Calculate mean and variance along a given dimension. + + Parameters + ---------- + a: af.Array + The input array. + + weights: optional: af.Array. default: None. + Array to calculate for the weighted mean. Must match size of + the input array. + + bias: optional: af.VARIANCE. default: DEFAULT. + population variance(VARIANCE.POPULATION) or + sample variance(VARIANCE.SAMPLE). + + dim: optional: int. default: -1. + The dimension for which to obtain the variance from input data. + + Returns + ------- + mean: af.Array + Array containing the mean of the input array along a given + dimension. + variance: af.Array + Array containing the variance of the input array along a given + dimension. + """ + + mean_out = Array() + var_out = Array() + + if weights is None: + weights = Array() + + safe_call(backend.get().af_meanvar(c_pointer(mean_out.arr), c_pointer(var_out.arr), + a.arr, weights.arr, bias.value, c_int_t(dim))) + + return mean_out, var_out + + def stdev(a, dim=None): """ Calculate standard deviation along a given dimension. diff --git a/arrayfire/util.py b/arrayfire/util.py index 709bd7811..44af6000d 100644 --- a/arrayfire/util.py +++ b/arrayfire/util.py @@ -105,7 +105,8 @@ def get_reversion(): 'l' : Dtype.s64, 'L' : Dtype.u64, 'F' : Dtype.c32, - 'D' : Dtype.c64} + 'D' : Dtype.c64, + 'hf': Dtype.f16} to_typecode = {Dtype.f32.value : 'f', Dtype.f64.value : 'd', @@ -118,7 +119,8 @@ def get_reversion(): Dtype.s64.value : 'l', Dtype.u64.value : 'L', Dtype.c32.value : 'F', - Dtype.c64.value : 'D'} + Dtype.c64.value : 'D', + Dtype.f16.value : 'hf'} to_c_type = {Dtype.f32.value : c_float_t, Dtype.f64.value : c_double_t, @@ -131,7 +133,8 @@ def get_reversion(): Dtype.s64.value : c_longlong_t, Dtype.u64.value : c_ulonglong_t, Dtype.c32.value : c_float_t * 2, - Dtype.c64.value : c_double_t * 2} + Dtype.c64.value : c_double_t * 2, + Dtype.f16.value : c_ushort_t} to_typename = {Dtype.f32.value : 'float', Dtype.f64.value : 'double', @@ -144,4 +147,5 @@ def get_reversion(): Dtype.s64.value : 'long int', Dtype.u64.value : 'unsigned long int', Dtype.c32.value : 'float complex', - Dtype.c64.value : 'double complex'} + Dtype.c64.value : 'double complex', + Dtype.f16.value : 'half'} diff --git a/setup.cfg b/setup.cfg index 0e02078f1..e4f536a88 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = arrayfire -version = 3.6.20181017 +version = 3.7.20200213 description = Python bindings for ArrayFire licence = BSD long_description = file: README.md diff --git a/tests/simple/algorithm.py b/tests/simple/algorithm.py index 5b40d6916..b9e42f138 100644 --- a/tests/simple/algorithm.py +++ b/tests/simple/algorithm.py @@ -27,6 +27,30 @@ def simple_algorithm(verbose=False): display_func(af.sum(a, 0)) display_func(af.sum(a, 1)) + rk = af.constant(1, 3, dtype=af.Dtype.u32) + rk[2] = 0 + af.eval(rk) + display_func(af.sumByKey(rk, a, dim=0)) + display_func(af.sumByKey(rk, a, dim=1)) + + display_func(af.productByKey(rk, a, dim=0)) + display_func(af.productByKey(rk, a, dim=1)) + + display_func(af.minByKey(rk, a, dim=0)) + display_func(af.minByKey(rk, a, dim=1)) + + display_func(af.maxByKey(rk, a, dim=0)) + display_func(af.maxByKey(rk, a, dim=1)) + + display_func(af.anyTrueByKey(rk, a, dim=0)) + display_func(af.anyTrueByKey(rk, a, dim=1)) + + display_func(af.allTrueByKey(rk, a, dim=0)) + display_func(af.allTrueByKey(rk, a, dim=1)) + + display_func(af.countByKey(rk, a, dim=0)) + display_func(af.countByKey(rk, a, dim=1)) + display_func(af.product(a, 0)) display_func(af.product(a, 1)) diff --git a/tests/simple/arith.py b/tests/simple/arith.py index 306b93fff..5d4d83d00 100644 --- a/tests/simple/arith.py +++ b/tests/simple/arith.py @@ -192,6 +192,7 @@ def simple_arith(verbose=False): display_func(af.log10(a)) display_func(af.log2(a)) display_func(af.sqrt(a)) + display_func(af.rsqrt(a)) display_func(af.cbrt(a)) a = af.round(5 * af.randu(3, 3) - 1) diff --git a/tests/simple/data.py b/tests/simple/data.py index d80f9e125..d091497eb 100644 --- a/tests/simple/data.py +++ b/tests/simple/data.py @@ -72,5 +72,6 @@ def simple_data(verbose=False): af.replace(a, a > 0.3, -0.3) display_func(a) + display_func(af.pad(a, (1, 1, 0, 0), (2, 2, 0, 0))) _util.tests["data"] = simple_data diff --git a/tests/simple/image.py b/tests/simple/image.py index 1489e94dc..8c2212974 100644 --- a/tests/simple/image.py +++ b/tests/simple/image.py @@ -51,6 +51,9 @@ def simple_image(verbose=False): display_func(af.maxfilt(a)) display_func(af.regions(af.round(a) > 3)) + display_func(af.confidenceCC(af.randu(10, 10), + (af.randu(2) * 9).as_type(af.Dtype.u32), (af.randu(2) * 9).as_type(af.Dtype.u32), 3, 3, 10, 0.1)) + dx, dy = af.sobel_derivatives(a) display_func(dx) diff --git a/tests/simple/lapack.py b/tests/simple/lapack.py index e27fb6bc0..8cd3e9ac3 100644 --- a/tests/simple/lapack.py +++ b/tests/simple/lapack.py @@ -58,6 +58,9 @@ def simple_lapack(verbose=False): display_func(a) display_func(ai) + ai = af.pinverse(a) + display_func(ai) + x0 = af.randu(5, 3) b = af.matmul(a, x0) x1 = af.solve(a, b) diff --git a/tests/simple/signal.py b/tests/simple/signal.py index d92526488..9e72e6e35 100644 --- a/tests/simple/signal.py +++ b/tests/simple/signal.py @@ -101,6 +101,11 @@ def simple_signal(verbose=False): display_func(af.convolve(a, b)) display_func(af.fft_convolve(a, b)) + c = af.convolve2NN(a, b) + display_func(c) + g = af.convolve2NN(a, b, c, gradType=af.CONV_GRADIENT.DATA) + display_func(g) + a = af.randu(5, 5, 3) b = af.randu(3, 3, 2) display_func(af.convolve3(a, b)) diff --git a/tests/simple/statistics.py b/tests/simple/statistics.py index 2815af335..be639ea4a 100644 --- a/tests/simple/statistics.py +++ b/tests/simple/statistics.py @@ -34,6 +34,13 @@ def simple_statistics(verbose=False): print_func(af.var(a, isbiased=True)) print_func(af.var(a, weights=w)) + mean, var = af.mean_var(a, dim=0) + display_func(mean) + display_func(var) + mean, var = af.mean_var(a, weights=w, bias=VARIANCE.SAMPLE, dim=0) + display_func(mean) + display_func(var) + display_func(af.stdev(a, dim=0)) print_func(af.stdev(a)) From 76d8a5ba5242c0ee3375cee66e0f1a6b55d68586 Mon Sep 17 00:00:00 2001 From: syurkevi Date: Mon, 13 Apr 2020 17:41:56 -0400 Subject: [PATCH 181/212] update arrayfire library directory on 64 bit systems --- arrayfire/library.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index 915ca950a..6119293e0 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -551,7 +551,10 @@ class _clibrary(object): def __libname(self, name, head='af', ver_major=AF_VER_MAJOR): post = self.__post.replace(_VER_MAJOR_PLACEHOLDER, ver_major) libname = self.__pre + head + name + post - libname_full = self.AF_PATH + '/lib/' + libname + if os.path.isdir(self.AF_PATH + '/lib64'): + libname_full = self.AF_PATH + '/lib64/' + libname + else: + libname_full = self.AF_PATH + '/lib/' + libname return (libname, libname_full) def set_unsafe(self, name): From a1d5a1f57aedd8a97d3702a0a765b8dda9c1119e Mon Sep 17 00:00:00 2001 From: miketrumpis Date: Mon, 27 Jan 2020 10:49:35 -0800 Subject: [PATCH 182/212] BF: check AF library paths for pkg vs source install --- arrayfire/library.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arrayfire/library.py b/arrayfire/library.py index 6119293e0..e46fa2b08 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -517,7 +517,10 @@ def _setup(): post = '.' + _VER_MAJOR_PLACEHOLDER + '.dylib' if AF_SEARCH_PATH is None: - AF_SEARCH_PATH='/usr/local/' + if os.path.exists('/opt/arrayfire'): + AF_SEARCH_PATH = '/opt/arrayfire/' + else: + AF_SEARCH_PATH = '/usr/local/' if CUDA_PATH is None: CUDA_PATH='/usr/local/cuda/' From e7fdf7eb24746e60444b22659aeb3f5be6451710 Mon Sep 17 00:00:00 2001 From: syurkevi Date: Tue, 10 Mar 2020 14:00:49 -0400 Subject: [PATCH 183/212] adds missing deconv functions to python wrapper --- arrayfire/image.py | 72 +++++++++++++++++++++++++++++++++++++++++++ arrayfire/library.py | 15 +++++++++ tests/simple/image.py | 7 +++++ 3 files changed, 94 insertions(+) diff --git a/arrayfire/image.py b/arrayfire/image.py index 2fdce0aef..f626a4802 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -1324,6 +1324,78 @@ def anisotropic_diffusion(image, time_step, conductance, iterations, flux_functi flux_function_type.value, diffusion_kind.value)) return out +def iterativeDeconv(image, psf, iterations, relax_factor, algo = ITERATIVE_DECONV.DEFAULT): + """ + Iterative deconvolution algorithm. + + Parameters + ---------- + image: af.Array + The blurred input image. + + psf: af.Array + The kernel(point spread function) known to have caused + the blur in the system. + + iterations: + Number of times the algorithm will run. + + relax_factor: scalar. + is the relaxation factor multiplied with distance + of estimate from observed image. + + algo: + takes enum value of type af.ITERATIVE_DECONV + indicating the iterative deconvolution algorithm to be used + + Returns + ------- + out: af.Array + sharp image estimate generated from the blurred input + + Note + ------- + relax_factor argument is ignored when the RICHARDSONLUCY algorithm is used. + + """ + out = Array() + safe_call(backend.get(). + af_iterative_deconv(c_pointer(out.arr), image.arr, psf.arr, + c_uint_t(iterations), c_float_t(relax_factor), algo.value)) + return out + +def inverseDeconv(image, psf, gamma, algo = ITERATIVE_DECONV.DEFAULT): + """ + Inverse deconvolution algorithm. + + Parameters + ---------- + image: af.Array + The blurred input image. + + psf: af.Array + The kernel(point spread function) known to have caused + the blur in the system. + + gamma: scalar. + is a user defined regularization constant + + algo: + takes enum value of type af.INVERSE_DECONV + indicating the inverse deconvolution algorithm to be used + + Returns + ------- + out: af.Array + sharp image estimate generated from the blurred input + + """ + out = Array() + safe_call(backend.get(). + af_inverse_deconv(c_pointer(out.arr), image.arr, psf.arr, + c_float_t(gamma), algo.value)) + return out + def is_image_io_available(): """ Function to check if the arrayfire library was built with Image IO support. diff --git a/arrayfire/library.py b/arrayfire/library.py index e46fa2b08..863c6746f 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -459,6 +459,21 @@ class TOPK(_Enum): MIN = _Enum_Type(1) MAX = _Enum_Type(2) +class ITERATIVE_DECONV(_Enum): + """ + Iterative deconvolution algorithm + """ + DEFAULT = _Enum_Type(0) + LANDWEBER = _Enum_Type(1) + RICHARDSONLUCY = _Enum_Type(2) + +class INVERSE_DECONV(_Enum): + """ + Inverse deconvolution algorithm + """ + DEFAULT = _Enum_Type(0) + TIKHONOV = _Enum_Type(1) + class VARIANCE(_Enum): """ Variance bias type diff --git a/tests/simple/image.py b/tests/simple/image.py index 8c2212974..6f2e12186 100644 --- a/tests/simple/image.py +++ b/tests/simple/image.py @@ -88,5 +88,12 @@ def simple_image(verbose=False): display_func(af.anisotropic_diffusion(a, 0.125, 1.0, 64, af.FLUX.QUADRATIC, af.DIFFUSION.GRAD)) + a = af.randu(10, 10) + psf = af.gaussian_kernel(3, 3) + cimg = af.convolve(a, psf) + display_func(af.iterativeDeconv(cimg, psf, 100, 0.5, af.ITERATIVE_DECONV.LANDWEBER)) + display_func(af.iterativeDeconv(cimg, psf, 100, 0.5, af.ITERATIVE_DECONV.RICHARDSONLUCY)) + display_func(af.inverseDeconv(cimg, psf, 1.0, af.INVERSE_DECONV.TIKHONOV)) + _util.tests["image"] = simple_image From a2cd9cecdf1ae58a28ef6a52f92704683305aefc Mon Sep 17 00:00:00 2001 From: syurkevi Date: Wed, 29 Apr 2020 19:23:44 -0400 Subject: [PATCH 184/212] corrects invert operation to non-inplace bitwise inversion --- arrayfire/array.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arrayfire/array.py b/arrayfire/array.py index 289ef4699..50db2a9a8 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -1090,9 +1090,8 @@ def __invert__(self): Return ~self """ out = Array() - safe_call(backend.get().af_not(c_pointer(out.arr), self.arr)) - self = out - return self + safe_call(backend.get().af_bitnot(c_pointer(out.arr), self.arr)) + return out def __nonzero__(self): return self != 0 From e053bb5f35ae141db85e68755f0c522d13944cd3 Mon Sep 17 00:00:00 2001 From: syurkevi Date: Thu, 13 Aug 2020 19:39:23 -0400 Subject: [PATCH 185/212] adds updated approx functions to python wrapper --- arrayfire/signal.py | 204 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 185 insertions(+), 19 deletions(-) diff --git a/arrayfire/signal.py b/arrayfire/signal.py index 1fa6c424d..35e0fba87 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -27,7 +27,7 @@ def _scale_pos_axis1(y_curr, y_orig): dy = y_orig[0, 1, 0, 0] - y0 return((y_curr - y0) / dy) -def approx1(signal, x, method=INTERP.LINEAR, off_grid=0.0, xp = None): +def approx1(signal, x, method=INTERP.LINEAR, off_grid=0.0, xp = None, output = None): """ Interpolate along a single dimension.Interpolation is performed along axis 0 of the input array. @@ -51,6 +51,10 @@ def approx1(signal, x, method=INTERP.LINEAR, off_grid=0.0, xp = None): xp : af.Array The x-coordinates of the input data points + output: None or af.Array + Optional preallocated output array. If it is a sub-array of an existing af_array, + only the corresponding portion of the af_array will be overwritten + Returns ------- @@ -65,20 +69,86 @@ def approx1(signal, x, method=INTERP.LINEAR, off_grid=0.0, xp = None): where N is the length of the first dimension of `signal`. """ - output = Array() + if output is None: + output = Array() + + if(xp is not None): + pos0 = _scale_pos_axis0(x, xp) + else: + pos0 = x + + safe_call(backend.get().af_approx1(c_pointer(output.arr), signal.arr, pos0.arr, + method.value, c_float_t(off_grid))) - if(xp is not None): - pos0 = _scale_pos_axis0(x, xp) else: - pos0 = x + if(xp is not None): + pos0 = _scale_pos_axis0(x, xp) + else: + pos0 = x + safe_call(backend.get().af_approx1_v2(c_pointer(output.arr), signal.arr, pos0.arr, + method.value, c_float_t(off_grid))) + return output + + +def approx1_uniform(signal, x, interp_dim, idx_start, idx_step, method=INTERP.LINEAR, off_grid=0.0, output = None): + """ + Interpolation on one dimensional signals along specified dimension. + + af_approx1_uniform() accepts the dimension to perform the interpolation along the input. + It also accepts start and step values which define the uniform range of corresponding indices. + + Parameters + ---------- + + signal: af.Array + Input signal array (signal = f(x)) + + x: af.Array + The x-coordinates of the interpolation points. The interpolation + function is queried at these set of points. + + interp_dim: scalar + is the dimension to perform interpolation across. + + idx_start: scalar + is the first index value along interp_dim. + + idx_step: scalar + is the uniform spacing value between subsequent indices along interp_dim. - safe_call(backend.get().af_approx1(c_pointer(output.arr), signal.arr, pos0.arr, - method.value, c_float_t(off_grid))) + method: optional: af.INTERP. default: af.INTERP.LINEAR. + Interpolation method. + + off_grid: optional: scalar. default: 0.0. + The value used for positions outside the range. + + output: None or af.Array + Optional preallocated output array. If it is a sub-array of an existing af_array, + only the corresponding portion of the af_array will be overwritten + + Returns + ------- + + output: af.Array + Values calculated at interpolation points. + + """ + + if output is None: + output = Array() + + safe_call(backend.get().af_approx1_uniform(c_pointer(output.arr), signal.arr, x.arr, + c_dim_t(interp_dim), c_double_t(idx_start), c_double_t(idx_step), + method.value, c_float_t(off_grid))) + else: + safe_call(backend.get().af_approx1_uniform_v2(c_pointer(output.arr), signal.arr, x.arr, + c_dim_t(interp_dim), c_double_t(idx_start), c_double_t(idx_step), + method.value, c_float_t(off_grid))) return output + def approx2(signal, x, y, - method=INTERP.LINEAR, off_grid=0.0, xp = None, yp = None - ): + method=INTERP.LINEAR, off_grid=0.0, xp = None, yp = None, output = None): """ Interpolate along a two dimension.Interpolation is performed along axes 0 and 1 of the input array. @@ -112,6 +182,10 @@ def approx2(signal, x, y, The y-coordinates of the input data points. The convention followed is that the y-coordinates vary along axis 1 + output: None or af.Array + Optional preallocated output array. If it is a sub-array of an existing af_array, + only the corresponding portion of the af_array will be overwritten + Returns ------- @@ -127,22 +201,114 @@ def approx2(signal, x, y, and N is the length of the second dimension of `signal`. """ - output = Array() - - if(xp is not None): - pos0 = _scale_pos_axis0(x, xp) + if output is None: + output = Array() + + if(xp is not None): + pos0 = _scale_pos_axis0(x, xp) + else: + pos0 = x + + if(yp is not None): + pos1 = _scale_pos_axis1(y, yp) + else: + pos1 = y + + safe_call(backend.get().af_approx2(c_pointer(output.arr), signal.arr, + pos0.arr, pos1.arr, method.value, c_float_t(off_grid))) else: - pos0 = x + if(xp is not None): + pos0 = _scale_pos_axis0(x, xp) + else: + pos0 = x + + if(yp is not None): + pos1 = _scale_pos_axis1(y, yp) + else: + pos1 = y + + safe_call(backend.get().af_approx2_v2(c_pointer(output.arr), signal.arr, + pos0.arr, pos1.arr, method.value, c_float_t(off_grid))) + + return output + +def approx2_uniform(signal, pos0, interp_dim0, idx_start0, idx_step0, pos1, interp_dim1, idx_start1, idx_step1, + method=INTERP.LINEAR, off_grid=0.0, output = None): + """ + Interpolate along two uniformly spaced dimensions of the input array. + af_approx2_uniform() accepts two dimensions to perform the interpolation along the input. + It also accepts start and step values which define the uniform range of corresponding indices. + + Parameters + ---------- + + signal: af.Array + Input signal array (signal = f(x, y)) + + pos0 : af.Array + positions of the interpolation points along interp_dim0. + + interp_dim0: scalar + is the first dimension to perform interpolation across. + + idx_start0: scalar + is the first index value along interp_dim0. + + idx_step0: scalar + is the uniform spacing value between subsequent indices along interp_dim0. + + pos1 : af.Array + positions of the interpolation points along interp_dim1. + + interp_dim1: scalar + is the second dimension to perform interpolation across. + + idx_start1: scalar + is the first index value along interp_dim1. + + idx_step1: scalar + is the uniform spacing value between subsequent indices along interp_dim1. + + method: optional: af.INTERP. default: af.INTERP.LINEAR. + Interpolation method. + + off_grid: optional: scalar. default: 0.0. + The value used for positions outside the range. + + output: None or af.Array + Optional preallocated output array. If it is a sub-array of an existing af_array, + only the corresponding portion of the af_array will be overwritten + + Returns + ------- + + output: af.Array + Values calculated at interpolation points. + + Note + ----- + This holds applicable when x_input/y_input isn't provided: - if(yp is not None): - pos1 = _scale_pos_axis1(y, yp) + The initial measurements are assumed to have taken place at equal steps between [(0,0) - [M - 1, N - 1]] + where M is the length of the first dimension of `signal`, + and N is the length of the second dimension of `signal`. + """ + + if output is None: + output = Array() + safe_call(backend.get().af_approx2_uniform(c_pointer(output.arr), signal.arr, + pos0.arr, c_dim_t(interp_dim0), c_double_t(idx_start0), c_double_t(idx_step0), + pos1.arr, c_dim_t(interp_dim1), c_double_t(idx_start1), c_double_t(idx_step1), + method.value, c_float_t(off_grid))) else: - pos1 = y + safe_call(backend.get().af_approx2_uniform_v2(c_pointer(output.arr), signal.arr, + pos0.arr, c_dim_t(interp_dim0), c_double_t(idx_start0), c_double_t(idx_step0), + pos1.arr, c_dim_t(interp_dim1), c_double_t(idx_start1), c_double_t(idx_step1), + method.value, c_float_t(off_grid))) - safe_call(backend.get().af_approx2(c_pointer(output.arr), signal.arr, - pos0.arr, pos1.arr, method.value, c_float_t(off_grid))) return output + def fft(signal, dim0 = None , scale = None): """ Fast Fourier Transform: 1D From a914b02e93a407394b318159df17f36362f79d28 Mon Sep 17 00:00:00 2001 From: syurkevi Date: Thu, 13 Aug 2020 19:40:10 -0400 Subject: [PATCH 186/212] adds gemm functionality, complex ctypes --- arrayfire/blas.py | 106 +++++++++++++++++++++++++++++++++++++++++++ arrayfire/library.py | 7 +++ 2 files changed, 113 insertions(+) diff --git a/arrayfire/blas.py b/arrayfire/blas.py index f0e9dfdc6..1f1cb1359 100644 --- a/arrayfire/blas.py +++ b/arrayfire/blas.py @@ -202,3 +202,109 @@ def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE, return_scalar = safe_call(backend.get().af_dot(c_pointer(out.arr), lhs.arr, rhs.arr, lhs_opts.value, rhs_opts.value)) return out + +def gemm(lhs, rhs, alpha=1.0, beta=0.0, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE, C=None): + """ + BLAS general matrix multiply (GEMM) of two af_array objects. + + This provides a general interface to the BLAS level 3 general matrix multiply (GEMM), which is generally defined as: + + C = α ∗ opA(A) opB(B)+ β∗C + + where α (alpha) and β (beta) are both scalars; A and B are the matrix multiply operands; + and opA and opB are noop (if AF_MAT_NONE) or transpose (if AF_MAT_TRANS) operations + on A or B before the actual GEMM operation. + Batched GEMM is supported if at least either A or B have more than two dimensions + (see af::matmul for more details on broadcasting). + However, only one alpha and one beta can be used for all of the batched matrix operands. + + Parameters + ---------- + + lhs : af.Array + A 2 dimensional, real or complex arrayfire array. + + rhs : af.Array + A 2 dimensional, real or complex arrayfire array. + + alpha : scalar + + beta : scalar + + lhs_opts: optional: af.MATPROP. default: af.MATPROP.NONE. + Can be one of + - af.MATPROP.NONE - If no op should be done on `lhs`. + - af.MATPROP.TRANS - If `lhs` has to be transposed before multiplying. + - af.MATPROP.CTRANS - If `lhs` has to be hermitian transposed before multiplying. + + rhs_opts: optional: af.MATPROP. default: af.MATPROP.NONE. + Can be one of + - af.MATPROP.NONE - If no op should be done on `rhs`. + - af.MATPROP.TRANS - If `rhs` has to be transposed before multiplying. + - af.MATPROP.CTRANS - If `rhs` has to be hermitian transposed before multiplying. + + Returns + ------- + + out : af.Array + Output of the matrix multiplication on `lhs` and `rhs`. + + Note + ----- + + - The data types of `lhs` and `rhs` should be the same. + - Batches are not supported. + + """ + if C is None: + out = Array() + else: + out = C + + ltype = lhs.dtype() + + if ltype == Dtype.f32: + aptr = c_cast(c_pointer(c_float_t(alpha)),c_void_ptr_t) + bptr = c_cast(c_pointer(c_float_t(beta)), c_void_ptr_t) + elif ltype == Dtype.c32: + if isinstance(alpha, af_cfloat_t): + aptr = c_cast(c_pointer(alpha), c_void_ptr_t) + elif isinstance(alpha, tuple): + aptr = c_cast(c_pointer(af_cfloat_t(alpha[0], alpha[1])), c_void_ptr_t) + else: + aptr = c_cast(c_pointer(af_cfloat_t(alpha)), c_void_ptr_t) + + if isinstance(beta, af_cfloat_t): + bptr = c_cast(c_pointer(beta), c_void_ptr_t) + elif isinstance(beta, tuple): + bptr = c_cast(c_pointer(af_cfloat_t(beta[0], beta[1])), c_void_ptr_t) + else: + bptr = c_cast(c_pointer(af_cfloat_t(beta)), c_void_ptr_t) + + elif ltype == Dtype.f64: + aptr = c_cast(c_pointer(c_double_t(alpha)),c_void_ptr_t) + bptr = c_cast(c_pointer(c_double_t(beta)), c_void_ptr_t) + elif ltype == Dtype.c64: + if isinstance(alpha, af_cdouble_t): + aptr = c_cast(c_pointer(alpha), c_void_ptr_t) + elif isinstance(alpha, tuple): + aptr = c_cast(c_pointer(af_cdouble_t(alpha[0], alpha[1])), c_void_ptr_t) + else: + aptr = c_cast(c_pointer(af_cdouble_t(alpha)), c_void_ptr_t) + + if isinstance(beta, af_cdouble_t): + bptr = c_cast(c_pointer(beta), c_void_ptr_t) + elif isinstance(beta, tuple): + bptr = c_cast(c_pointer(af_cdouble_t(beta[0], beta[1])), c_void_ptr_t) + else: + bptr = c_cast(c_pointer(af_cdouble_t(beta)), c_void_ptr_t) + elif ltype == Dtype.f16: + raise TypeError("fp16 currently unsupported gemm() input type") + else: + raise TypeError("unsupported input type") + + + safe_call(backend.get().af_gemm(c_pointer(out.arr), + lhs_opts.value, rhs_opts.value, + aptr, lhs.arr, rhs.arr, bptr)) + return out diff --git a/arrayfire/library.py b/arrayfire/library.py index 863c6746f..009a8e122 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -31,6 +31,13 @@ c_void_ptr_t = ct.c_void_p c_char_ptr_t = ct.c_char_p c_size_t = ct.c_size_t +c_cast = ct.cast + +class af_cfloat_t(ct.Structure): + _fields_ = [("real", ct.c_float), ("imag", ct.c_float)] + +class af_cdouble_t(ct.Structure): + _fields_ = [("real", ct.c_double), ("imag", ct.c_double)] AF_VER_MAJOR = '3' From bd1b38e9b147e7d409957751a0f0324af23dd1c9 Mon Sep 17 00:00:00 2001 From: syurkevi Date: Fri, 24 Jul 2020 01:53:27 -0400 Subject: [PATCH 187/212] adds missing logical operations on Array --- arrayfire/array.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arrayfire/array.py b/arrayfire/array.py index 50db2a9a8..1b71db2c7 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -1093,6 +1093,30 @@ def __invert__(self): safe_call(backend.get().af_bitnot(c_pointer(out.arr), self.arr)) return out + def logical_not(self): + """ + Return ~self + """ + out = Array() + safe_call(backend.get().af_not(c_pointer(out.arr), self.arr)) + return out + + def logical_and(self, other): + """ + Return self && other. + """ + out = Array() + safe_call(backend.get().af_and(c_pointer(out.arr), self.arr, other.arr)) #TODO: bcast var? + return out + + def logical_or(self, other): + """ + Return self || other. + """ + out = Array() + safe_call(backend.get().af_or(c_pointer(out.arr), self.arr, other.arr)) #TODO: bcast var? + return out + def __nonzero__(self): return self != 0 From f61d8103a6aaeddb30f796ce91504fb8d5f4a540 Mon Sep 17 00:00:00 2001 From: pradeep Date: Thu, 20 Aug 2020 14:29:59 +0530 Subject: [PATCH 188/212] Fix non-ASCII character(alpha,beta) usage in doc strings of gemm --- arrayfire/blas.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arrayfire/blas.py b/arrayfire/blas.py index 1f1cb1359..448261e90 100644 --- a/arrayfire/blas.py +++ b/arrayfire/blas.py @@ -209,10 +209,10 @@ def gemm(lhs, rhs, alpha=1.0, beta=0.0, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP. This provides a general interface to the BLAS level 3 general matrix multiply (GEMM), which is generally defined as: - C = α ∗ opA(A) opB(B)+ β∗C + C = alpha * opA(A) opB(B) + beta * C - where α (alpha) and β (beta) are both scalars; A and B are the matrix multiply operands; - and opA and opB are noop (if AF_MAT_NONE) or transpose (if AF_MAT_TRANS) operations + where alpha and beta are both scalars; A and B are the matrix multiply operands; + and opA and opB are noop (if AF_MAT_NONE) or transpose (if AF_MAT_TRANS) operations on A or B before the actual GEMM operation. Batched GEMM is supported if at least either A or B have more than two dimensions (see af::matmul for more details on broadcasting). From 5203d02e482844a9030325c09310dffe26611304 Mon Sep 17 00:00:00 2001 From: pradeep Date: Thu, 20 Aug 2020 14:30:59 +0530 Subject: [PATCH 189/212] Update copyright year and authors in package config and docs --- docs/conf.py | 4 ++-- setup.cfg | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 04937888d..44374afb1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -58,8 +58,8 @@ # General information about the project. project = 'ArrayFire' -copyright = '2016, Pavan Yalamanchili' -author = 'Pavan Yalamanchili' +copyright = '2020, ArrayFire' +author = 'Stefan Yurkevitch, Pradeep Garigipati, Umar Arshad' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/setup.cfg b/setup.cfg index e4f536a88..831f2063b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,8 +4,8 @@ version = 3.7.20200213 description = Python bindings for ArrayFire licence = BSD long_description = file: README.md -maintainer = Pavan Yalamanchili -maintainer_email = contact@pavanky.com +maintainer = ArrayFire +maintainer_email = technical@arrayfire.com url = http://arrayfire.com classifiers = Programming Language :: Python From b4992b6f561d61bde74ca91246b637d78429c117 Mon Sep 17 00:00:00 2001 From: pradeep Date: Thu, 20 Aug 2020 14:33:51 +0530 Subject: [PATCH 190/212] Fix meanvar & convolve2NNGradient API unit tests --- tests/simple/signal.py | 4 +++- tests/simple/statistics.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/simple/signal.py b/tests/simple/signal.py index 9e72e6e35..0e3e8da9d 100644 --- a/tests/simple/signal.py +++ b/tests/simple/signal.py @@ -103,7 +103,9 @@ def simple_signal(verbose=False): c = af.convolve2NN(a, b) display_func(c) - g = af.convolve2NN(a, b, c, gradType=af.CONV_GRADIENT.DATA) + in_dims = c.dims() + incoming_grad = af.constant(1, in_dims[0], in_dims[1]); + g = af.convolve2GradientNN(incoming_grad, a, b, c) display_func(g) a = af.randu(5, 5, 3) diff --git a/tests/simple/statistics.py b/tests/simple/statistics.py index be639ea4a..174af0a5b 100644 --- a/tests/simple/statistics.py +++ b/tests/simple/statistics.py @@ -34,10 +34,10 @@ def simple_statistics(verbose=False): print_func(af.var(a, isbiased=True)) print_func(af.var(a, weights=w)) - mean, var = af.mean_var(a, dim=0) + mean, var = af.meanvar(a, dim=0) display_func(mean) display_func(var) - mean, var = af.mean_var(a, weights=w, bias=VARIANCE.SAMPLE, dim=0) + mean, var = af.meanvar(a, weights=w, bias=af.VARIANCE.SAMPLE, dim=0) display_func(mean) display_func(var) From a2a85ac8d8b17dddcf927cab3b0b0ff9567a579b Mon Sep 17 00:00:00 2001 From: pradeep Date: Thu, 20 Aug 2020 15:11:32 +0530 Subject: [PATCH 191/212] Fix documentation of convolve2GradientNN --- arrayfire/ml.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/arrayfire/ml.py b/arrayfire/ml.py index 9140cc278..7e0fc53de 100644 --- a/arrayfire/ml.py +++ b/arrayfire/ml.py @@ -18,11 +18,14 @@ def convolve2GradientNN(incoming_gradient, original_signal, original_kernel, convolved_output, stride = (1, 1), padding = (0, 0), dilation = (1, 1), gradType = CONV_GRADIENT.DEFAULT): """ - This version of convolution is consistent with the machine learning - formulation that will spatially convolve a filter on 2-dimensions against a - signal. Multiple signals and filters can be batched against each other. - Furthermore, the signals and filters can be multi-dimensional however their - dimensions must match. + Function for calculating backward pass gradient of 2D convolution. + + This function calculates the gradient with respect to the output of the + \ref convolve2NN() function that uses the machine learning formulation + for the dimensions of the signals and filters + + Multiple signals and filters can be batched against each other, however + their dimensions must match. Example: Signals with dimensions: d0 x d1 x d2 x Ns @@ -33,12 +36,18 @@ def convolve2GradientNN(incoming_gradient, original_signal, original_kernel, con Parameters ----------- - signal: af.Array + incoming_gradient: af.Array + - Gradients to be distributed in backwards pass + + original_signal: af.Array - A 2 dimensional signal or batch of 2 dimensional signals. - kernel: af.Array + original_kernel: af.Array - A 2 dimensional kernel or batch of 2 dimensional kernels. + convolved_output: af.Array + - output of forward pass of convolution + stride: tuple of ints. default: (1, 1). - Specifies how much to stride along each dimension From 96a66da4d8d3e09d51071b3eb4b52ab5e3f1bf86 Mon Sep 17 00:00:00 2001 From: pradeep Date: Thu, 20 Aug 2020 16:16:59 +0530 Subject: [PATCH 192/212] Fix a semantic error in indexing unit test --- tests/simple/index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/simple/index.py b/tests/simple/index.py index a0b0cc757..8bb4b571a 100644 --- a/tests/simple/index.py +++ b/tests/simple/index.py @@ -70,7 +70,7 @@ def simple_index(verbose=False): rows = af.constant(0, 1, dtype=af.Dtype.s32) b = a[:, rows] display_func(b) - for r in rows: + for r in range(rows.elements()): display_func(r) display_func(b[:, r]) From 834dc14fcb132a8eb028159779671fc07ee7f958 Mon Sep 17 00:00:00 2001 From: pradeep Date: Thu, 20 Aug 2020 16:18:35 +0530 Subject: [PATCH 193/212] Add assets submodule for graphics examples to be added later --- .gitmodules | 3 +++ assets | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 assets diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..154589c05 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "assets"] + path = assets + url = https://github.com/arrayfire/assets.git diff --git a/assets b/assets new file mode 160000 index 000000000..cd08d7496 --- /dev/null +++ b/assets @@ -0,0 +1 @@ +Subproject commit cd08d749611b324012555ad6f23fd76c5465bd6c From fabe335e30e902ffed537fc9636137507886efc1 Mon Sep 17 00:00:00 2001 From: Mark Poscablo Date: Mon, 4 Feb 2019 17:02:22 -0500 Subject: [PATCH 194/212] Added logistic regression example --- examples/common/idxio.py | 64 ++++++ .../machine_learning/logistic_regression.py | 205 ++++++++++++++++++ examples/machine_learning/mnist_common.py | 101 +++++++++ 3 files changed, 370 insertions(+) create mode 100644 examples/common/idxio.py create mode 100644 examples/machine_learning/logistic_regression.py create mode 100644 examples/machine_learning/mnist_common.py diff --git a/examples/common/idxio.py b/examples/common/idxio.py new file mode 100644 index 000000000..2aa4208a9 --- /dev/null +++ b/examples/common/idxio.py @@ -0,0 +1,64 @@ +#!/usr/bin/python + +####################################################### +# Copyright (c) 2019, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +def reverse_char(b): + b = (b & 0xF0) >> 4 | (b & 0x0F) << 4 + b = (b & 0xCC) >> 2 | (b & 0x33) << 2 + b = (b & 0xAA) >> 1 | (b & 0x55) << 1 + return b + + +# http://stackoverflow.com/a/9144870/2192361 +def reverse(x): + x = ((x >> 1) & 0x55555555) | ((x & 0x55555555) << 1) + x = ((x >> 2) & 0x33333333) | ((x & 0x33333333) << 2) + x = ((x >> 4) & 0x0f0f0f0f) | ((x & 0x0f0f0f0f) << 4) + x = ((x >> 8) & 0x00ff00ff) | ((x & 0x00ff00ff) << 8) + x = ((x >> 16) & 0xffff) | ((x & 0xffff) << 16); + return x + + +def read_idx(name): + with open(name, 'rb') as f: + # In the C++ version, bytes the size of 4 chars are being read + # May not work properly in machines where a char is not 1 byte + bytes_read = f.read(4) + bytes_read = bytearray(bytes_read) + + if bytes_read[2] != 8: + raise RuntimeError('Unsupported data type') + + numdims = bytes_read[3] + elemsize = 1 + + # Read the dimensions + elem = 1 + dims = [0] * numdims + for i in range(numdims): + bytes_read = bytearray(f.read(4)) + + # Big endian to little endian + for j in range(4): + bytes_read[j] = reverse_char(bytes_read[j]) + bytes_read_int = int.from_bytes(bytes_read, 'little') + dim = reverse(bytes_read_int) + + elem = elem * dim; + dims[i] = dim; + + # Read the data + cdata = f.read(elem * elemsize) + cdata = list(cdata) + data = [float(cdata_elem) for cdata_elem in cdata] + + return (dims, data) + + diff --git a/examples/machine_learning/logistic_regression.py b/examples/machine_learning/logistic_regression.py new file mode 100644 index 000000000..79596cbc8 --- /dev/null +++ b/examples/machine_learning/logistic_regression.py @@ -0,0 +1,205 @@ +#!/usr/bin/python + +####################################################### +# Copyright (c) 2019, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +from mnist_common import display_results, setup_mnist + +import sys +import time + +import arrayfire as af +from arrayfire.algorithm import max, imax, count, sum +from arrayfire.arith import abs, sigmoid, log +from arrayfire.array import transpose +from arrayfire.blas import matmul, matmulTN +from arrayfire.data import constant, join, lookup, moddims +from arrayfire.device import set_device, sync, eval + + +def accuracy(predicted, target): + _, tlabels = af.imax(target, 1) + _, plabels = af.imax(predicted, 1) + return 100 * af.count(plabels == tlabels) / tlabels.elements() + + +def abserr(predicted, target): + return 100 * af.sum(af.abs(predicted - target)) / predicted.elements() + + +# Predict (probability) based on given parameters +def predict_proba(X, Weights): + Z = af.matmul(X, Weights) + return af.sigmoid(Z) + + +# Predict (log probability) based on given parameters +def predict_log_proba(X, Weights): + return af.log(predict_proba(X, Weights)) + + +# Give most likely class based on given parameters +def predict(X, Weights): + probs = predict_proba(X, Weights) + _, classes = af.imax(probs, 1) + return classes + + +def cost(Weights, X, Y, lambda_param=1.0): + # Number of samples + m = Y.dims()[0] + + dim0 = Weights.dims()[0] + dim1 = Weights.dims()[1] if len(Weights.dims()) > 1 else None + dim2 = Weights.dims()[2] if len(Weights.dims()) > 2 else None + dim3 = Weights.dims()[3] if len(Weights.dims()) > 3 else None + # Make the lambda corresponding to Weights(0) == 0 + lambdat = af.constant(lambda_param, dim0, dim1, dim2, dim3) + + # No regularization for bias weights + lambdat[0, :] = 0 + + # Get the prediction + H = predict_proba(X, Weights) + + # Cost of misprediction + Jerr = -1 * af.sum(Y * af.log(H) + (1 - Y) * af.log(1 - H), dim=0) + + # Regularization cost + Jreg = 0.5 * af.sum(lambdat * Weights * Weights, dim=0) + + # Total cost + J = (Jerr + Jreg) / m + + # Find the gradient of cost + D = (H - Y) + dJ = (af.matmulTN(X, D) + lambdat * Weights) / m + + return J, dJ + + +def train(X, Y, alpha=0.1, lambda_param=1.0, maxerr=0.01, maxiter=1000, verbose=False): + # Initialize parameters to 0 + Weights = af.constant(0, X.dims()[1], Y.dims()[1]) + + for i in range(maxiter): + # Get the cost and gradient + J, dJ = cost(Weights, X, Y, lambda_param) + + err = af.max(af.abs(J)) + if err < maxerr: + print('Iteration {0:4d} Err: {1:4f}'.format(i + 1, err)) + print('Training converged') + return Weights + + if verbose and ((i+1) % 10 == 0): + print('Iteration {0:4d} Err: {1:4f}'.format(i + 1, err)) + + # Update the parameters via gradient descent + Weights = Weights - alpha * dJ + + if verbose: + print('Training stopped after {0:d} iterations'.format(maxiter)) + + return Weights + + +def benchmark_logistic_regression(train_feats, train_targets, test_feats): + t0 = time.time() + Weights = train(train_feats, train_targets, 0.1, 1.0, 0.01, 1000) + af.eval(Weights) + sync() + t1 = time.time() + dt = t1 - t0 + print('Training time: {0:4.4f} s'.format(dt)) + + t0 = time.time() + iters = 100 + for i in range(iters): + test_outputs = predict(test_feats, Weights) + af.eval(test_outputs) + sync() + t1 = time.time() + dt = t1 - t0 + print('Prediction time: {0:4.4f} s'.format(dt / iters)) + + +# Demo of one vs all logistic regression +def logit_demo(console, perc): + # Load mnist data + frac = float(perc) / 100.0 + mnist_data = setup_mnist(frac, True) + num_classes = mnist_data[0] + num_train = mnist_data[1] + num_test = mnist_data[2] + train_images = mnist_data[3] + test_images = mnist_data[4] + train_targets = mnist_data[5] + test_targets = mnist_data[6] + + # Reshape images into feature vectors + feature_length = int(train_images.elements() / num_train); + train_feats = af.transpose(af.moddims(train_images, feature_length, num_train)) + test_feats = af.transpose(af.moddims(test_images, feature_length, num_test)) + + train_targets = af.transpose(train_targets) + test_targets = af.transpose(test_targets) + + num_train = train_feats.dims()[0] + num_test = test_feats.dims()[0] + + # Add a bias that is always 1 + train_bias = af.constant(1, num_train, 1) + test_bias = af.constant(1, num_test, 1) + train_feats = af.join(1, train_bias, train_feats) + test_feats = af.join(1, test_bias, test_feats) + + # Train logistic regression parameters + Weights = train(train_feats, train_targets, + 0.1, # learning rate + 1.0, # regularization constant + 0.01, # max error + 1000, # max iters + True # verbose mode + ) + af.eval(Weights) + af.sync() + + # Predict the results + train_outputs = predict_proba(train_feats, Weights) + test_outputs = predict_proba(test_feats, Weights) + + print('Accuracy on training data: {0:2.2f}'.format(accuracy(train_outputs, train_targets))) + print('Accuracy on testing data: {0:2.2f}'.format(accuracy(test_outputs, test_targets))) + print('Maximum error on testing data: {0:2.2f}'.format(abserr(test_outputs, test_targets))) + + benchmark_logistic_regression(train_feats, train_targets, test_feats) + + if not console: + test_outputs = af.transpose(test_outputs) + # Get 20 random test images + display_results(test_images, test_outputs, af.transpose(test_targets), 20, True) + +def main(): + argc = len(sys.argv) + + device = int(sys.argv[1]) if argc > 1 else 0 + console = sys.argv[2][0] == '-' if argc > 2 else False + perc = int(sys.argv[3]) if argc > 3 else 60 + + try: + af.set_device(device) + af.info() + logit_demo(console, perc) + except Exception as e: + print('Error: ', str(e)) + + +if __name__ == '__main__': + main() diff --git a/examples/machine_learning/mnist_common.py b/examples/machine_learning/mnist_common.py new file mode 100644 index 000000000..3911cbd34 --- /dev/null +++ b/examples/machine_learning/mnist_common.py @@ -0,0 +1,101 @@ +#!/usr/bin/python + +####################################################### +# Copyright (c) 2019, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +import sys +sys.path.insert(0, '../common') +from idxio import read_idx + +import arrayfire as af +from arrayfire.algorithm import where +from arrayfire.array import Array +from arrayfire.data import constant, lookup, moddims +from arrayfire.random import randu + + +def classify(arr, k, expand_labels): + ret_str = '' + if expand_labels: + vec = arr[:, k].as_type(af.Dtype.f32) + h_vec = vec.to_list() + data = [] + + for i in range(vec.elements()): + data.append((h_vec[i], i)) + + data = sorted(data, key=lambda pair: pair[0], reverse=True) + + ret_str = str(data[0][1]) + + else: + ret_str = str(int(arr[k].as_type(af.Dtype.f32).scalar())) + + return ret_str + + +def setup_mnist(frac, expand_labels): + idims, idata = read_idx('../../assets/examples/data/mnist/images-subset') + ldims, ldata = read_idx('../../assets/examples/data/mnist/labels-subset') + + idims.reverse() + numdims = len(idims) + images = af.Array(idata, tuple(idims)) + + R = af.randu(10000, 1); + cond = R < min(frac, 0.8) + train_indices = af.where(cond) + test_indices = af.where(~cond) + + train_images = af.lookup(images, train_indices, 2) / 255 + test_images = af.lookup(images, test_indices, 2) / 255 + + num_classes = 10 + num_train = train_images.dims()[2] + num_test = test_images.dims()[2] + + if expand_labels: + train_labels = af.constant(0, num_classes, num_train) + test_labels = af.constant(0, num_classes, num_test) + + h_train_idx = train_indices.to_list() + h_test_idx = test_indices.to_list() + + for i in range(num_train): + train_labels[ldata[h_train_idx[i]], i] = 1 + + for i in range(num_test): + test_labels[ldata[h_test_idx[i]], i] = 1 + + else: + labels = af.Array(ldata, tuple(ldims)) + train_labels = labels[train_indices] + test_labels = labels[test_indices] + + return (num_classes, + num_train, + num_test, + train_images, + test_images, + train_labels, + test_labels) + + +def display_results(test_images, test_output, test_actual, num_display, expand_labels): + for i in range(num_display): + print('Predicted: ', classify(test_output, i, expand_labels)) + print('Actual: ', classify(test_actual, i, expand_labels)) + + img = (test_images[:, :, i] > 0.1).as_type(af.Dtype.u8) + img = af.moddims(img, img.elements()).to_list() + for j in range(28): + for k in range(28): + print('\u2588' if img[j * 28 + k] > 0 else ' ', end='') + print() + input() From 956a2276c0299364de3bc2fb642ba341243b9e44 Mon Sep 17 00:00:00 2001 From: Mark Poscablo Date: Tue, 5 Feb 2019 10:54:24 -0500 Subject: [PATCH 195/212] Corrected predict method names --- .../machine_learning/logistic_regression.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/machine_learning/logistic_regression.py b/examples/machine_learning/logistic_regression.py index 79596cbc8..ffe7efa4b 100644 --- a/examples/machine_learning/logistic_regression.py +++ b/examples/machine_learning/logistic_regression.py @@ -34,19 +34,19 @@ def abserr(predicted, target): # Predict (probability) based on given parameters -def predict_proba(X, Weights): +def predict_prob(X, Weights): Z = af.matmul(X, Weights) return af.sigmoid(Z) # Predict (log probability) based on given parameters -def predict_log_proba(X, Weights): - return af.log(predict_proba(X, Weights)) +def predict_log_prob(X, Weights): + return af.log(predict_prob(X, Weights)) # Give most likely class based on given parameters -def predict(X, Weights): - probs = predict_proba(X, Weights) +def predict_class(X, Weights): + probs = predict_prob(X, Weights) _, classes = af.imax(probs, 1) return classes @@ -66,7 +66,7 @@ def cost(Weights, X, Y, lambda_param=1.0): lambdat[0, :] = 0 # Get the prediction - H = predict_proba(X, Weights) + H = predict_prob(X, Weights) # Cost of misprediction Jerr = -1 * af.sum(Y * af.log(H) + (1 - Y) * af.log(1 - H), dim=0) @@ -122,7 +122,7 @@ def benchmark_logistic_regression(train_feats, train_targets, test_feats): t0 = time.time() iters = 100 for i in range(iters): - test_outputs = predict(test_feats, Weights) + test_outputs = predict_prob(test_feats, Weights) af.eval(test_outputs) sync() t1 = time.time() @@ -172,8 +172,8 @@ def logit_demo(console, perc): af.sync() # Predict the results - train_outputs = predict_proba(train_feats, Weights) - test_outputs = predict_proba(test_feats, Weights) + train_outputs = predict_prob(train_feats, Weights) + test_outputs = predict_prob(test_feats, Weights) print('Accuracy on training data: {0:2.2f}'.format(accuracy(train_outputs, train_targets))) print('Accuracy on testing data: {0:2.2f}'.format(accuracy(test_outputs, test_targets))) From a2caffadcc20cbceaa51f58cbd81cc85830d8d6a Mon Sep 17 00:00:00 2001 From: pradeep Date: Tue, 8 Sep 2020 11:08:11 +0530 Subject: [PATCH 196/212] Use os util to fetch mnist data location from example location --- examples/machine_learning/mnist_common.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/machine_learning/mnist_common.py b/examples/machine_learning/mnist_common.py index 3911cbd34..6a5ba8be9 100644 --- a/examples/machine_learning/mnist_common.py +++ b/examples/machine_learning/mnist_common.py @@ -9,6 +9,7 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## +import os import sys sys.path.insert(0, '../common') from idxio import read_idx @@ -41,8 +42,10 @@ def classify(arr, k, expand_labels): def setup_mnist(frac, expand_labels): - idims, idata = read_idx('../../assets/examples/data/mnist/images-subset') - ldims, ldata = read_idx('../../assets/examples/data/mnist/labels-subset') + root_path = os.path.dirname(os.path.abspath(__file__)) + file_path = root_path + '/../../assets/examples/data/mnist/' + idims, idata = read_idx(file_path + 'images-subset') + ldims, ldata = read_idx(file_path + 'labels-subset') idims.reverse() numdims = len(idims) From e85cefc745afb47511d58ce6d7de8bf905bb503b Mon Sep 17 00:00:00 2001 From: pradeep Date: Wed, 9 Sep 2020 13:11:03 +0530 Subject: [PATCH 197/212] Update python sheband in ML examples to widely adopted convention --- examples/common/idxio.py | 2 +- examples/machine_learning/logistic_regression.py | 2 +- examples/machine_learning/mnist_common.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/common/idxio.py b/examples/common/idxio.py index 2aa4208a9..8776c62dc 100644 --- a/examples/common/idxio.py +++ b/examples/common/idxio.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### # Copyright (c) 2019, ArrayFire diff --git a/examples/machine_learning/logistic_regression.py b/examples/machine_learning/logistic_regression.py index ffe7efa4b..b1d8b6e42 100644 --- a/examples/machine_learning/logistic_regression.py +++ b/examples/machine_learning/logistic_regression.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### # Copyright (c) 2019, ArrayFire diff --git a/examples/machine_learning/mnist_common.py b/examples/machine_learning/mnist_common.py index 6a5ba8be9..3f38302df 100644 --- a/examples/machine_learning/mnist_common.py +++ b/examples/machine_learning/mnist_common.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### # Copyright (c) 2019, ArrayFire From 0570570b67b9c23e778943fea0cb9ab26d7f00e5 Mon Sep 17 00:00:00 2001 From: syurkevi Date: Thu, 30 Aug 2018 16:43:57 -0400 Subject: [PATCH 198/212] adds computer vision example --- examples/computer_vision/fast.py | 81 ++++++++++++++++++ examples/computer_vision/harris.py | 119 +++++++++++++++++++++++++++ examples/computer_vision/matching.py | 105 +++++++++++++++++++++++ examples/computer_vision/susan.py | 81 ++++++++++++++++++ 4 files changed, 386 insertions(+) create mode 100644 examples/computer_vision/fast.py create mode 100644 examples/computer_vision/harris.py create mode 100644 examples/computer_vision/matching.py create mode 100644 examples/computer_vision/susan.py diff --git a/examples/computer_vision/fast.py b/examples/computer_vision/fast.py new file mode 100644 index 000000000..f70193e5e --- /dev/null +++ b/examples/computer_vision/fast.py @@ -0,0 +1,81 @@ +#!/usr/bin/python + +####################################################### +# Copyright (c) 2018, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +from time import time +import arrayfire as af +import sys + +def draw_corners(img, x, y, draw_len): + # Draw vertical line of (draw_len * 2 + 1) pixels centered on the corner + # Set only the first channel to 1 (green lines) + xmin = max(0, x - draw_len) + xmax = min(img.dims()[1], x + draw_len) + + img[y, xmin : xmax, 0] = 0.0 + img[y, xmin : xmax, 1] = 1.0 + img[y, xmin : xmax, 2] = 0.0 + + # Draw vertical line of (draw_len * 2 + 1) pixels centered on the corner + # Set only the first channel to 1 (green lines) + ymin = max(0, y - draw_len) + ymax = min(img.dims()[0], y + draw_len) + + img[ymin : ymax, x, 0] = 0.0 + img[ymin : ymax, x, 1] = 1.0 + img[ymin : ymax, x, 2] = 0.0 + return img + +def fast_demo(console): + + if console: + img_color = af.load_image("../../assets/examples/images/square.png", True); + else: + img_color = af.load_image("../../assets/examples/images/man.jpg", True); + + img_color /= 255.0 + img = af.color_space(img_color, af.CSPACE.GRAY, af.CSPACE.RGB) + + features = af.fast(img) + + xs = features.get_xpos() + ys = features.get_ypos() + + draw_len = 3; + num_features = features.num_features().value + for f in range(num_features): + print(f) + x = xs[f] + y = ys[f] + + img_color = draw_corners(img_color, x, y, draw_len) + + + print("Features found: {}".format(num_features)) + if not console: + # Previews color image with green crosshairs + wnd = af.Window(512, 512, "FAST Feature Detector") + + while not wnd.close(): + wnd.image(img_color) + else: + print(xs); + print(ys); + + +if __name__ == "__main__": + if (len(sys.argv) > 1): + af.set_device(int(sys.argv[1])) + console = (sys.argv[2] == '-') if len(sys.argv) > 2 else False + + af.info() + print("** ArrayFire FAST Feature Detector Demo **\n") + fast_demo(console) + diff --git a/examples/computer_vision/harris.py b/examples/computer_vision/harris.py new file mode 100644 index 000000000..bb89c3ac4 --- /dev/null +++ b/examples/computer_vision/harris.py @@ -0,0 +1,119 @@ +#!/usr/bin/python + +####################################################### +# Copyright (c) 2018, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +from time import time +import arrayfire as af +import sys + +def draw_corners(img, x, y, draw_len): + # Draw vertical line of (draw_len * 2 + 1) pixels centered on the corner + # Set only the first channel to 1 (green lines) + xmin = max(0, x - draw_len) + xmax = min(img.dims()[1], x + draw_len) + + img[y, xmin : xmax, 0] = 0.0 + img[y, xmin : xmax, 1] = 1.0 + img[y, xmin : xmax, 2] = 0.0 + + # Draw vertical line of (draw_len * 2 + 1) pixels centered on the corner + # Set only the first channel to 1 (green lines) + ymin = max(0, y - draw_len) + ymax = min(img.dims()[0], y + draw_len) + + img[ymin : ymax, x, 0] = 0.0 + img[ymin : ymax, x, 1] = 1.0 + img[ymin : ymax, x, 2] = 0.0 + return img + +def harris_demo(console): + + if console: + img_color = af.load_image("../../assets/examples/images/square.png", True); + else: + img_color = af.load_image("../../assets/examples/images/man.jpg", True); + + img_color /= 255.0 + img = af.color_space(img_color, af.CSPACE.GRAY, af.CSPACE.RGB) + + ix, iy = af.gradient(img) + ixx = ix * ix + ixy = ix * iy + iyy = iy * iy + + # Compute a Gaussian kernel with standard deviation of 1.0 and length of 5 pixels + # These values can be changed to use a smaller or larger window + gauss_filt = af.gaussian_kernel(5, 5, 1.0, 1.0) + + # Filter second order derivatives + ixx = af.convolve(ixx, gauss_filt) + ixy = af.convolve(ixy, gauss_filt) + iyy = af.convolve(iyy, gauss_filt) + + # Calculate trace + itr = ixx + iyy + + # Calculate determinant + idet = ixx * iyy - ixy * ixy + + # Calculate Harris response + response = idet - 0.04 * (itr * itr) + + # Get maximum response for each 3x3 neighborhood + mask = af.constant(1, 3, 3) + max_resp = af.dilate(response, mask) + + # Discard responses that are not greater than threshold + corners = response > 1e5 + corners = corners * response + + # Discard responses that are not equal to maximum neighborhood response, + # scale them to original value + corners = (corners == max_resp) * corners + + # Copy device array to python list on host + corners_list = corners.to_list() + + draw_len = 3 + good_corners = 0 + for x in range(img_color.dims()[1]): + for y in range(img_color.dims()[0]): + if corners_list[x][y] > 1e5: + img_color = draw_corners(img_color, x, y, draw_len) + good_corners += 1 + + + print("Corners found: {}".format(good_corners)) + if not console: + # Previews color image with green crosshairs + wnd = af.Window(512, 512, "FAST Feature Detector") + + while not wnd.close(): + wnd.image(img_color) + else: + idx = af.where(corners) + + corners_x = idx / corners.dims()[0] + corners_y = idx % corners.dims()[0] + + print(corners_x) + print(corners_y) + + +if __name__ == "__main__": + if (len(sys.argv) > 1): + af.set_device(int(sys.argv[1])) + console = (sys.argv[2] == '-') if len(sys.argv) > 2 else False + + af.info() + print("** ArrayFire Harris Corner Detector Demo **\n") + + harris_demo(console) + diff --git a/examples/computer_vision/matching.py b/examples/computer_vision/matching.py new file mode 100644 index 000000000..797781212 --- /dev/null +++ b/examples/computer_vision/matching.py @@ -0,0 +1,105 @@ +#!/usr/bin/python + +####################################################### +# Copyright (c) 2018, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +from time import time +import arrayfire as af +import sys + +def normalize(a): + max_ = float(af.max(a)) + min_ = float(af.min(a)) + return (a - min_) / (max_ - min_) + +def draw_rectangle(img, x, y, wx, wy): + print("\nMatching patch origin = ({}, {})\n".format(x, y)) + + # top edge + img[y, x : x + wx, 0] = 0.0 + img[y, x : x + wx, 1] = 0.0 + img[y, x : x + wx, 2] = 1.0 + + # bottom edge + img[y + wy, x : x + wx, 0] = 0.0 + img[y + wy, x : x + wx, 1] = 0.0 + img[y + wy, x : x + wx, 2] = 1.0 + + # left edge + img[y : y + wy, x, 0] = 0.0 + img[y : y + wy, x, 1] = 0.0 + img[y : y + wy, x, 2] = 1.0 + + # left edge + img[y : y + wy, x + wx, 0] = 0.0 + img[y : y + wy, x + wx, 1] = 0.0 + img[y : y + wy, x + wx, 2] = 1.0 + + return img + +def templateMatchingDemo(console): + + if console: + img_color = af.load_image("../../assets/examples/images/square.png", True); + else: + img_color = af.load_image("../../assets/examples/images/man.jpg", True); + + # Convert the image from RGB to gray-scale + img = af.color_space(img_color, af.CSPACE.GRAY, af.CSPACE.RGB) + iDims = img.dims() + print("Input image dimensions: ", iDims) + + # Extract a patch from the input image + patch_size = 100 + tmp_img = img[100 : 100+patch_size, 100 : 100+patch_size] + + result = af.match_template(img, tmp_img) # Default disparity metric is + # Sum of Absolute differences (SAD) + # Currently supported metrics are + # AF_SAD, AF_ZSAD, AF_LSAD, AF_SSD, + # AF_ZSSD, AF_LSSD + + disp_img = img / 255.0 + disp_tmp = tmp_img / 255.0 + disp_res = normalize(result) + + minval, minloc = af.imin(disp_res) + print("Location(linear index) of minimum disparity value = {}".format(minloc)) + + if not console: + marked_res = af.tile(disp_img, 1, 1, 3) + marked_res = draw_rectangle(marked_res, minloc%iDims[0], minloc/iDims[0],\ + patch_size, patch_size) + + print("Note: Based on the disparity metric option provided to matchTemplate function") + print("either minimum or maximum disparity location is the starting corner") + print("of our best matching patch to template image in the search image") + + wnd = af.Window(512, 512, "Template Matching Demo") + + while not wnd.close(): + wnd.set_colormap(af.COLORMAP.DEFAULT) + wnd.grid(2, 2) + wnd[0, 0].image(disp_img, "Search Image" ) + wnd[0, 1].image(disp_tmp, "Template Patch" ) + wnd[1, 0].image(marked_res, "Best Match" ) + wnd.set_colormap(af.COLORMAP.HEAT) + wnd[1, 1].image(disp_res, "Disparity Values") + wnd.show() + + +if __name__ == "__main__": + if (len(sys.argv) > 1): + af.set_device(int(sys.argv[1])) + console = (sys.argv[2] == '-') if len(sys.argv) > 2 else False + + af.info() + print("** ArrayFire template matching Demo **\n") + templateMatchingDemo(console) + diff --git a/examples/computer_vision/susan.py b/examples/computer_vision/susan.py new file mode 100644 index 000000000..6211128d5 --- /dev/null +++ b/examples/computer_vision/susan.py @@ -0,0 +1,81 @@ +#!/usr/bin/python + +####################################################### +# Copyright (c) 2018, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + +from time import time +import arrayfire as af +import sys + +def draw_corners(img, x, y, draw_len): + # Draw vertical line of (draw_len * 2 + 1) pixels centered on the corner + # Set only the first channel to 1 (green lines) + xmin = max(0, x - draw_len) + xmax = min(img.dims()[1], x + draw_len) + + img[y, xmin : xmax, 0] = 0.0 + img[y, xmin : xmax, 1] = 1.0 + img[y, xmin : xmax, 2] = 0.0 + + # Draw vertical line of (draw_len * 2 + 1) pixels centered on the corner + # Set only the first channel to 1 (green lines) + ymin = max(0, y - draw_len) + ymax = min(img.dims()[0], y + draw_len) + + img[ymin : ymax, x, 0] = 0.0 + img[ymin : ymax, x, 1] = 1.0 + img[ymin : ymax, x, 2] = 0.0 + return img + +def susan_demo(console): + + if console: + img_color = af.load_image("../../assets/examples/images/square.png", True); + else: + img_color = af.load_image("../../assets/examples/images/man.jpg", True); + + img_color /= 255.0 + img = af.color_space(img_color, af.CSPACE.GRAY, af.CSPACE.RGB) + + features = af.susan(img) + + xs = features.get_xpos() + ys = features.get_ypos() + + draw_len = 3; + num_features = features.num_features().value + for f in range(num_features): + print(f) + x = xs[f] + y = ys[f] + + img_color = draw_corners(img_color, x, y, draw_len) + + + print("Features found: {}".format(num_features)) + if not console: + # Previews color image with green crosshairs + wnd = af.Window(512, 512, "SUSAN Feature Detector") + + while not wnd.close(): + wnd.image(img_color) + else: + print(xs); + print(ys); + + +if __name__ == "__main__": + if (len(sys.argv) > 1): + af.set_device(int(sys.argv[1])) + console = (sys.argv[2] == '-') if len(sys.argv) > 2 else False + + af.info() + print("** ArrayFire SUSAN Feature Detector Demo **\n") + susan_demo(console) + From 7501eeab36d21beaf705b5546cdc1855fde98462 Mon Sep 17 00:00:00 2001 From: syurkevi Date: Thu, 30 Aug 2018 17:04:20 -0400 Subject: [PATCH 199/212] image range updates fixing matching --- examples/computer_vision/fast.py | 10 +++++----- examples/computer_vision/harris.py | 6 +++--- examples/computer_vision/susan.py | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/computer_vision/fast.py b/examples/computer_vision/fast.py index f70193e5e..584ff6618 100644 --- a/examples/computer_vision/fast.py +++ b/examples/computer_vision/fast.py @@ -25,8 +25,8 @@ def draw_corners(img, x, y, draw_len): # Draw vertical line of (draw_len * 2 + 1) pixels centered on the corner # Set only the first channel to 1 (green lines) - ymin = max(0, y - draw_len) - ymax = min(img.dims()[0], y + draw_len) + ymin = int(max(0, y - draw_len)) + ymax = int(min(img.dims()[0], y + draw_len)) img[ymin : ymax, x, 0] = 0.0 img[ymin : ymax, x, 1] = 1.0 @@ -40,13 +40,13 @@ def fast_demo(console): else: img_color = af.load_image("../../assets/examples/images/man.jpg", True); - img_color /= 255.0 img = af.color_space(img_color, af.CSPACE.GRAY, af.CSPACE.RGB) + img_color /= 255.0 features = af.fast(img) - xs = features.get_xpos() - ys = features.get_ypos() + xs = features.get_xpos().to_list() + ys = features.get_ypos().to_list() draw_len = 3; num_features = features.num_features().value diff --git a/examples/computer_vision/harris.py b/examples/computer_vision/harris.py index bb89c3ac4..1c8e53804 100644 --- a/examples/computer_vision/harris.py +++ b/examples/computer_vision/harris.py @@ -40,8 +40,8 @@ def harris_demo(console): else: img_color = af.load_image("../../assets/examples/images/man.jpg", True); - img_color /= 255.0 img = af.color_space(img_color, af.CSPACE.GRAY, af.CSPACE.RGB) + img_color /= 255.0 ix, iy = af.gradient(img) ixx = ix * ix @@ -100,8 +100,8 @@ def harris_demo(console): else: idx = af.where(corners) - corners_x = idx / corners.dims()[0] - corners_y = idx % corners.dims()[0] + corners_x = idx / float(corners.dims()[0]) + corners_y = idx % float(corners.dims()[0]) print(corners_x) print(corners_y) diff --git a/examples/computer_vision/susan.py b/examples/computer_vision/susan.py index 6211128d5..025001b49 100644 --- a/examples/computer_vision/susan.py +++ b/examples/computer_vision/susan.py @@ -40,13 +40,13 @@ def susan_demo(console): else: img_color = af.load_image("../../assets/examples/images/man.jpg", True); - img_color /= 255.0 img = af.color_space(img_color, af.CSPACE.GRAY, af.CSPACE.RGB) + img_color /= 255.0 features = af.susan(img) - xs = features.get_xpos() - ys = features.get_ypos() + xs = features.get_xpos().to_list() + ys = features.get_ypos().to_list() draw_len = 3; num_features = features.num_features().value From 5416519319359abbab8f16d7f6a4b948d121ce03 Mon Sep 17 00:00:00 2001 From: pradeep Date: Tue, 8 Sep 2020 10:39:16 +0530 Subject: [PATCH 200/212] Use os path util to fetch example path to determine assets location --- examples/computer_vision/fast.py | 8 ++++++-- examples/computer_vision/harris.py | 8 ++++++-- examples/computer_vision/matching.py | 8 ++++++-- examples/computer_vision/susan.py | 8 ++++++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/examples/computer_vision/fast.py b/examples/computer_vision/fast.py index 584ff6618..1091271c8 100644 --- a/examples/computer_vision/fast.py +++ b/examples/computer_vision/fast.py @@ -11,6 +11,7 @@ from time import time import arrayfire as af +import os import sys def draw_corners(img, x, y, draw_len): @@ -35,10 +36,13 @@ def draw_corners(img, x, y, draw_len): def fast_demo(console): + root_path = os.path.dirname(os.path.abspath(__file__)) + file_path = root_path if console: - img_color = af.load_image("../../assets/examples/images/square.png", True); + file_path += "/../../assets/examples/images/square.png" else: - img_color = af.load_image("../../assets/examples/images/man.jpg", True); + file_path += "/../../assets/examples/images/man.jpg" + img_color = af.load_image(file_path, True); img = af.color_space(img_color, af.CSPACE.GRAY, af.CSPACE.RGB) img_color /= 255.0 diff --git a/examples/computer_vision/harris.py b/examples/computer_vision/harris.py index 1c8e53804..34659ebc3 100644 --- a/examples/computer_vision/harris.py +++ b/examples/computer_vision/harris.py @@ -11,6 +11,7 @@ from time import time import arrayfire as af +import os import sys def draw_corners(img, x, y, draw_len): @@ -35,10 +36,13 @@ def draw_corners(img, x, y, draw_len): def harris_demo(console): + root_path = os.path.dirname(os.path.abspath(__file__)) + file_path = root_path if console: - img_color = af.load_image("../../assets/examples/images/square.png", True); + file_path += "/../../assets/examples/images/square.png" else: - img_color = af.load_image("../../assets/examples/images/man.jpg", True); + file_path += "/../../assets/examples/images/man.jpg" + img_color = af.load_image(file_path, True); img = af.color_space(img_color, af.CSPACE.GRAY, af.CSPACE.RGB) img_color /= 255.0 diff --git a/examples/computer_vision/matching.py b/examples/computer_vision/matching.py index 797781212..8bdeb4b78 100644 --- a/examples/computer_vision/matching.py +++ b/examples/computer_vision/matching.py @@ -11,6 +11,7 @@ from time import time import arrayfire as af +import os import sys def normalize(a): @@ -45,10 +46,13 @@ def draw_rectangle(img, x, y, wx, wy): def templateMatchingDemo(console): + root_path = os.path.dirname(os.path.abspath(__file__)) + file_path = root_path if console: - img_color = af.load_image("../../assets/examples/images/square.png", True); + file_path += "/../../assets/examples/images/square.png" else: - img_color = af.load_image("../../assets/examples/images/man.jpg", True); + file_path += "/../../assets/examples/images/man.jpg" + img_color = af.load_image(file_path, True); # Convert the image from RGB to gray-scale img = af.color_space(img_color, af.CSPACE.GRAY, af.CSPACE.RGB) diff --git a/examples/computer_vision/susan.py b/examples/computer_vision/susan.py index 025001b49..8fb00c3bd 100644 --- a/examples/computer_vision/susan.py +++ b/examples/computer_vision/susan.py @@ -11,6 +11,7 @@ from time import time import arrayfire as af +import os import sys def draw_corners(img, x, y, draw_len): @@ -35,10 +36,13 @@ def draw_corners(img, x, y, draw_len): def susan_demo(console): + root_path = os.path.dirname(os.path.abspath(__file__)) + file_path = root_path if console: - img_color = af.load_image("../../assets/examples/images/square.png", True); + file_path += "/../../assets/examples/images/square.png" else: - img_color = af.load_image("../../assets/examples/images/man.jpg", True); + file_path += "/../../assets/examples/images/man.jpg" + img_color = af.load_image(file_path, True); img = af.color_space(img_color, af.CSPACE.GRAY, af.CSPACE.RGB) img_color /= 255.0 From 6fc8488fdca96959df8d51b3460e66bc348504b8 Mon Sep 17 00:00:00 2001 From: pradeep Date: Tue, 8 Sep 2020 10:39:41 +0530 Subject: [PATCH 201/212] Fix typo in harris detector example --- examples/computer_vision/harris.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/computer_vision/harris.py b/examples/computer_vision/harris.py index 34659ebc3..85388eea9 100644 --- a/examples/computer_vision/harris.py +++ b/examples/computer_vision/harris.py @@ -97,7 +97,7 @@ def harris_demo(console): print("Corners found: {}".format(good_corners)) if not console: # Previews color image with green crosshairs - wnd = af.Window(512, 512, "FAST Feature Detector") + wnd = af.Window(512, 512, "Harris Feature Detector") while not wnd.close(): wnd.image(img_color) From fc60534983fff230ad97755571e1425dbd1778d3 Mon Sep 17 00:00:00 2001 From: pradeep Date: Tue, 8 Sep 2020 10:39:47 +0530 Subject: [PATCH 202/212] Workaround in susan example for swapped coordinates of features I believe this has to be fixed from upstream and then later fixed here. Added a TODO inside the example for the same --- examples/computer_vision/susan.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/computer_vision/susan.py b/examples/computer_vision/susan.py index 8fb00c3bd..4ae33fb09 100644 --- a/examples/computer_vision/susan.py +++ b/examples/computer_vision/susan.py @@ -59,7 +59,8 @@ def susan_demo(console): x = xs[f] y = ys[f] - img_color = draw_corners(img_color, x, y, draw_len) + # TODO fix coord order to x,y after upstream fix + img_color = draw_corners(img_color, y, x, draw_len) print("Features found: {}".format(num_features)) From 534b8c2ab4db5b08347f4d3d2f86a58ba8fcfdb6 Mon Sep 17 00:00:00 2001 From: pradeep Date: Wed, 9 Sep 2020 13:09:47 +0530 Subject: [PATCH 203/212] Update python sheband in examples to widely adopted convention --- examples/computer_vision/fast.py | 2 +- examples/computer_vision/harris.py | 2 +- examples/computer_vision/matching.py | 2 +- examples/computer_vision/susan.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/computer_vision/fast.py b/examples/computer_vision/fast.py index 1091271c8..e3a1299e3 100644 --- a/examples/computer_vision/fast.py +++ b/examples/computer_vision/fast.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### # Copyright (c) 2018, ArrayFire diff --git a/examples/computer_vision/harris.py b/examples/computer_vision/harris.py index 85388eea9..27fd6c6f8 100644 --- a/examples/computer_vision/harris.py +++ b/examples/computer_vision/harris.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### # Copyright (c) 2018, ArrayFire diff --git a/examples/computer_vision/matching.py b/examples/computer_vision/matching.py index 8bdeb4b78..cab0cccdf 100644 --- a/examples/computer_vision/matching.py +++ b/examples/computer_vision/matching.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### # Copyright (c) 2018, ArrayFire diff --git a/examples/computer_vision/susan.py b/examples/computer_vision/susan.py index 4ae33fb09..37a5dbd11 100644 --- a/examples/computer_vision/susan.py +++ b/examples/computer_vision/susan.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### # Copyright (c) 2018, ArrayFire From 65040c10833506f212f13e5bcc0e49cb20645e6e Mon Sep 17 00:00:00 2001 From: parag-hub <72143455+parag-hub@users.noreply.github.com> Date: Wed, 30 Sep 2020 23:52:27 +0530 Subject: [PATCH 204/212] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2d3f8c05a..fb3a1b8a1 100644 --- a/README.md +++ b/README.md @@ -51,14 +51,14 @@ pip install arrayfire pip install git+git://github.com/arrayfire/arrayfire-python.git@devel ``` -**Installing offline** +**Installing offline:** ``` cd path/to/arrayfire-python python setup.py install ``` -**Post Installation** +**Post Installation:** Please follow [these instructions](https://github.com/arrayfire/arrayfire-python/wiki) to ensure the arrayfire-python can find the arrayfire libraries. From 70c96cadc0b8b16f25f700f8936739b2382bc37b Mon Sep 17 00:00:00 2001 From: syurkevi Date: Tue, 2 Mar 2021 23:56:15 -0500 Subject: [PATCH 205/212] change setup.py to optionally build binaries in source distribution (#245) * adds initial skbuild configuration load from local lib directory loads local binaries if they are available * remove git from toml dependencies * additional cmake args in setup.py * add description format for pypi * directory corrections for skbuild * load local nvrtc-builtins when possible * make mkl libs static for distribution * Update README to include information about wheels * remove extra import platform Co-authored-by: pradeep --- CMakeLists.txt | 18 +++++++++ README.md | 28 ++++++------- arrayfire/library.py | 96 ++++++++++++++++++++++++++++++++++---------- pyproject.toml | 2 + setup.cfg | 5 ++- setup.py | 96 ++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 205 insertions(+), 40 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 pyproject.toml diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..4c1808108 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.11.0) +project(arrayfire-python) +find_package(PythonExtensions REQUIRED) +include(FetchContent) + +set(CMAKE_MODULE_PATH_OLD ${CMAKE_MODULE_PATH}) +set(CMAKE_MODULE_PATH "") +set(NO_SONAME) + +FetchContent_Declare( + arrayfire + GIT_REPOSITORY https://github.com/arrayfire/arrayfire.git + GIT_TAG v3.8 +) +FetchContent_MakeAvailable(arrayfire) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH_OLD}) + +set(ignoreWarning "${SKBUILD}") diff --git a/README.md b/README.md index fb3a1b8a1..02af7fe26 100644 --- a/README.md +++ b/README.md @@ -25,30 +25,29 @@ def calc_pi_device(samples): Choosing a particular backend can be done using `af.set_backend(name)` where name is either "_cuda_", "_opencl_", or "_cpu_". The default device is chosen in the same order of preference. -## Requirements - -Currently, this project is tested only on Linux and OSX. You also need to have the ArrayFire C/C++ library installed on your machine. You can get it from the following sources. +## Getting started +ArrayFire can be installed from a variety of sources. [Pre-built wheels](https://repo.arrayfire.com/python/wheels/3.8.0/) are available for a number of systems and toolkits. Wheels for some systems are available on PyPI. Unsupported systems will require separate installation of the ArrayFire C/C++ libraries and only the python wrapper will be installed in that case. +You can get the ArrayFire C/C++ library from the following sources: - [Download and install binaries](https://arrayfire.com/download) - [Build and install from source](https://github.com/arrayfire/arrayfire) -Please check the following links for dependencies. - -- [Linux dependencies](http://www.arrayfire.com/docs/using_on_linux.htm) -- [OSX dependencies](http://www.arrayfire.com/docs/using_on_osx.htm) - -## Getting started - -**Install the last stable version:** +**Install the last stable version:** ``` pip install arrayfire ``` -**Install the development version:** +**Install a pre-built wheel for a specific CUDA toolkit version:** +``` +pip install arrayfire==3.8.0+cu112 -f https://repo.arrayfire.com/python/wheels/3.8.0/ +# Replace the +cu112 local version with the desired toolkit +``` + +**Install the development source distribution:** ``` -pip install git+git://github.com/arrayfire/arrayfire-python.git@devel +pip install git+git://github.com/arrayfire/arrayfire-python.git@master ``` **Installing offline:** @@ -57,10 +56,11 @@ pip install git+git://github.com/arrayfire/arrayfire-python.git@devel cd path/to/arrayfire-python python setup.py install ``` +Rather than installing and building ArrayFire elsewhere in the system, you can also build directly through python by first setting the `AF_BUILD_LOCAL_LIBS=1` environment variable. Additional setup will be required to build ArrayFire, including satisfying dependencies and further CMake configuration. Details on how to pass additional arguments to the build systems can be found in the [scikit-build documentation.](https://scikit-build.readthedocs.io/en/latest/) **Post Installation:** -Please follow [these instructions](https://github.com/arrayfire/arrayfire-python/wiki) to ensure the arrayfire-python can find the arrayfire libraries. +If you are not using one of the pre-built wheels, you may need to ensure arrayfire-python can find the installed arrayfire libraries. Please follow [these instructions](https://github.com/arrayfire/arrayfire-python/wiki) to ensure that arrayfire-python can find the arrayfire libraries. To run arrayfire tests, you can run the following command from command line. diff --git a/arrayfire/library.py b/arrayfire/library.py index 009a8e122..27ca4f4d9 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -15,6 +15,7 @@ import ctypes as ct import traceback import os +import sys c_float_t = ct.c_float c_double_t = ct.c_double @@ -492,8 +493,6 @@ class VARIANCE(_Enum): _VER_MAJOR_PLACEHOLDER = "__VER_MAJOR__" def _setup(): - import platform - platform_name = platform.system() try: @@ -527,7 +526,7 @@ def _setup(): ct.windll.kernel32.SetErrorMode(0x0001 | 0x0002) if AF_SEARCH_PATH is None: - AF_SEARCH_PATH="C:/Program Files/ArrayFire/v" + AF_VER_MAJOR +"/" + AF_SEARCH_PATH = "C:/Program Files/ArrayFire/v" + AF_VER_MAJOR +"/" if CUDA_PATH is not None: CUDA_FOUND = os.path.isdir(CUDA_PATH + '/bin') and os.path.isdir(CUDA_PATH + '/nvvm/bin/') @@ -554,7 +553,12 @@ def _setup(): post = '.so.' + _VER_MAJOR_PLACEHOLDER if AF_SEARCH_PATH is None: - AF_SEARCH_PATH='/opt/arrayfire-' + AF_VER_MAJOR + '/' + if os.path.exists('/opt/arrayfire-' + AF_VER_MAJOR + '/'): + AF_SEARCH_PATH = '/opt/arrayfire-' + AF_VER_MAJOR + '/' + elif os.path.exists('/opt/arrayfire/'): + AF_SEARCH_PATH = '/opt/arrayfire/' + else: + AF_SEARCH_PATH = '/usr/local/' if CUDA_PATH is None: CUDA_PATH='/usr/local/cuda/' @@ -566,21 +570,46 @@ def _setup(): else: raise OSError(platform_name + ' not supported') - if AF_PATH is None: - os.environ['AF_PATH'] = AF_SEARCH_PATH - - return pre, post, AF_SEARCH_PATH, CUDA_FOUND + return pre, post, AF_PATH, AF_SEARCH_PATH, CUDA_FOUND class _clibrary(object): + def __find_nvrtc_builtins_libname(self, search_path): + filelist = os.listdir(search_path) + for f in filelist: + if 'nvrtc-builtins' in f: + return f + return None + def __libname(self, name, head='af', ver_major=AF_VER_MAJOR): post = self.__post.replace(_VER_MAJOR_PLACEHOLDER, ver_major) libname = self.__pre + head + name + post - if os.path.isdir(self.AF_PATH + '/lib64'): - libname_full = self.AF_PATH + '/lib64/' + libname + + if self.AF_PATH: + if os.path.isdir(self.AF_PATH + '/lib64'): + path_search = self.AF_PATH + '/lib64/' + else: + path_search = self.AF_PATH + '/lib/' + else: + if os.path.isdir(self.AF_SEARCH_PATH + '/lib64'): + path_search = self.AF_SEARCH_PATH + '/lib64/' + else: + path_search = self.AF_SEARCH_PATH + '/lib/' + + if platform.architecture()[0][:2] == '64': + path_site = sys.prefix + '/lib64/' + else: + path_site = sys.prefix + '/lib/' + + path_local = self.AF_PYMODULE_PATH + libpaths = [('', libname), + (path_site, libname), + (path_local,libname)] + if self.AF_PATH: #prefer specified AF_PATH if exists + libpaths.append((path_search, libname)) else: - libname_full = self.AF_PATH + '/lib/' + libname - return (libname, libname_full) + libpaths.insert(2, (path_search, libname)) + return libpaths def set_unsafe(self, name): lib = self.__clibs[name] @@ -592,13 +621,19 @@ def __init__(self): more_info_str = "Please look at https://github.com/arrayfire/arrayfire-python/wiki for more information." - pre, post, AF_PATH, CUDA_FOUND = _setup() + pre, post, AF_PATH, AF_SEARCH_PATH, CUDA_FOUND = _setup() self.__pre = pre self.__post = post self.AF_PATH = AF_PATH + self.AF_SEARCH_PATH = AF_SEARCH_PATH self.CUDA_FOUND = CUDA_FOUND + # prefer locally packaged arrayfire libraries if they exist + af_module = __import__(__name__) + self.AF_PYMODULE_PATH = af_module.__path__[0] + '/' if af_module.__path__ else None + + self.__name = None self.__clibs = {'cuda' : None, @@ -618,7 +653,7 @@ def __init__(self): 'opencl' : 4} # Try to pre-load forge library if it exists - libnames = self.__libname('forge', head='', ver_major=FORGE_VER_MAJOR) + libnames = reversed(self.__libname('forge', head='', ver_major=FORGE_VER_MAJOR)) try: VERBOSE_LOADS = os.environ['AF_VERBOSE_LOADS'] == '1' @@ -628,14 +663,15 @@ def __init__(self): for libname in libnames: try: - ct.cdll.LoadLibrary(libname) + full_libname = libname[0] + libname[1] + ct.cdll.LoadLibrary(full_libname) if VERBOSE_LOADS: - print('Loaded ' + libname) + print('Loaded ' + full_libname) break except OSError: if VERBOSE_LOADS: traceback.print_exc() - print('Unable to load ' + libname) + print('Unable to load ' + full_libname) pass c_dim4 = c_dim_t*4 @@ -644,24 +680,39 @@ def __init__(self): # Iterate in reverse order of preference for name in ('cpu', 'opencl', 'cuda', ''): - libnames = self.__libname(name) + libnames = reversed(self.__libname(name)) for libname in libnames: try: - ct.cdll.LoadLibrary(libname) + full_libname = libname[0] + libname[1] + + ct.cdll.LoadLibrary(full_libname) __name = 'unified' if name == '' else name - clib = ct.CDLL(libname) + clib = ct.CDLL(full_libname) self.__clibs[__name] = clib err = clib.af_randu(c_pointer(out), 4, c_pointer(dims), Dtype.f32.value) if (err == ERR.NONE.value): self.__name = __name clib.af_release_array(out) if VERBOSE_LOADS: - print('Loaded ' + libname) + print('Loaded ' + full_libname) + + # load nvrtc-builtins library if using cuda + if name == 'cuda': + nvrtc_name = self.__find_nvrtc_builtins_libname(libname[0]) + if nvrtc_name: + ct.cdll.LoadLibrary(libname[0] + nvrtc_name) + + if VERBOSE_LOADS: + print('Loaded ' + libname[0] + nvrtc_name) + else: + if VERBOSE_LOADS: + print('Could not find local nvrtc-builtins libarary') + break; except OSError: if VERBOSE_LOADS: traceback.print_exc() - print('Unable to load ' + libname) + print('Unable to load ' + full_libname) pass if (self.__name is None): @@ -689,6 +740,7 @@ def parse(self, res): lst.append(key) return tuple(lst) + backend = _clibrary() def set_backend(name, unsafe=False): diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..75335283e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[build-system] +requires = ["setuptools", "wheel", "scikit-build", "cmake", "ninja"] diff --git a/setup.cfg b/setup.cfg index 831f2063b..e5414158b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,9 +1,10 @@ [metadata] name = arrayfire -version = 3.7.20200213 +version = 3.8.0 description = Python bindings for ArrayFire licence = BSD long_description = file: README.md +long_description_content_type = text/markdown maintainer = ArrayFire maintainer_email = technical@arrayfire.com url = http://arrayfire.com @@ -15,6 +16,8 @@ classifiers = [options] packages = find: +install_requires= + scikit-build [options.packages.find] include = arrayfire diff --git a/setup.py b/setup.py index e4d485c30..b6d37bb86 100644 --- a/setup.py +++ b/setup.py @@ -9,8 +9,98 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -# TODO: Look for af libraries during setup +import os +import re -from setuptools import setup +# package can be distributed with arrayfire binaries or +# just with python wrapper files, the AF_BUILD_LOCAL +# environment var determines whether to build the arrayfire +# binaries locally rather than searching in a system install + +AF_BUILD_LOCAL_LIBS = os.environ.get('AF_BUILD_LOCAL_LIBS') +print(f'AF_BUILD_LOCAL_LIBS={AF_BUILD_LOCAL_LIBS}') +if AF_BUILD_LOCAL_LIBS: + print('Proceeding to build ArrayFire libraries') +else: + print('Skipping binaries installation, only python files will be installed') + +AF_BUILD_CPU = os.environ.get('AF_BUILD_CPU') +AF_BUILD_CPU = 1 if AF_BUILD_CPU is None else int(AF_BUILD_CPU) +AF_BUILD_CPU_CMAKE_STR = '-DAF_BUILD_CPU:BOOL=ON' if (AF_BUILD_CPU == 1) else '-DAF_BUILD_CPU:BOOL=OFF' + +AF_BUILD_CUDA = os.environ.get('AF_BUILD_CUDA') +AF_BUILD_CUDA = 1 if AF_BUILD_CUDA is None else int(AF_BUILD_CUDA) +AF_BUILD_CUDA_CMAKE_STR = '-DAF_BUILD_CUDA:BOOL=ON' if (AF_BUILD_CUDA == 1) else '-DAF_BUILD_CUDA:BOOL=OFF' + +AF_BUILD_OPENCL = os.environ.get('AF_BUILD_OPENCL') +AF_BUILD_OPENCL = 1 if AF_BUILD_OPENCL is None else int(AF_BUILD_OPENCL) +AF_BUILD_OPENCL_CMAKE_STR = '-DAF_BUILD_OPENCL:BOOL=ON' if (AF_BUILD_OPENCL == 1) else '-DAF_BUILD_OPENCL:BOOL=OFF' + +AF_BUILD_UNIFIED = os.environ.get('AF_BUILD_UNIFIED') +AF_BUILD_UNIFIED = 1 if AF_BUILD_UNIFIED is None else int(AF_BUILD_UNIFIED) +AF_BUILD_UNIFIED_CMAKE_STR = '-DAF_BUILD_UNIFIED:BOOL=ON' if (AF_BUILD_UNIFIED == 1) else '-DAF_BUILD_UNIFIED:BOOL=OFF' + +if AF_BUILD_LOCAL_LIBS: + # invoke cmake and build arrayfire libraries to install locally in package + from skbuild import setup + + def filter_af_files(cmake_manifest): + cmake_manifest = list(filter(lambda name: not (name.endswith('.h') + or name.endswith('.cpp') + or name.endswith('.hpp') + or name.endswith('.cmake') + or name.endswith('jpg') + or name.endswith('png') + or name.endswith('libaf.so') #avoids duplicates due to symlinks + or re.match('.*libaf\.so\.3\..*', name) is not None + or name.endswith('libafcpu.so') + or re.match('.*libafcpu\.so\.3\..*', name) is not None + or name.endswith('libafcuda.so') + or re.match('.*libafcuda\.so\.3\..*', name) is not None + or name.endswith('libafopencl.so') + or re.match('.*libafopencl\.so\.3\..*', name) is not None + or name.endswith('libforge.so') + or re.match('.*libforge\.so\.1\..*', name) is not None + or 'examples' in name), cmake_manifest)) + return cmake_manifest + + print('Building CMAKE with following configurable variables: ') + print(AF_BUILD_CPU_CMAKE_STR) + print(AF_BUILD_CUDA_CMAKE_STR) + print(AF_BUILD_OPENCL_CMAKE_STR) + print(AF_BUILD_UNIFIED_CMAKE_STR) + + + setup( + packages=['arrayfire'], + cmake_install_dir='', + cmake_process_manifest_hook=filter_af_files, + include_package_data=False, + cmake_args=[AF_BUILD_CPU_CMAKE_STR, + AF_BUILD_CUDA_CMAKE_STR, + AF_BUILD_OPENCL_CMAKE_STR, + AF_BUILD_UNIFIED_CMAKE_STR, + # todo: pass additional args from environ + '-DCMAKE_BUILD_TYPE:STRING="RelWithDebInfo"', + '-DFG_USE_STATIC_CPPFLAGS:BOOL=OFF', + '-DFG_WITH_FREEIMAGE:BOOL=OFF', + '-DCUDA_architecture_build_targets:STRING=All', + '-DAF_BUILD_DOCS:BOOL=OFF', + '-DAF_BUILD_EXAMPLES:BOOL=OFF', + '-DAF_INSTALL_STANDALONE:BOOL=ON', + '-DAF_WITH_IMAGEIO:BOOL=ON', + '-DAF_WITH_LOGGING:BOOL=ON', + '-DBUILD_TESTING:BOOL=OFF', + '-DAF_BUILD_FORGE:BOOL=ON', + '-DAF_INSTALL_LIB_DIR:STRING=arrayfire', + '-DAF_INSTALL_BIN_DIR:STRING=arrayfire', + '-DFG_INSTALL_LIB_DIR:STRING=arrayfire', + '-DAF_WITH_STATIC_MKL=ON', + ] + ) + +else: + # ignores local arrayfire libraries, will search system instead + from setuptools import setup + setup() -setup() From b37f7ea71f036d5f88045e0732c4e5012cacdeef Mon Sep 17 00:00:00 2001 From: syurkevi Date: Wed, 3 Mar 2021 01:06:28 -0500 Subject: [PATCH 206/212] Bump __af_version__ for docs --- __af_version__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/__af_version__.py b/__af_version__.py index dfa78b826..16f06c5ae 100644 --- a/__af_version__.py +++ b/__af_version__.py @@ -9,6 +9,6 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -version = "3.7" -release = "20200213" +version = "3.8" +release = "20210303" full_version = version + "." + release From 8ac4a8d317a4a2af5a61973bba6a0fb4e2977c08 Mon Sep 17 00:00:00 2001 From: pradeep Date: Wed, 3 Mar 2021 12:56:59 +0530 Subject: [PATCH 207/212] Add missing Machine Learning module documentation --- docs/arrayfire.ml.rst | 7 +++++++ docs/arrayfire.rst | 1 + 2 files changed, 8 insertions(+) create mode 100644 docs/arrayfire.ml.rst diff --git a/docs/arrayfire.ml.rst b/docs/arrayfire.ml.rst new file mode 100644 index 000000000..0c53c1719 --- /dev/null +++ b/docs/arrayfire.ml.rst @@ -0,0 +1,7 @@ +arrayfire.ml module +======================= + +.. automodule:: arrayfire.ml + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/arrayfire.rst b/docs/arrayfire.rst index 2951fcb3b..7504fd82b 100644 --- a/docs/arrayfire.rst +++ b/docs/arrayfire.rst @@ -26,6 +26,7 @@ Submodules arrayfire.interop arrayfire.lapack arrayfire.library + arrayfire.ml arrayfire.opencl arrayfire.random arrayfire.sparse From da192a7d307215f87185fc2ece436ed887405c06 Mon Sep 17 00:00:00 2001 From: pradeep Date: Wed, 3 Mar 2021 17:02:20 +0530 Subject: [PATCH 208/212] Refactor cov, var, stdev APIs to reflect 3.8 release Also adds set_cublas_mode utility function to explicitly enable tensor ops for blas functions --- arrayfire/algorithm.py | 28 ++++++++++++++++++++ arrayfire/cuda.py | 7 +++++ arrayfire/library.py | 7 +++++ arrayfire/statistics.py | 53 ++++++++++++++++++-------------------- tests/simple/statistics.py | 8 +++--- 5 files changed, 71 insertions(+), 32 deletions(-) diff --git a/arrayfire/algorithm.py b/arrayfire/algorithm.py index d5adbcce5..6f06cee14 100644 --- a/arrayfire/algorithm.py +++ b/arrayfire/algorithm.py @@ -250,6 +250,34 @@ def max(a, dim=None): else: return _reduce_all(a, backend.get().af_max_all) +def maxRagged(vals, lens, dim): + """ + Find the maximum value of a subset of elements along a specified dimension. + + The size of the subset of elements along the given dimension are decided based on the lengths + provided in the `lens` array. + + Parameters + ---------- + vals : af.Array + Multi dimensional arrayfire array. + lens : af.Array + Multi dimensional arrayfire array containing number of elements to reduce along given `dim` + dim: optional: int. default: None + Dimension along which the maximum value is required. + + Returns + ------- + (values, indices): A tuple of af.Array(s) + `values` af.Array will have the maximum values along given dimension for + subsets determined by lengths provided in `lens` + `idx` contains the locations of the maximum values as per the lengths provided in `lens` + """ + out_vals = Array() + out_idx = Array() + safe_call(backend().get().af_max_ragged(c_pointer(out_vals.arr), c_pointer(out_idx.arr), c_pointer(vals.arr), c_pointer(lens.arr), c_int_t(dim))) + return out_vals, out_idx + def maxByKey(keys, vals, dim=-1): """ Calculate the max of elements along a specified dimension according to a key. diff --git a/arrayfire/cuda.py b/arrayfire/cuda.py index ea24c0e30..e5ef819be 100644 --- a/arrayfire/cuda.py +++ b/arrayfire/cuda.py @@ -85,3 +85,10 @@ def set_native_id(idx): safe_call(backend.get().afcu_set_native_id(idx)) return + +def set_cublas_mode(mode=CUBLAS_MATH_MODE.DEFAULT): + """ + Set's cuBLAS math mode for CUDA backend. In other backends, this has no effect. + """ + safe_call(backend().get().afcu_cublasSetMathMode(mode.value)) + return diff --git a/arrayfire/library.py b/arrayfire/library.py index 27ca4f4d9..1b3c8b3ea 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -490,6 +490,13 @@ class VARIANCE(_Enum): SAMPLE = _Enum_Type(1) POPULATION = _Enum_Type(2) +class CUBLAS_MATH_MODE(_Enum): + """ + Enable Tensor Core usage if available on CUDA backend GPUs + """ + DEFAULT = _Enum_Type(0) + TENSOR_OP = _Enum_Type(1) + _VER_MAJOR_PLACEHOLDER = "__VER_MAJOR__" def _setup(): diff --git a/arrayfire/statistics.py b/arrayfire/statistics.py index f47f3a48d..158da18de 100644 --- a/arrayfire/statistics.py +++ b/arrayfire/statistics.py @@ -59,7 +59,7 @@ def mean(a, weights=None, dim=None): return real if imag == 0 else real + imag * 1j -def var(a, isbiased=False, weights=None, dim=None): +def var(a, bias=VARIANCE.DEFAULT, weights=None, dim=None): """ Calculate variance along a given dimension. @@ -68,9 +68,9 @@ def var(a, isbiased=False, weights=None, dim=None): a: af.Array The input array. - isbiased: optional: Boolean. default: False. - Boolean denoting population variance (false) or sample - variance (true). + bias: optional: af.VARIANCE. default: DEFAULT. + population variance(VARIANCE.POPULATION) or sample variance(VARIANCE.SAMPLE). + This is ignored if weights are provided. weights: optional: af.Array. default: None. Array to calculate for the weighted mean. Must match size of @@ -89,7 +89,7 @@ def var(a, isbiased=False, weights=None, dim=None): out = Array() if weights is None: - safe_call(backend.get().af_var(c_pointer(out.arr), a.arr, isbiased, c_int_t(dim))) + safe_call(backend.get().af_var_v2(c_pointer(out.arr), a.arr, bias.value, c_int_t(dim))) else: safe_call(backend.get().af_var_weighted(c_pointer(out.arr), a.arr, weights.arr, c_int_t(dim))) @@ -99,7 +99,7 @@ def var(a, isbiased=False, weights=None, dim=None): imag = c_double_t(0) if weights is None: - safe_call(backend.get().af_var_all(c_pointer(real), c_pointer(imag), a.arr, isbiased)) + safe_call(backend.get().af_var_all_v2(c_pointer(real), c_pointer(imag), a.arr, bias.value)) else: safe_call(backend.get().af_var_all_weighted(c_pointer(real), c_pointer(imag), a.arr, weights.arr)) @@ -150,7 +150,7 @@ def meanvar(a, weights=None, bias=VARIANCE.DEFAULT, dim=-1): return mean_out, var_out -def stdev(a, dim=None): +def stdev(a, bias=VARIANCE.DEFAULT, dim=None): """ Calculate standard deviation along a given dimension. @@ -159,6 +159,10 @@ def stdev(a, dim=None): a: af.Array The input array. + bias: optional: af.VARIANCE. default: DEFAULT. + population variance(VARIANCE.POPULATION) or sample variance(VARIANCE.SAMPLE). + This is ignored if weights are provided. + dim: optional: int. default: None. The dimension for which to obtain the standard deviation from input data. @@ -171,48 +175,41 @@ def stdev(a, dim=None): """ if dim is not None: out = Array() - safe_call(backend.get().af_stdev(c_pointer(out.arr), a.arr, c_int_t(dim))) + safe_call(backend.get().af_stdev_v2(c_pointer(out.arr), a.arr, bias.value, + c_int_t(dim))) return out else: real = c_double_t(0) imag = c_double_t(0) - safe_call(backend.get().af_stdev_all(c_pointer(real), c_pointer(imag), a.arr)) + safe_call(backend.get().af_stdev_all_v2(c_pointer(real), c_pointer(imag), a.arr, + bias.value)) real = real.value imag = imag.value return real if imag == 0 else real + imag * 1j -def cov(a, isbiased=False, dim=None): +def cov(a, b, bias=VARIANCE.DEFAULT): """ Calculate covariance along a given dimension. Parameters ---------- a: af.Array - The input array. + Input array. - isbiased: optional: Boolean. default: False. - Boolean denoting whether biased estimate should be taken. + b: af.Array + Input array. - dim: optional: int. default: None. - The dimension for which to obtain the covariance from input data. + bias: optional: af.VARIANCE. default: DEFAULT. + population variance(VARIANCE.POPULATION) or sample variance(VARIANCE.SAMPLE). Returns ------- output: af.Array - Array containing the covariance of the input array along a - given dimension. + Array containing the covariance of the input array along a given dimension. """ - if dim is not None: - out = Array() - safe_call(backend.get().af_cov(c_pointer(out.arr), a.arr, isbiased, c_int_t(dim))) - return out - else: - real = c_double_t(0) - imag = c_double_t(0) - safe_call(backend.get().af_cov_all(c_pointer(real), c_pointer(imag), a.arr, isbiased)) - real = real.value - imag = imag.value - return real if imag == 0 else real + imag * 1j + out = Array() + safe_call(backend.get().af_cov_v2(c_pointer(out.arr), a.arr, b.arr, bias.value)) + return out def median(a, dim=None): """ diff --git a/tests/simple/statistics.py b/tests/simple/statistics.py index 174af0a5b..39fe6703f 100644 --- a/tests/simple/statistics.py +++ b/tests/simple/statistics.py @@ -28,10 +28,10 @@ def simple_statistics(verbose=False): print_func(af.mean(a, weights=w)) display_func(af.var(a, dim=0)) - display_func(af.var(a, isbiased=True, dim=0)) + display_func(af.var(a, bias=af.VARIANCE.SAMPLE, dim=0)) display_func(af.var(a, weights=w, dim=0)) print_func(af.var(a)) - print_func(af.var(a, isbiased=True)) + print_func(af.var(a, bias=af.VARIANCE.SAMPLE)) print_func(af.var(a, weights=w)) mean, var = af.meanvar(a, dim=0) @@ -45,9 +45,9 @@ def simple_statistics(verbose=False): print_func(af.stdev(a)) display_func(af.var(a, dim=0)) - display_func(af.var(a, isbiased=True, dim=0)) + display_func(af.var(a, bias=af.VARIANCE.SAMPLE, dim=0)) print_func(af.var(a)) - print_func(af.var(a, isbiased=True)) + print_func(af.var(a, bias=af.VARIANCE.SAMPLE)) display_func(af.median(a, dim=0)) print_func(af.median(w)) From 96fa9768ee02e5fb5ffcaf3d1f744c898b141637 Mon Sep 17 00:00:00 2001 From: syurkevi Date: Thu, 4 Mar 2021 12:40:35 -0500 Subject: [PATCH 209/212] tweaks to pypi installation instructions --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 02af7fe26..737399adb 100644 --- a/README.md +++ b/README.md @@ -26,14 +26,14 @@ def calc_pi_device(samples): Choosing a particular backend can be done using `af.set_backend(name)` where name is either "_cuda_", "_opencl_", or "_cpu_". The default device is chosen in the same order of preference. ## Getting started -ArrayFire can be installed from a variety of sources. [Pre-built wheels](https://repo.arrayfire.com/python/wheels/3.8.0/) are available for a number of systems and toolkits. Wheels for some systems are available on PyPI. Unsupported systems will require separate installation of the ArrayFire C/C++ libraries and only the python wrapper will be installed in that case. +ArrayFire can be installed from a variety of sources. [Pre-built wheels](https://repo.arrayfire.com/python/wheels/3.8.0/) are available for a number of systems and toolkits. These will include a distribution of the ArrayFire libraries. Currently, only the python wrapper is available on PyPI. Wrapper-only installations will require a separate installation of the ArrayFire C/C++ libraries. You can get the ArrayFire C/C++ library from the following sources: - [Download and install binaries](https://arrayfire.com/download) - [Build and install from source](https://github.com/arrayfire/arrayfire) -**Install the last stable version:** +**Install the last stable version of python wrapper:** ``` pip install arrayfire ``` From 069251051f3426b8e56da249d0d2b5e629769777 Mon Sep 17 00:00:00 2001 From: Tucker Yazdani Date: Fri, 22 Apr 2022 14:29:24 -0400 Subject: [PATCH 210/212] adds linear algebra examples --- examples/lin_algebra/cholesky.py | 36 ++++++++++++++++++++++++++++++++ examples/lin_algebra/lu.py | 30 ++++++++++++++++++++++++++ examples/lin_algebra/qr.py | 32 ++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 examples/lin_algebra/cholesky.py create mode 100644 examples/lin_algebra/lu.py create mode 100644 examples/lin_algebra/qr.py diff --git a/examples/lin_algebra/cholesky.py b/examples/lin_algebra/cholesky.py new file mode 100644 index 000000000..ade2b7f09 --- /dev/null +++ b/examples/lin_algebra/cholesky.py @@ -0,0 +1,36 @@ +import arrayfire as af + +def main(): + try: + device = 0 + af.info() + + n = 5 + t = af.randu(n,n) + inn = af.matmulNT(t,t) + af.identity(n,n)*n + + print("Running Cholesky InPlace\n") + cin_upper = inn + cin_lower = inn + + af.cholesky_inplace(cin_upper, True) + af.cholesky_inplace(cin_lower, False) + + print(cin_upper) + print(cin_lower) + + print("Running Cholesky Out of place\n") + + out_upper = af.cholesky(inn, True) + out_lower = af.cholesky(inn, False) + + # Do we want to print the array like above? If yes this is correct. + print(out_upper[0]) + print(out_lower[0]) + + + except Exception as e: + print('Error: ',str(e)) + +if __name__ == '__main__': + main() diff --git a/examples/lin_algebra/lu.py b/examples/lin_algebra/lu.py new file mode 100644 index 000000000..9e3c083a7 --- /dev/null +++ b/examples/lin_algebra/lu.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +import arrayfire as af +def main(): + try: + device = 0 + #af.setDevice(device) + af.info() + + inn = af.randu(5,8) + print(inn) + + lin = inn + + print("Running LU InPlace\n") + # Ask if this is correct. + pivot = af.lu_inplace(lin) + print(lin) + print(pivot) + + print("Running LU with Upper Lower Factorization\n") + lower, upper, pivot = af.lu(inn) + print(lower) + print(upper) + print(pivot) + except Exception as e: + print('Error: ', str(e)) + +if __name__ == '__main__': + main() + diff --git a/examples/lin_algebra/qr.py b/examples/lin_algebra/qr.py new file mode 100644 index 000000000..32f026994 --- /dev/null +++ b/examples/lin_algebra/qr.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +import arrayfire as af +def main(): + try: + #Skip device=argc.... + device = 0 + af.info() + + print("Running QR InPlace\n") + inn = af.randu(5,8) + print(inn) + + qin = inn + tau = af.qr_inplace(qin) + + print(qin) + print(tau) + + print("Running QR with Q and R factorization\n") + q,r,tau = af.qr(inn) + + print(q) + print(r) + print(tau) + + except Exception as e: + print("Error: ",str(e)) + + + +if __name__ == '__main__': + main() From 33b05582c55bcfcf1af127a3817abb239c9c118c Mon Sep 17 00:00:00 2001 From: syurkevi Date: Fri, 22 Apr 2022 15:17:41 -0400 Subject: [PATCH 211/212] minor fixes to linear algebra examples --- examples/lin_algebra/cholesky.py | 39 ++++++++++++++++++++------------ examples/lin_algebra/lu.py | 25 ++++++++++++-------- examples/lin_algebra/qr.py | 28 ++++++++++++++--------- 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/examples/lin_algebra/cholesky.py b/examples/lin_algebra/cholesky.py index ade2b7f09..b3e550139 100644 --- a/examples/lin_algebra/cholesky.py +++ b/examples/lin_algebra/cholesky.py @@ -1,36 +1,45 @@ +#!/usr/bin/env python +####################################################### +# Copyright (c) 2022, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + import arrayfire as af def main(): try: - device = 0 af.info() - + n = 5 - t = af.randu(n,n) - inn = af.matmulNT(t,t) + af.identity(n,n)*n + t = af.randu(n, n) + arr_in = af.matmulNT(t, t) + af.identity(n, n) * n print("Running Cholesky InPlace\n") - cin_upper = inn - cin_lower = inn - + cin_upper = arr_in.copy() + cin_lower = arr_in.copy() + af.cholesky_inplace(cin_upper, True) af.cholesky_inplace(cin_lower, False) print(cin_upper) print(cin_lower) - print("Running Cholesky Out of place\n") + print("\nRunning Cholesky Out of place\n") - out_upper = af.cholesky(inn, True) - out_lower = af.cholesky(inn, False) - - # Do we want to print the array like above? If yes this is correct. - print(out_upper[0]) - print(out_lower[0]) + out_upper, upper_success = af.cholesky(arr_in, True) + out_lower, lower_success = af.cholesky(arr_in, False) + if upper_success == 0: + print(out_upper) + if lower_success == 0: + print(out_lower) except Exception as e: - print('Error: ',str(e)) + print('Error: ', str(e)) if __name__ == '__main__': main() diff --git a/examples/lin_algebra/lu.py b/examples/lin_algebra/lu.py index 9e3c083a7..14405cc29 100644 --- a/examples/lin_algebra/lu.py +++ b/examples/lin_algebra/lu.py @@ -1,27 +1,32 @@ #!/usr/bin/env python +####################################################### +# Copyright (c) 2022, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + import arrayfire as af + def main(): try: - device = 0 - #af.setDevice(device) af.info() - inn = af.randu(5,8) - print(inn) - - lin = inn + in_array = af.randu(5,8) print("Running LU InPlace\n") - # Ask if this is correct. - pivot = af.lu_inplace(lin) - print(lin) + pivot = af.lu_inplace(in_array) + print(in_array) print(pivot) print("Running LU with Upper Lower Factorization\n") - lower, upper, pivot = af.lu(inn) + lower, upper, pivot = af.lu(in_array) print(lower) print(upper) print(pivot) + except Exception as e: print('Error: ', str(e)) diff --git a/examples/lin_algebra/qr.py b/examples/lin_algebra/qr.py index 32f026994..adeebfd0e 100644 --- a/examples/lin_algebra/qr.py +++ b/examples/lin_algebra/qr.py @@ -1,32 +1,38 @@ #!/usr/bin/env python +####################################################### +# Copyright (c) 2022, ArrayFire +# All rights reserved. +# +# This file is distributed under 3-clause BSD license. +# The complete license agreement can be obtained at: +# http://arrayfire.com/licenses/BSD-3-Clause +######################################################## + import arrayfire as af + def main(): try: - #Skip device=argc.... - device = 0 af.info() + in_array = af.randu(5,8) print("Running QR InPlace\n") - inn = af.randu(5,8) - print(inn) + q_in = in_array.copy() + print(q_in) - qin = inn - tau = af.qr_inplace(qin) + tau = af.qr_inplace(q_in) - print(qin) + print(q_in) print(tau) print("Running QR with Q and R factorization\n") - q,r,tau = af.qr(inn) + q, r, tau = af.qr(in_array) print(q) print(r) print(tau) except Exception as e: - print("Error: ",str(e)) - - + print("Error: ", str(e)) if __name__ == '__main__': main() From 94ebafa4dd8834ae1c62637b04ce44fa85c21bad Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 26 Apr 2023 02:44:22 +0300 Subject: [PATCH 212/212] [Data API] Array Object Implementation (#261) * Refactoring of basic functionality to create an empty Array * Replace dim4 with CShape * Add tests for array api. Minor fixes. Update CI * Add arithmetic operators w/o tests * Fix array init bug. Add __getitem__. Change pytest for active debug mode * Add reflected arithmetic and array operators * Place TODO for repr * Add bitwise operators. Add in-place operators. Add missing reflected operators * Add tests for arithmetic operators * Added to_list and to_ctypes_array * Fix bug when scalar is empty returns None * Fix typing in array object. Add tests * Change tests and found bug with reflected operators * Fix reflected operators bug. Add test coverage for the rest of the arithmetic operators * Add required by specification methods * Change utils. Add docstrings * Add docstrings for operators * Add docstrings for other operators. Remove docstrings from mocks * Change tags and typings * Change typings from python 3.10 to python 3.8 * Add readme with reference to run tests * Revert changes accidentally made in original array * Add constructor initialization warning. Add Note on deviation from spec. Dump minimal numpy version required. * Fix warning messages for non-standard functions * Add NOTE tag to functions that are not a part of spec but custom solutions --------- Co-authored-by: Anton --- .github/workflows/build.yaml | 29 + .gitignore | 9 +- arrayfire/array_api/README.md | 9 + arrayfire/array_api/__init__.py | 9 + arrayfire/array_api/array_object.py | 1105 +++++++++++++++++ arrayfire/array_api/config.py | 6 + arrayfire/array_api/device.py | 10 + arrayfire/array_api/dtype_functions.py | 30 + arrayfire/array_api/dtypes.py | 57 + arrayfire/array_api/pytest.ini | 4 + arrayfire/array_api/tests/__init__.py | 0 .../array_api/tests/test_array_object.py | 459 +++++++ arrayfire/array_api/utils.py | 11 + arrayfire/library.py | 5 - requirements.txt | 5 + setup.cfg | 34 +- 16 files changed, 1773 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/build.yaml create mode 100644 arrayfire/array_api/README.md create mode 100644 arrayfire/array_api/__init__.py create mode 100644 arrayfire/array_api/array_object.py create mode 100644 arrayfire/array_api/config.py create mode 100644 arrayfire/array_api/device.py create mode 100644 arrayfire/array_api/dtype_functions.py create mode 100644 arrayfire/array_api/dtypes.py create mode 100644 arrayfire/array_api/pytest.ini create mode 100644 arrayfire/array_api/tests/__init__.py create mode 100644 arrayfire/array_api/tests/test_array_object.py create mode 100644 arrayfire/array_api/utils.py create mode 100644 requirements.txt diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 000000000..c3ca58a39 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,29 @@ +name: Run Tests + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + + - name: Set up Python 3.10 + uses: actions/setup-python@v1 + with: + python-version: "3.10" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Test with pytest + run: pytest + + - name: Install AF + run: apt install arrayfire + + - name: Test array_api + run: python -m pytest arrayfire/array_api diff --git a/.gitignore b/.gitignore index aa7bb5f1d..047939aae 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ htmlcov/ nosetests.xml coverage.xml *,cover +.pytest_cache # Translations *.mo @@ -56,6 +57,8 @@ docs/_build/ # PyBuilder target/ -# IDE -.idea -.vscode +# mypy +.mypy_cache + +# Virtual environment +venv diff --git a/arrayfire/array_api/README.md b/arrayfire/array_api/README.md new file mode 100644 index 000000000..df444ed68 --- /dev/null +++ b/arrayfire/array_api/README.md @@ -0,0 +1,9 @@ +# ArrayFire ArrayAPI + +Specification Documentation: [source](https://data-apis.org/array-api/latest/purpose_and_scope.html) + +Run tests + +```bash +python -m pytest arrayfire/array_api +``` diff --git a/arrayfire/array_api/__init__.py b/arrayfire/array_api/__init__.py new file mode 100644 index 000000000..675b27ade --- /dev/null +++ b/arrayfire/array_api/__init__.py @@ -0,0 +1,9 @@ +__all__ = [ + # array objects + "Array", + # dtypes + "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float32", "float64", + "complex64", "complex128", "bool"] + +from .array_object import Array +from .dtypes import bool, complex64, complex128, float32, float64, int16, int32, int64, uint8, uint16, uint32, uint64 diff --git a/arrayfire/array_api/array_object.py b/arrayfire/array_api/array_object.py new file mode 100644 index 000000000..616dca797 --- /dev/null +++ b/arrayfire/array_api/array_object.py @@ -0,0 +1,1105 @@ +from __future__ import annotations + +import array as py_array +import ctypes +import enum +import warnings +from dataclasses import dataclass +from typing import Any, List, Optional, Tuple, Union + +# TODO replace imports from original lib with refactored ones +from arrayfire import backend, safe_call +from arrayfire.algorithm import count +from arrayfire.array import _get_indices, _in_display_dims_limit + +from .device import PointerSource +from .dtypes import CShape, Dtype +from .dtypes import bool as af_bool +from .dtypes import c_dim_t +from .dtypes import complex64 as af_complex64 +from .dtypes import complex128 as af_complex128 +from .dtypes import float32 as af_float32 +from .dtypes import float64 as af_float64 +from .dtypes import int64 as af_int64 +from .dtypes import supported_dtypes +from .dtypes import uint64 as af_uint64 + +ShapeType = Tuple[int, ...] +# HACK, TODO replace for actual bcast_var after refactoring ~ https://github.com/arrayfire/arrayfire/pull/2871 +_bcast_var = False + +# TODO use int | float in operators -> remove bool | complex support + + +@dataclass +class _ArrayBuffer: + address: Optional[int] = None + length: int = 0 + + +class Array: + def __init__( + self, x: Union[None, Array, py_array.array, int, ctypes.c_void_p, List[Union[int, float]]] = None, + dtype: Union[None, Dtype, str] = None, shape: Optional[ShapeType] = None, + pointer_source: PointerSource = PointerSource.host, offset: Optional[ctypes._SimpleCData[int]] = None, + strides: Optional[ShapeType] = None) -> None: + _no_initial_dtype = False # HACK, FIXME + warnings.warn( + "Initialisation with __init__ constructor is not a part of array-api specification" + " and about to be replaced with asarray() method.", + DeprecationWarning, stacklevel=2) + + # Initialise array object + self.arr = ctypes.c_void_p(0) + + if isinstance(dtype, str): + dtype = _str_to_dtype(dtype) # type: ignore[arg-type] + + if dtype is None: + _no_initial_dtype = True + dtype = af_float32 + + if x is None: + if not shape: # shape is None or empty tuple + safe_call(backend.get().af_create_handle( + ctypes.pointer(self.arr), 0, ctypes.pointer(CShape().c_array), dtype.c_api_value)) + return + + # NOTE: applies inplace changes for self.arr + safe_call(backend.get().af_create_handle( + ctypes.pointer(self.arr), len(shape), ctypes.pointer(CShape(*shape).c_array), dtype.c_api_value)) + return + + if isinstance(x, Array): + safe_call(backend.get().af_retain_array(ctypes.pointer(self.arr), x.arr)) + return + + if isinstance(x, py_array.array): + _type_char = x.typecode + _array_buffer = _ArrayBuffer(*x.buffer_info()) + + elif isinstance(x, list): + _array = py_array.array("f", x) # BUG [True, False] -> dtype: f32 # TODO add int and float + _type_char = _array.typecode + _array_buffer = _ArrayBuffer(*_array.buffer_info()) + + elif isinstance(x, int) or isinstance(x, ctypes.c_void_p): # TODO + _array_buffer = _ArrayBuffer(x if not isinstance(x, ctypes.c_void_p) else x.value) + + if not shape: + raise TypeError("Expected to receive the initial shape due to the x being a data pointer.") + + if _no_initial_dtype: + raise TypeError("Expected to receive the initial dtype due to the x being a data pointer.") + + _type_char = dtype.typecode # type: ignore[assignment] # FIXME + + else: + raise TypeError("Passed object x is an object of unsupported class.") + + _cshape = _get_cshape(shape, _array_buffer.length) + + if not _no_initial_dtype and dtype.typecode != _type_char: + raise TypeError("Can not create array of requested type from input data type") + + if not (offset or strides): + if pointer_source == PointerSource.host: + safe_call(backend.get().af_create_array( + ctypes.pointer(self.arr), ctypes.c_void_p(_array_buffer.address), _cshape.original_shape, + ctypes.pointer(_cshape.c_array), dtype.c_api_value)) + return + + safe_call(backend.get().af_device_array( + ctypes.pointer(self.arr), ctypes.c_void_p(_array_buffer.address), _cshape.original_shape, + ctypes.pointer(_cshape.c_array), dtype.c_api_value)) + return + + if offset is None: + offset = c_dim_t(0) + + if strides is None: + strides = (1, _cshape[0], _cshape[0]*_cshape[1], _cshape[0]*_cshape[1]*_cshape[2]) + + if len(strides) < 4: + strides += (strides[-1], ) * (4 - len(strides)) + strides_cshape = CShape(*strides).c_array + + safe_call(backend.get().af_create_strided_array( + ctypes.pointer(self.arr), ctypes.c_void_p(_array_buffer.address), offset, _cshape.original_shape, + ctypes.pointer(_cshape.c_array), ctypes.pointer(strides_cshape), dtype.c_api_value, + pointer_source.value)) + + # Arithmetic Operators + + def __pos__(self) -> Array: + """ + Evaluates +self_i for each element of an array instance. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + + Returns + ------- + out : Array + An array containing the evaluated result for each element. The returned array must have the same data type + as self. + """ + return self + + def __neg__(self) -> Array: + """ + Evaluates +self_i for each element of an array instance. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + + Returns + ------- + out : Array + An array containing the evaluated result for each element in self. The returned array must have a data type + determined by Type Promotion Rules. + + """ + return 0 - self # type: ignore[no-any-return, operator] # FIXME + + def __add__(self, other: Union[int, float, Array], /) -> Array: + """ + Calculates the sum for each element of an array instance with the respective element of the array other. + + Parameters + ---------- + self : Array + Array instance (augend array). Should have a numeric data type. + other: Union[int, float, Array] + Addend array. Must be compatible with self (see Broadcasting). Should have a numeric data type. + + Returns + ------- + out : Array + An array containing the element-wise sums. The returned array must have a data type determined + by Type Promotion Rules. + """ + return _process_c_function(self, other, backend.get().af_add) + + def __sub__(self, other: Union[int, float, Array], /) -> Array: + """ + Calculates the difference for each element of an array instance with the respective element of the array other. + + The result of self_i - other_i must be the same as self_i + (-other_i) and must be governed by the same + floating-point rules as addition (see array.__add__()). + + Parameters + ---------- + self : Array + Array instance (minuend array). Should have a numeric data type. + other: Union[int, float, Array] + Subtrahend array. Must be compatible with self (see Broadcasting). Should have a numeric data type. + + Returns + ------- + out : Array + An array containing the element-wise differences. The returned array must have a data type determined + by Type Promotion Rules. + """ + return _process_c_function(self, other, backend.get().af_sub) + + def __mul__(self, other: Union[int, float, Array], /) -> Array: + """ + Calculates the product for each element of an array instance with the respective element of the array other. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + other: Union[int, float, Array] + Other array. Must be compatible with self (see Broadcasting). Should have a numeric data type. + + Returns + ------- + out : Array + An array containing the element-wise products. The returned array must have a data type determined + by Type Promotion Rules. + """ + return _process_c_function(self, other, backend.get().af_mul) + + def __truediv__(self, other: Union[int, float, Array], /) -> Array: + """ + Evaluates self_i / other_i for each element of an array instance with the respective element of the + array other. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + other: Union[int, float, Array] + Other array. Must be compatible with self (see Broadcasting). Should have a numeric data type. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array should have a floating-point data type + determined by Type Promotion Rules. + + Note + ---- + - If one or both of self and other have integer data types, the result is implementation-dependent, as type + promotion between data type “kinds” (e.g., integer versus floating-point) is unspecified. + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise + results. If an array is returned, the array must have a real-valued floating-point data type. + """ + return _process_c_function(self, other, backend.get().af_div) + + def __floordiv__(self, other: Union[int, float, Array], /) -> Array: + # TODO + return NotImplemented + + def __mod__(self, other: Union[int, float, Array], /) -> Array: + """ + Evaluates self_i % other_i for each element of an array instance with the respective element of the + array other. + + Parameters + ---------- + self : Array + Array instance. Should have a real-valued data type. + other: Union[int, float, Array] + Other array. Must be compatible with self (see Broadcasting). Should have a real-valued data type. + + Returns + ------- + out : Array + An array containing the element-wise results. Each element-wise result must have the same sign as the + respective element other_i. The returned array must have a real-valued floating-point data type determined + by Type Promotion Rules. + + Note + ---- + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and + thus implementation-defined. + """ + return _process_c_function(self, other, backend.get().af_mod) + + def __pow__(self, other: Union[int, float, Array], /) -> Array: + """ + Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of + an array instance to the power of other_i (the exponent), where other_i is the corresponding element of the + array other. + + Parameters + ---------- + self : Array + Array instance whose elements correspond to the exponentiation base. Should have a numeric data type. + other: Union[int, float, Array] + Other array whose elements correspond to the exponentiation exponent. Must be compatible with self + (see Broadcasting). Should have a numeric data type. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array must have a data type determined + by Type Promotion Rules. + """ + return _process_c_function(self, other, backend.get().af_pow) + + # Array Operators + + def __matmul__(self, other: Array, /) -> Array: + # TODO get from blas - make vanilla version and not copy af.matmul as is + return NotImplemented + + # Bitwise Operators + + def __invert__(self) -> Array: + """ + Evaluates ~self_i for each element of an array instance. + + Parameters + ---------- + self : Array + Array instance. Should have an integer or boolean data type. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array must have the same data type as self. + """ + out = Array() + safe_call(backend.get().af_bitnot(ctypes.pointer(out.arr), self.arr)) + return out + + def __and__(self, other: Union[int, bool, Array], /) -> Array: + """ + Evaluates self_i & other_i for each element of an array instance with the respective element of the + array other. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + other: Union[int, bool, Array] + Other array. Must be compatible with self (see Broadcasting). Should have a numeric data type. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array must have a data type determined + by Type Promotion Rules. + """ + return _process_c_function(self, other, backend.get().af_bitand) + + def __or__(self, other: Union[int, bool, Array], /) -> Array: + """ + Evaluates self_i | other_i for each element of an array instance with the respective element of the + array other. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + other: Union[int, bool, Array] + Other array. Must be compatible with self (see Broadcasting). Should have a numeric data type. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array must have a data type determined + by Type Promotion Rules. + """ + return _process_c_function(self, other, backend.get().af_bitor) + + def __xor__(self, other: Union[int, bool, Array], /) -> Array: + """ + Evaluates self_i ^ other_i for each element of an array instance with the respective element of the + array other. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + other: Union[int, bool, Array] + Other array. Must be compatible with self (see Broadcasting). Should have a numeric data type. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array must have a data type determined + by Type Promotion Rules. + """ + return _process_c_function(self, other, backend.get().af_bitxor) + + def __lshift__(self, other: Union[int, Array], /) -> Array: + """ + Evaluates self_i << other_i for each element of an array instance with the respective element of the + array other. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + other: Union[int, Array] + Other array. Must be compatible with self (see Broadcasting). Should have a numeric data type. + Each element must be greater than or equal to 0. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array must have the same data type as self. + """ + return _process_c_function(self, other, backend.get().af_bitshiftl) + + def __rshift__(self, other: Union[int, Array], /) -> Array: + """ + Evaluates self_i >> other_i for each element of an array instance with the respective element of the + array other. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + other: Union[int, Array] + Other array. Must be compatible with self (see Broadcasting). Should have a numeric data type. + Each element must be greater than or equal to 0. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array must have the same data type as self. + """ + return _process_c_function(self, other, backend.get().af_bitshiftr) + + # Comparison Operators + + def __lt__(self, other: Union[int, float, Array], /) -> Array: + """ + Computes the truth value of self_i < other_i for each element of an array instance with the respective + element of the array other. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + other: Union[int, float, Array] + Other array. Must be compatible with self (see Broadcasting). Should have a real-valued data type. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array must have a data type of bool. + """ + return _process_c_function(self, other, backend.get().af_lt) + + def __le__(self, other: Union[int, float, Array], /) -> Array: + """ + Computes the truth value of self_i <= other_i for each element of an array instance with the respective + element of the array other. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + other: Union[int, float, Array] + Other array. Must be compatible with self (see Broadcasting). Should have a real-valued data type. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array must have a data type of bool. + """ + return _process_c_function(self, other, backend.get().af_le) + + def __gt__(self, other: Union[int, float, Array], /) -> Array: + """ + Computes the truth value of self_i > other_i for each element of an array instance with the respective + element of the array other. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + other: Union[int, float, Array] + Other array. Must be compatible with self (see Broadcasting). Should have a real-valued data type. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array must have a data type of bool. + """ + return _process_c_function(self, other, backend.get().af_gt) + + def __ge__(self, other: Union[int, float, Array], /) -> Array: + """ + Computes the truth value of self_i >= other_i for each element of an array instance with the respective + element of the array other. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + other: Union[int, float, Array] + Other array. Must be compatible with self (see Broadcasting). Should have a real-valued data type. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array must have a data type of bool. + """ + return _process_c_function(self, other, backend.get().af_ge) + + def __eq__(self, other: Union[int, float, bool, Array], /) -> Array: # type: ignore[override] # FIXME + """ + Computes the truth value of self_i == other_i for each element of an array instance with the respective + element of the array other. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + other: Union[int, float, bool, Array] + Other array. Must be compatible with self (see Broadcasting). May have any data type. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array must have a data type of bool. + """ + return _process_c_function(self, other, backend.get().af_eq) + + def __ne__(self, other: Union[int, float, bool, Array], /) -> Array: # type: ignore[override] # FIXME + """ + Computes the truth value of self_i != other_i for each element of an array instance with the respective + element of the array other. + + Parameters + ---------- + self : Array + Array instance. Should have a numeric data type. + other: Union[int, float, bool, Array] + Other array. Must be compatible with self (see Broadcasting). May have any data type. + + Returns + ------- + out : Array + An array containing the element-wise results. The returned array must have a data type of bool. + """ + return _process_c_function(self, other, backend.get().af_neq) + + # Reflected Arithmetic Operators + + def __radd__(self, other: Array, /) -> Array: + """ + Return other + self. + """ + return _process_c_function(other, self, backend.get().af_add) + + def __rsub__(self, other: Array, /) -> Array: + """ + Return other - self. + """ + return _process_c_function(other, self, backend.get().af_sub) + + def __rmul__(self, other: Array, /) -> Array: + """ + Return other * self. + """ + return _process_c_function(other, self, backend.get().af_mul) + + def __rtruediv__(self, other: Array, /) -> Array: + """ + Return other / self. + """ + return _process_c_function(other, self, backend.get().af_div) + + def __rfloordiv__(self, other: Array, /) -> Array: + # TODO + return NotImplemented + + def __rmod__(self, other: Array, /) -> Array: + """ + Return other % self. + """ + return _process_c_function(other, self, backend.get().af_mod) + + def __rpow__(self, other: Array, /) -> Array: + """ + Return other ** self. + """ + return _process_c_function(other, self, backend.get().af_pow) + + # Reflected Array Operators + + def __rmatmul__(self, other: Array, /) -> Array: + # TODO + return NotImplemented + + # Reflected Bitwise Operators + + def __rand__(self, other: Array, /) -> Array: + """ + Return other & self. + """ + return _process_c_function(other, self, backend.get().af_bitand) + + def __ror__(self, other: Array, /) -> Array: + """ + Return other | self. + """ + return _process_c_function(other, self, backend.get().af_bitor) + + def __rxor__(self, other: Array, /) -> Array: + """ + Return other ^ self. + """ + return _process_c_function(other, self, backend.get().af_bitxor) + + def __rlshift__(self, other: Array, /) -> Array: + """ + Return other << self. + """ + return _process_c_function(other, self, backend.get().af_bitshiftl) + + def __rrshift__(self, other: Array, /) -> Array: + """ + Return other >> self. + """ + return _process_c_function(other, self, backend.get().af_bitshiftr) + + # In-place Arithmetic Operators + + def __iadd__(self, other: Union[int, float, Array], /) -> Array: + # TODO discuss either we need to support complex and bool as other input type + """ + Return self += other. + """ + return _process_c_function(self, other, backend.get().af_add) + + def __isub__(self, other: Union[int, float, Array], /) -> Array: + """ + Return self -= other. + """ + return _process_c_function(self, other, backend.get().af_sub) + + def __imul__(self, other: Union[int, float, Array], /) -> Array: + """ + Return self *= other. + """ + return _process_c_function(self, other, backend.get().af_mul) + + def __itruediv__(self, other: Union[int, float, Array], /) -> Array: + """ + Return self /= other. + """ + return _process_c_function(self, other, backend.get().af_div) + + def __ifloordiv__(self, other: Union[int, float, Array], /) -> Array: + # TODO + return NotImplemented + + def __imod__(self, other: Union[int, float, Array], /) -> Array: + """ + Return self %= other. + """ + return _process_c_function(self, other, backend.get().af_mod) + + def __ipow__(self, other: Union[int, float, Array], /) -> Array: + """ + Return self **= other. + """ + return _process_c_function(self, other, backend.get().af_pow) + + # In-place Array Operators + + def __imatmul__(self, other: Array, /) -> Array: + # TODO + return NotImplemented + + # In-place Bitwise Operators + + def __iand__(self, other: Union[int, bool, Array], /) -> Array: + """ + Return self &= other. + """ + return _process_c_function(self, other, backend.get().af_bitand) + + def __ior__(self, other: Union[int, bool, Array], /) -> Array: + """ + Return self |= other. + """ + return _process_c_function(self, other, backend.get().af_bitor) + + def __ixor__(self, other: Union[int, bool, Array], /) -> Array: + """ + Return self ^= other. + """ + return _process_c_function(self, other, backend.get().af_bitxor) + + def __ilshift__(self, other: Union[int, Array], /) -> Array: + """ + Return self <<= other. + """ + return _process_c_function(self, other, backend.get().af_bitshiftl) + + def __irshift__(self, other: Union[int, Array], /) -> Array: + """ + Return self >>= other. + """ + return _process_c_function(self, other, backend.get().af_bitshiftr) + + # Methods + + def __abs__(self) -> Array: + # TODO + return NotImplemented + + def __array_namespace__(self, *, api_version: Optional[str] = None) -> Any: + # TODO + return NotImplemented + + def __bool__(self) -> bool: + # TODO consider using scalar() and is_scalar() + return NotImplemented + + def __complex__(self) -> complex: + # TODO + return NotImplemented + + def __dlpack__(self, *, stream: Union[None, int, Any] = None): # type: ignore[no-untyped-def] + # TODO implementation and expected return type -> PyCapsule + return NotImplemented + + def __dlpack_device__(self) -> Tuple[enum.Enum, int]: + # TODO + return NotImplemented + + def __float__(self) -> float: + # TODO + return NotImplemented + + def __getitem__(self, key: Union[int, slice, Tuple[Union[int, slice, ], ...], Array], /) -> Array: + """ + Returns self[key]. + + Parameters + ---------- + self : Array + Array instance. + key : Union[int, slice, Tuple[Union[int, slice, ], ...], Array] + Index key. + + Returns + ------- + out : Array + An array containing the accessed value(s). The returned array must have the same data type as self. + """ + # TODO + # API Specification - key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array]. + # consider using af.span to replace ellipsis during refactoring + out = Array() + ndims = self.ndim + + if isinstance(key, Array) and key == af_bool.c_api_value: + ndims = 1 + if count(key) == 0: + return out + + safe_call(backend.get().af_index_gen( + ctypes.pointer(out.arr), self.arr, c_dim_t(ndims), _get_indices(key).pointer)) + return out + + def __index__(self) -> int: + # TODO + return NotImplemented + + def __int__(self) -> int: + # TODO + return NotImplemented + + def __len__(self) -> int: + # NOTE not a part of the array-api spec + return self.shape[0] if self.shape else 0 + + def __setitem__( + self, key: Union[int, slice, Tuple[Union[int, slice, ], ...], Array], + value: Union[int, float, bool, Array], /) -> None: + # TODO + return NotImplemented # type: ignore[return-value] # FIXME + + def __str__(self) -> str: + # NOTE not a part of the array-api spec + # TODO change the look of array str. E.g., like np.array + if not _in_display_dims_limit(self.shape): + return _metadata_string(self.dtype, self.shape) + + return _metadata_string(self.dtype) + _array_as_str(self) + + def __repr__(self) -> str: + # NOTE not a part of the array-api spec + # return _metadata_string(self.dtype, self.shape) + # TODO change the look of array representation. E.g., like np.array + return _array_as_str(self) + + def to_device(self, device: Any, /, *, stream: Union[int, Any] = None) -> Array: + # TODO implementation and change device type from Any to Device + return NotImplemented + + # Attributes + + @property + def dtype(self) -> Dtype: + """ + Data type of the array elements. + + Returns + ------- + out : Dtype + Array data type. + """ + out = ctypes.c_int() + safe_call(backend.get().af_get_type(ctypes.pointer(out), self.arr)) + return _c_api_value_to_dtype(out.value) + + @property + def device(self) -> Any: + # TODO + return NotImplemented + + @property + def mT(self) -> Array: + # TODO + return NotImplemented + + @property + def T(self) -> Array: + """ + Transpose of the array. + + Returns + ------- + out : Array + Two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to + original array. The returned array must have the same data type as the original array. + + Note + ---- + - The array instance must be two-dimensional. If the array instance is not two-dimensional, an error + should be raised. + """ + if self.ndim < 2: + raise TypeError(f"Array should be at least 2-dimensional. Got {self.ndim}-dimensional array") + + # TODO add check if out.dtype == self.dtype + out = Array() + safe_call(backend.get().af_transpose(ctypes.pointer(out.arr), self.arr, False)) + return out + + @property + def size(self) -> int: + """ + Number of elements in an array. + + Returns + ------- + out : int + Number of elements in an array + + Note + ---- + - This must equal the product of the array's dimensions. + """ + # NOTE previously - elements() + out = c_dim_t(0) + safe_call(backend.get().af_get_elements(ctypes.pointer(out), self.arr)) + return out.value + + @property + def ndim(self) -> int: + """ + Number of array dimensions (axes). + + out : int + Number of array dimensions (axes). + """ + out = ctypes.c_uint(0) + safe_call(backend.get().af_get_numdims(ctypes.pointer(out), self.arr)) + return out.value + + @property + def shape(self) -> ShapeType: + """ + Array dimensions. + + Returns + ------- + out : tuple[int, ...] + Array dimensions. + """ + # TODO refactor + d0 = c_dim_t(0) + d1 = c_dim_t(0) + d2 = c_dim_t(0) + d3 = c_dim_t(0) + safe_call(backend.get().af_get_dims( + ctypes.pointer(d0), ctypes.pointer(d1), ctypes.pointer(d2), ctypes.pointer(d3), self.arr)) + return (d0.value, d1.value, d2.value, d3.value)[:self.ndim] # Skip passing None values + + def scalar(self) -> Union[None, int, float, bool, complex]: + """ + Return the first element of the array + """ + # NOTE not a part of the array-api spec + # TODO change the logic of this method + if self.is_empty(): + return None + + out = self.dtype.c_type() + safe_call(backend.get().af_get_scalar(ctypes.pointer(out), self.arr)) + return out.value # type: ignore[no-any-return] # FIXME + + def is_empty(self) -> bool: + """ + Check if the array is empty i.e. it has no elements. + """ + # NOTE not a part of the array-api spec + out = ctypes.c_bool() + safe_call(backend.get().af_is_empty(ctypes.pointer(out), self.arr)) + return out.value + + def to_list(self, row_major: bool = False) -> List[Union[None, int, float, bool, complex]]: + # NOTE not a part of the array-api spec + if self.is_empty(): + return [] + + array = _reorder(self) if row_major else self + ctypes_array = _get_ctypes_array(array) + + if array.ndim == 1: + return list(ctypes_array) + + out = [] + for i in range(array.size): + idx = i + sub_list = [] + for j in range(array.ndim): + div = array.shape[j] + sub_list.append(idx % div) + idx //= div + out.append(ctypes_array[sub_list[::-1]]) # type: ignore[call-overload] # FIXME + return out + + def to_ctype_array(self, row_major: bool = False) -> ctypes.Array: + # NOTE not a part of the array-api spec + if self.is_empty(): + raise RuntimeError("Can not convert an empty array to ctype.") + + array = _reorder(self) if row_major else self + return _get_ctypes_array(array) + + +def _get_ctypes_array(array: Array) -> ctypes.Array: + c_shape = array.dtype.c_type * array.size + ctypes_array = c_shape() + safe_call(backend.get().af_get_data_ptr(ctypes.pointer(ctypes_array), array.arr)) + return ctypes_array + + +def _reorder(array: Array) -> Array: + """ + Returns a reordered array to help interoperate with row major formats. + """ + if array.ndim == 1: + return array + + out = Array() + c_shape = CShape(*(tuple(reversed(range(array.ndim))) + tuple(range(array.ndim, 4)))) + safe_call(backend.get().af_reorder(ctypes.pointer(out.arr), array.arr, *c_shape)) + return out + + +def _array_as_str(array: Array) -> str: + arr_str = ctypes.c_char_p(0) + # FIXME add description to passed arguments + safe_call(backend.get().af_array_to_string(ctypes.pointer(arr_str), "", array.arr, 4, True)) + py_str = _to_str(arr_str) + safe_call(backend.get().af_free_host(arr_str)) + return py_str + + +def _metadata_string(dtype: Dtype, dims: Optional[ShapeType] = None) -> str: + return ( + "arrayfire.Array()\n" + f"Type: {dtype.typename}\n" + f"Dims: {str(dims) if dims else ''}") + + +def _get_cshape(shape: Optional[ShapeType], buffer_length: int) -> CShape: + if shape: + return CShape(*shape) + + if buffer_length != 0: + return CShape(buffer_length) + + raise RuntimeError("Shape and buffer length have invalid size to process them into C shape.") + + +def _c_api_value_to_dtype(value: int) -> Dtype: + for dtype in supported_dtypes: + if value == dtype.c_api_value: + return dtype + + raise TypeError("There is no supported dtype that matches passed dtype C API value.") + + +def _to_str(c_str: ctypes.c_char_p) -> str: + return str(c_str.value.decode("utf-8")) # type: ignore[union-attr] + + +def _str_to_dtype(value: int) -> Dtype: + for dtype in supported_dtypes: + if value == dtype.typecode or value == dtype.typename: + return dtype + + raise TypeError("There is no supported dtype that matches passed dtype typecode.") + + +def _process_c_function( + lhs: Union[int, float, Array], rhs: Union[int, float, Array], + c_function: Any) -> Array: + out = Array() + + if isinstance(lhs, Array) and isinstance(rhs, Array): + lhs_array = lhs.arr + rhs_array = rhs.arr + + elif isinstance(lhs, Array) and isinstance(rhs, (int, float)): + rhs_dtype = _implicit_dtype(rhs, lhs.dtype) + rhs_constant_array = _constant_array(rhs, CShape(*lhs.shape), rhs_dtype) + + lhs_array = lhs.arr + rhs_array = rhs_constant_array.arr + + elif isinstance(lhs, (int, float)) and isinstance(rhs, Array): + lhs_dtype = _implicit_dtype(lhs, rhs.dtype) + lhs_constant_array = _constant_array(lhs, CShape(*rhs.shape), lhs_dtype) + + lhs_array = lhs_constant_array.arr + rhs_array = rhs.arr + + else: + raise TypeError(f"{type(rhs)} is not supported and can not be passed to C binary function.") + + safe_call(c_function(ctypes.pointer(out.arr), lhs_array, rhs_array, _bcast_var)) + + return out + + +def _implicit_dtype(value: Union[int, float], array_dtype: Dtype) -> Dtype: + if isinstance(value, bool): + value_dtype = af_bool + if isinstance(value, int): + value_dtype = af_int64 + elif isinstance(value, float): + value_dtype = af_float64 + elif isinstance(value, complex): + value_dtype = af_complex128 + else: + raise TypeError(f"{type(value)} is not supported and can not be converted to af.Dtype.") + + if not (array_dtype == af_float32 or array_dtype == af_complex64): + return value_dtype + + if value_dtype == af_float64: + return af_float32 + + if value_dtype == af_complex128: + return af_complex64 + + return value_dtype + + +def _constant_array(value: Union[int, float], shape: CShape, dtype: Dtype) -> Array: + out = Array() + + if isinstance(value, complex): + if dtype != af_complex64 and dtype != af_complex128: + dtype = af_complex64 + + safe_call(backend.get().af_constant_complex( + ctypes.pointer(out.arr), ctypes.c_double(value.real), ctypes.c_double(value.imag), 4, + ctypes.pointer(shape.c_array), dtype.c_api_value)) + elif dtype == af_int64: + # TODO discuss workaround for passing float to ctypes + safe_call(backend.get().af_constant_long( + ctypes.pointer(out.arr), ctypes.c_longlong(value.real), # type: ignore[arg-type] + 4, ctypes.pointer(shape.c_array))) + elif dtype == af_uint64: + safe_call(backend.get().af_constant_ulong( + ctypes.pointer(out.arr), ctypes.c_ulonglong(value.real), # type: ignore[arg-type] + 4, ctypes.pointer(shape.c_array))) + else: + safe_call(backend.get().af_constant( + ctypes.pointer(out.arr), ctypes.c_double(value), 4, ctypes.pointer(shape.c_array), dtype.c_api_value)) + + return out diff --git a/arrayfire/array_api/config.py b/arrayfire/array_api/config.py new file mode 100644 index 000000000..588cbdfd2 --- /dev/null +++ b/arrayfire/array_api/config.py @@ -0,0 +1,6 @@ +import platform + + +def is_arch_x86() -> bool: + machine = platform.machine() + return platform.architecture()[0][0:2] == "32" and (machine[-2:] == "86" or machine[0:3] == "arm") diff --git a/arrayfire/array_api/device.py b/arrayfire/array_api/device.py new file mode 100644 index 000000000..fde5d6a54 --- /dev/null +++ b/arrayfire/array_api/device.py @@ -0,0 +1,10 @@ +import enum + + +class PointerSource(enum.Enum): + """ + Source of the pointer. + """ + # FIXME + device = 0 + host = 1 diff --git a/arrayfire/array_api/dtype_functions.py b/arrayfire/array_api/dtype_functions.py new file mode 100644 index 000000000..905d1ba97 --- /dev/null +++ b/arrayfire/array_api/dtype_functions.py @@ -0,0 +1,30 @@ +from .array_object import Array +from .dtypes import Dtype + +# TODO implement functions + + +def astype(x: Array, dtype: Dtype, /, *, copy: bool = True) -> Array: + return NotImplemented + + +def can_cast(from_: Dtype | Array, to: Dtype, /) -> bool: + return NotImplemented + + +def finfo(type: Dtype | Array, /): # type: ignore[no-untyped-def] + # NOTE expected return type -> finfo_object + return NotImplemented + + +def iinfo(type: Dtype | Array, /): # type: ignore[no-untyped-def] + # NOTE expected return type -> iinfo_object + return NotImplemented + + +def isdtype(dtype: Dtype, kind: Dtype | str | tuple[Dtype | str, ...]) -> bool: + return NotImplemented + + +def result_type(*arrays_and_dtypes: Dtype | Array) -> Dtype: + return NotImplemented diff --git a/arrayfire/array_api/dtypes.py b/arrayfire/array_api/dtypes.py new file mode 100644 index 000000000..0059bf9cf --- /dev/null +++ b/arrayfire/array_api/dtypes.py @@ -0,0 +1,57 @@ +from __future__ import annotations + +import ctypes +from dataclasses import dataclass +from typing import Type + +from .config import is_arch_x86 + +c_dim_t = ctypes.c_int if is_arch_x86() else ctypes.c_longlong + + +@dataclass +class Dtype: + typecode: str + c_type: Type[ctypes._SimpleCData] + typename: str + c_api_value: int # Internal use only + + +# Specification required +# int8 - Not Supported, b8? # HACK Dtype("i8", ctypes.c_char, "int8", 4) +int16 = Dtype("h", ctypes.c_short, "short int", 10) +int32 = Dtype("i", ctypes.c_int, "int", 5) +int64 = Dtype("l", ctypes.c_longlong, "long int", 8) +uint8 = Dtype("B", ctypes.c_ubyte, "unsigned_char", 7) +uint16 = Dtype("H", ctypes.c_ushort, "unsigned short int", 11) +uint32 = Dtype("I", ctypes.c_uint, "unsigned int", 6) +uint64 = Dtype("L", ctypes.c_ulonglong, "unsigned long int", 9) +float32 = Dtype("f", ctypes.c_float, "float", 0) +float64 = Dtype("d", ctypes.c_double, "double", 2) +complex64 = Dtype("F", ctypes.c_float*2, "float complext", 1) # type: ignore[arg-type] +complex128 = Dtype("D", ctypes.c_double*2, "double complext", 3) # type: ignore[arg-type] +bool = Dtype("b", ctypes.c_bool, "bool", 4) + +supported_dtypes = [ + int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64, complex64, complex128, bool +] + + +class CShape(tuple): + def __new__(cls, *args: int) -> CShape: + cls.original_shape = len(args) + return tuple.__new__(cls, args) + + def __init__(self, x1: int = 1, x2: int = 1, x3: int = 1, x4: int = 1) -> None: + self.x1 = x1 + self.x2 = x2 + self.x3 = x3 + self.x4 = x4 + + def __repr__(self) -> str: + return f"{self.__class__.__name__}{self.x1, self.x2, self.x3, self.x4}" + + @property + def c_array(self): # type: ignore[no-untyped-def] + c_shape = c_dim_t * 4 # ctypes.c_int | ctypes.c_longlong * 4 + return c_shape(c_dim_t(self.x1), c_dim_t(self.x2), c_dim_t(self.x3), c_dim_t(self.x4)) diff --git a/arrayfire/array_api/pytest.ini b/arrayfire/array_api/pytest.ini new file mode 100644 index 000000000..7fd828bec --- /dev/null +++ b/arrayfire/array_api/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +addopts = --cache-clear --cov=./arrayfire/array_api --flake8 --isort -s ./arrayfire/array_api +console_output_style = classic +markers = mypy diff --git a/arrayfire/array_api/tests/__init__.py b/arrayfire/array_api/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/arrayfire/array_api/tests/test_array_object.py b/arrayfire/array_api/tests/test_array_object.py new file mode 100644 index 000000000..f30567553 --- /dev/null +++ b/arrayfire/array_api/tests/test_array_object.py @@ -0,0 +1,459 @@ +import array as pyarray +import math +from typing import Any + +import pytest + +from arrayfire.array_api.array_object import Array +from arrayfire.array_api.dtypes import float32, int16, supported_dtypes + +# TODO change separated methods with setup and teardown to avoid code duplication +# TODO add tests for array arguments: device, offset, strides +# TODO add tests for all supported dtypes on initialisation +# TODO check if e.g. abs(x1-x2) < 1e-6 ~ https://davidamos.dev/the-right-way-to-compare-floats-in-python/ + + +def test_create_empty_array() -> None: + array = Array() + + assert array.dtype == float32 + assert array.ndim == 0 + assert array.size == 0 + assert array.shape == () + assert len(array) == 0 + + +def test_create_empty_array_with_nonempty_dtype() -> None: + array = Array(dtype=int16) + + assert array.dtype == int16 + assert array.ndim == 0 + assert array.size == 0 + assert array.shape == () + assert len(array) == 0 + + +def test_create_empty_array_with_str_dtype() -> None: + array = Array(dtype="short int") + + assert array.dtype == int16 + assert array.ndim == 0 + assert array.size == 0 + assert array.shape == () + assert len(array) == 0 + + +def test_create_empty_array_with_literal_dtype() -> None: + array = Array(dtype="h") + + assert array.dtype == int16 + assert array.ndim == 0 + assert array.size == 0 + assert array.shape == () + assert len(array) == 0 + + +def test_create_empty_array_with_not_matching_str_dtype() -> None: + with pytest.raises(TypeError): + Array(dtype="hello world") + + +def test_create_empty_array_with_nonempty_shape() -> None: + array = Array(shape=(2, 3)) + + assert array.dtype == float32 + assert array.ndim == 2 + assert array.size == math.prod(array.shape) == 6 + assert array.shape == (2, 3) + assert len(array) == 2 + + +def test_create_array_from_1d_list() -> None: + array = Array([1, 2, 3]) + + assert array.dtype == float32 + assert array.ndim == 1 + assert array.size == math.prod(array.shape) == 3 + assert array.shape == (3,) + assert len(array) == 3 + + +def test_create_array_from_2d_list() -> None: + with pytest.raises(TypeError): + Array([[1, 2, 3], [1, 2, 3]]) + + +def test_create_array_from_pyarray() -> None: + py_array = pyarray.array("f", [1, 2, 3]) + array = Array(py_array) + + assert array.dtype == float32 + assert array.ndim == 1 + assert array.size == math.prod(array.shape) == 3 + assert array.shape == (3,) + assert len(array) == 3 + + +def test_array_from_list_with_unsupported_dtype() -> None: + for dtype in supported_dtypes: + if dtype == float32: + continue + with pytest.raises(TypeError): + Array([1, 2, 3], dtype=dtype) + + +def test_array_from_af_array() -> None: + array1 = Array([1]) + array2 = Array(array1) + + assert array1.dtype == array2.dtype == float32 + assert array1.ndim == array2.ndim == 1 + assert array1.size == array2.size == math.prod(array1.shape) == math.prod(array2.shape) == 1 + assert array1.shape == array2.shape == (1,) + assert len(array1) == len(array2) == 1 + + +def test_array_from_int_without_shape() -> None: + with pytest.raises(TypeError): + Array(1) + + +def test_array_from_int_without_dtype() -> None: + with pytest.raises(TypeError): + Array(1, shape=(1,)) + +# def test_array_from_int_with_parameters() -> None: # BUG seg fault +# array = Array(1, shape=(1,), dtype=float32) + +# assert array.dtype == float32 +# assert array.ndim == 1 +# assert array.size == 1 +# assert array.shape == (1,) +# assert len(array) == 1 + + +def test_array_from_unsupported_type() -> None: + with pytest.raises(TypeError): + Array((5, 5)) # type: ignore[arg-type] + + with pytest.raises(TypeError): + Array({1: 2, 3: 4}) # type: ignore[arg-type] + + +def test_array_getitem() -> None: + array = Array([1, 2, 3, 4, 5]) + + int_item = array[2] + assert array.dtype == int_item.dtype + assert int_item.scalar() == 3 + + # TODO add more tests for different dtypes + + +def test_scalar() -> None: + array = Array([1, 2, 3]) + assert array[1].scalar() == 2 + + +def test_scalar_is_empty() -> None: + array = Array() + assert array.scalar() is None + + +def test_array_to_list() -> None: + array = Array([1, 2, 3]) + assert array.to_list() == [1, 2, 3] + + +def test_array_to_list_is_empty() -> None: + array = Array() + assert array.to_list() == [] + + +class TestArithmeticOperators: + def setup_method(self, method: Any) -> None: + self.list = [1, 2, 3] + self.const_int = 2 + self.const_float = 1.5 + self.array = Array(self.list) + self.array_other = Array([9, 9, 9]) + + self.tuple = (1, 2, 3) + self.const_str = "15" + + def test_add_int(self) -> None: + res = self.array + self.const_int + assert res[0].scalar() == 3 + assert res[1].scalar() == 4 + assert res[2].scalar() == 5 + + # Test __add__, __iadd__, __radd__ + + def test_add_float(self) -> None: + res = self.array + self.const_float + assert res[0].scalar() == 2.5 + assert res[1].scalar() == 3.5 + assert res[2].scalar() == 4.5 + + def test_add_array(self) -> None: + res = self.array + self.array_other + assert res[0].scalar() == 10 + assert res[1].scalar() == 11 + assert res[2].scalar() == 12 + + def test_add_inplace_and_reflected(self) -> None: + res = self.array + self.const_int + ires = self.array + ires += self.const_int + rres = self.const_int + self.array # type: ignore[operator] + + assert res[0].scalar() == ires[0].scalar() == rres[0].scalar() == 3 + assert res[1].scalar() == ires[1].scalar() == rres[1].scalar() == 4 + assert res[2].scalar() == ires[2].scalar() == rres[2].scalar() == 5 + + assert res.dtype == ires.dtype == rres.dtype + assert res.ndim == ires.ndim == rres.ndim + assert res.size == ires.size == ires.size + assert res.shape == ires.shape == rres.shape + assert len(res) == len(ires) == len(rres) + + def test_add_raises_type_error(self) -> None: + with pytest.raises(TypeError): + self.array + self.const_str # type: ignore[operator] + + with pytest.raises(TypeError): + self.array + self.tuple # type: ignore[operator] + + # Test __sub__, __isub__, __rsub__ + + def test_sub_int(self) -> None: + res = self.array - self.const_int + assert res[0].scalar() == -1 + assert res[1].scalar() == 0 + assert res[2].scalar() == 1 + + def test_sub_float(self) -> None: + res = self.array - self.const_float + assert res[0].scalar() == -0.5 + assert res[1].scalar() == 0.5 + assert res[2].scalar() == 1.5 + + def test_sub_arr(self) -> None: + res = self.array - self.array_other + assert res[0].scalar() == -8 + assert res[1].scalar() == -7 + assert res[2].scalar() == -6 + + def test_sub_inplace_and_reflected(self) -> None: + res = self.array - self.const_int + ires = self.array + ires -= self.const_int + rres = self.const_int - self.array # type: ignore[operator] + + assert res[0].scalar() == ires[0].scalar() == -1 + assert res[1].scalar() == ires[1].scalar() == 0 + assert res[2].scalar() == ires[2].scalar() == 1 + + assert rres[0].scalar() == 1 + assert rres[1].scalar() == 0 + assert rres[2].scalar() == -1 + + assert res.dtype == ires.dtype == rres.dtype + assert res.ndim == ires.ndim == rres.ndim + assert res.size == ires.size == ires.size + assert res.shape == ires.shape == rres.shape + assert len(res) == len(ires) == len(rres) + + def test_sub_raises_type_error(self) -> None: + with pytest.raises(TypeError): + self.array - self.const_str # type: ignore[operator] + + with pytest.raises(TypeError): + self.array - self.tuple # type: ignore[operator] + + # Test __mul__, __imul__, __rmul__ + + def test_mul_int(self) -> None: + res = self.array * self.const_int + assert res[0].scalar() == 2 + assert res[1].scalar() == 4 + assert res[2].scalar() == 6 + + def test_mul_float(self) -> None: + res = self.array * self.const_float + assert res[0].scalar() == 1.5 + assert res[1].scalar() == 3 + assert res[2].scalar() == 4.5 + + def test_mul_array(self) -> None: + res = self.array * self.array_other + assert res[0].scalar() == 9 + assert res[1].scalar() == 18 + assert res[2].scalar() == 27 + + def test_mul_inplace_and_reflected(self) -> None: + res = self.array * self.const_int + ires = self.array + ires *= self.const_int + rres = self.const_int * self.array # type: ignore[operator] + + assert res[0].scalar() == ires[0].scalar() == rres[0].scalar() == 2 + assert res[1].scalar() == ires[1].scalar() == rres[1].scalar() == 4 + assert res[2].scalar() == ires[2].scalar() == rres[2].scalar() == 6 + + assert res.dtype == ires.dtype == rres.dtype + assert res.ndim == ires.ndim == rres.ndim + assert res.size == ires.size == ires.size + assert res.shape == ires.shape == rres.shape + assert len(res) == len(ires) == len(rres) + + def test_mul_raises_type_error(self) -> None: + with pytest.raises(TypeError): + self.array * self.const_str # type: ignore[operator] + + with pytest.raises(TypeError): + self.array * self.tuple # type: ignore[operator] + + # Test __truediv__, __itruediv__, __rtruediv__ + + def test_truediv_int(self) -> None: + res = self.array / self.const_int + assert res[0].scalar() == 0.5 + assert res[1].scalar() == 1 + assert res[2].scalar() == 1.5 + + def test_truediv_float(self) -> None: + res = self.array / self.const_float + assert round(res[0].scalar(), 5) == 0.66667 # type: ignore[arg-type] + assert round(res[1].scalar(), 5) == 1.33333 # type: ignore[arg-type] + assert res[2].scalar() == 2 + + def test_truediv_array(self) -> None: + res = self.array / self.array_other + assert round(res[0].scalar(), 5) == 0.11111 # type: ignore[arg-type] + assert round(res[1].scalar(), 5) == 0.22222 # type: ignore[arg-type] + assert round(res[2].scalar(), 5) == 0.33333 # type: ignore[arg-type] + + def test_truediv_inplace_and_reflected(self) -> None: + res = self.array / self.const_int + ires = self.array + ires /= self.const_int + rres = self.const_int / self.array # type: ignore[operator] + + assert res[0].scalar() == ires[0].scalar() == 0.5 + assert res[1].scalar() == ires[1].scalar() == 1 + assert res[2].scalar() == ires[2].scalar() == 1.5 + + assert rres[0].scalar() == 2 + assert rres[1].scalar() == 1 + assert round(rres[2].scalar(), 5) == 0.66667 + + assert res.dtype == ires.dtype == rres.dtype + assert res.ndim == ires.ndim == rres.ndim + assert res.size == ires.size == ires.size + assert res.shape == ires.shape == rres.shape + assert len(res) == len(ires) == len(rres) + + def test_truediv_raises_type_error(self) -> None: + with pytest.raises(TypeError): + self.array / self.const_str # type: ignore[operator] + + with pytest.raises(TypeError): + self.array / self.tuple # type: ignore[operator] + + # TODO + # Test __floordiv__, __ifloordiv__, __rfloordiv__ + + # Test __mod__, __imod__, __rmod__ + + def test_mod_int(self) -> None: + res = self.array % self.const_int + assert res[0].scalar() == 1 + assert res[1].scalar() == 0 + assert res[2].scalar() == 1 + + def test_mod_float(self) -> None: + res = self.array % self.const_float + assert res[0].scalar() == 1.0 + assert res[1].scalar() == 0.5 + assert res[2].scalar() == 0.0 + + def test_mod_array(self) -> None: + res = self.array % self.array_other + assert res[0].scalar() == 1.0 + assert res[1].scalar() == 2.0 + assert res[2].scalar() == 3.0 + + def test_mod_inplace_and_reflected(self) -> None: + res = self.array % self.const_int + ires = self.array + ires %= self.const_int + rres = self.const_int % self.array # type: ignore[operator] + + assert res[0].scalar() == ires[0].scalar() == 1 + assert res[1].scalar() == ires[1].scalar() == 0 + assert res[2].scalar() == ires[2].scalar() == 1 + + assert rres[0].scalar() == 0 + assert rres[1].scalar() == 0 + assert rres[2].scalar() == 2 + + assert res.dtype == ires.dtype == rres.dtype + assert res.ndim == ires.ndim == rres.ndim + assert res.size == ires.size == ires.size + assert res.shape == ires.shape == rres.shape + assert len(res) == len(ires) == len(rres) + + def test_mod_raises_type_error(self) -> None: + with pytest.raises(TypeError): + self.array % self.const_str # type: ignore[operator] + + with pytest.raises(TypeError): + self.array % self.tuple # type: ignore[operator] + + # Test __pow__, __ipow__, __rpow__ + + def test_pow_int(self) -> None: + res = self.array ** self.const_int + assert res[0].scalar() == 1 + assert res[1].scalar() == 4 + assert res[2].scalar() == 9 + + def test_pow_float(self) -> None: + res = self.array ** self.const_float + assert res[0].scalar() == 1 + assert round(res[1].scalar(), 5) == 2.82843 # type: ignore[arg-type] + assert round(res[2].scalar(), 5) == 5.19615 # type: ignore[arg-type] + + def test_pow_array(self) -> None: + res = self.array ** self.array_other + assert res[0].scalar() == 1 + assert res[1].scalar() == 512 + assert res[2].scalar() == 19683 + + def test_pow_inplace_and_reflected(self) -> None: + res = self.array ** self.const_int + ires = self.array + ires **= self.const_int + rres = self.const_int ** self.array # type: ignore[operator] + + assert res[0].scalar() == ires[0].scalar() == 1 + assert res[1].scalar() == ires[1].scalar() == 4 + assert res[2].scalar() == ires[2].scalar() == 9 + + assert rres[0].scalar() == 2 + assert rres[1].scalar() == 4 + assert rres[2].scalar() == 8 + + assert res.dtype == ires.dtype == rres.dtype + assert res.ndim == ires.ndim == rres.ndim + assert res.size == ires.size == ires.size + assert res.shape == ires.shape == rres.shape + assert len(res) == len(ires) == len(rres) + + def test_pow_raises_type_error(self) -> None: + with pytest.raises(TypeError): + self.array % self.const_str # type: ignore[operator] + + with pytest.raises(TypeError): + self.array % self.tuple # type: ignore[operator] diff --git a/arrayfire/array_api/utils.py b/arrayfire/array_api/utils.py new file mode 100644 index 000000000..779459efb --- /dev/null +++ b/arrayfire/array_api/utils.py @@ -0,0 +1,11 @@ +from .array_object import Array + +# TODO implement functions + + +def all(x: Array, /, *, axis: None | int | tuple[int, ...] = None, keepdims: bool = False) -> Array: + return NotImplemented + + +def any(x: Array, /, *, axis: None | int | tuple[int, ...] = None, keepdims: bool = False) -> Array: + return NotImplemented diff --git a/arrayfire/library.py b/arrayfire/library.py index 1b3c8b3ea..df68f97d8 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -506,7 +506,6 @@ def _setup(): AF_PATH = os.environ['AF_PATH'] except KeyError: AF_PATH = None - pass AF_SEARCH_PATH = AF_PATH @@ -514,7 +513,6 @@ def _setup(): CUDA_PATH = os.environ['CUDA_PATH'] except KeyError: CUDA_PATH= None - pass CUDA_FOUND = False @@ -666,7 +664,6 @@ def __init__(self): VERBOSE_LOADS = os.environ['AF_VERBOSE_LOADS'] == '1' except KeyError: VERBOSE_LOADS = False - pass for libname in libnames: try: @@ -679,7 +676,6 @@ def __init__(self): if VERBOSE_LOADS: traceback.print_exc() print('Unable to load ' + full_libname) - pass c_dim4 = c_dim_t*4 out = c_void_ptr_t(0) @@ -720,7 +716,6 @@ def __init__(self): if VERBOSE_LOADS: traceback.print_exc() print('Unable to load ' + full_libname) - pass if (self.__name is None): raise RuntimeError("Could not load any ArrayFire libraries.\n" + more_info_str) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..3b997e873 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +# Build requirements +wheel~=0.38.4 + +# Development requirements +-e .[dev,test] diff --git a/setup.cfg b/setup.cfg index e5414158b..b40ac55e5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -16,16 +16,48 @@ classifiers = [options] packages = find: -install_requires= +install_requires = scikit-build +python_requires = + >=3.8.0 [options.packages.find] include = arrayfire exclude = examples tests +install_requires = + numpy~=1.22.0 + +[options.extras_require] +dev = + autopep8~=1.6.0 + isort~=5.10.1 + flake8~=4.0.1 + flake8-quotes~=3.2.0 + mypy~=0.942 +test = + pytest~=7.1.2 + pytest-cov~=3.0.0 + pytest-isort~=3.0.0 + pytest-flake8~=1.1.1 + pytest-mypy~=0.9.1 + +[tool:isort] +line_length = 119 +multi_line_output = 4 [flake8] +exclude = venv application-import-names = arrayfire import-order-style = pep8 +inline-quotes = double max-line-length = 119 + +[mypy] +exclude = venv +disallow_incomplete_defs = true +disallow_untyped_defs = true +ignore_missing_imports = true +show_error_codes = true +warn_return_any = true