diff --git a/.gitignore b/.gitignore index aa7bb5f1d..8d944a440 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ __pycache__/ *.so # Distribution / packaging -.Python env/ build/ develop-eggs/ @@ -23,39 +22,15 @@ var/ .installed.cfg *.egg -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover - -# Translations -*.mo -*.pot - -# Django stuff: -*.log - # Sphinx documentation docs/_build/ -# PyBuilder -target/ +# Environments +env +venv +.env +.venv -# IDE -.idea +# IDEs .vscode +.idea diff --git a/LICENSE b/LICENSE index 211cf4e30..46131f7c6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015, ArrayFire +Copyright (c) 2019, ArrayFire All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/__af_version__.py b/__af_version__.py deleted file mode 100644 index dfa78b826..000000000 --- a/__af_version__.py +++ /dev/null @@ -1,14 +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 -######################################################## - -version = "3.7" -release = "20200213" -full_version = version + "." + release diff --git a/arrayfire/__init__.py b/arrayfire/__init__.py index 5cb009951..595d9615c 100644 --- a/arrayfire/__init__.py +++ b/arrayfire/__init__.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2020, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -48,39 +48,408 @@ """ +# ============================================================================= +# Algorithm module +# ============================================================================= +from .algorithm import accum # noqa : E401 +from .algorithm import all_true # noqa : E401 +from .algorithm import allTrueByKey # noqa : E401 +from .algorithm import any_true # noqa : E401 +from .algorithm import anyTrueByKey # noqa : E401 +from .algorithm import count # noqa : E401 +from .algorithm import countByKey # noqa : E401 +from .algorithm import diff1 # noqa : E401 +from .algorithm import diff2 # noqa : E401 +from .algorithm import imax # noqa : E401 +from .algorithm import imin # noqa : E401 +from .algorithm import max # noqa : E401 # FIXME: do not use python reserved variable names +from .algorithm import maxByKey # noqa : E401 +from .algorithm import min # noqa : E401 # FIXME: do not use python reserved variable names +from .algorithm import minByKey # noqa : E401 +from .algorithm import product # noqa : E401 +from .algorithm import productByKey # noqa : E401 +from .algorithm import scan # noqa : E401 +from .algorithm import scan_by_key # noqa : E401 +from .algorithm import set_intersect # noqa : E401 +from .algorithm import set_union # noqa : E401 +from .algorithm import set_unique # noqa : E401 +from .algorithm import sort # noqa : E401 +from .algorithm import sort_by_key # noqa : E401 +from .algorithm import sort_index # noqa : E401 +from .algorithm import sum # noqa : E401 # FIXME: do not use python reserved variable names +from .algorithm import sumByKey # noqa : E401 +from .algorithm import where # noqa : E401 +# ============================================================================= +# Arith module +# ============================================================================= +from .arith import abs # noqa : E401 # FIXME: do not use python reserved variable names +from .arith import acos # noqa : E401 +from .arith import acosh # noqa : E401 +from .arith import arg # noqa : E401 +from .arith import asin # noqa : E401 +from .arith import asinh # noqa : E401 +from .arith import atan # noqa : E401 +from .arith import atan2 # noqa : E401 +from .arith import atanh # noqa : E401 +from .arith import cast # noqa : E401 +from .arith import cbrt # noqa : E401 +from .arith import ceil # noqa : E401 +from .arith import clamp # noqa : E401 +from .arith import conjg # noqa : E401 +from .arith import cos # noqa : E401 +from .arith import cosh # noqa : E401 +from .arith import cplx # noqa : E401 +from .arith import erf # noqa : E401 +from .arith import erfc # noqa : E401 +from .arith import exp # noqa : E401 +from .arith import expm1 # noqa : E401 +from .arith import factorial # noqa : E401 +from .arith import floor # noqa : E401 +from .arith import hypot # noqa : E401 +from .arith import imag # noqa : E401 +from .arith import isinf # noqa : E401 +from .arith import isnan # noqa : E401 +from .arith import iszero # noqa : E401 +from .arith import lgamma # noqa : E401 +from .arith import log # noqa : E401 +from .arith import log1p # noqa : E401 +from .arith import log2 # noqa : E401 +from .arith import log10 # noqa : E401 +from .arith import maxof # noqa : E401 +from .arith import minof # noqa : E401 +from .arith import mod # noqa : E401 +from .arith import pow # noqa : E401 # FIXME: do not use python reserved variable names +from .arith import pow2 # noqa : E401 +from .arith import real # noqa : E401 +from .arith import rem # noqa : E401 +from .arith import root # noqa : E401 +from .arith import round # noqa : E401 # FIXME: do not use python reserved variable names +from .arith import rsqrt # noqa : E401 +from .arith import sigmoid # noqa : E401 +from .arith import sign # noqa : E401 +from .arith import sin # noqa : E401 +from .arith import sinh # noqa : E401 +from .arith import sqrt # noqa : E401 +from .arith import tan # noqa : E401 +from .arith import tanh # noqa : E401 +from .arith import tgamma # noqa : E401 +from .arith import trunc # noqa : E401 +# ============================================================================= +# Array module +# ============================================================================= +from .array import Array # noqa : E401 +from .array import constant_array # noqa : E401 +from .array import display # noqa : E401 +from .array import get_display_dims_limit # noqa : E401 +from .array import read_array # noqa : E401 +from .array import save_array # noqa : E401 +from .array import set_display_dims_limit # noqa : E401 +from .array import transpose # noqa : E401 +from .array import transpose_inplace # noqa : E401 +# ============================================================================= +# Base module +# ============================================================================= +from .base import BaseArray # noqa : E401 +# ============================================================================= +# Bcast module +# ============================================================================= +from .bcast import broadcast # noqa : E401 +# ============================================================================= +# Blas module +# ============================================================================= +from .blas import dot # noqa : E401 +from .blas import gemm # noqa : E401 +from .blas import matmul # noqa : E401 +from .blas import matmulNT # noqa : E401 +from .blas import matmulTN # noqa : E401 +from .blas import matmulTT # noqa : E401 +# ============================================================================= +# Cuda module +# ============================================================================= +from .cuda import get_native_id # noqa : E401 +from .cuda import get_stream # noqa : E401 +from .cuda import set_native_id # noqa : E401 +# ============================================================================= +# Data module +# ============================================================================= +from .data import constant # noqa : E401 +from .data import diag # noqa : E401 +from .data import flat # noqa : E401 +from .data import flip # noqa : E401 +from .data import identity # noqa : E401 +from .data import iota # noqa : E401 +from .data import join # noqa : E401 +from .data import lookup # noqa : E401 +from .data import lower # noqa : E401 +from .data import moddims # noqa : E401 +from .data import pad # noqa : E401 +from .data import range # noqa : E401 # FIXME: do not use python reserved variable names +from .data import reorder # noqa : E401 +from .data import replace # noqa : E401 +from .data import select # noqa : E401 +from .data import shift # noqa : E401 +from .data import tile # noqa : E401 +from .data import upper # noqa : E401 +# ============================================================================= +# Device module +# ============================================================================= +from .device import alloc_device # noqa : E401 +from .device import alloc_host # noqa : E401 +from .device import alloc_pinned # noqa : E401 +from .device import device_gc # noqa : E401 +from .device import device_info # noqa : E401 +from .device import device_mem_info # noqa : E401 +from .device import eval # noqa : E401 # FIXME: do not use python reserved variable names +from .device import free_device # noqa : E401 +from .device import free_host # noqa : E401 +from .device import free_pinned # noqa : E401 +from .device import get_device # noqa : E401 +from .device import get_device_count # noqa : E401 +from .device import get_device_ptr # noqa : E401 +from .device import get_manual_eval_flag # noqa : E401 +from .device import info # noqa : E401 +from .device import info_str # noqa : E401 +from .device import init # noqa : E401 +from .device import is_dbl_supported # noqa : E401 +from .device import is_half_supported # noqa : E401 +from .device import is_locked_array # noqa : E401 +from .device import lock_array # noqa : E401 +from .device import lock_device_ptr # noqa : E401 +from .device import print_mem_info # noqa : E401 +from .device import set_device # noqa : E401 +from .device import set_manual_eval_flag # noqa : E401 +from .device import sync # noqa : E401 +from .device import unlock_array # noqa : E401 +from .device import unlock_device_ptr # noqa : E401 +# ============================================================================= +# Graphics module +# ============================================================================= +from .graphics import Window # noqa : E401 +# ============================================================================= +# Image module +# ============================================================================= +from .image import ITERATIVE_DECONV # noqa : E401 +from .image import anisotropic_diffusion # noqa : E401 +from .image import bilateral # noqa : E401 +from .image import canny # noqa : E401 +from .image import color_space # noqa : E401 +from .image import confidenceCC # noqa : E401 +from .image import dilate # noqa : E401 +from .image import dilate3 # noqa : E401 +from .image import erode # noqa : E401 +from .image import erode3 # noqa : E401 +from .image import gaussian_kernel # noqa : E401 +from .image import gradient # noqa : E401 +from .image import gray2rgb # noqa : E401 +from .image import hist_equal # noqa : E401 +from .image import histogram # noqa : E401 +from .image import hsv2rgb # noqa : E401 +from .image import is_image_io_available # noqa : E401 +from .image import inverseDeconv # noqa : E401 +from .image import iterativeDeconv # noqa : E401 +from .image import load_image # noqa : E401 +from .image import load_image_native # noqa : E401 +from .image import maxfilt # noqa : E401 +from .image import mean_shift # noqa : E401 +from .image import minfilt # noqa : E401 +from .image import moments # noqa : E401 +from .image import regions # noqa : E401 +from .image import resize # noqa : E401 +from .image import rgb2gray # noqa : E401 +from .image import rgb2hsv # noqa : E401 +from .image import rgb2ycbcr # noqa : E401 +from .image import rotate # noqa : E401 +from .image import sat # noqa : E401 +from .image import save_image # noqa : E401 +from .image import save_image_native # noqa : E401 +from .image import scale # noqa : E401 +from .image import skew # noqa : E401 +from .image import sobel_derivatives # noqa : E401 +from .image import sobel_filter # noqa : E401 +from .image import transform # noqa : E401 +from .image import translate # noqa : E401 +from .image import unwrap # noqa : E401 +from .image import wrap # noqa : E401 +from .image import ycbcr2rgb # noqa : E401 +# ============================================================================= +# Index module +# ============================================================================= +from .index import Index # noqa : E401 +from .index import ParallelRange # noqa : E401 +from .index import Seq # noqa : E401 +# ============================================================================= +# Interop module +# ============================================================================= +from .interop import AF_NUMBA_FOUND # noqa : E401 +from .interop import AF_NUMPY_FOUND # noqa : E401 +from .interop import AF_PYCUDA_FOUND # noqa : E401 +from .interop import AF_PYOPENCL_FOUND # noqa : E401 +from .interop import to_array # noqa : E401 +# ============================================================================= +# Lapack module +# ============================================================================= +from .lapack import cholesky # noqa : E401 +from .lapack import cholesky_inplace # noqa : E401 +from .lapack import det # noqa : E401 +from .lapack import inverse # noqa : E401 +from .lapack import is_lapack_available # noqa : E401 +from .lapack import lu # noqa : E401 +from .lapack import lu_inplace # noqa : E401 +from .lapack import norm # noqa : E401 +from .lapack import pinverse # noqa : E401 +from .lapack import qr # noqa : E401 +from .lapack import qr_inplace # noqa : E401 +from .lapack import rank # noqa : E401 +from .lapack import solve # noqa : E401 +from .lapack import solve_lu # noqa : E401 +from .lapack import svd # noqa : E401 +from .lapack import svd_inplace # noqa : E401 +# ============================================================================= +# Library module +# ============================================================================= +from .library import AF_VER_MAJOR # noqa : E401 +from .library import BACKEND # noqa : E401 +from .library import BINARYOP # noqa : E401 +from .library import CANNY_THRESHOLD # noqa : E401 +from .library import COLORMAP # noqa : E401 +from .library import CONNECTIVITY # noqa : E401 +from .library import CONV_DOMAIN # noqa : E401 +from .library import CONV_GRADIENT # noqa : E401 +from .library import CONV_MODE # noqa : E401 +from .library import CSPACE # noqa : E401 +from .library import DIFFUSION # noqa : E401 +from .library import ERR # noqa : E401 +from .library import FLUX # noqa : E401 +from .library import FORGE_VER_MAJOR # noqa : E401 +from .library import HOMOGRAPHY # noqa : E401 +from .library import IMAGE_FORMAT # noqa : E401 +from .library import INTERP # noqa : E401 +from .library import INVERSE_DECONV # noqa : E401 +from .library import ITERATIVE_DECONV # noqa : E401 +from .library import MARKER # noqa : E401 +from .library import MATCH # noqa : E401 +from .library import MATPROP # noqa : E401 +from .library import MOMENT # noqa : E401 +from .library import NORM # noqa : E401 +from .library import PAD # noqa : E401 +from .library import RANDOM_ENGINE # noqa : E401 +from .library import STORAGE # noqa : E401 +from .library import TOPK # noqa : E401 +from .library import VARIANCE # noqa : E401 +from .library import YCC_STD # noqa : E401 +from .library import Dtype # noqa : E401 +from .library import Source # noqa : E401 +from .library import get_active_backend # noqa : E401 +from .library import get_available_backends # noqa : E401 +from .library import get_backend # noqa : E401 +from .library import get_backend_count # noqa : E401 +from .library import get_backend_id # noqa : E401 +from .library import get_device_id # noqa : E401 +from .library import get_size_of # noqa : E401 +from .library import safe_call # noqa : E401 +from .library import set_backend # noqa : E401 +# ============================================================================= +# Machine Learning (ML) module +# ============================================================================= +from .ml import convolve2GradientNN # noqa : E401 +# ============================================================================= +# Random module +# ============================================================================= +from .random import Random_Engine # noqa : E401 +from .random import get_default_random_engine # noqa : E401 +from .random import get_seed # noqa : E401 +from .random import randn # noqa : E401 +from .random import randu # noqa : E401 +from .random import set_default_random_engine_type # noqa : E401 +from .random import set_seed # noqa : E401 +# ============================================================================= +# Signal module +# ============================================================================= +from .signal import approx1 # noqa : E401 +from .signal import approx1_uniform # noqa : E401 +from .signal import approx2 # noqa : E401 +from .signal import approx2_uniform # noqa : E401 +from .signal import convolve # noqa : E401 +from .signal import convolve1 # noqa : E401 +from .signal import convolve2 # noqa : E401 +from .signal import convolve2_separable # noqa : E401 +from .signal import convolve2NN # noqa : E401 +from .signal import convolve3 # noqa : E401 +from .signal import dft # noqa : E401 +from .signal import fft # noqa : E401 +from .signal import fft2 # noqa : E401 +from .signal import fft2_c2r # noqa : E401 +from .signal import fft2_inplace # noqa : E401 +from .signal import fft2_r2c # noqa : E401 +from .signal import fft3 # noqa : E401 +from .signal import fft3_c2r # noqa : E401 +from .signal import fft3_inplace # noqa : E401 +from .signal import fft3_r2c # noqa : E401 +from .signal import fft_c2r # noqa : E401 +from .signal import fft_convolve # noqa : E401 +from .signal import fft_convolve1 # noqa : E401 +from .signal import fft_convolve2 # noqa : E401 +from .signal import fft_convolve3 # noqa : E401 +from .signal import fft_inplace # noqa : E401 +from .signal import fft_r2c # noqa : E401 +from .signal import fir # noqa : E401 +from .signal import idft # noqa : E401 +from .signal import ifft # noqa : E401 +from .signal import ifft2 # noqa : E401 +from .signal import ifft2_inplace # noqa : E401 +from .signal import ifft3 # noqa : E401 +from .signal import ifft3_inplace # noqa : E401 +from .signal import ifft_inplace # noqa : E401 +from .signal import iir # noqa : E401 +from .signal import medfilt # noqa : E401 +from .signal import medfilt1 # noqa : E401 +from .signal import medfilt2 # noqa : E401 +from .signal import set_fft_plan_cache_size # noqa : E401 +# ============================================================================= +# Sparse module +# ============================================================================= +from .sparse import convert_sparse # noqa : E401 +from .sparse import convert_sparse_to_dense # noqa : E401 +from .sparse import create_sparse # noqa : E401 +from .sparse import create_sparse_from_dense # noqa : E401 +from .sparse import create_sparse_from_host # noqa : E401 +from .sparse import sparse_get_col_idx # noqa : E401 +from .sparse import sparse_get_info # noqa : E401 +from .sparse import sparse_get_nnz # noqa : E401 +from .sparse import sparse_get_row_idx # noqa : E401 +from .sparse import sparse_get_storage # noqa : E401 +from .sparse import sparse_get_values # noqa : E401 +# ============================================================================= +# Statistics module +# ============================================================================= +from .statistics import corrcoef # noqa : E401 +from .statistics import cov # noqa : E401 +from .statistics import mean # noqa : E401 +from .statistics import meanvar # noqa : E401 +from .statistics import median # noqa : E401 +from .statistics import stdev # noqa : E401 +from .statistics import topk # noqa : E401 +from .statistics import var # noqa : E401 +# ============================================================================= +# Timer module +# ============================================================================= +from .timer import timeit # noqa : E401 +# ============================================================================= +# Utils module +# ============================================================================= +from .util import dim4 # noqa : E401 +from .util import dim4_to_tuple # noqa : E401 +from .util import get_reversion # noqa : E401 +from .util import get_version # noqa : E401 +from .util import implicit_dtype # noqa : E401 +from .util import number_dtype # noqa : E401 +from .util import to_c_type # noqa : E401 +from .util import to_dtype # noqa : E401 +from .util import to_str # noqa : E401 +from .util import to_typecode # noqa : E401 + try: - import pycuda.autoinit + # FIXME: pycuda imported but unused + import pycuda.autoinit # noqa : E401 except ImportError: pass - -from .library import * -from .array import * -from .data import * -from .util import * -from .algorithm import * -from .device import * -from .blas import * -from .arith import * -from .statistics import * -from .lapack import * -from .signal import * -from .image import * -from .features import * -from .vision import * -from .graphics import * -from .bcast import * -from .index import * -from .interop import * -from .timer import * -from .random import * -from .sparse import * -from .ml import * - -# do not export default modules as part of arrayfire -del ct -del inspect -del numbers -del os - -if (AF_NUMPY_FOUND): - del np diff --git a/arrayfire/algorithm.py b/arrayfire/algorithm.py index d5adbcce5..84d02422f 100644 --- a/arrayfire/algorithm.py +++ b/arrayfire/algorithm.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,8 +11,8 @@ Vector algorithms (sum, min, sort, etc). """ -from .library import * -from .array import * +from .array import Array +from .library import backend, safe_call, BINARYOP, c_bool_t, c_double_t, c_int_t, c_pointer, c_uint_t def _parallel_dim(a, dim, c_func): out = Array() @@ -88,16 +88,16 @@ def sum(a, dim=None, nan_val=None): The sum of all elements in `a` along dimension `dim`. If `dim` is `None`, sum of the entire Array is returned. """ - if (nan_val is not None): + if nan_val is not None: if dim is not None: return _nan_parallel_dim(a, dim, backend.get().af_sum_nan, nan_val) - else: - return _nan_reduce_all(a, backend.get().af_sum_nan_all, nan_val) - else: - if dim is not None: - return _parallel_dim(a, dim, backend.get().af_sum) - else: - return _reduce_all(a, backend.get().af_sum_all) + return _nan_reduce_all(a, backend.get().af_sum_nan_all, nan_val) + + if dim is not None: + return _parallel_dim(a, dim, backend.get().af_sum) + return _reduce_all(a, backend.get().af_sum_all) + + def sumByKey(keys, vals, dim=-1, nan_val=None): @@ -146,16 +146,15 @@ def product(a, dim=None, nan_val=None): The product of all elements in `a` along dimension `dim`. If `dim` is `None`, product of the entire Array is returned. """ - if (nan_val is not None): + if nan_val is not None: if dim is not None: return _nan_parallel_dim(a, dim, backend.get().af_product_nan, nan_val) - else: - return _nan_reduce_all(a, backend.get().af_product_nan_all, nan_val) - else: - if dim is not None: - return _parallel_dim(a, dim, backend.get().af_product) - else: - return _reduce_all(a, backend.get().af_product_all) + return _nan_reduce_all(a, backend.get().af_product_nan_all, nan_val) + + if dim is not None: + return _parallel_dim(a, dim, backend.get().af_product) + return _reduce_all(a, backend.get().af_product_all) + def productByKey(keys, vals, dim=-1, nan_val=None): """ @@ -203,8 +202,8 @@ def min(a, dim=None): """ if dim is not None: return _parallel_dim(a, dim, backend.get().af_min) - else: - return _reduce_all(a, backend.get().af_min_all) + return _reduce_all(a, backend.get().af_min_all) + def minByKey(keys, vals, dim=-1): """ @@ -247,8 +246,8 @@ def max(a, dim=None): """ if dim is not None: return _parallel_dim(a, dim, backend.get().af_max) - else: - return _reduce_all(a, backend.get().af_max_all) + return _reduce_all(a, backend.get().af_max_all) + def maxByKey(keys, vals, dim=-1): """ @@ -291,8 +290,8 @@ def all_true(a, dim=None): """ if dim is not None: return _parallel_dim(a, dim, backend.get().af_all_true) - else: - return _reduce_all(a, backend.get().af_all_true_all) + return _reduce_all(a, backend.get().af_all_true_all) + def allTrueByKey(keys, vals, dim=-1): """ @@ -382,6 +381,7 @@ 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. @@ -426,16 +426,17 @@ def imin(a, dim=None): out = Array() idx = Array() 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 = 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 - return val,idx.value + return out, idx + + 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 + return val, idx.value + def imax(a, dim=None): """ @@ -459,16 +460,16 @@ def imax(a, dim=None): out = Array() idx = Array() 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 = 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 - return val,idx.value + return out, idx + + 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 + return val, idx.value def accum(a, dim=0): @@ -489,6 +490,7 @@ def accum(a, dim=0): """ return _parallel_dim(a, dim, backend.get().af_accum) + def scan(a, dim=0, op=BINARYOP.ADD, inclusive_scan=True): """ Generalized scan of an array. @@ -520,6 +522,7 @@ def scan(a, dim=0, op=BINARYOP.ADD, inclusive_scan=True): 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): """ Generalized scan by key of an array. @@ -554,6 +557,7 @@ def scan_by_key(key, a, dim=0, op=BINARYOP.ADD, inclusive_scan=True): 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): """ Find the indices of non zero elements @@ -572,6 +576,7 @@ def where(a): safe_call(backend.get().af_where(c_pointer(out.arr), a.arr)) return out + def diff1(a, dim=0): """ Find the first order differences along specified dimensions @@ -590,6 +595,7 @@ def diff1(a, dim=0): """ return _parallel_dim(a, dim, backend.get().af_diff1) + def diff2(a, dim=0): """ Find the second order differences along specified dimensions @@ -608,6 +614,7 @@ def diff2(a, dim=0): """ return _parallel_dim(a, dim, backend.get().af_diff2) + def sort(a, dim=0, is_ascending=True): """ Sort the array along a specified dimension @@ -634,6 +641,7 @@ def sort(a, dim=0, is_ascending=True): 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): """ Sort the array along a specified dimension and get the indices. @@ -659,9 +667,10 @@ def sort_index(a, dim=0, is_ascending=True): """ out = Array() idx = Array() - 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 + 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(ik, iv, dim=0, is_ascending=True): """ @@ -690,9 +699,10 @@ def sort_by_key(ik, iv, dim=0, is_ascending=True): """ ov = Array() ok = Array() - 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 + 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): """ @@ -714,6 +724,7 @@ def set_unique(a, is_sorted=False): 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): """ Find the union of two arrays. @@ -736,6 +747,7 @@ def set_union(a, b, is_unique=False): 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): """ Find the intersect of two arrays. diff --git a/arrayfire/arith.py b/arrayfire/arith.py index e4dc2fdfd..85176436a 100644 --- a/arrayfire/arith.py +++ b/arrayfire/arith.py @@ -1,5 +1,6 @@ + ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,10 +12,11 @@ Math functions (sin, sqrt, exp, etc). """ -from .library import * -from .array import * +from .array import Array, constant_array from .bcast import _bcast_var -from .util import _is_number +from .library import backend, safe_call, c_pointer +from .util import _is_number, dim4_to_tuple, implicit_dtype + def _arith_binary_func(lhs, rhs, c_func): out = Array() @@ -25,10 +27,10 @@ def _arith_binary_func(lhs, rhs, c_func): if not (is_left_array or is_right_array): raise TypeError("Atleast one input needs to be of type arrayfire.array") - elif (is_left_array and is_right_array): + if is_left_array and is_right_array: safe_call(c_func(c_pointer(out.arr), lhs.arr, rhs.arr, _bcast_var.get())) - elif (_is_number(rhs)): + elif _is_number(rhs): ldims = dim4_to_tuple(lhs.dims()) rty = implicit_dtype(rhs, lhs.type()) other = Array() @@ -44,15 +46,16 @@ def _arith_binary_func(lhs, rhs, c_func): return out + def _arith_unary_func(a, c_func): out = Array() safe_call(c_func(c_pointer(out.arr), a.arr)) return out + def cast(a, dtype): """ Cast an array to a specified type - Parameters ---------- a : af.Array @@ -78,6 +81,7 @@ def cast(a, dtype): safe_call(backend.get().af_cast(c_pointer(out.arr), a.arr, dtype.value)) return out + def minof(lhs, rhs): """ Find the minimum value of two inputs at each location. @@ -102,6 +106,7 @@ def minof(lhs, rhs): """ return _arith_binary_func(lhs, rhs, backend.get().af_minof) + def maxof(lhs, rhs): """ Find the maximum value of two inputs at each location. @@ -126,6 +131,7 @@ 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 @@ -164,6 +170,7 @@ def clamp(val, low, high): return out + def mod(lhs, rhs): """ Find the modulus. @@ -184,6 +191,7 @@ def mod(lhs, rhs): """ return _arith_binary_func(lhs, rhs, backend.get().af_mod) + def rem(lhs, rhs): """ Find the remainder. @@ -208,6 +216,7 @@ def rem(lhs, rhs): """ return _arith_binary_func(lhs, rhs, backend.get().af_rem) + def abs(a): """ Find the absolute values. @@ -224,6 +233,7 @@ def abs(a): """ return _arith_unary_func(a, backend.get().af_abs) + def arg(a): """ Find the theta value of the inputs in polar co-ordinates. @@ -240,6 +250,7 @@ def arg(a): """ return _arith_unary_func(a, backend.get().af_arg) + def sign(a): """ Find the sign of the inputs. @@ -256,6 +267,7 @@ def sign(a): """ return _arith_unary_func(a, backend.get().af_sign) + def round(a): """ Round the values to nearest integer. @@ -272,6 +284,7 @@ def round(a): """ return _arith_unary_func(a, backend.get().af_round) + def trunc(a): """ Round the values towards zero. @@ -288,6 +301,7 @@ def trunc(a): """ return _arith_unary_func(a, backend.get().af_trunc) + def floor(a): """ Round the values towards a smaller integer. @@ -304,6 +318,7 @@ def floor(a): """ return _arith_unary_func(a, backend.get().af_floor) + def ceil(a): """ Round the values towards a bigger integer. @@ -320,6 +335,7 @@ def ceil(a): """ return _arith_unary_func(a, backend.get().af_ceil) + def hypot(lhs, rhs): """ Find the value of the hypotunese. @@ -344,6 +360,7 @@ def hypot(lhs, rhs): """ return _arith_binary_func(lhs, rhs, backend.get().af_hypot) + def sin(a): """ Sine of each element in the array. @@ -364,6 +381,7 @@ def sin(a): """ return _arith_unary_func(a, backend.get().af_sin) + def cos(a): """ Cosine of each element in the array. @@ -384,6 +402,7 @@ def cos(a): """ return _arith_unary_func(a, backend.get().af_cos) + def tan(a): """ Tangent of each element in the array. @@ -404,6 +423,7 @@ def tan(a): """ return _arith_unary_func(a, backend.get().af_tan) + def asin(a): """ Arc Sine of each element in the array. @@ -424,6 +444,7 @@ def asin(a): """ return _arith_unary_func(a, backend.get().af_asin) + def acos(a): """ Arc Cosine of each element in the array. @@ -444,6 +465,7 @@ def acos(a): """ return _arith_unary_func(a, backend.get().af_acos) + def atan(a): """ Arc Tangent of each element in the array. @@ -464,6 +486,7 @@ def atan(a): """ return _arith_unary_func(a, backend.get().af_atan) + def atan2(lhs, rhs): """ Find the arc tan using two values. @@ -490,6 +513,7 @@ def atan2(lhs, rhs): """ return _arith_binary_func(lhs, rhs, backend.get().af_atan2) + def cplx(lhs, rhs=None): """ Create a complex array from real inputs. @@ -516,8 +540,8 @@ def cplx(lhs, rhs=None): """ if rhs is None: return _arith_unary_func(lhs, backend.get().af_cplx) - else: - return _arith_binary_func(lhs, rhs, backend.get().af_cplx2) + return _arith_binary_func(lhs, rhs, backend.get().af_cplx2) + def real(a): """ @@ -536,6 +560,7 @@ def real(a): """ return _arith_unary_func(a, backend.get().af_real) + def imag(a): """ Find the imaginary values of the input. @@ -552,6 +577,7 @@ def imag(a): """ return _arith_unary_func(a, backend.get().af_imag) + def conjg(a): """ Find the complex conjugate values of the input. @@ -568,6 +594,7 @@ def conjg(a): """ return _arith_unary_func(a, backend.get().af_conjg) + def sinh(a): """ Hyperbolic Sine of each element in the array. @@ -588,6 +615,7 @@ def sinh(a): """ return _arith_unary_func(a, backend.get().af_sinh) + def cosh(a): """ Hyperbolic Cosine of each element in the array. @@ -608,6 +636,7 @@ def cosh(a): """ return _arith_unary_func(a, backend.get().af_cosh) + def tanh(a): """ Hyperbolic Tangent of each element in the array. @@ -628,6 +657,7 @@ def tanh(a): """ return _arith_unary_func(a, backend.get().af_tanh) + def asinh(a): """ Arc Hyperbolic Sine of each element in the array. @@ -648,6 +678,7 @@ def asinh(a): """ return _arith_unary_func(a, backend.get().af_asinh) + def acosh(a): """ Arc Hyperbolic Cosine of each element in the array. @@ -668,6 +699,7 @@ def acosh(a): """ return _arith_unary_func(a, backend.get().af_acosh) + def atanh(a): """ Arc Hyperbolic Tangent of each element in the array. @@ -688,6 +720,7 @@ def atanh(a): """ return _arith_unary_func(a, backend.get().af_atanh) + def root(lhs, rhs): """ Find the root values of two inputs at each location. @@ -712,6 +745,7 @@ def root(lhs, rhs): """ return _arith_binary_func(lhs, rhs, backend.get().af_root) + def pow(lhs, rhs): """ Find the power of two inputs at each location. @@ -736,6 +770,7 @@ def pow(lhs, rhs): """ return _arith_binary_func(lhs, rhs, backend.get().af_pow) + def pow2(a): """ Raise 2 to the power of each element in input. @@ -756,6 +791,7 @@ def pow2(a): """ return _arith_unary_func(a, backend.get().af_pow2) + def sigmoid(a): """ Raise 2 to the power of each element in input. @@ -776,6 +812,7 @@ def sigmoid(a): """ return _arith_unary_func(a, backend.get().af_sigmoid) + def exp(a): """ Exponential of each element in the array. @@ -796,6 +833,7 @@ def exp(a): """ return _arith_unary_func(a, backend.get().af_exp) + def expm1(a): """ Exponential of each element in the array minus 1. @@ -817,6 +855,7 @@ def expm1(a): """ return _arith_unary_func(a, backend.get().af_expm1) + def erf(a): """ Error function of each element in the array. @@ -837,6 +876,7 @@ def erf(a): """ return _arith_unary_func(a, backend.get().af_erf) + def erfc(a): """ Complementary error function of each element in the array. @@ -857,6 +897,7 @@ def erfc(a): """ return _arith_unary_func(a, backend.get().af_erfc) + def log(a): """ Natural logarithm of each element in the array. @@ -877,6 +918,7 @@ def log(a): """ return _arith_unary_func(a, backend.get().af_log) + def log1p(a): """ Logarithm of each element in the array plus 1. @@ -898,6 +940,7 @@ def log1p(a): """ return _arith_unary_func(a, backend.get().af_log1p) + def log10(a): """ Logarithm base 10 of each element in the array. @@ -918,6 +961,7 @@ def log10(a): """ return _arith_unary_func(a, backend.get().af_log10) + def log2(a): """ Logarithm base 2 of each element in the array. @@ -938,6 +982,7 @@ def log2(a): """ return _arith_unary_func(a, backend.get().af_log2) + def sqrt(a): """ Square root of each element in the array. @@ -978,6 +1023,7 @@ def rsqrt(a): """ return _arith_unary_func(a, backend.get().af_rsqrt) + def cbrt(a): """ Cube root of each element in the array. @@ -998,6 +1044,7 @@ def cbrt(a): """ return _arith_unary_func(a, backend.get().af_cbrt) + def factorial(a): """ factorial of each element in the array. @@ -1018,6 +1065,7 @@ def factorial(a): """ return _arith_unary_func(a, backend.get().af_factorial) + def tgamma(a): """ Performs the gamma function for each element in the array. @@ -1038,6 +1086,7 @@ def tgamma(a): """ return _arith_unary_func(a, backend.get().af_tgamma) + def lgamma(a): """ Performs the logarithm of gamma function for each element in the array. @@ -1058,6 +1107,7 @@ def lgamma(a): """ return _arith_unary_func(a, backend.get().af_lgamma) + def iszero(a): """ Check if each element of the input is zero. @@ -1078,6 +1128,7 @@ def iszero(a): """ return _arith_unary_func(a, backend.get().af_iszero) + def isinf(a): """ Check if each element of the input is infinity. @@ -1098,6 +1149,7 @@ def isinf(a): """ return _arith_unary_func(a, backend.get().af_isinf) + def isnan(a): """ Check if each element of the input is NaN. diff --git a/arrayfire/array.py b/arrayfire/array.py index 1b71db2c7..acbf14230 100644 --- a/arrayfire/array.py +++ b/arrayfire/array.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -13,18 +13,22 @@ import inspect import os -from .library import * -from .util import * -from .util import _is_number + +from .base import BaseArray from .bcast import _bcast_var -from .base import * -from .index import * -from .index import _Index4 +from .index import Index, ParallelRange, _Index4 +from .library import backend, safe_call +from .library import ( + Dtype, Source, c_bool_t, c_char_ptr_t, c_dim_t, c_double_t, c_int_t, c_longlong_t, c_pointer, c_size_t, c_uint_t, + c_ulonglong_t, c_void_ptr_t) +from .util import ( + _is_number, dim4, dim4_to_tuple, implicit_dtype, to_c_type, to_dtype, to_str, to_typecode, to_typename) _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 @@ -44,6 +48,7 @@ def set_display_dims_limit(*dims): 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 @@ -67,6 +72,7 @@ def get_display_dims_limit(): """ return _display_dims_limit + def _in_display_dims_limit(dims): if _is_running_in_py_charm: return False @@ -80,17 +86,19 @@ def _in_display_dims_limit(dims): 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]) - if (not is_device): - safe_call(backend.get().af_create_array(c_pointer(out_arr), c_void_ptr_t(buf), - numdims, c_pointer(c_dims), dtype.value)) + if not is_device: + 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(c_pointer(out_arr), c_void_ptr_t(buf), - numdims, c_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 = c_void_ptr_t(0) c_dims = dim4(idims[0], idims[1], idims[2], idims[3]) @@ -106,27 +114,27 @@ 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(c_pointer(out_arr), c_void_ptr_t(buf), - offset, numdims, c_pointer(c_dims), - c_pointer(strides), dtype.value, - location.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 = c_void_ptr_t(0) - if numdims == 0: return out_arr + 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)) + 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): """ Internal function to create a C array. Should not be used externall. """ - if not isinstance(dtype, c_int_t): if isinstance(dtype, int): dtype = c_int_t(dtype) @@ -142,11 +150,10 @@ def constant_array(val, d0, d1=None, d2=None, d3=None, dtype=Dtype.f32): 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): + if dtype.value != Dtype.c32.value and dtype.value != Dtype.c64.value: dtype = Dtype.c32.value - safe_call(backend.get().af_constant_complex(c_pointer(out), c_real, c_imag, - 4, c_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 = c_longlong_t(val.real) safe_call(backend.get().af_constant_long(c_pointer(out), c_val, 4, c_pointer(dims))) @@ -164,7 +171,7 @@ def _binary_func(lhs, rhs, c_func): out = Array() other = rhs - if (_is_number(rhs)): + if _is_number(rhs): ldims = dim4_to_tuple(lhs.dims()) rty = implicit_dtype(rhs, lhs.type()) other = Array() @@ -176,11 +183,12 @@ def _binary_func(lhs, rhs, c_func): return out + def _binary_funcr(lhs, rhs, c_func): out = Array() other = lhs - if (_is_number(lhs)): + if _is_number(lhs): rdims = dim4_to_tuple(rhs.dims()) lty = implicit_dtype(lhs, rhs.type()) other = Array() @@ -192,16 +200,18 @@ def _binary_funcr(lhs, rhs, c_func): return out + def _ctype_to_lists(ctype_arr, dim, shape, offset=0): - if (dim == 0): - return list(ctype_arr[offset : offset + shape[0]]) - else: - dim_len = shape[dim] - res = [[]] * dim_len - for n in range(dim_len): - res[n] = _ctype_to_lists(ctype_arr, dim - 1, shape, offset) - offset += shape[0] - return res + if dim == 0: + return list(ctype_arr[offset: offset + shape[0]]) + + dim_len = shape[dim] + res = [[]] * dim_len + for n in range(dim_len): + res[n] = _ctype_to_lists(ctype_arr, dim - 1, shape, offset) + offset += shape[0] + return res + def _slice_to_length(key, dim): tkey = [key.start, key.stop, key.step] @@ -221,6 +231,7 @@ def _slice_to_length(key, dim): return int(((tkey[1] - tkey[0] - 1) / tkey[2]) + 1) + def _get_info(dims, buf_len): elements = 1 numdims = 0 @@ -230,7 +241,7 @@ def _get_info(dims, buf_len): for i in range(numdims): elements *= dims[i] idims[i] = dims[i] - elif (buf_len != 0): + elif buf_len != 0: idims = [buf_len, 1, 1, 1] numdims = 1 else: @@ -250,51 +261,53 @@ def _get_indices(key): return inds -def _get_assign_dims(key, idims): +def _get_assign_dims(key, idims): + from .algorithm import sum dims = [1]*4 - for n in range(len(idims)): + for n, _ in enumerate(idims): dims[n] = idims[n] if _is_number(key): dims[0] = 1 return dims - elif isinstance(key, slice): + if isinstance(key, slice): dims[0] = _slice_to_length(key, idims[0]) return dims - elif isinstance(key, ParallelRange): + if isinstance(key, ParallelRange): dims[0] = _slice_to_length(key.S, idims[0]) return dims - elif isinstance(key, BaseArray): + if isinstance(key, BaseArray): # If the array is boolean take only the number of nonzeros - if(key.dtype() is Dtype.b8): + if key.dtype() is Dtype.b8: dims[0] = int(sum(key)) else: dims[0] = key.elements() return dims - elif isinstance(key, tuple): - n_inds = len(key) - - for n in range(n_inds): - if (_is_number(key[n])): - dims[n] = 1 - elif (isinstance(key[n], BaseArray)): - # If the array is boolean take only the number of nonzeros - if(key[n].dtype() is Dtype.b8): - dims[n] = int(sum(key[n])) - else: - dims[n] = key[n].elements() - elif (isinstance(key[n], slice)): - dims[n] = _slice_to_length(key[n], idims[n]) - elif (isinstance(key[n], ParallelRange)): - dims[n] = _slice_to_length(key[n].S, idims[n]) + if not isinstance(key, tuple): + raise IndexError("Invalid type while assigning to arrayfire.array") + + n_inds = len(key) + + for n in range(n_inds): + if _is_number(key[n]): + dims[n] = 1 + elif isinstance(key[n], BaseArray): + # If the array is boolean take only the number of nonzeros + if key[n].dtype() is Dtype.b8: + dims[n] = int(sum(key[n])) else: - raise IndexError("Invalid type while assigning to arrayfire.array") + dims[n] = key[n].elements() + elif isinstance(key[n], slice): + dims[n] = _slice_to_length(key[n], idims[n]) + elif isinstance(key[n], ParallelRange): + dims[n] = _slice_to_length(key[n].S, idims[n]) + else: + raise IndexError("Invalid type while assigning to arrayfire.array") + + return dims - return dims - else: - raise IndexError("Invalid type while assigning to arrayfire.array") def transpose(a, conj=False): """ @@ -318,6 +331,7 @@ def transpose(a, conj=False): safe_call(backend.get().af_transpose(c_pointer(out.arr), a.arr, conj)) return out + def transpose_inplace(a, conj=False): """ Perform inplace transpose on an input. @@ -338,6 +352,7 @@ def transpose_inplace(a, conj=False): """ safe_call(backend.get().af_transpose_inplace(a.arr, conj)) + class Array(BaseArray): """ @@ -436,7 +451,6 @@ class Array(BaseArray): - numpy uses row major format by default which can cause issues during conversion """ - # 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 @@ -444,11 +458,10 @@ class Array(BaseArray): __array_priority__ = 30 def __init__(self, src=None, dims=None, dtype=None, is_device=False, offset=None, strides=None): + super().__init__() - super(Array, self).__init__() - - buf=None - buf_len=0 + buf = None + buf_len = 0 if dtype is not None: if isinstance(dtype, str): @@ -458,26 +471,26 @@ def __init__(self, src=None, dims=None, dtype=None, is_device=False, offset=None else: type_char = None - _type_char='f' + _type_char = 'f' if src is not None: - if (isinstance(src, Array)): + if isinstance(src, Array): safe_call(backend.get().af_retain_array(c_pointer(self.arr), src.arr)) return host = __import__("array") if isinstance(src, host.array): - buf,buf_len = src.buffer_info() + buf, buf_len = src.buffer_info() _type_char = src.typecode numdims, idims = _get_info(dims, buf_len) elif isinstance(src, list): tmp = host.array('f', src) - buf,buf_len = tmp.buffer_info() + buf, buf_len = tmp.buffer_info() _type_char = tmp.typecode numdims, idims = _get_info(dims, buf_len) - elif isinstance(src, int) or isinstance(src, c_void_ptr_t): + elif isinstance(src, (c_void_ptr_t, int)): buf = src if not isinstance(src, c_void_ptr_t) else src.value numdims, idims = _get_info(dims, buf_len) @@ -486,10 +499,10 @@ def __init__(self, src=None, dims=None, dtype=None, is_device=False, offset=None for dim in idims: elements *= dim - if (elements == 0): + if elements == 0: raise RuntimeError("Expected dims when src is data pointer") - if (type_char is None): + if type_char is None: raise TypeError("Expected type_char when src is data pointer") _type_char = type_char @@ -497,18 +510,13 @@ def __init__(self, src=None, dims=None, dtype=None, is_device=False, offset=None else: raise TypeError("src is an object of unsupported class") - if (type_char is not None and - type_char != _type_char): + if type_char is not None and type_char != _type_char: raise TypeError("Can not create array of requested type from input data type") - if(offset is None and strides is 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: - if type_char is None: type_char = 'f' @@ -528,6 +536,7 @@ def as_type(self, ty): ---------- ty : Return data type """ + from .arith import cast return cast(self, ty) def copy(self): @@ -547,9 +556,10 @@ def __del__(self): """ Release the C array when going out of scope """ - if self.arr.value: - backend.get().af_release_array(self.arr) - self.arr.value = 0 + if not self.arr.value: + return + backend.get().af_release_array(self.arr) + self.arr.value = 0 def device_ptr(self): """ @@ -563,10 +573,13 @@ 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. + - 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. + - 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 = c_void_ptr_t(0) backend.get().af_get_device_ptr(c_pointer(ptr), self.arr) @@ -619,9 +632,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(c_pointer(s0), c_pointer(s1), - c_pointer(s2), c_pointer(s3), self.arr)) - strides = (s0.value,s1.value,s2.value,s3.value) + 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()] def elements(self): @@ -633,7 +645,7 @@ def elements(self): return num.value def __len__(self): - return(self.elements()) + return self.elements() def allocated(self): """ @@ -679,9 +691,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(c_pointer(d0), c_pointer(d1), - c_pointer(d2), c_pointer(d3), self.arr)) - dims = (d0.value,d1.value,d2.value,d3.value) + 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()] @property @@ -906,7 +917,7 @@ def __itruediv__(self, other): """ Perform self /= other. """ - self = _binary_func(self, other, backend.get().af_div) + self = _binary_func(self, other, backend.get().af_div) return self def __rtruediv__(self, other): @@ -925,7 +936,7 @@ def __idiv__(self, other): """ Perform other / self. """ - self = _binary_func(self, other, backend.get().af_div) + self = _binary_func(self, other, backend.get().af_div) return self def __rdiv__(self, other): @@ -944,7 +955,7 @@ def __imod__(self, other): """ Perform self %= other. """ - self = _binary_func(self, other, backend.get().af_mod) + self = _binary_func(self, other, backend.get().af_mod) return self def __rmod__(self, other): @@ -963,7 +974,7 @@ def __ipow__(self, other): """ Perform self **= other. """ - self = _binary_func(self, other, backend.get().af_pow) + self = _binary_func(self, other, backend.get().af_pow) return self def __rpow__(self, other): @@ -1120,7 +1131,7 @@ def logical_or(self, other): def __nonzero__(self): return self != 0 - # TODO: + # TODO: define abs # def __abs__(self): # return self @@ -1133,23 +1144,22 @@ def __getitem__(self, key): Ellipsis not supported as key """ try: + from .algorithm import count out = Array() n_dims = self.numdims() - if (isinstance(key, Array) and key.type() == Dtype.b8.value): + if isinstance(key, Array) and key.type() == Dtype.b8.value: n_dims = 1 - if (count(key) == 0): + if count(key) == 0: return out inds = _get_indices(key) - safe_call(backend.get().af_index_gen(c_pointer(out.arr), - self.arr, c_dim_t(n_dims), inds.pointer)) + 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: raise IndexError(str(e)) - def __setitem__(self, key, val): """ Perform self[key] = val @@ -1159,34 +1169,34 @@ def __setitem__(self, key, val): Ellipsis not supported as key """ try: + from .algorithm import count n_dims = self.numdims() is_boolean_idx = isinstance(key, Array) and key.type() == Dtype.b8.value - if (is_boolean_idx): + if is_boolean_idx: n_dims = 1 num = count(key) - if (num == 0): + if num == 0: return - if (_is_number(val)): + if _is_number(val): tdims = _get_assign_dims(key, self.dims()) - if (is_boolean_idx): + 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()) + other_arr = constant_array(val, tdims[0], tdims[1], tdims[2], tdims[3], self.type()) del_other = True else: other_arr = val.arr del_other = False out_arr = c_void_ptr_t(0) - inds = _get_indices(key) + inds = _get_indices(key) - 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_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)) if del_other: safe_call(backend.get().af_release_array(other_arr)) @@ -1200,7 +1210,7 @@ def _reorder(self): Returns a reordered array to help interoperate with row major formats. """ ndims = self.numdims() - if (ndims == 1): + if ndims == 1: return self rdims = tuple(reversed(range(ndims))) + tuple(range(ndims, 4)) @@ -1230,19 +1240,17 @@ def to_ctype(self, row_major=False, return_shape=False): (res, dims): tuple of the ctypes array and the shape of the array """ - if (self.arr.value == 0): + if self.arr.value == 0: raise RuntimeError("Can not call to_ctype on empty array") - 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): + if return_shape: return res, self.dims() - else: - return res + + return res def to_array(self, row_major=False, return_shape=False): """ @@ -1266,7 +1274,7 @@ def to_array(self, row_major=False, return_shape=False): (res, dims): array.array and the shape of the array """ - if (self.arr.value == 0): + if self.arr.value == 0: raise RuntimeError("Can not call to_array on empty array") res = self.to_ctype(row_major, return_shape) @@ -1274,10 +1282,10 @@ def to_array(self, row_major=False, return_shape=False): host = __import__("array") h_type = to_typecode[self.type()] - if (return_shape): + if return_shape: return host.array(h_type, res[0]), res[1] - else: - return host.array(h_type, res) + + return host.array(h_type, res) def to_list(self, row_major=False): """ @@ -1308,8 +1316,7 @@ def scalar(self): """ Return the first element of the array """ - - if (self.arr.value == 0): + if self.arr.value == 0: raise RuntimeError("Can not call to_ctype on empty array") ctype_type = to_c_type[self.type()] @@ -1325,7 +1332,6 @@ def __str__(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._get_metadata_str() @@ -1339,12 +1345,11 @@ def __repr__(self): ---- You can use af.display(a, pres) to display the contents of the array. """ - 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 '') + _dims = "Dims: {}".format(str(self.dims())) if dims else "" + return "arrayfire.Array()\nType: {}\n{}".format(to_typename[self.type()], _dims) def _as_str(self): arr_str = c_char_ptr_t(0) @@ -1358,6 +1363,7 @@ def __array__(self): """ Constructs a numpy.array from arrayfire.Array """ + # FIXME: import insdie of a function 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(c_void_ptr_t(res.ctypes.data), self.arr)) @@ -1383,10 +1389,10 @@ def to_ndarray(self, output=None): if output is None: return self.__array__() - if (output.dtype != to_typecode[self.type()]): + if output.dtype != to_typecode[self.type()]: raise TypeError("Output is not the same type as the array") - if (output.size != self.elements()): + if output.size != self.elements(): raise RuntimeError("Output size does not match that of input") flags = output.flags @@ -1401,6 +1407,7 @@ def to_ndarray(self, output=None): 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. @@ -1416,15 +1423,15 @@ def display(a, precision=4): name = "" try: - if (expr is not None): + if expr is not None: st = expr[0].find('(') + 1 en = expr[0].rfind(')') name = expr[0][st:en] except IndexError: pass - safe_call(backend.get().af_print_array_gen(name.encode('utf-8'), - a.arr, c_int_t(precision))) + safe_call(backend.get().af_print_array_gen(name.encode('utf-8'), a.arr, c_int_t(precision))) + def save_array(key, a, filename, append=False): """ @@ -1450,13 +1457,11 @@ def save_array(key, a, filename, append=False): The index of the array stored in the file. """ 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'), - append)) + safe_call(backend.get().af_save_array( + c_pointer(index), key.encode('utf-8'), a.arr, filename.encode('utf-8'), append)) return index.value + def read_array(filename, index=None, key=None): """ Read an array from disk. @@ -1480,16 +1485,10 @@ 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(c_pointer(out.arr), - filename.encode('utf-8'), - index)) - elif (key is not None): - safe_call(backend.get().af_read_array_key(c_pointer(out.arr), - filename.encode('utf-8'), - key.encode('utf-8'))) - + if index is not None: + 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(c_pointer(out.arr), filename.encode('utf-8'), key.encode('utf-8'))) return out -from .algorithm import (sum, count) -from .arith import cast + diff --git a/arrayfire/base.py b/arrayfire/base.py index ca072fa2c..df3112676 100644 --- a/arrayfire/base.py +++ b/arrayfire/base.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,12 +11,13 @@ Implementation of BaseArray class. """ -from .library import * -from .util import * +from .library import c_void_ptr_t -class BaseArray(object): + +class BaseArray: """ Base array class for arrayfire. For internal use only. """ + def __init__(self): self.arr = c_void_ptr_t(0) diff --git a/arrayfire/bcast.py b/arrayfire/bcast.py index 0b8109244..c838b1b1b 100644 --- a/arrayfire/bcast.py +++ b/arrayfire/bcast.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,8 +11,10 @@ Function to perform broadcasting operations. """ -class _bcast(object): + +class _bcast: _flag = False + def get(self): return _bcast._flag @@ -22,8 +24,10 @@ def set(self, flag): def toggle(self): _bcast._flag ^= True + _bcast_var = _bcast() + def broadcast(func, *args): """ Function to perform broadcast operations. @@ -83,14 +87,13 @@ def broadcast(func, *args): 1.5328 0.8898 0.7185 """ - def wrapper(*func_args): _bcast_var.toggle() res = func(*func_args) _bcast_var.toggle() return res - if len(args) == 0: + if not args: return wrapper - else: - return wrapper(*args) + + return wrapper(*args) diff --git a/arrayfire/blas.py b/arrayfire/blas.py index 448261e90..a62110fc1 100644 --- a/arrayfire/blas.py +++ b/arrayfire/blas.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,8 +11,9 @@ BLAS functions (matmul, dot, etc) """ -from .library import * -from .array import * +from .array import Array +from .library import backend, safe_call, MATPROP, c_double_t, c_pointer + def matmul(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE): """ @@ -53,10 +54,11 @@ def matmul(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE): """ out = Array() - safe_call(backend.get().af_matmul(c_pointer(out.arr), lhs.arr, rhs.arr, - lhs_opts.value, rhs_opts.value)) + safe_call(backend.get().af_matmul( + c_pointer(out.arr), lhs.arr, rhs.arr, lhs_opts.value, rhs_opts.value)) return out + def matmulTN(lhs, rhs): """ Matrix multiplication after transposing the first matrix. @@ -84,10 +86,11 @@ def matmulTN(lhs, rhs): """ out = Array() - safe_call(backend.get().af_matmul(c_pointer(out.arr), lhs.arr, rhs.arr, - MATPROP.TRANS.value, MATPROP.NONE.value)) + safe_call(backend.get().af_matmul( + c_pointer(out.arr), lhs.arr, rhs.arr, MATPROP.TRANS.value, MATPROP.NONE.value)) return out + def matmulNT(lhs, rhs): """ Matrix multiplication after transposing the second matrix. @@ -115,10 +118,11 @@ def matmulNT(lhs, rhs): """ out = Array() - safe_call(backend.get().af_matmul(c_pointer(out.arr), lhs.arr, rhs.arr, - MATPROP.NONE.value, MATPROP.TRANS.value)) + safe_call(backend.get().af_matmul( + c_pointer(out.arr), lhs.arr, rhs.arr, MATPROP.NONE.value, MATPROP.TRANS.value)) return out + def matmulTT(lhs, rhs): """ Matrix multiplication after transposing both inputs. @@ -146,11 +150,12 @@ def matmulTT(lhs, rhs): """ out = Array() - safe_call(backend.get().af_matmul(c_pointer(out.arr), lhs.arr, rhs.arr, - MATPROP.TRANS.value, MATPROP.TRANS.value)) + safe_call(backend.get().af_matmul( + c_pointer(out.arr), lhs.arr, rhs.arr, MATPROP.TRANS.value, MATPROP.TRANS.value)) return out -def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE, return_scalar = False): + +def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE, return_scalar=False): """ Dot product of two input vectors. @@ -192,8 +197,8 @@ def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE, return_scalar = 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)) + 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 @@ -203,6 +208,7 @@ def dot(lhs, rhs, lhs_opts=MATPROP.NONE, rhs_opts=MATPROP.NONE, return_scalar = 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. diff --git a/arrayfire/cuda.py b/arrayfire/cuda.py index ea24c0e30..ab5c5673b 100644 --- a/arrayfire/cuda.py +++ b/arrayfire/cuda.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -13,6 +13,9 @@ This module provides interoperability with other CUDA libraries. """ +from .library import c_int_t, c_pointer, c_void_ptr_t + + def get_stream(idx): """ Get the CUDA stream used for the device `idx` by ArrayFire. @@ -27,18 +30,19 @@ def get_stream(idx): ----------- stream : integer denoting the stream id. """ - + # FIXME: ctypes imported but unused import ctypes as ct - from .util import safe_call as safe_call - from .library import backend as backend + from .util import safe_call + from .library import backend - if (backend.name() != "cuda"): + if backend.name() != "cuda": raise RuntimeError("Invalid backend loaded") 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): """ Get native (unsorted) CUDA device ID @@ -53,18 +57,19 @@ def get_native_id(idx): ----------- native_idx : integer denoting the native cuda id. """ - + # FIXME: ctypes imported but unused import ctypes as ct - from .util import safe_call as safe_call - from .library import backend as backend + from .util import safe_call + from .library import backend - if (backend.name() != "cuda"): + if backend.name() != "cuda": raise RuntimeError("Invalid backend loaded") 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): """ Set native (unsorted) CUDA device ID @@ -75,13 +80,12 @@ def set_native_id(idx): idx : int. Specifies the (unsorted) native index of the device. """ - + # FIXME: ctypes imported but unused import ctypes as ct - from .util import safe_call as safe_call - from .library import backend as backend + from .util import safe_call + from .library import backend - if (backend.name() != "cuda"): + if backend.name() != "cuda": raise RuntimeError("Invalid backend loaded") safe_call(backend.get().afcu_set_native_id(idx)) - return diff --git a/arrayfire/data.py b/arrayfire/data.py index 1fbe17a53..9fac5a3cc 100644 --- a/arrayfire/data.py +++ b/arrayfire/data.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,12 +11,10 @@ Functions to create and manipulate arrays. """ -from sys import version_info -from .library import * -from .array import * -from .util import * -from .util import _is_number -from .random import randu, randn, set_seed, get_seed +from .array import Array, constant_array +from .library import backend, safe_call, Dtype, c_double_t, c_int_t, c_pointer, c_void_ptr_t, PAD +from .util import _is_number, dim4 + def constant(val, d0, d1=None, d2=None, d3=None, dtype=Dtype.f32): """ @@ -52,14 +50,15 @@ def constant(val, d0, d1=None, d2=None, d3=None, dtype=Dtype.f32): - 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() out.arr = constant_array(val, d0, d1, d2, d3, dtype.value) return out + # Store builtin range function to be used later _brange = range + def range(d0, d1=None, d2=None, d3=None, dim=0, dtype=Dtype.f32): """ Create a multi dimensional array using length of a dimension as range. @@ -122,7 +121,7 @@ def range(d0, d1=None, d2=None, d3=None, dim=0, dtype=Dtype.f32): return out -def iota(d0, d1=None, d2=None, d3=None, dim=-1, tile_dims=None, dtype=Dtype.f32): +def iota(d0, d1=None, d2=None, d3=None, tile_dims=None, dtype=Dtype.f32): """ Create a multi dimensional array using the number of elements in the array as the range. @@ -175,7 +174,7 @@ def iota(d0, d1=None, d2=None, d3=None, dim=-1, tile_dims=None, dtype=Dtype.f32) """ out = Array() dims = dim4(d0, d1, d2, d3) - td=[1]*4 + td = [1]*4 if tile_dims is not None: for i in _brange(len(tile_dims)): @@ -183,10 +182,11 @@ 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(c_pointer(out.arr), 4, c_pointer(dims), - 4, c_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): """ Create an identity matrix or batch of identity matrices. @@ -217,13 +217,13 @@ def identity(d0, d1, d2=None, d3=None, dtype=Dtype.f32): - If d2 is not None and d3 is None, `out` is 3D of size (d0, d1, d2). - If d2, d3 are not None, `out` is 4D of size (d0, d1, d2, d3). """ - out = Array() dims = dim4(d0, d1, d2, d3) 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): """ Create a diagonal matrix or Extract the diagonal from a matrix. @@ -257,6 +257,7 @@ def diag(a, num=0, extract=True): 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): """ Join two or more arrayfire arrays along a specified dimension. @@ -316,7 +317,7 @@ def join(dim, first, second, third=None, fourth=None): 0.5367 0.8359 0.8719 0.6275 0.0495 0.6591 """ out = Array() - if (third is None and fourth is None): + if third is None and fourth is None: safe_call(backend.get().af_join(c_pointer(out.arr), dim, first.arr, second.arr)) else: c_void_p_4 = c_void_ptr_t * 4 @@ -324,10 +325,10 @@ def join(dim, first, second, third=None, fourth=None): num = 2 if third is not None: c_array_vec[num] = third.arr - num+=1 + num += 1 if fourth is not None: c_array_vec[num] = fourth.arr - num+=1 + num += 1 safe_call(backend.get().af_join_many(c_pointer(out.arr), dim, num, c_pointer(c_array_vec))) return out @@ -397,6 +398,7 @@ 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. @@ -481,6 +483,7 @@ def reorder(a, d0=1, d1=0, d2=2, d3=3): 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): """ Shift the input along each dimension. @@ -537,6 +540,7 @@ def shift(a, d0, d1=0, d2=0, d3=0): 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): """ Modify the shape of the array without changing the data layout. @@ -571,6 +575,7 @@ def moddims(a, d0, d1=1, d2=1, d3=1): safe_call(backend.get().af_moddims(c_pointer(out.arr), a.arr, 4, c_pointer(dims))) return out + def flat(a): """ Flatten the input array. @@ -591,6 +596,7 @@ def flat(a): safe_call(backend.get().af_flat(c_pointer(out.arr), a.arr)) return out + def flip(a, dim=0): """ Flip an array along a dimension. @@ -638,6 +644,7 @@ def flip(a, dim=0): 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): """ Extract the lower triangular matrix from the input. @@ -661,6 +668,7 @@ def lower(a, is_unit_diag=False): safe_call(backend.get().af_lower(c_pointer(out.arr), a.arr, is_unit_diag)) return out + def upper(a, is_unit_diag=False): """ Extract the upper triangular matrix from the input. @@ -684,6 +692,7 @@ def upper(a, is_unit_diag=False): safe_call(backend.get().af_upper(c_pointer(out.arr), a.arr, is_unit_diag)) return out + def select(cond, lhs, rhs): """ Select elements from one of two arrays based on condition. @@ -741,16 +750,16 @@ def select(cond, lhs, rhs): if not (is_left_array or is_right_array): raise TypeError("Atleast one input needs to be of type arrayfire.array") - elif (is_left_array and is_right_array): + if is_left_array and is_right_array: safe_call(backend.get().af_select(c_pointer(out.arr), cond.arr, lhs.arr, rhs.arr)) - - elif (_is_number(rhs)): + elif _is_number(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(c_pointer(out.arr), cond.arr, c_double_t(lhs), rhs.arr)) return out + def replace(lhs, cond, rhs): """ Select elements from one of two arrays based on condition. @@ -794,10 +803,10 @@ def replace(lhs, cond, rhs): """ is_right_array = isinstance(rhs, Array) - if (is_right_array): + 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, c_double_t(rhs))) + safe_call(backend.get().af_replace_scalar(lhs.arr, cond.arr, c_double_t(rhs))) + def pad(a, beginPadding, endPadding, padFillType = PAD.ZERO): """ diff --git a/arrayfire/device.py b/arrayfire/device.py index 53f302db5..e12f74c41 100644 --- a/arrayfire/device.py +++ b/arrayfire/device.py @@ -1,17 +1,20 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# 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 ######################################################## + """ Functions to handle the available devices in the backend. """ -from .library import * -from .util import (safe_call, to_str, get_version) +from .array import Array +from .library import backend, safe_call, c_bool_t, c_char_t, c_dim_t, c_int_t, c_pointer, c_size_t, c_void_ptr_t +from .util import to_str + def init(): """ @@ -21,6 +24,7 @@ def init(): """ safe_call(backend.get().af_init()) + def info(): """ Displays the information about the following: @@ -31,6 +35,7 @@ def info(): """ safe_call(backend.get().af_info()) + def device_info(): """ Returns a map with the following fields: @@ -45,8 +50,8 @@ def device_info(): toolkit = c_char_256() compute = c_char_256() - safe_call(backend.get().af_device_info(c_pointer(device_name), c_pointer(backend_name), - c_pointer(toolkit), c_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) @@ -55,6 +60,7 @@ def device_info(): return dev_info + def get_device_count(): """ Returns the number of devices available. @@ -63,6 +69,7 @@ def get_device_count(): 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. @@ -71,6 +78,7 @@ def get_device(): safe_call(backend.get().af_get_device(c_pointer(c_dev))) return c_dev.value + def set_device(num): """ Change the active device to the specified id. @@ -82,7 +90,8 @@ def set_device(num): """ safe_call(backend.get().af_set_device(num)) -def info_str(verbose = False): + +def info_str(): """ Returns information about the following as a string: - ArrayFire version number. @@ -90,6 +99,7 @@ def info_str(verbose = False): - The names of the devices. - The current device being used. """ + # FIXME: import inside of a function import platform res_str = 'ArrayFire' @@ -105,32 +115,33 @@ def info_str(verbose = False): for n in range(num_devices): # To suppress warnings on CPU - if (n != curr_device_id): + if n != curr_device_id: set_device(n) - if (n == curr_device_id): + if n == curr_device_id: res_str += '[%d] ' % n else: res_str += '-%d- ' % n dev_info = device_info() - if (backend_str.lower() == 'opencl'): + if backend_str.lower() == 'opencl': res_str += dev_info['toolkit'] res_str += ': ' + dev_info['device'] - if (backend_str.lower() != 'cpu'): + if backend_str.lower() != 'cpu': res_str += ' (Compute ' + dev_info['compute'] + ')' res_str += '\n' # To suppress warnings on CPU - if (curr_device_id != get_device()): + if curr_device_id != get_device(): set_device(curr_device_id) return res_str + def is_dbl_supported(device=None): """ Check if double precision is supported on specified device. @@ -150,6 +161,7 @@ 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. @@ -181,17 +193,18 @@ def sync(device=None): dev = device if device is not None else get_device() safe_call(backend.get().af_sync(dev)) + def __eval(*args): nargs = len(args) - if (nargs == 1): + if nargs == 1: safe_call(backend.get().af_eval(args[0].arr)) - else: - 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(c_int_t(nargs), c_pointer(arrs))) - return + + 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(c_int_t(nargs), c_pointer(arrs))) + def eval(*args): """ @@ -236,6 +249,7 @@ def eval(*args): __eval(*args) + def set_manual_eval_flag(flag): """ Tells the backend JIT engine to disable heuristics for determining when to evaluate a JIT tree. @@ -252,6 +266,7 @@ def set_manual_eval_flag(flag): """ safe_call(backend.get().af_set_manual_eval_flag(flag)) + def get_manual_eval_flag(): """ Query the backend JIT engine to see if the user disabled heuristic evaluation of the JIT tree. @@ -264,6 +279,7 @@ def get_manual_eval_flag(): safe_call(backend.get().af_get_manual_eval_flag(c_pointer(res))) return res.value + def device_mem_info(): """ Returns a map with the following fields: @@ -285,14 +301,15 @@ def device_mem_info(): 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))) + 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} + mem_info['alloc'] = {'buffers': alloc_buffers.value, 'bytes': alloc_bytes.value} + mem_info['lock'] = {'buffers': lock_buffers.value, 'bytes': lock_bytes.value} return mem_info -def print_mem_info(title = "Memory Info", device_id = None): + +def print_mem_info(title="Memory Info", device_id=None): """ Prints the memory used for the specified device. @@ -338,12 +355,14 @@ def print_mem_info(title = "Memory Info", device_id = None): 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 """ safe_call(backend.get().af_device_gc()) + def get_device_ptr(a): """ Get the raw device pointer of an array @@ -367,14 +386,17 @@ def get_device_ptr(a): safe_call(backend.get().af_get_device_ptr(c_pointer(ptr), a.arr)) return ptr + def lock_device_ptr(a): """ This functions is deprecated. Please use lock_array instead. """ + # FIXME: import inside of a function 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. @@ -390,6 +412,7 @@ def lock_array(a): """ safe_call(backend.get().af_lock_array(a.arr)) + def is_locked_array(a): """ Check if the input array is locked by the user. @@ -407,14 +430,17 @@ def is_locked_array(a): safe_call(backend.get().af_is_locked_array(c_pointer(res), a.arr)) return res.value + def unlock_device_ptr(a): """ This functions is deprecated. Please use unlock_array instead. """ + # FIXME: import inside of a function 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. @@ -427,6 +453,7 @@ 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. @@ -436,6 +463,7 @@ def alloc_device(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. @@ -445,6 +473,7 @@ def alloc_host(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. @@ -454,6 +483,7 @@ def alloc_pinned(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 @@ -461,6 +491,7 @@ def free_device(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 @@ -468,6 +499,7 @@ def free_host(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 @@ -475,4 +507,3 @@ def free_pinned(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 2f76a97eb..3025f4c1b 100644 --- a/arrayfire/features.py +++ b/arrayfire/features.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,10 +11,12 @@ Features class used for Computer Vision algorithms. """ -from .library import * -from .array import * import numbers +from .array import Array +from .library import backend, safe_call, c_dim_t, c_pointer, c_void_ptr_t + + class Features(object): """ A container class used for various feature detectors. @@ -29,16 +31,17 @@ class Features(object): def __init__(self, num=0): self.feat = c_void_ptr_t(0) if num is not None: - assert(isinstance(num, numbers.Number)) + 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 + if not self.feat: + return + backend.get().af_release_features(self.feat) + self.feat = None def num_features(self): """ diff --git a/arrayfire/graphics.py b/arrayfire/graphics.py index 70881f42c..bb214d983 100644 --- a/arrayfire/graphics.py +++ b/arrayfire/graphics.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,15 +11,18 @@ Graphics functions (plot, image, etc). """ -from .library import * -from .array import * +import ctypes as ct + +from .library import backend, safe_call, COLORMAP, MARKER, c_bool_t, c_char_ptr_t, c_double_t, c_float_t, c_int_t, c_pointer, c_void_ptr_t from .util import _is_number + class _Cell(ct.Structure): - _fields_ = [("row", c_int_t), - ("col", c_int_t), - ("title", c_char_ptr_t), - ("cmap", c_int_t)] + _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 @@ -27,7 +30,8 @@ def __init__(self, r, c, title, cmap): self.title = title if title is not None else c_char_ptr_t() self.cmap = cmap.value -class Window(object): + +class Window: """ Class to create the Window object. @@ -51,15 +55,14 @@ def __init__(self, width=1280, height=720, title="ArrayFire"): self._wnd = c_void_ptr_t(0) self._cmap = COLORMAP.DEFAULT - _width = 1280 if width is None else width - _height = 720 if height is None else height - _title = "ArrayFire" if title is None else title + _width = 1280 if width is None else width + _height = 720 if height is None else height + _title = "ArrayFire" if title is None else title _title = _title.encode("ascii") - safe_call(backend.get().af_create_window(c_pointer(self._wnd), - c_int_t(_width), c_int_t(_height), - c_char_ptr_t(_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): """ @@ -171,11 +174,11 @@ 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, c_pointer(_cell))) + safe_call( + backend.get().af_draw_scatter_2d(self._wnd, X.arr, Y.arr, marker.value, c_pointer(_cell))) else: - safe_call(backend.get().af_draw_scatter_3d(self._wnd, X.arr, Y.arr, Z.arr, - marker.value, c_pointer(_cell))) + safe_call( + backend.get().af_draw_scatter_3d(self._wnd, X.arr, Y.arr, Z.arr, marker.value, c_pointer(_cell))) else: safe_call(backend.get().af_draw_scatter_nd(self._wnd, points.arr, marker.value, c_pointer(_cell))) @@ -195,10 +198,9 @@ def scatter2(self, points, marker=MARKER.POINT, title=None): title: str. Title used for the plot. """ - assert(points.numdims() == 2) + 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, c_pointer(_cell))) + safe_call(backend.get().af_draw_scatter2(self._wnd, points.arr, marker.value, c_pointer(_cell))) def scatter3(self, points, marker=MARKER.POINT, title=None): """ @@ -216,11 +218,11 @@ def scatter3(self, points, marker=MARKER.POINT, title=None): title: str. Title used for the plot. """ - assert(points.numdims() == 3) + 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, c_pointer(_cell))) - def plot(self, X, Y, Z=None, line = None, title=None): + safe_call(backend.get().af_draw_scatter3(self._wnd, points.arr, marker.value, c_pointer(_cell))) + + def plot(self, X, Y, Z=None, line=None, title=None): """ Display a 2D or 3D Plot. @@ -274,8 +276,7 @@ def plot2(self, line, title=None): Title used for the plot. """ - - assert(line.numdims() == 2) + 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, c_pointer(_cell))) @@ -292,13 +293,12 @@ def plot3(self, X=None, Y=None, Z=None, line=None, title=None): title: str. Title used for the plot. """ - - assert(line.numdims() == 3) + 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, c_pointer(_cell))) def vector_field(self, xpoints, xdirs, ypoints, ydirs, zpoints=None, zdirs=None, - points = None, dirs = None, title=None): + points=None, dirs=None, title=None): """ Display a 2D or 3D Vector_Field. @@ -346,17 +346,15 @@ def vector_field(self, xpoints, xdirs, ypoints, ydirs, zpoints=None, zdirs=None, The line parameter takes precedence. """ _cell = _Cell(self._r, self._c, title, self._cmap) + # BUG: line and Z variables are not defined. 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, - c_pointer(_cell))) + safe_call(backend.get().af_draw_vector_field_2d( + self._wnd, xpoints.arr, ypoints.arr, xdirs.arr, ydirs.arr, 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, - c_pointer(_cell))) + safe_call(backend.get().af_draw_vector_field_2d( + self._wnd, xpoints.arr, ypoints.arr, zpoints.arr, xdirs.arr, ydirs.arr, zdirs.arr, + c_pointer(_cell))) else: safe_call(backend.get().af_draw_plot_nd(self._wnd, points.arr, dirs.arr, c_pointer(_cell))) @@ -380,9 +378,8 @@ def surface(self, x_vals, y_vals, z_vals, title=None): Title used for the plot. """ _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, - c_pointer(_cell))) + safe_call(backend.get().af_draw_surface( + self._wnd, x_vals.arr, y_vals.arr, z_vals.arr, c_pointer(_cell))) def hist(self, X, min_val, max_val, title=None): """ @@ -404,9 +401,8 @@ def hist(self, X, min_val, max_val, title=None): Title used for the histogram. """ _cell = _Cell(self._r, self._c, title, self._cmap) - safe_call(backend.get().af_draw_hist(self._wnd, X.arr, - c_double_t(max_val), c_double_t(min_val), - c_pointer(_cell))) + safe_call(backend.get().af_draw_hist( + self._wnd, X.arr, c_double_t(max_val), c_double_t(min_val), c_pointer(_cell))) def grid(self, rows, cols): """ @@ -440,7 +436,7 @@ def close(self): safe_call(backend.get().af_is_window_closed(c_pointer(tmp), self._wnd)) return tmp - def set_visibility(is_visible): + def set_visibility(self, is_visible): """ A flag that shows or hides the window as requested. @@ -484,17 +480,14 @@ def set_axes_limits(self, xmin, xmax, ymin, ymax, zmin=None, zmax=None, exact=Fa 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, - c_float_t(xmin), c_float_t(xmax), - c_float_t(ymin), c_float_t(ymax), - exact, c_pointer(_cell))) + if zmin is None or zmax is None: + safe_call(backend.get().af_set_axes_limits_2d( + self._wnd, 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, - 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))) + safe_call(backend.get().af_set_axes_limits_2d( + self._wnd, 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 set_axes_label_format(self, xformat="4.1%f", yformat="4.1%f", zformat="4.1%f"): """ diff --git a/arrayfire/image.py b/arrayfire/image.py index f626a4802..9e4de7fe0 100644 --- a/arrayfire/image.py +++ b/arrayfire/image.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,12 +11,16 @@ Image processing functions. """ -from .library import * -from .array import * -from .data import constant -from .signal import medfilt import os +from .array import Array +from .data import constant +from .library import ( + CANNY_THRESHOLD, CONNECTIVITY, DIFFUSION, FLUX, INTERP, ITERATIVE_DECONV, MOMENT, PAD, YCC_STD, Dtype, c_bool_t, c_char_ptr_t, + c_dim_t, c_double_t, c_float_t, c_int_t, c_pointer, c_uint_t) +from .library import backend, safe_call + + def gradient(image): """ Find the horizontal and vertical gradients. @@ -39,6 +43,7 @@ def gradient(image): 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): """ Load an image on the disk as an array. @@ -57,12 +62,13 @@ def load_image(file_name, is_color=False): A 2 dimensional (1 channel) or 3 dimensional (3 channel) array containing the image. """ - assert(os.path.isfile(file_name)) + assert os.path.isfile(file_name) image = Array() - safe_call(backend.get().af_load_image(c_pointer(image.arr), - c_char_ptr_t(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): """ Save an array as an image on the disk. @@ -75,7 +81,7 @@ def save_image(image, file_name): file_name: str - Full path of the file name on the disk. """ - assert(isinstance(file_name, str)) + assert isinstance(file_name, str) safe_call(backend.get().af_save_image(c_char_ptr_t(file_name.encode('ascii')), image.arr)) return image @@ -95,12 +101,13 @@ def load_image_native(file_name): A 2 dimensional (1 channel) or 3 dimensional (3 or 4 channel) array containing the image. """ - assert(os.path.isfile(file_name)) + assert os.path.isfile(file_name) image = Array() - safe_call(backend.get().af_load_image_native(c_pointer(image.arr), - c_char_ptr_t(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): """ Save an array as an image on the disk in native format. @@ -113,10 +120,11 @@ def save_image_native(image, file_name): file_name: str - Full path of the file name on the disk. """ - assert(isinstance(file_name, str)) + assert isinstance(file_name, str) 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): """ Resize an image. @@ -151,22 +159,21 @@ def resize(image, scale=None, odim0=None, odim1=None, method=INTERP.NEAREST): - If `scale` is not None, `odim0` and `odim1` are ignored. """ - if (scale is None): - assert(odim0 is not None) - assert(odim1 is not None) + # FIXME: scale is not redefined. Consider changing to bool + if scale is None: + assert odim0 is not None + assert odim1 is not None else: idims = image.dims() odim0 = int(scale * idims[0]) odim1 = int(scale * idims[1]) output = Array() - safe_call(backend.get().af_resize(c_pointer(output.arr), - image.arr, c_dim_t(odim0), - c_dim_t(odim1), method.value)) - + safe_call(backend.get().af_resize(c_pointer(output.arr), image.arr, c_dim_t(odim0), c_dim_t(odim1), method.value)) return output -def transform(image, trans_mat, odim0 = 0, odim1 = 0, method=INTERP.NEAREST, is_inverse=True): + +def transform(image, trans_mat, odim0=0, odim1=0, method=INTERP.NEAREST, is_inverse=True): """ Transform an image using a transformation matrix. @@ -203,14 +210,12 @@ def transform(image, trans_mat, odim0 = 0, odim1 = 0, method=INTERP.NEAREST, is_ """ output = Array() - 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)) + 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)) return output -def rotate(image, theta, is_crop = True, method = INTERP.NEAREST): +def rotate(image, theta, is_crop=True, method=INTERP.NEAREST): """ Rotate an image. @@ -235,11 +240,11 @@ def rotate(image, theta, is_crop = True, method = INTERP.NEAREST): - Output image after rotating. """ output = Array() - safe_call(backend.get().af_rotate(c_pointer(output.arr), image.arr, - c_float_t(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): + +def translate(image, trans0, trans1, odim0=0, odim1=0, method=INTERP.NEAREST): """ Translate an image. @@ -276,12 +281,12 @@ def translate(image, trans0, trans1, odim0 = 0, odim1 = 0, method = INTERP.NEARE """ output = Array() - safe_call(backend.get().af_translate(c_pointer(output.arr), - image.arr, trans0, trans1, - c_dim_t(odim0), c_dim_t(odim1), method.value)) + 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 -def scale(image, scale0, scale1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST): + +def scale(image, scale0, scale1, odim0=0, odim1=0, method=INTERP.NEAREST): """ Scale an image. @@ -318,12 +323,13 @@ def scale(image, scale0, scale1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST): """ output = Array() - 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)) + 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 -def skew(image, skew0, skew1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST, is_inverse=True): + +def skew(image, skew0, skew1, odim0=0, odim1=0, method=INTERP.NEAREST, is_inverse=True): """ Skew an image. @@ -363,14 +369,14 @@ def skew(image, skew0, skew1, odim0 = 0, odim1 = 0, method = INTERP.NEAREST, is_ """ output = Array() - 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)) + 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)) return output -def histogram(image, nbins, min_val = None, max_val = None): + +def histogram(image, nbins, min_val=None, max_val=None): """ Find the histogram of an image. @@ -407,11 +413,11 @@ def histogram(image, nbins, min_val = None, max_val = None): max_val = af_max(image) output = Array() - 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))) + 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): """ Equalize an image based on a histogram. @@ -436,7 +442,8 @@ def hist_equal(image, hist): safe_call(backend.get().af_hist_equal(c_pointer(output.arr), image.arr, hist.arr)) return output -def dilate(image, mask = None): + +def dilate(image, mask=None): """ Run image dilate on the image. @@ -462,10 +469,10 @@ def dilate(image, mask = None): output = Array() safe_call(backend.get().af_dilate(c_pointer(output.arr), image.arr, mask.arr)) - return output -def dilate3(volume, mask = None): + +def dilate3(volume, mask=None): """ Run volume dilate on a volume. @@ -491,10 +498,10 @@ def dilate3(volume, mask = None): output = Array() safe_call(backend.get().af_dilate3(c_pointer(output.arr), volume.arr, mask.arr)) - return output -def erode(image, mask = None): + +def erode(image, mask=None): """ Run image erode on the image. @@ -520,10 +527,10 @@ def erode(image, mask = None): output = Array() safe_call(backend.get().af_erode(c_pointer(output.arr), image.arr, mask.arr)) - return output -def erode3(volume, mask = None): + +def erode3(volume, mask=None): """ Run volume erode on the volume. @@ -544,16 +551,15 @@ def erode3(volume, mask = None): - The eroded volume. """ - if mask is None: mask = constant(1, 3, 3, 3, dtype=Dtype.f32) output = Array() safe_call(backend.get().af_erode3(c_pointer(output.arr), volume.arr, mask.arr)) - return output -def bilateral(image, s_sigma, c_sigma, is_color = False): + +def bilateral(image, s_sigma, c_sigma, is_color=False): """ Apply bilateral filter to the image. @@ -580,12 +586,12 @@ def bilateral(image, s_sigma, c_sigma, is_color = False): """ output = Array() - safe_call(backend.get().af_bilateral(c_pointer(output.arr), - image.arr, c_float_t(s_sigma), - c_float_t(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): + +def mean_shift(image, s_sigma, c_sigma, n_iter, is_color=False): """ Apply mean shift to the image. @@ -615,12 +621,12 @@ def mean_shift(image, s_sigma, c_sigma, n_iter, is_color = False): """ output = Array() - 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)) + 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): + +def minfilt(image, w_len=3, w_wid=3, edge_pad=PAD.ZERO): """ Apply min filter for the image. @@ -647,12 +653,12 @@ def minfilt(image, w_len = 3, w_wid = 3, edge_pad = PAD.ZERO): """ output = Array() - 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)) + 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 -def maxfilt(image, w_len = 3, w_wid = 3, edge_pad = PAD.ZERO): + +def maxfilt(image, w_len=3, w_wid=3, edge_pad=PAD.ZERO): """ Apply max filter for the image. @@ -679,12 +685,12 @@ def maxfilt(image, w_len = 3, w_wid = 3, edge_pad = PAD.ZERO): """ output = Array() - 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)) + 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 -def regions(image, conn = CONNECTIVITY.FOUR, out_type = Dtype.f32): + +def regions(image, conn=CONNECTIVITY.FOUR, out_type=Dtype.f32): """ Find the connected components in the image. @@ -707,10 +713,10 @@ def regions(image, conn = CONNECTIVITY.FOUR, out_type = Dtype.f32): """ output = Array() - safe_call(backend.get().af_regions(c_pointer(output.arr), image.arr, - conn.value, out_type.value)) + safe_call(backend.get().af_regions(c_pointer(output.arr), image.arr, 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. @@ -754,6 +760,7 @@ def confidenceCC(image, seedx, seedy, radius, multiplier, iters, segmented_value 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. @@ -777,11 +784,11 @@ def sobel_derivatives(image, w_len=3): """ dx = Array() dy = Array() - 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 + 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): + +def gaussian_kernel(rows, cols, sigma_r=None, sigma_c=None): """ Create a gaussian kernel with the given parameters. @@ -812,18 +819,18 @@ def gaussian_kernel(rows, cols, sigma_r = None, sigma_c = None): """ out = Array() - if (sigma_r is None): + if sigma_r is None: sigma_r = 0.25 * rows + 0.75 - if (sigma_c is None): + if sigma_c is None: sigma_c = 0.25 * cols + 0.75 - 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))) + 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): + +def sobel_filter(image, w_len=3, is_fast=False): """ Apply sobel filter to the image. @@ -846,16 +853,18 @@ def sobel_filter(image, w_len = 3, is_fast = False): - Image containing the magnitude of the sobel derivatives. """ + # FIXME: import inside of a function from .arith import abs as af_abs from .arith import hypot as af_hypot - dx,dy = sobel_derivatives(image, w_len) - if (is_fast): + dx, dy = sobel_derivatives(image, w_len) + if is_fast: return af_abs(dx) + af_abs(dy) - else: - return af_hypot(dx, dy) -def rgb2gray(image, r_factor = 0.2126, g_factor = 0.7152, b_factor = 0.0722): + return af_hypot(dx, dy) + + +def rgb2gray(image, r_factor=0.2126, g_factor=0.7152, b_factor=0.0722): """ Convert RGB image to Grayscale. @@ -881,12 +890,13 @@ def rgb2gray(image, r_factor = 0.2126, g_factor = 0.7152, b_factor = 0.0722): - A grayscale image. """ - output=Array() - 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))) + output = Array() + 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): + +def gray2rgb(image, r_factor=1.0, g_factor=1.0, b_factor=1.0): """ Convert Grayscale image to an RGB image. @@ -913,11 +923,12 @@ def gray2rgb(image, r_factor = 1.0, g_factor = 1.0, b_factor = 1.0): - The channels are not coalesced, i.e. they appear along the third dimension. """ - output=Array() - 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))) + output = Array() + 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): """ Convert HSV image to RGB. @@ -939,6 +950,7 @@ def hsv2rgb(image): safe_call(backend.get().af_hsv2rgb(c_pointer(output.arr), image.arr)) return output + def rgb2hsv(image): """ Convert RGB image to HSV. @@ -960,6 +972,7 @@ def rgb2hsv(image): safe_call(backend.get().af_rgb2hsv(c_pointer(output.arr), image.arr)) return output + def color_space(image, to_type, from_type): """ Convert an image from one color space to another. @@ -983,10 +996,10 @@ def color_space(image, to_type, from_type): """ output = Array() - safe_call(backend.get().af_color_space(c_pointer(output.arr), image.arr, - to_type.value, from_type.value)) + safe_call(backend.get().af_color_space(c_pointer(output.arr), image.arr, to_type.value, from_type.value)) return output + def unwrap(image, wx, wy, sx, sy, px=0, py=0, is_column=True): """ Unrwap an image into an array. @@ -1047,15 +1060,13 @@ def unwrap(image, wx, wy, sx, sy, px=0, py=0, is_column=True): 0.3775 0.6456 0.6600 0.8060 0.8395 0.7270 0.9250 0.9313 0.6592 0.3027 0.5591 0.0764 0.5938 0.1933 0.0322 0.3063 0.8684 0.4387 """ - out = Array() - 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), - is_column)) + 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), + is_column)) return out + def wrap(a, ox, oy, wx, wy, sx, sy, px=0, py=0, is_column=True): """ Wrap an array into an image. @@ -1129,16 +1140,13 @@ def wrap(a, ox, oy, wx, wy, sx, sy, px=0, py=0, is_column=True): """ - out = Array() - 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), - c_dim_t(px), c_dim_t(py), - is_column)) + 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), + c_dim_t(px), c_dim_t(py), is_column)) return out + def sat(image): """ Summed Area Tables @@ -1153,11 +1161,11 @@ def sat(image): out : af.Array A multi dimensional array containing the summed area table of input image """ - out = Array() safe_call(backend.get().af_sat(c_pointer(out.arr), image.arr)) return out + def ycbcr2rgb(image, standard=YCC_STD.BT_601): """ YCbCr to RGB colorspace conversion. @@ -1179,11 +1187,11 @@ def ycbcr2rgb(image, standard=YCC_STD.BT_601): A multi dimensional array containing an image or batch of images in RGB format """ - out = Array() safe_call(backend.get().af_ycbcr2rgb(c_pointer(out.arr), image.arr, standard.value)) return out + def rgb2ycbcr(image, standard=YCC_STD.BT_601): """ RGB to YCbCr colorspace conversion. @@ -1205,12 +1213,12 @@ def rgb2ycbcr(image, standard=YCC_STD.BT_601): A multi dimensional array containing an image or batch of images in YCbCr format """ - out = Array() safe_call(backend.get().af_rgb2ycbcr(c_pointer(out.arr), image.arr, standard.value)) return out -def moments(image, moment = MOMENT.FIRST_ORDER): + +def moments(image, moment=MOMENT.FIRST_ORDER): """ Calculate image moments. @@ -1237,10 +1245,10 @@ 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, - threshold_type = CANNY_THRESHOLD.MANUAL, - sobel_window = 3, is_fast = False): + +def canny( + image, low_threshold, high_threshold=None, threshold_type=CANNY_THRESHOLD.MANUAL, sobel_window=3, + is_fast=False): """ Canny edge detector. @@ -1274,16 +1282,17 @@ def canny(image, """ output = Array() if threshold_type.value == CANNY_THRESHOLD.MANUAL.value: - assert(high_threshold is not None) + 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))) + 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 anisotropic_diffusion(image, time_step, conductance, iterations, flux_function_type = FLUX.QUADRATIC, diffusion_kind = DIFFUSION.GRAD): + +def anisotropic_diffusion( + image, time_step, conductance, iterations, flux_function_type=FLUX.QUADRATIC, diffusion_kind=DIFFUSION.GRAD): """ Anisotropic smoothing filter. @@ -1318,12 +1327,12 @@ def anisotropic_diffusion(image, time_step, conductance, iterations, flux_functi """ 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)) + 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 iterativeDeconv(image, psf, iterations, relax_factor, algo = ITERATIVE_DECONV.DEFAULT): """ Iterative deconvolution algorithm. @@ -1359,9 +1368,8 @@ def iterativeDeconv(image, psf, iterations, relax_factor, algo = ITERATIVE_DECON """ 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)) + 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): @@ -1396,6 +1404,7 @@ def inverseDeconv(image, psf, gamma, algo = ITERATIVE_DECONV.DEFAULT): 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/index.py b/arrayfire/index.py index 093a88336..ae49e4934 100644 --- a/arrayfire/index.py +++ b/arrayfire/index.py @@ -1,22 +1,25 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# 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 ######################################################## + """ Index and Seq classes used in indexing operations. """ -from .library import * -from .util import * -from .util import _is_number -from .base import * -from .bcast import _bcast_var +import ctypes as ct import math +from .base import BaseArray +from .bcast import _bcast_var +from .library import backend, safe_call, Dtype, c_bool_t, c_double_t, c_pointer, c_void_ptr_t +from .util import _is_number + + class Seq(ct.Structure): """ arrayfire equivalent of slice @@ -39,45 +42,46 @@ class Seq(ct.Structure): S: slice or number. """ - _fields_ = [("begin", c_double_t), - ("end" , c_double_t), - ("step" , c_double_t)] + _fields_ = [ + ("begin", c_double_t), + ("end", c_double_t), + ("step", c_double_t)] - def __init__ (self, S): - self.begin = c_double_t( 0) - self.end = c_double_t(-1) - self.step = c_double_t( 1) + def __init__(self, S): + self.begin = c_double_t(0) + self.end = c_double_t(-1) + self.step = c_double_t(1) if _is_number(S): self.begin = c_double_t(S) - self.end = c_double_t(S) + self.end = c_double_t(S) elif isinstance(S, slice): - if (S.step is not None): - self.step = c_double_t(S.step) - if(S.step < 0): + if S.step is not None: + 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): + if S.start is not None: self.begin = c_double_t(S.start) - if (S.stop is not None): + if S.stop is not None: 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: + 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 + 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 + self.end = -2 + self.step = -1 - if (S.stop is not None): + if S.stop is not None: self.end = self.end - math.copysign(1, self.step) else: raise IndexError("Invalid type while indexing arrayfire.array") -class ParallelRange(Seq): +class ParallelRange(Seq): """ Class used to parallelize for loop. @@ -129,14 +133,14 @@ class ParallelRange(Seq): 1.4719 0.5282 1.1657 """ - def __init__(self, start, stop=None, step=None): - if (stop is None): + def __init__(self, start, stop=None, step=None): + if stop is None: stop = start start = 0 self.S = slice(start, stop, step) - super(ParallelRange, self).__init__(self.S) + super().__init__(self.S) def __iter__(self): return self @@ -145,12 +149,12 @@ def next(self): """ Function called by the iterator in Python 2 """ - if _bcast_var.get() is True: + if _bcast_var.get(): _bcast_var.toggle() raise StopIteration - else: - _bcast_var.toggle() - return self + + _bcast_var.toggle() + return self def __next__(self): """ @@ -158,14 +162,18 @@ def __next__(self): """ return self.next() + class _uidx(ct.Union): - _fields_ = [("arr", c_void_ptr_t), - ("seq", Seq)] + _fields_ = [ + ("arr", c_void_ptr_t), + ("seq", Seq)] + class Index(ct.Structure): - _fields_ = [("idx", _uidx), - ("isSeq", c_bool_t), - ("isBatch", c_bool_t)] + _fields_ = [ + ("idx", _uidx), + ("isSeq", c_bool_t), + ("isBatch", c_bool_t)] """ Container for the index class in arrayfire C library @@ -199,23 +207,23 @@ class Index(ct.Structure): """ - def __init__ (self, idx): + def __init__(self, idx): - self.idx = _uidx() + self.idx = _uidx() self.isBatch = False - self.isSeq = True + self.isSeq = True if isinstance(idx, BaseArray): arr = c_void_ptr_t(0) - if (idx.type() == Dtype.b8.value): + if idx.type() == Dtype.b8.value: safe_call(backend.get().af_where(c_pointer(arr), idx.arr)) else: safe_call(backend.get().af_retain_array(c_pointer(arr), idx.arr)) self.idx.arr = arr - self.isSeq = False + self.isSeq = False elif isinstance(idx, ParallelRange): self.idx.seq = idx self.isBatch = True @@ -230,7 +238,10 @@ 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): index_vec = Index * 4 @@ -239,6 +250,7 @@ def __init__(self): # no reference to them. Otherwise the destructor # is prematurely called self.idxs = [_span, _span, _span, _span] + @property def pointer(self): return c_pointer(self.array) diff --git a/arrayfire/interop.py b/arrayfire/interop.py index f2b9a1f68..3c75d271f 100644 --- a/arrayfire/interop.py +++ b/arrayfire/interop.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -19,11 +19,12 @@ """ -from .array import * -from .device import * +from .array import Array +from .library import Dtype, c_void_ptr_t +from .device import get_device_count, info, lock_array, set_device -def _fc_to_af_array(in_ptr, in_shape, in_dtype, is_device=False, copy = True): +def _fc_to_af_array(in_ptr, in_shape, in_dtype, is_device=False, copy=True): """ Fortran Contiguous to af array """ @@ -35,40 +36,45 @@ def _fc_to_af_array(in_ptr, in_shape, in_dtype, is_device=False, copy = True): 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): + +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) - else: - shape = tuple(reversed(in_shape)) - res = Array(in_ptr, shape, in_dtype, is_device=is_device) - if is_device: lock_array(res) - return res._reorder() - -_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} + + shape = tuple(reversed(in_shape)) + res = Array(in_ptr, shape, in_dtype, is_device=is_device) + if is_device: + lock_array(res) + # FIXME: access a protected member of Array class. + return res._reorder() + + +_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: + # FIXME: numpy imported but unused import numpy as np except ImportError: - AF_NUMPY_FOUND=False + AF_NUMPY_FOUND = False else: from numpy import ndarray as NumpyArray - from .data import reorder - AF_NUMPY_FOUND=True + AF_NUMPY_FOUND = True def np_to_af_array(np_arr, copy=True): """ @@ -86,7 +92,6 @@ def np_to_af_array(np_arr, copy=True): --------- af_arr : arrayfire.Array() """ - in_shape = np_arr.shape in_ptr = np_arr.ctypes.data_as(c_void_ptr_t) in_dtype = _nptype_to_aftype[np_arr.dtype.str[1:]] @@ -94,22 +99,23 @@ def np_to_af_array(np_arr, copy=True): if not copy: raise RuntimeError("Copy can not be False for numpy arrays") - if (np_arr.flags['F_CONTIGUOUS']): + if np_arr.flags['F_CONTIGUOUS']: return _fc_to_af_array(in_ptr, in_shape, in_dtype) - elif (np_arr.flags['C_CONTIGUOUS']): + if np_arr.flags['C_CONTIGUOUS']: return _cc_to_af_array(in_ptr, np_arr.ndim, in_shape, in_dtype) - else: - return np_to_af_array(np_arr.copy()) + + return np_to_af_array(np_arr.copy()) from_ndarray = np_to_af_array try: + # FIXME: pycuda imported but unused import pycuda.gpuarray except ImportError: - AF_PYCUDA_FOUND=False + AF_PYCUDA_FOUND = False else: from pycuda.gpuarray import GPUArray as CudaArray - AF_PYCUDA_FOUND=True + AF_PYCUDA_FOUND = True def pycuda_to_af_array(pycu_arr, copy=True): """ @@ -131,7 +137,6 @@ def pycuda_to_af_array(pycu_arr, copy=True): ---------- The input array is copied to af.Array """ - in_ptr = pycu_arr.ptr in_shape = pycu_arr.shape in_dtype = pycu_arr.dtype.char @@ -139,23 +144,23 @@ def pycuda_to_af_array(pycu_arr, copy=True): 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): + if pycu_arr.flags.f_contiguous: return _fc_to_af_array(in_ptr, in_shape, in_dtype, True, copy) - elif (pycu_arr.flags.c_contiguous): + if pycu_arr.flags.c_contiguous: 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()) + + return pycuda_to_af_array(pycu_arr.copy()) try: from pyopencl.array import Array as OpenclArray except ImportError: - AF_PYOPENCL_FOUND=False + 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 from .opencl import get_context as _get_context - AF_PYOPENCL_FOUND=True + AF_PYOPENCL_FOUND = True def pyopencl_to_af_array(pycl_arr, copy=True): """ @@ -177,7 +182,6 @@ def pyopencl_to_af_array(pycl_arr, copy=True): ---------- The input array is copied to af.Array """ - ctx = pycl_arr.context.int_ptr que = pycl_arr.queue.int_ptr dev = pycl_arr.queue.device.int_ptr @@ -188,11 +192,10 @@ def pyopencl_to_af_array(pycl_arr, copy=True): set_device(n) dev_idx = _get_device_id() ctx_idx = _get_context() - if (dev_idx == dev and ctx_idx == ctx): + 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): + if (dev_idx is None or ctx_idx is 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) @@ -207,21 +210,22 @@ def pyopencl_to_af_array(pycl_arr, copy=True): print("Copying array") print(pycl_arr.base_data.int_ptr) - if (pycl_arr.flags.f_contiguous): + if pycl_arr.flags.f_contiguous: return _fc_to_af_array(in_ptr, in_shape, in_dtype, True, copy) - elif (pycl_arr.flags.c_contiguous): + if pycl_arr.flags.c_contiguous: 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()) + + return pyopencl_to_af_array(pycl_arr.copy()) try: + # FIXME: numba imported but unused import numba except ImportError: - AF_NUMBA_FOUND=False + AF_NUMBA_FOUND = False else: from numba import cuda NumbaCudaArray = cuda.cudadrv.devicearray.DeviceNDArray - AF_NUMBA_FOUND=True + AF_NUMBA_FOUND = True def numba_to_af_array(nb_arr, copy=True): """ @@ -243,7 +247,6 @@ def numba_to_af_array(nb_arr, copy=True): ---------- 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:]] @@ -251,14 +254,15 @@ def numba_to_af_array(nb_arr, copy=True): 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()): + 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()): + if 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()) -def to_array(in_array, copy = True): + return numba_to_af_array(nb_arr.copy()) + + +def to_array(in_array, copy=True): """ Helper function to convert input from a different module to af.Array diff --git a/arrayfire/lapack.py b/arrayfire/lapack.py index 97ad92c7a..639a53006 100644 --- a/arrayfire/lapack.py +++ b/arrayfire/lapack.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,8 +11,9 @@ Dense Linear Algebra functions (solve, inverse, etc). """ -from .library import * -from .array import * +from .array import Array +from .library import backend, safe_call, MATPROP, NORM, c_bool_t, c_double_t, c_int_t, c_pointer, c_uint_t + def lu(A): """ @@ -42,7 +43,8 @@ def lu(A): U = Array() P = Array() safe_call(backend.get().af_lu(c_pointer(L.arr), c_pointer(U.arr), c_pointer(P.arr), A.arr)) - return L,U,P + return L, U, P + def lu_inplace(A, pivot="lapack"): """ @@ -67,10 +69,11 @@ def lu_inplace(A, pivot="lapack"): """ P = Array() - is_pivot_lapack = False if (pivot == "full") else True + is_pivot_lapack = bool(pivot != "full") safe_call(backend.get().af_lu_inplace(c_pointer(P.arr), A.arr, is_pivot_lapack)) return P + def qr(A): """ QR decomposition. @@ -99,7 +102,8 @@ def qr(A): R = Array() T = Array() safe_call(backend.get().af_qr(c_pointer(Q.arr), c_pointer(R.arr), c_pointer(T.arr), A.arr)) - return Q,R,T + return Q, R, T + def qr_inplace(A): """ @@ -125,6 +129,7 @@ def qr_inplace(A): safe_call(backend.get().af_qr_inplace(c_pointer(T.arr), A.arr)) return T + def cholesky(A, is_upper=True): """ Cholesky decomposition @@ -156,6 +161,7 @@ def cholesky(A, is_upper=True): 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): """ In place Cholesky decomposition. @@ -179,6 +185,7 @@ def cholesky_inplace(A, is_upper=True): safe_call(backend.get().af_cholesky_inplace(c_pointer(info), A.arr, is_upper)) return info.value + def solve(A, B, options=MATPROP.NONE): """ Solve a system of linear equations. @@ -206,6 +213,7 @@ def solve(A, B, options=MATPROP.NONE): 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): """ Solve a system of linear equations, using LU decomposition. @@ -234,6 +242,7 @@ def solve_lu(A, P, B, options=MATPROP.NONE): 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): """ Invert a matrix. @@ -264,6 +273,7 @@ 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. @@ -297,6 +307,7 @@ def pinverse(A, tol=1E-6, options=MATPROP.NONE): 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. @@ -320,6 +331,7 @@ def rank(A, tol=1E-5): safe_call(backend.get().af_rank(c_pointer(r), A.arr, c_double_t(tol))) return r.value + def det(A): """ Determinant of a matrix. @@ -341,7 +353,8 @@ def det(A): 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 + return re if im == 0 else re + im * 1j + def norm(A, norm_type=NORM.EUCLID, p=1.0, q=1.0): """ @@ -370,10 +383,10 @@ def norm(A, norm_type=NORM.EUCLID, p=1.0, q=1.0): """ 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))) + 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): """ Singular Value Decomposition @@ -408,6 +421,7 @@ def svd(A): 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): """ Singular Value Decomposition @@ -439,10 +453,10 @@ def svd_inplace(A): U = Array() S = Array() Vt = Array() - safe_call(backend.get().af_svd_inplace(c_pointer(U.arr), c_pointer(S.arr), c_pointer(Vt.arr), - A.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 + def is_lapack_available(): """ Function to check if the arrayfire library was built with lapack support. diff --git a/arrayfire/library.py b/arrayfire/library.py index 009a8e122..f4031cc5b 100644 --- a/arrayfire/library.py +++ b/arrayfire/library.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -13,8 +13,8 @@ import platform import ctypes as ct -import traceback import os +import traceback c_float_t = ct.c_float c_double_t = ct.c_double @@ -489,54 +489,53 @@ class VARIANCE(_Enum): SAMPLE = _Enum_Type(1) POPULATION = _Enum_Type(2) +from .util import to_str + +AF_VER_MAJOR = "3" +FORGE_VER_MAJOR = "1" _VER_MAJOR_PLACEHOLDER = "__VER_MAJOR__" + def _setup(): import platform platform_name = platform.system() try: - AF_PATH = os.environ['AF_PATH'] + AF_PATH = os.environ["AF_PATH"] except KeyError: AF_PATH = None - pass AF_SEARCH_PATH = AF_PATH try: - CUDA_PATH = os.environ['CUDA_PATH'] + CUDA_PATH = os.environ["CUDA_PATH"] except KeyError: - CUDA_PATH= None - pass + CUDA_PATH = None CUDA_FOUND = False - assert(len(platform_name) >= 3) - if platform_name == 'Windows' or platform_name[:3] == 'CYG': - - ## Windows specific setup - pre = '' - post = '.dll' + assert len(platform_name) >= 3 + if platform_name == "Windows" or platform_name[:3] == "CYG": + # Windows specific setup + pre = "" + post = ".dll" if platform_name == "Windows": - ''' - Supressing crashes caused by missing dlls - http://stackoverflow.com/questions/8347266/missing-dll-print-message-instead-of-launching-a-popup - https://msdn.microsoft.com/en-us/library/windows/desktop/ms680621.aspx - ''' + # Supressing crashes caused by missing dlls + # http://stackoverflow.com/questions/8347266/missing-dll-print-message-instead-of-launching-a-popup + # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680621.aspx 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/') - - elif platform_name == 'Darwin': + CUDA_FOUND = os.path.isdir(CUDA_PATH + "/bin") and os.path.isdir(CUDA_PATH + "/nvvm/bin/") - ## OSX specific setup - pre = 'lib' - post = '.' + _VER_MAJOR_PLACEHOLDER + '.dylib' + elif platform_name == "Darwin": + # OSX specific setup + pre = "lib" + post = "." + _VER_MAJOR_PLACEHOLDER + ".dylib" if AF_SEARCH_PATH is None: if os.path.exists('/opt/arrayfire'): @@ -545,35 +544,36 @@ def _setup(): AF_SEARCH_PATH = '/usr/local/' if CUDA_PATH is None: - CUDA_PATH='/usr/local/cuda/' + CUDA_PATH = "/usr/local/cuda/" - CUDA_FOUND = 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' - post = '.so.' + _VER_MAJOR_PLACEHOLDER + elif platform_name == "Linux": + pre = "lib" + post = ".so." + _VER_MAJOR_PLACEHOLDER if AF_SEARCH_PATH is None: - AF_SEARCH_PATH='/opt/arrayfire-' + AF_VER_MAJOR + '/' + AF_SEARCH_PATH = "/opt/arrayfire-" + AF_VER_MAJOR + "/" if CUDA_PATH is None: - CUDA_PATH='/usr/local/cuda/' + CUDA_PATH = "/usr/local/cuda/" - if platform.architecture()[0][:2] == '64': - CUDA_FOUND = 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_FOUND = 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') + raise OSError(platform_name + " not supported") if AF_PATH is None: - os.environ['AF_PATH'] = AF_SEARCH_PATH + os.environ["AF_PATH"] = AF_SEARCH_PATH return pre, post, AF_SEARCH_PATH, CUDA_FOUND + class _clibrary(object): - def __libname(self, name, head='af', ver_major=AF_VER_MAJOR): + 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'): @@ -584,12 +584,11 @@ def __libname(self, name, head='af', ver_major=AF_VER_MAJOR): def set_unsafe(self, name): lib = self.__clibs[name] - if (lib is None): + if lib is None: raise RuntimeError("Backend not found") self.__name = name 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() @@ -601,70 +600,71 @@ def __init__(self): self.__name = None - self.__clibs = {'cuda' : None, - 'opencl' : None, - 'cpu' : None, - 'unified' : None} - - 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} + self.__clibs = { + "cuda": None, + "opencl": None, + "cpu": None, + "unified": None} + + 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} # Try to pre-load forge library if it exists - libnames = self.__libname('forge', head='', ver_major=FORGE_VER_MAJOR) + libnames = self.__libname("forge", head="", ver_major=FORGE_VER_MAJOR) try: - VERBOSE_LOADS = os.environ['AF_VERBOSE_LOADS'] == '1' + 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) + print("Loaded " + libname) break except OSError: if VERBOSE_LOADS: traceback.print_exc() - print('Unable to load ' + libname) - pass + print("Unable to load " + libname) c_dim4 = c_dim_t*4 out = c_void_ptr_t(0) dims = c_dim4(10, 10, 1, 1) # Iterate in reverse order of preference - for name in ('cpu', 'opencl', 'cuda', ''): + for name in {"cpu", "opencl", "cuda", ""}: libnames = self.__libname(name) for libname in libnames: try: ct.cdll.LoadLibrary(libname) - __name = 'unified' if name == '' else name + __name = "unified" if name == "" else name clib = ct.CDLL(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) - break; + if err != ERR.NONE.value: + return + self.__name = __name + clib.af_release_array(out) + if VERBOSE_LOADS: + print("Loaded " + libname) + break except OSError: if VERBOSE_LOADS: traceback.print_exc() - print('Unable to load ' + libname) - pass + print("Unable to load " + libname) - if (self.__name is None): + if self.__name is None: raise RuntimeError("Could not load any ArrayFire libraries.\n" + more_info_str) def get_id(self, name): @@ -680,17 +680,19 @@ def name(self): return self.__name def is_unified(self): - return self.__name == 'unified' + return self.__name == "unified" def parse(self, res): lst = [] - for key,value in self.__backend_name_map.items(): - if (value & res): + for key, value in self.__backend_name_map.items(): + if value & res: lst.append(key) return tuple(lst) + backend = _clibrary() + def set_backend(name, unsafe=False): """ Set a specific backend by name @@ -703,14 +705,14 @@ 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 unsafe == False): + if not (backend.is_unified() or unsafe): raise RuntimeError("Can not change backend to %s after loading %s" % (name, backend.name())) - if (backend.is_unified()): + if backend.is_unified(): safe_call(backend.get().af_set_backend(backend.get_id(name))) - else: - backend.set_unsafe(name) - return + + backend.set_unsafe(name) + def get_backend(): """ @@ -718,6 +720,7 @@ def get_backend(): """ return backend.name() + def get_backend_id(A): """ Get backend name of an array @@ -736,6 +739,7 @@ def get_backend_id(A): 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(): """ Get number of available backends @@ -750,6 +754,7 @@ def get_backend_count(): safe_call(backend.get().af_get_backend_count(c_pointer(count))) return count.value + def get_available_backends(): """ Get names of available backends @@ -764,6 +769,7 @@ def get_available_backends(): safe_call(backend.get().af_get_available_backends(c_pointer(available))) return backend.parse(int(available.value)) + def get_active_backend(): """ Get the current active backend @@ -775,6 +781,7 @@ def get_active_backend(): safe_call(backend.get().af_get_active_backend(c_pointer(backend_id))) return backend.get_name(backend_id.value) + def get_device_id(A): """ Get the device id of the array @@ -793,6 +800,7 @@ def get_device_id(A): 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 @@ -801,4 +809,11 @@ def get_size_of(dtype): safe_call(backend.get().af_get_size_of(c_pointer(size), dtype.value)) return size.value -from .util import safe_call + +def safe_call(af_error): + if af_error == ERR.NONE.value: + return + err_str = c_char_ptr_t(0) + err_len = c_dim_t(0) + backend.get().af_get_last_error(c_pointer(err_str), c_pointer(err_len)) + raise RuntimeError(to_str(err_str)) diff --git a/arrayfire/ml.py b/arrayfire/ml.py index 7e0fc53de..d8249c1f8 100644 --- a/arrayfire/ml.py +++ b/arrayfire/ml.py @@ -13,10 +13,14 @@ - Forward and backward convolution passes """ -from .library import * -from .array import * +from .array import Array +from .library import backend, safe_call, c_pointer, CONV_GRADIENT +from .util import dim4 -def convolve2GradientNN(incoming_gradient, original_signal, original_kernel, convolved_output, stride = (1, 1), padding = (0, 0), dilation = (1, 1), gradType = CONV_GRADIENT.DEFAULT): + +def convolve2GradientNN( + incoming_gradient, original_signal, original_kernel, convolved_output, stride=(1, 1), padding=(0, 0), + dilation=(1, 1), gradType=CONV_GRADIENT.DEFAULT): """ Function for calculating backward pass gradient of 2D convolution. @@ -65,19 +69,11 @@ def convolve2GradientNN(incoming_gradient, original_signal, original_kernel, con """ output = Array() - stride_dim = dim4(stride[0], stride[1]) - padding_dim = dim4(padding[0], padding[1]) + 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)) + 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/opencl.py b/arrayfire/opencl.py index 266e1095a..5c21e5cb8 100644 --- a/arrayfire/opencl.py +++ b/arrayfire/opencl.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -13,30 +13,32 @@ This module provides interoperability with other OpenCL libraries. """ -from .util import * -from .library import (_Enum, _Enum_Type) +from .library import _Enum, _Enum_Type, c_int_t, c_pointer, c_void_ptr_t + 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) + 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) + AMD = _Enum_Type(0) + APPLE = _Enum_Type(1) + INTEL = _Enum_Type(2) + NVIDIA = _Enum_Type(3) BEIGNET = _Enum_Type(4) - POCL = _Enum_Type(5) + POCL = _Enum_Type(5) UNKNOWN = _Enum_Type(-1) + def get_context(retain=False): """ Get the current OpenCL context being used by ArrayFire. @@ -51,18 +53,19 @@ def get_context(retain=False): ----------- context : integer denoting the context id. """ - + # FIXME: ctypes imported but unused import ctypes as ct from .util import safe_call as safe_call from .library import backend - if (backend.name() != "opencl"): + if backend.name() != "opencl": raise RuntimeError("Invalid backend loaded") context = c_void_ptr_t(0) safe_call(backend.get().afcl_get_context(c_pointer(context), retain)) return context.value + def get_queue(retain): """ Get the current OpenCL command queue being used by ArrayFire. @@ -77,18 +80,19 @@ def get_queue(retain): ----------- queue : integer denoting the queue id. """ - + # FIXME: ctypes imported but unused import ctypes as ct from .util import safe_call as safe_call from .library import backend - if (backend.name() != "opencl"): + if backend.name() != "opencl": raise RuntimeError("Invalid backend loaded") queue = c_int_t(0) safe_call(backend.get().afcl_get_queue(c_pointer(queue), retain)) return queue.value + def get_device_id(): """ Get native (unsorted) OpenCL device ID @@ -99,18 +103,19 @@ def get_device_id(): idx : int. Specifies the `cl_device_id` of the device. """ - + # FIXME: ctypes imported but unused import ctypes as ct from .util import safe_call as safe_call from .library import backend - if (backend.name() != "opencl"): + if backend.name() != "opencl": raise RuntimeError("Invalid backend loaded") idx = c_int_t(0) safe_call(backend.get().afcl_get_device_id(c_pointer(idx))) return idx.value + def set_device_id(idx): """ Set native (unsorted) OpenCL device ID @@ -121,17 +126,18 @@ def set_device_id(idx): idx : int. Specifies the `cl_device_id` of the device. """ - + # FIXME: ctypes imported but unused import ctypes as ct from .util import safe_call as safe_call from .library import backend - if (backend.name() != "opencl"): + if backend.name() != "opencl": raise RuntimeError("Invalid backend loaded") 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 @@ -146,15 +152,17 @@ def add_device_context(dev, ctx, que): que : cl_command_queue """ + # FIXME: ctypes imported but unused import ctypes as ct from .util import safe_call as safe_call from .library import backend - if (backend.name() != "opencl"): + 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 @@ -167,15 +175,17 @@ def set_device_context(dev, ctx): ctx : cl_context """ + # FIXME: ctypes imported but unused import ctypes as ct from .util import safe_call as safe_call from .library import backend - if (backend.name() != "opencl"): + 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 @@ -188,54 +198,60 @@ def delete_device_context(dev, ctx): ctx : cl_context """ + # FIXME: ctypes imported but unused import ctypes as ct from .util import safe_call as safe_call from .library import backend - if (backend.name() != "opencl"): + 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_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} +_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 """ + # FIXME: ctypes imported but unused import ctypes as ct from .util import safe_call as safe_call from .library import backend - if (backend.name() != "opencl"): + 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] + def get_platform(): """ Get opencl platform """ + # FIXME: ctypes imported but unused import ctypes as ct from .util import safe_call as safe_call from .library import backend - if (backend.name() != "opencl"): + if backend.name() != "opencl": raise RuntimeError("Invalid backend loaded") res = c_int_t(PLATFORM.UNKNOWN.value) diff --git a/arrayfire/random.py b/arrayfire/random.py index 179833db8..622660342 100644 --- a/arrayfire/random.py +++ b/arrayfire/random.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,11 +11,12 @@ Random engine class and functions to generate random numbers. """ -from .library import * -from .array import * -import numbers +from .array import Array +from .library import backend, safe_call, RANDOM_ENGINE, Dtype, c_int_t, c_longlong_t, c_pointer, c_ulonglong_t, c_void_ptr_t +from .util import dim4 -class Random_Engine(object): + +class Random_Engine: """ Class to handle random number generator engines. @@ -40,10 +41,11 @@ class Random_Engine(object): - 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 = c_void_ptr_t(0) - safe_call(backend.get().af_create_random_engine(c_pointer(self.engine), engine_type.value, c_longlong_t(seed))) + def __init__(self, engine_type=RANDOM_ENGINE.PHILOX, seed=0, engine=None): + if engine is None: + 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 @@ -60,9 +62,8 @@ 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] + __to_random_engine_type = [ + RANDOM_ENGINE.PHILOX_4X32_10, RANDOM_ENGINE.THREEFRY_2X32_16, RANDOM_ENGINE.MERSENNE_GP11213] 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] @@ -81,6 +82,7 @@ def get_seed(self): 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): """ Create a multi dimensional array containing values from a uniform distribution. @@ -125,6 +127,7 @@ def randu(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, engine=None): return out + 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. @@ -159,7 +162,6 @@ def randn(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, engine=None): - 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) @@ -170,6 +172,7 @@ def randn(d0, d1=None, d2=None, d3=None, dtype=Dtype.f32, engine=None): return out + def set_seed(seed=0): """ Set the seed for the random number generator. @@ -181,6 +184,7 @@ def set_seed(seed=0): """ safe_call(backend.get().af_set_seed(c_ulonglong_t(seed))) + def get_seed(): """ Get the seed for the random number generator. @@ -194,6 +198,7 @@ def get_seed(): safe_call(backend.get().af_get_seed(c_pointer(seed))) return seed.value + def set_default_random_engine_type(engine_type): """ Set random engine type for default random engine. @@ -214,8 +219,10 @@ def set_default_random_engine_type(engine_type): This only affects randu and randn when a random engine is not specified. """ + # FIXME: not a class method. Remove self safe_call(backend.get().af_set_default_random_engine_type(c_pointer(self.engine), engine_type.value)) + def get_default_random_engine(): """ Get the default random engine diff --git a/arrayfire/signal.py b/arrayfire/signal.py index 35e0fba87..059b584a7 100644 --- a/arrayfire/signal.py +++ b/arrayfire/signal.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,21 +11,25 @@ Signal processing functions (fft, convolve, etc). """ -from .library import * -from .array import * +from .array import Array from .bcast import broadcast +from .library import backend, safe_call, CONV_DOMAIN, CONV_MODE, INTERP, PAD, c_dim_t, c_double_t, c_float_t, c_pointer, c_size_t +from .util import dim4, dim4_to_tuple + @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) + return (x_curr - x0) / dx + @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) + return (y_curr - y0) / dy + def approx1(signal, x, method=INTERP.LINEAR, off_grid=0.0, xp = None, output = None): """ @@ -39,7 +43,7 @@ def approx1(signal, x, method=INTERP.LINEAR, off_grid=0.0, xp = None, output = N Input signal array (signal = f(x)) x: af.Array - The x-coordinates of the interpolation points. The interpolation + 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. @@ -160,12 +164,12 @@ def approx2(signal, x, y, Input signal array (signal = f(x, y)) x : af.Array - The x-coordinates of the interpolation points. The interpolation + The x-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 + 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. @@ -232,6 +236,7 @@ def approx2(signal, x, y, 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): """ @@ -305,10 +310,10 @@ def approx2_uniform(signal, pos0, interp_dim0, idx_start0, idx_step0, pos1, inte 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))) - return output + def fft(signal, dim0 = None , scale = None): """ Fast Fourier Transform: 1D @@ -334,7 +339,6 @@ def fft(signal, dim0 = None , scale = None): A complex af.Array containing the full output of the fft. """ - if dim0 is None: dim0 = 0 @@ -345,7 +349,8 @@ def fft(signal, dim0 = None , scale = None): 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): + +def fft2(signal, dim0=None, dim1=None, scale=None): """ Fast Fourier Transform: 2D @@ -384,11 +389,12 @@ def fft2(signal, dim0 = None, dim1 = None , scale = None): scale = 1.0 output = Array() - safe_call(backend.get().af_fft2(c_pointer(output.arr), signal.arr, c_double_t(scale), - c_dim_t(dim0), c_dim_t(dim1))) + 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 -def fft3(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): + +def fft3(signal, dim0=None, dim1=None, dim2=None, scale=None): """ Fast Fourier Transform: 3D @@ -434,11 +440,12 @@ def fft3(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): scale = 1.0 output = Array() - 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))) + 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 -def ifft(signal, dim0 = None , scale = None): + +def ifft(signal, dim0=None, scale=None): """ Inverse Fast Fourier Transform: 1D @@ -468,7 +475,6 @@ def ifft(signal, dim0 = None , scale = None): The output is always complex. """ - if dim0 is None: dim0 = signal.dims()[0] @@ -479,7 +485,8 @@ def ifft(signal, dim0 = None , scale = None): 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): + +def ifft2(signal, dim0=None, dim1=None, scale=None): """ Inverse Fast Fourier Transform: 2D @@ -513,7 +520,6 @@ def ifft2(signal, dim0 = None, dim1 = None , scale = None): The output is always complex. """ - dims = signal.dims() if dim0 is None: @@ -526,11 +532,12 @@ def ifft2(signal, dim0 = None, dim1 = None , scale = None): scale = 1.0/float(dim0 * dim1) output = Array() - safe_call(backend.get().af_ifft2(c_pointer(output.arr), signal.arr, c_double_t(scale), - c_dim_t(dim0), c_dim_t(dim1))) + 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 -def ifft3(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): + +def ifft3(signal, dim0=None, dim1=None, dim2=None, scale=None): """ Inverse Fast Fourier Transform: 3D @@ -568,7 +575,6 @@ def ifft3(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): The output is always complex. """ - dims = signal.dims() if dim0 is None: @@ -584,11 +590,12 @@ 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(c_pointer(output.arr), signal.arr, c_double_t(scale), - c_dim_t(dim0), c_dim_t(dim1), c_dim_t(dim2))) + 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 -def fft_inplace(signal, scale = None): + +def fft_inplace(signal, scale=None): """ In-place Fast Fourier Transform: 1D @@ -603,13 +610,13 @@ def fft_inplace(signal, scale = None): - If None, scale is set to 1. """ - if scale is None: scale = 1.0 safe_call(backend.get().af_fft_inplace(signal.arr, c_double_t(scale))) -def fft2_inplace(signal, scale = None): + +def fft2_inplace(signal, scale=None): """ In-place Fast Fourier Transform: 2D @@ -624,13 +631,13 @@ def fft2_inplace(signal, scale = None): - If None, scale is set to 1. """ - if scale is None: scale = 1.0 safe_call(backend.get().af_fft2_inplace(signal.arr, c_double_t(scale))) -def fft3_inplace(signal, scale = None): + +def fft3_inplace(signal, scale=None): """ In-place Fast Fourier Transform: 3D @@ -644,14 +651,15 @@ def fft3_inplace(signal, scale = None): - Specifies the scaling factor. - If None, scale is set to 1. """ - if scale is None: scale = 1.0 + # FIXME: output is assigned, but not used in function output = Array() safe_call(backend.get().af_fft3_inplace(signal.arr, c_double_t(scale))) -def ifft_inplace(signal, scale = None): + +def ifft_inplace(signal, scale=None): """ Inverse In-place Fast Fourier Transform: 1D @@ -665,14 +673,14 @@ def ifft_inplace(signal, scale = None): - Specifies the scaling factor. - If None, scale is set to 1.0 / (signal.dims()[0]) """ - if scale is None: dim0 = signal.dims()[0] scale = 1.0/float(dim0) safe_call(backend.get().af_ifft_inplace(signal.arr, c_double_t(scale))) -def ifft2_inplace(signal, scale = None): + +def ifft2_inplace(signal, scale=None): """ Inverse In-place Fast Fourier Transform: 2D @@ -686,7 +694,6 @@ def ifft2_inplace(signal, scale = None): - Specifies the scaling factor. - If None, scale is set to 1.0 / (signal.dims()[0] * signal.dims()[1]) """ - dims = signal.dims() if scale is None: @@ -696,7 +703,8 @@ def ifft2_inplace(signal, scale = None): safe_call(backend.get().af_ifft2_inplace(signal.arr, c_double_t(scale))) -def ifft3_inplace(signal, scale = None): + +def ifft3_inplace(signal, scale=None): """ Inverse In-place Fast Fourier Transform: 3D @@ -710,7 +718,6 @@ def ifft3_inplace(signal, scale = None): - Specifies the scaling factor. - If None, scale is set to 1.0 / (signal.dims()[0] * signal.dims()[1] * signal.dims()[2]). """ - dims = signal.dims() if scale is None: @@ -721,7 +728,8 @@ def ifft3_inplace(signal, scale = None): safe_call(backend.get().af_ifft3_inplace(signal.arr, c_double_t(scale))) -def fft_r2c(signal, dim0 = None , scale = None): + +def fft_r2c(signal, dim0=None, scale=None): """ Real to Complex Fast Fourier Transform: 1D @@ -746,7 +754,6 @@ def fft_r2c(signal, dim0 = None , scale = None): A complex af.Array containing the non-redundant parts of the full FFT. """ - if dim0 is None: dim0 = 0 @@ -757,7 +764,8 @@ def fft_r2c(signal, dim0 = None , scale = None): 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): + +def fft2_r2c(signal, dim0=None, dim1=None, scale=None): """ Real to Complex Fast Fourier Transform: 2D @@ -796,11 +804,12 @@ def fft2_r2c(signal, dim0 = None, dim1 = None , scale = None): scale = 1.0 output = Array() - 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))) + 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 -def fft3_r2c(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): + +def fft3_r2c(signal, dim0=None, dim1=None, dim2=None, scale=None): """ Real to Complex Fast Fourier Transform: 3D @@ -846,14 +855,16 @@ def fft3_r2c(signal, dim0 = None, dim1 = None , dim2 = None, scale = None): scale = 1.0 output = Array() - 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))) + 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 + def _get_c2r_dim(dim, is_odd): - return 2 *(dim - 1) + int(is_odd) + return 2 * (dim - 1) + int(is_odd) -def fft_c2r(signal, is_odd = False, scale = None): + +def fft_c2r(signal, is_odd=False, scale=None): """ Real to Complex Fast Fourier Transform: 1D @@ -877,8 +888,6 @@ def fft_c2r(signal, is_odd = False, scale = None): A real af.Array containing the full output of the fft. """ - - if scale is None: dim0 = _get_c2r_dim(signal.dims()[0], is_odd) scale = 1.0/float(dim0) @@ -887,7 +896,8 @@ def fft_c2r(signal, is_odd = False, scale = None): 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): + +def fft2_c2r(signal, is_odd=False, scale=None): """ Real to Complex Fast Fourier Transform: 2D @@ -922,7 +932,8 @@ def fft2_c2r(signal, is_odd = False, scale = None): 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): + +def fft3_c2r(signal, is_odd=False, scale=None): """ Real to Complex Fast Fourier Transform: 3D @@ -959,8 +970,7 @@ def fft3_c2r(signal, is_odd = False, scale = None): return output -def dft(signal, odims=(None, None, None, None), scale = None): - +def dft(signal, odims=(None, None, None, None), scale=None): """ Non batched Fourier transform. @@ -985,20 +995,21 @@ def dft(signal, odims=(None, None, None, None), scale = None): - A complex array that is the ouput of n-dimensional fourier transform. """ - + # FIXME: odims4 is assigned, but not used in function odims4 = dim4_to_tuple(odims, default=None) dims = signal.dims() ndims = len(dims) - if (ndims == 1): + if ndims == 1: return fft(signal, dims[0], scale) - elif (ndims == 2): + if ndims == 2: return fft2(signal, dims[0], dims[1], scale) - else: - return fft3(signal, dims[0], dims[1], dims[2], scale) -def idft(signal, scale = None, odims=(None, None, None, None)): + return fft3(signal, dims[0], dims[1], dims[2], scale) + + +def idft(signal, scale=None, odims=(None, None, None, None)): """ Non batched Inverse Fourier transform. @@ -1028,20 +1039,21 @@ def idft(signal, scale = None, odims=(None, None, None, None)): the output is always complex. """ - + # FIXME: odims4 is assigned, but not used in function odims4 = dim4_to_tuple(odims, default=None) dims = signal.dims() ndims = len(dims) - if (ndims == 1): + if ndims == 1: return ifft(signal, scale, dims[0]) - elif (ndims == 2): + if ndims == 2: return ifft2(signal, scale, dims[0], dims[1]) - else: - return ifft3(signal, scale, dims[0], dims[1], dims[2]) -def convolve1(signal, kernel, conv_mode = CONV_MODE.DEFAULT, conv_domain = CONV_DOMAIN.AUTO): + return ifft3(signal, scale, dims[0], dims[1], dims[2]) + + +def convolve1(signal, kernel, conv_mode=CONV_MODE.DEFAULT, conv_domain=CONV_DOMAIN.AUTO): """ Convolution: 1D @@ -1086,11 +1098,12 @@ def convolve1(signal, kernel, conv_mode = CONV_MODE.DEFAULT, conv_domain = CONV_ """ output = Array() - safe_call(backend.get().af_convolve1(c_pointer(output.arr), signal.arr, kernel.arr, - conv_mode.value, conv_domain.value)) + safe_call(backend.get().af_convolve1( + c_pointer(output.arr), signal.arr, kernel.arr, conv_mode.value, conv_domain.value)) return output -def convolve2(signal, kernel, conv_mode = CONV_MODE.DEFAULT, conv_domain = CONV_DOMAIN.AUTO): + +def convolve2(signal, kernel, conv_mode=CONV_MODE.DEFAULT, conv_domain=CONV_DOMAIN.AUTO): """ Convolution: 2D @@ -1134,8 +1147,8 @@ def convolve2(signal, kernel, conv_mode = CONV_MODE.DEFAULT, conv_domain = CONV_ """ output = Array() - safe_call(backend.get().af_convolve2(c_pointer(output.arr), signal.arr, kernel.arr, - conv_mode.value, conv_domain.value)) + safe_call(backend.get().af_convolve2( + c_pointer(output.arr), signal.arr, kernel.arr, conv_mode.value, conv_domain.value)) return output def convolve2NN(signal, kernel, stride = (1, 1), padding = (0, 0), dilation = (1, 1)): @@ -1214,12 +1227,12 @@ 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(c_pointer(output.arr), - col_kernel.arr, row_kernel.arr,signal.arr, - conv_mode.value)) + safe_call(backend.get().af_convolve2_sep( + c_pointer(output.arr), col_kernel.arr, row_kernel.arr, signal.arr, conv_mode.value)) return output -def convolve3(signal, kernel, conv_mode = CONV_MODE.DEFAULT, conv_domain = CONV_DOMAIN.AUTO): + +def convolve3(signal, kernel, conv_mode=CONV_MODE.DEFAULT, conv_domain=CONV_DOMAIN.AUTO): """ Convolution: 3D @@ -1261,11 +1274,12 @@ def convolve3(signal, kernel, conv_mode = CONV_MODE.DEFAULT, conv_domain = CONV_ """ output = Array() - safe_call(backend.get().af_convolve3(c_pointer(output.arr), signal.arr, kernel.arr, - conv_mode.value, conv_domain.value)) + safe_call(backend.get().af_convolve3( + c_pointer(output.arr), signal.arr, kernel.arr, conv_mode.value, conv_domain.value)) return output -def convolve(signal, kernel, conv_mode = CONV_MODE.DEFAULT, conv_domain = CONV_DOMAIN.AUTO): + +def convolve(signal, kernel, conv_mode=CONV_MODE.DEFAULT, conv_domain=CONV_DOMAIN.AUTO): """ Non batched Convolution. @@ -1296,18 +1310,18 @@ def convolve(signal, kernel, conv_mode = CONV_MODE.DEFAULT, conv_domain = CONV_D output: af.Array - Output of n-dimensional convolution. """ - dims = signal.dims() ndims = len(dims) - if (ndims == 1): + if ndims == 1: return convolve1(signal, kernel, conv_mode, conv_domain) - elif (ndims == 2): + if ndims == 2: return convolve2(signal, kernel, conv_mode, conv_domain) - else: - return convolve3(signal, kernel, conv_mode, conv_domain) -def fft_convolve1(signal, kernel, conv_mode = CONV_MODE.DEFAULT): + return convolve3(signal, kernel, conv_mode, conv_domain) + + +def fft_convolve1(signal, kernel, conv_mode=CONV_MODE.DEFAULT): """ FFT based Convolution: 1D @@ -1348,11 +1362,11 @@ def fft_convolve1(signal, kernel, conv_mode = CONV_MODE.DEFAULT): """ output = Array() - safe_call(backend.get().af_fft_convolve1(c_pointer(output.arr), signal.arr, kernel.arr, - conv_mode.value)) + safe_call(backend.get().af_fft_convolve1(c_pointer(output.arr), signal.arr, kernel.arr, conv_mode.value)) return output -def fft_convolve2(signal, kernel, conv_mode = CONV_MODE.DEFAULT): + +def fft_convolve2(signal, kernel, conv_mode=CONV_MODE.DEFAULT): """ FFT based Convolution: 2D @@ -1392,11 +1406,11 @@ def fft_convolve2(signal, kernel, conv_mode = CONV_MODE.DEFAULT): """ output = Array() - safe_call(backend.get().af_fft_convolve2(c_pointer(output.arr), signal.arr, kernel.arr, - conv_mode.value)) + safe_call(backend.get().af_fft_convolve2(c_pointer(output.arr), signal.arr, kernel.arr, conv_mode.value)) return output -def fft_convolve3(signal, kernel, conv_mode = CONV_MODE.DEFAULT): + +def fft_convolve3(signal, kernel, conv_mode=CONV_MODE.DEFAULT): """ FFT based Convolution: 3D @@ -1434,11 +1448,11 @@ def fft_convolve3(signal, kernel, conv_mode = CONV_MODE.DEFAULT): """ output = Array() - safe_call(backend.get().af_fft_convolve3(c_pointer(output.arr), signal.arr, kernel.arr, - conv_mode.value)) + safe_call(backend.get().af_fft_convolve3(c_pointer(output.arr), signal.arr, kernel.arr, conv_mode.value)) return output -def fft_convolve(signal, kernel, conv_mode = CONV_MODE.DEFAULT): + +def fft_convolve(signal, kernel, conv_mode=CONV_MODE.DEFAULT): """ Non batched FFT Convolution. @@ -1472,12 +1486,13 @@ def fft_convolve(signal, kernel, conv_mode = CONV_MODE.DEFAULT): dims = signal.dims() ndims = len(dims) - if (ndims == 1): + if ndims == 1: return fft_convolve1(signal, kernel, conv_mode) - elif (ndims == 2): + if ndims == 2: return fft_convolve2(signal, kernel, conv_mode) - else: - return fft_convolve3(signal, kernel, conv_mode) + + return fft_convolve3(signal, kernel, conv_mode) + def fir(B, X): """ @@ -1503,6 +1518,7 @@ def fir(B, X): safe_call(backend.get().af_fir(c_pointer(Y.arr), B.arr, X.arr)) return Y + def iir(B, A, X): """ Infinite impulse response filter. @@ -1530,7 +1546,8 @@ def iir(B, A, X): 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): + +def medfilt(signal, w0=3, w1=3, edge_pad=PAD.ZERO): """ Apply median filter for the signal. @@ -1557,12 +1574,11 @@ def medfilt(signal, w0 = 3, w1 = 3, edge_pad = PAD.ZERO): """ output = Array() - safe_call(backend.get().af_medfilt(c_pointer(output.arr), - signal.arr, c_dim_t(w0), - c_dim_t(w1), edge_pad.value)) + 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 -def medfilt1(signal, length = 3, edge_pad = PAD.ZERO): + +def medfilt1(signal, length=3, edge_pad=PAD.ZERO): """ Apply median filter for the signal. @@ -1589,7 +1605,8 @@ def medfilt1(signal, length = 3, edge_pad = PAD.ZERO): 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): + +def medfilt2(signal, w0=3, w1=3, edge_pad=PAD.ZERO): """ Apply median filter for the signal. @@ -1616,11 +1633,10 @@ def medfilt2(signal, w0 = 3, w1 = 3, edge_pad = PAD.ZERO): """ output = Array() - safe_call(backend.get().af_medfilt2(c_pointer(output.arr), - signal.arr, c_dim_t(w0), - c_dim_t(w1), edge_pad.value)) + 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 + def set_fft_plan_cache_size(cache_size): """ Sets plan cache size. diff --git a/arrayfire/sparse.py b/arrayfire/sparse.py index 91b8f7a23..4305988cf 100644 --- a/arrayfire/sparse.py +++ b/arrayfire/sparse.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,18 +11,18 @@ Functions to create and manipulate sparse matrices. """ -from .library import * -from .array import * -import numbers +from .array import Array +from .library import backend, safe_call, STORAGE, Dtype, c_dim_t, c_int_t, c_pointer from .interop import to_array -__to_sparse_enum = [STORAGE.DENSE, - STORAGE.CSR, - STORAGE.CSC, - STORAGE.COO] +__to_sparse_enum = [ + STORAGE.DENSE, + STORAGE.CSR, + STORAGE.CSC, + STORAGE.COO] -def create_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. @@ -52,15 +52,16 @@ def create_sparse(values, row_idx, col_idx, nrows, ncols, storage = STORAGE.CSR) A sparse matrix. """ - assert(isinstance(values, Array)) - assert(isinstance(row_idx, Array)) - assert(isinstance(col_idx, Array)) + assert isinstance(values, Array) + assert isinstance(row_idx, Array) + assert isinstance(col_idx, Array) out = Array() - 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)) + 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 -def create_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,12 +91,12 @@ 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).as_type(Dtype.s32), - to_array(col_idx).as_type(Dtype.s32), - 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): +def create_sparse_from_dense(dense, storage=STORAGE.CSR): """ Create a sparse matrix from a dense matrix. @@ -113,11 +114,12 @@ def create_sparse_from_dense(dense, storage = STORAGE.CSR): A sparse matrix. """ - assert(isinstance(dense, Array)) + assert isinstance(dense, Array) out = Array() safe_call(backend.get().af_create_sparse_array_from_dense(c_pointer(out.arr), dense.arr, storage.value)) return out + def convert_sparse_to_dense(sparse): """ Create a dense matrix from a sparse matrix. @@ -137,6 +139,7 @@ def convert_sparse_to_dense(sparse): safe_call(backend.get().af_sparse_to_dense(c_pointer(out.arr), sparse.arr)) return out + def sparse_get_info(sparse): """ Get the constituent arrays and storage info from a sparse matrix. @@ -159,11 +162,11 @@ def sparse_get_info(sparse): row_idx = Array() col_idx = Array() 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)) + 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]) + def sparse_get_values(sparse): """ Get the non zero values from sparse matrix. @@ -183,6 +186,7 @@ def sparse_get_values(sparse): safe_call(backend.get().af_sparse_get_values(c_pointer(values.arr), sparse.arr)) return values + def sparse_get_row_idx(sparse): """ Get the row indices from sparse matrix. @@ -202,6 +206,7 @@ def sparse_get_row_idx(sparse): 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): """ Get the column indices from sparse matrix. @@ -221,6 +226,7 @@ def sparse_get_col_idx(sparse): safe_call(backend.get().af_sparse_get_col_idx(c_pointer(col_idx.arr), sparse.arr)) return col_idx + def sparse_get_nnz(sparse): """ Get the column indices from sparse matrix. @@ -240,6 +246,7 @@ def sparse_get_nnz(sparse): safe_call(backend.get().af_sparse_get_nnz(c_pointer(nnz), sparse.arr)) return nnz.value + def sparse_get_storage(sparse): """ Get the column indices from sparse matrix. @@ -259,6 +266,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 convert_sparse(sparse, storage): """ Convert sparse matrix from one format to another. diff --git a/arrayfire/statistics.py b/arrayfire/statistics.py index f47f3a48d..bc51fcbad 100644 --- a/arrayfire/statistics.py +++ b/arrayfire/statistics.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,8 +11,9 @@ Statistical algorithms (mean, var, stdev, etc). """ -from .library import * -from .array import * +from .array import Array +from .library import TOPK, VARIANCE, c_double_t, c_int_t, c_pointer, backend, safe_call + def mean(a, weights=None, dim=None): """ @@ -45,19 +46,20 @@ def mean(a, weights=None, dim=None): safe_call(backend.get().af_mean_weighted(c_pointer(out.arr), a.arr, weights.arr, c_int_t(dim))) return out + + real = c_double_t(0) + imag = c_double_t(0) + + if weights is None: + safe_call(backend.get().af_mean_all(c_pointer(real), c_pointer(imag), a.arr)) else: - real = c_double_t(0) - imag = c_double_t(0) + safe_call(backend.get().af_mean_all_weighted(c_pointer(real), c_pointer(imag), a.arr, weights.arr)) - if weights is None: - safe_call(backend.get().af_mean_all(c_pointer(real), c_pointer(imag), a.arr)) - else: - safe_call(backend.get().af_mean_all_weighted(c_pointer(real), c_pointer(imag), a.arr, weights.arr)) + real = real.value + imag = imag.value - real = real.value - imag = imag.value + return real if imag == 0 else real + imag * 1j - return real if imag == 0 else real + imag * 1j def var(a, isbiased=False, weights=None, dim=None): """ @@ -94,19 +96,20 @@ def var(a, isbiased=False, weights=None, dim=None): safe_call(backend.get().af_var_weighted(c_pointer(out.arr), a.arr, weights.arr, c_int_t(dim))) return out + + real = c_double_t(0) + 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)) else: - real = c_double_t(0) - imag = c_double_t(0) + safe_call(backend.get().af_var_all_weighted(c_pointer(real), c_pointer(imag), a.arr, weights.arr)) - if weights is None: - 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(c_pointer(real), c_pointer(imag), a.arr, weights.arr)) + real = real.value + imag = imag.value - real = real.value - imag = imag.value + return real if imag == 0 else real + imag * 1j - return real if imag == 0 else real + imag * 1j def meanvar(a, weights=None, bias=VARIANCE.DEFAULT, dim=-1): """ @@ -173,13 +176,14 @@ def stdev(a, dim=None): out = Array() safe_call(backend.get().af_stdev(c_pointer(out.arr), a.arr, 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)) - real = real.value - imag = imag.value - return real if imag == 0 else real + imag * 1j + + 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 + def cov(a, isbiased=False, dim=None): """ @@ -206,13 +210,14 @@ def cov(a, isbiased=False, dim=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 + + 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 + def median(a, dim=None): """ @@ -236,13 +241,14 @@ def median(a, dim=None): out = Array() safe_call(backend.get().af_median(c_pointer(out.arr), a.arr, c_int_t(dim))) return out - else: - 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 + + 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): """ @@ -268,6 +274,7 @@ def corrcoef(x, y): 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. @@ -297,10 +304,10 @@ def topk(data, k, dim=0, order=TOPK.DEFAULT): 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)) + 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 + return values, indices diff --git a/arrayfire/timer.py b/arrayfire/timer.py index d523fcd93..537aed09f 100644 --- a/arrayfire/timer.py +++ b/arrayfire/timer.py @@ -1,19 +1,21 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# 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 ######################################################## + """ Functions to time arrayfire. """ -from .library import * -from .device import (sync, eval) -from time import time import math +from time import time + +from .device import eval, sync + def timeit(af_func, *args): """ @@ -31,25 +33,24 @@ def timeit(af_func, *args): t : Time in seconds """ - sample_trials = 3 sample_time = 1E20 - for i in range(sample_trials): + for _ in range(sample_trials): start = time() res = af_func(*args) eval(res) sync() sample_time = min(sample_time, time() - start) - if (sample_time >= 0.5): + if sample_time >= 0.5: return sample_time num_iters = max(math.ceil(1.0 / sample_time), 3.0) start = time() - for i in range(int(num_iters)): + for _ in range(int(num_iters)): res = af_func(*args) eval(res) sync() diff --git a/arrayfire/util.py b/arrayfire/util.py index 44af6000d..bf01639a0 100644 --- a/arrayfire/util.py +++ b/arrayfire/util.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,32 +11,41 @@ Utility functions to help with Array metadata. """ -from .library import * import numbers +from .library import ( + Dtype, c_char_t, c_dim_t, c_double_t, c_float_t, c_int_t, c_longlong_t, c_short_t, c_uchar_t, c_uint_t, + c_ulonglong_t, c_ushort_t) + + def dim4(d0=1, d1=1, d2=1, d3=1): c_dim4 = c_dim_t * 4 out = c_dim4(1, 1, 1, 1) for i, dim in enumerate((d0, d1, d2, d3)): - if (dim is not None): out[i] = c_dim_t(dim) + if dim is None: + continue + out[i] = c_dim_t(dim) return out + def _is_number(a): return isinstance(a, numbers.Number) + def number_dtype(a): if isinstance(a, bool): return Dtype.b8 if isinstance(a, int): return Dtype.s64 - elif isinstance(a, float): + if isinstance(a, float): return Dtype.f64 - elif isinstance(a, complex): + if isinstance(a, complex): return Dtype.c64 - else: - return to_dtype[a.dtype.char] + + return to_dtype[a.dtype.char] + def implicit_dtype(number, a_dtype): n_dtype = number_dtype(number) @@ -47,19 +56,20 @@ def implicit_dtype(number, a_dtype): c32v = Dtype.c32.value c64v = Dtype.c64.value - if n_value == f64v and (a_dtype == f32v or a_dtype == c32v): + if n_value == f64v and a_dtype in {f32v, c32v}: return Dtype.f32 - if n_value == c64v and (a_dtype == f32v or a_dtype == c32v): + if n_value == c64v and a_dtype in {f32v, c32v}: return Dtype.c32 return n_dtype + def dim4_to_tuple(dims, default=1): - assert(isinstance(dims, tuple)) + assert isinstance(dims, tuple) - if (default is not None): - assert(_is_number(default)) + if default is not None: + assert _is_number(default) out = [default]*4 @@ -68,15 +78,10 @@ def dim4_to_tuple(dims, default=1): return tuple(out) + def to_str(c_str): return str(c_str.value.decode('utf-8')) -def safe_call(af_error): - if (af_error != ERR.NONE.value): - err_str = c_char_ptr_t(0) - err_len = c_dim_t(0) - backend.get().af_get_last_error(c_pointer(err_str), c_pointer(err_len)) - raise RuntimeError(to_str(err_str)) def get_version(): """ @@ -88,6 +93,7 @@ def get_version(): 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(): """ Function to get the revision hash of the library. diff --git a/arrayfire/vision.py b/arrayfire/vision.py index 49cdc8fd8..0399fb696 100644 --- a/arrayfire/vision.py +++ b/arrayfire/vision.py @@ -1,5 +1,5 @@ ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -11,9 +11,10 @@ Computer vision functions (FAST, ORB, etc) """ -from .library import * -from .array import * -from .features import * +from .array import Array +from .library import backend, safe_call, HOMOGRAPHY, MATCH, Dtype, c_dim_t, c_float_t, c_int_t, c_pointer, c_uint_t +from .features import Features + def fast(image, threshold=20.0, arc_length=9, non_max=True, feature_ratio=0.05, edge=3): """ @@ -47,11 +48,12 @@ def fast(image, threshold=20.0, arc_length=9, non_max=True, feature_ratio=0.05, """ out = Features() - 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))) + 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): """ Harris corner detector. @@ -91,12 +93,13 @@ def harris(image, max_corners=500, min_response=1E5, sigma=1.0, block_size=0, k_ """ out = Features() - 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))) + 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): + +def orb(image, threshold=20.0, max_features=400, scale=1.5, num_levels=4, blur_image=False): """ ORB Feature descriptor. @@ -131,12 +134,13 @@ 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), image.arr, - c_float_t(threshold), c_uint_t(max_features), - c_float_t(scale), c_uint_t(num_levels), blur_image)) + 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 -def hamming_matcher(query, database, dim = 0, num_nearest = 1): + +def hamming_matcher(query, database, dim=0, num_nearest=1): """ Hamming distance matcher. @@ -164,12 +168,12 @@ def hamming_matcher(query, database, dim = 0, num_nearest = 1): """ index = Array() dist = Array() - 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))) + 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 -def nearest_neighbour(query, database, dim = 0, num_nearest = 1, match_type=MATCH.SSD): + +def nearest_neighbour(query, database, dim=0, num_nearest=1, match_type=MATCH.SSD): """ Nearest Neighbour matcher. @@ -200,13 +204,13 @@ 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(index.arr), c_pointer(dist.arr), - query.arr, database.arr, - c_dim_t(dim), c_dim_t(num_nearest), - match_type.value)) + 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)) return index, dist -def match_template(image, template, match_type = MATCH.SAD): + +def match_template(image, template, match_type=MATCH.SAD): """ Find the closest match of a template in an image. @@ -229,11 +233,10 @@ def match_template(image, template, match_type = MATCH.SAD): """ out = Array() - safe_call(backend.get().af_match_template(c_pointer(out.arr), - image.arr, template.arr, - match_type.value)) + safe_call(backend.get().af_match_template(c_pointer(out.arr), image.arr, template.arr, match_type.value)) return out + def susan(image, radius=3, diff_thr=32, geom_thr=10, feature_ratio=0.05, edge=3): """ SUSAN corner detector. @@ -266,12 +269,12 @@ 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(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))) + 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): """ Difference of gaussians. @@ -299,14 +302,13 @@ def dog(image, radius1, radius2): The sigma values are calculated to be 0.25 * radius. """ - out = Array() - safe_call(backend.get().af_dog(c_pointer(out.arr), - image.arr, radius1, radius2)) + safe_call(backend.get().af_dog(c_pointer(out.arr), image.arr, radius1, radius2)) return out -def sift(image, num_layers=3, contrast_threshold=0.04, edge_threshold=10.0, initial_sigma = 1.6, - double_input = True, intensity_scale = 0.00390625, feature_ratio = 0.05): + +def sift(image, num_layers=3, contrast_threshold=0.04, edge_threshold=10.0, initial_sigma=1.6, + double_input=True, intensity_scale=0.00390625, feature_ratio=0.05): """ SIFT feature detector and descriptor. @@ -342,17 +344,18 @@ def sift(image, num_layers=3, contrast_threshold=0.04, edge_threshold=10.0, init - descriptor is an af.Array of size N x 128 """ - feat = Features() desc = Array() - 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))) + 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) -def gloh(image, num_layers=3, contrast_threshold=0.04, edge_threshold=10.0, initial_sigma = 1.6, - double_input = True, intensity_scale = 0.00390625, feature_ratio = 0.05): + +def gloh(image, num_layers=3, contrast_threshold=0.04, edge_threshold=10.0, initial_sigma=1.6, + double_input=True, intensity_scale=0.00390625, feature_ratio=0.05): """ GLOH feature detector and descriptor. @@ -388,19 +391,18 @@ def gloh(image, num_layers=3, contrast_threshold=0.04, edge_threshold=10.0, init - descriptor is an af.Array of size N x 272 """ - feat = Features() desc = Array() - 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))) + 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) -def homography(x_src, y_src, x_dst, y_dst, htype = HOMOGRAPHY.RANSAC, - ransac_threshold = 3.0, iters = 1000, out_type = Dtype.f32): + +def homography(x_src, y_src, x_dst, y_dst, htype=HOMOGRAPHY.RANSAC, ransac_threshold=3.0, + iters=1000, out_type=Dtype.f32): """ Homography estimation @@ -433,10 +435,9 @@ def homography(x_src, y_src, x_dst, y_dst, htype = HOMOGRAPHY.RANSAC, ------- (H, inliers) : A tuple of (af.Array, integer) """ - H = Array() 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)) + 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) diff --git a/docs/conf.py b/docs/conf.py index 44374afb1..b68eb8e81 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # -*- coding: utf-8 -*- # # ArrayFire documentation build configuration file, created by @@ -19,8 +19,14 @@ # import os import sys +from configparser import ConfigParser + + +config = ConfigParser() +config.read(os.path.abspath("setup.cfg")) +full_version = config.get("metadata", "version") + sys.path.insert(0, os.path.abspath('..')) -from __af_version__ import full_version # -- General configuration ------------------------------------------------ @@ -32,13 +38,13 @@ # 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'] + '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'] @@ -247,21 +253,21 @@ # -- Options for LaTeX output --------------------------------------------- latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples diff --git a/examples/benchmarks/bench_blas.py b/examples/benchmarks/bench_blas.py index 21b776869..9cfe625f0 100644 --- a/examples/benchmarks/bench_blas.py +++ b/examples/benchmarks/bench_blas.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -9,9 +9,9 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## - import sys from time import time + import arrayfire as af try: @@ -26,6 +26,7 @@ def calc_arrayfire(n): def run(iters): for t in range(iters): + # FIXME: B is assigned, but not used in function B = af.matmul(A, A) af.sync() @@ -38,6 +39,7 @@ def calc_numpy(n): def run(iters): for t in range(iters): + # FIXME: B is assigned, but not used in function B = np.dot(A, A) return run @@ -57,8 +59,7 @@ def bench(calc, iters=100, upto=2048): if __name__ == "__main__": - - if (len(sys.argv) > 1): + if len(sys.argv) > 1: af.set_device(int(sys.argv[1])) af.info() diff --git a/examples/benchmarks/bench_cg.py b/examples/benchmarks/bench_cg.py index 33c5b856c..9421f7af0 100644 --- a/examples/benchmarks/bench_cg.py +++ b/examples/benchmarks/bench_cg.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -9,9 +9,9 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## - import sys from time import time + import arrayfire as af try: @@ -34,13 +34,10 @@ 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) +def to_scipy_sparse(spA, fmt="csr"): # BUG: 'fmt' argument is unused. + 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) @@ -57,11 +54,11 @@ def setup_input(n, sparsity=7): return A, b, x0 -def input_info(A, Asp): +def input_info(A, Asp): # BUG: 'Asp' argument is unused. 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(" 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: ") @@ -70,7 +67,7 @@ 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): + for _ in range(maxiter): Ap = af.matmul(A, p) alpha_num = af.dot(r, r) alpha_den = af.dot(p, Ap) @@ -89,7 +86,7 @@ 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): + for _ in range(maxiter): Ap = np.dot(A, p) alpha_num = np.dot(r, r) alpha_den = np.dot(p, Ap) @@ -107,7 +104,7 @@ 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): + for _ in range(maxiter): Ap = A*p alpha_num = np.dot(r, r) alpha_den = np.dot(p, Ap) @@ -130,7 +127,7 @@ def calc_scipy_sparse_linalg_cg(A, b, x0, maxiter=10): def timeit(calc, iters, args): t0 = time() - for i in range(iters): + for _ in range(iters): calc(*args) dt = time() - t0 return 1000*dt/iters # ms @@ -163,36 +160,36 @@ def test(): def bench(n=4*1024, sparsity=7, maxiter=10, iters=10): - # generate data - print("\nGenerating benchmark data for n = %i ..." %n) + 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) + print("Benchmarking CG solver for n = %i ..." % n) t1 = timeit(calc_arrayfire, iters, args=(A, b, x0, maxiter)) - print(" arrayfire - dense: %f ms" %t1) + print(" arrayfire - dense: %f ms" % t1) t2 = timeit(calc_arrayfire, iters, args=(Asp, b, x0, maxiter)) - print(" arrayfire - sparse: %f ms" %t2) + 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) + 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) + 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) + print(" scipy - sparse.linalg.cg: %f ms" % t5) + if __name__ == "__main__": - #af.set_backend('cpu', unsafe=True) + # af.set_backend("cpu", unsafe=True) - if (len(sys.argv) > 1): + if len(sys.argv) > 1: af.set_device(int(sys.argv[1])) af.info() diff --git a/examples/benchmarks/bench_fft.py b/examples/benchmarks/bench_fft.py index 4d9a3d7b1..0df179b8d 100644 --- a/examples/benchmarks/bench_fft.py +++ b/examples/benchmarks/bench_fft.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -9,9 +9,9 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## - import sys from time import time + import arrayfire as af try: @@ -25,8 +25,8 @@ def calc_arrayfire(n): af.sync() def run(iters): - for t in range(iters): - B = af.fft2(A) + for _ in range(iters): + B = af.fft2(A) # FIXME: 'B' is assigned, but not used. af.sync() @@ -38,8 +38,8 @@ def calc_numpy(n): A = np.random.rand(n, n).astype(np.float32) def run(iters): - for t in range(iters): - B = np.fft.fft2(A) + for _ in range(iters): + B = np.fft.fft2(A) # FIXME: 'B' is assigned, but not used. return run @@ -59,8 +59,7 @@ def bench(calc, iters=100, upto=13): if __name__ == "__main__": - - if (len(sys.argv) > 1): + if len(sys.argv) > 1: af.set_device(int(sys.argv[1])) af.info() diff --git a/examples/benchmarks/monte_carlo_pi.py b/examples/benchmarks/monte_carlo_pi.py index 440c01594..4e5f92b4b 100755 --- a/examples/benchmarks/monte_carlo_pi.py +++ b/examples/benchmarks/monte_carlo_pi.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -9,55 +9,62 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## +import sys from random import random from time import time + import arrayfire as af -import sys try: import numpy as np except ImportError: np = None -#alias range / xrange because xrange is faster than range in python2 +# alias range / xrange because xrange is faster than range in python2 try: - frange = xrange #Python2 + frange = xrange # Python2 except NameError: - frange = range #Python3 + frange = range # Python3 + -# Having the function outside is faster than the lambda inside def in_circle(x, y): + # Having the function outside is faster than the lambda inside 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).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): count = sum(1 for k in frange(samples) if in_circle(random(), random())) return 4 * float(count) / samples + def bench(calc_pi, samples=1000000, iters=25): func_name = calc_pi.__name__[8:] - print("Monte carlo estimate of pi on %s with %d million samples: %f" % \ + print("Monte carlo estimate of pi on %s with %d million samples: %f" % (func_name, samples/1e6, calc_pi(samples))) start = time() - for k in frange(iters): + for _ in frange(iters): calc_pi(samples) end = time() print("Average time taken: %f ms" % (1000 * (end - start) / iters)) + if __name__ == "__main__": - if (len(sys.argv) > 1): + if len(sys.argv) > 1: af.set_device(int(sys.argv[1])) af.info() diff --git a/examples/financial/black_scholes_options.py b/examples/financial/black_scholes_options.py index e53a4ab19..e2dd2714f 100644 --- a/examples/financial/black_scholes_options.py +++ b/examples/financial/black_scholes_options.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -9,17 +9,20 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -import arrayfire as af -from time import time import math import sys +from time import time + +import arrayfire as af sqrt2 = math.sqrt(2.0) + def cnd(x): temp = (x > 0) return temp * (0.5 + af.erf(x/sqrt2)/2) + (1 - temp) * (0.5 - af.erf((-x)/sqrt2)/2) + def black_scholes(S, X, R, V, T): # S = Underlying stock price # X = Strike Price @@ -36,12 +39,13 @@ def black_scholes(S, X, R, V, T): cnd_d2 = cnd(d2) C = S * cnd_d1 - (X * af.exp((-R) * T) * cnd_d2) - P = X * af.exp((-R) * T) * (1 - cnd_d2) - (S * (1 -cnd_d1)) + P = X * af.exp((-R) * T) * (1 - cnd_d2) - (S * (1 - cnd_d1)) return (C, P) + if __name__ == "__main__": - if (len(sys.argv) > 1): + if len(sys.argv) > 1: af.set_device(int(sys.argv[1])) af.info() @@ -53,7 +57,7 @@ def black_scholes(S, X, R, V, T): V = af.randu(M, 1) T = af.randu(M, 1) - (C, P) = black_scholes(S, X, R, V, T) + C, P = black_scholes(S, X, R, V, T) af.eval(C) af.eval(P) af.sync() @@ -71,7 +75,7 @@ def black_scholes(S, X, R, V, T): start = time() for i in range(num_iter): - (C, P) = black_scholes(S, X, R, V, T) + C, P = black_scholes(S, X, R, V, T) af.eval(C) af.eval(P) af.sync() diff --git a/examples/financial/heston_model.py b/examples/financial/heston_model.py index 640127eeb..c63dc6022 100644 --- a/examples/financial/heston_model.py +++ b/examples/financial/heston_model.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ############################################################################################## -# Copyright (c) 2015, Michael Nowotny +# Copyright (c) 2019, Michael Nowotny # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, @@ -31,12 +31,13 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ############################################################################################### -import arrayfire as af import math import time -def simulateHestonModel( T, N, R, mu, kappa, vBar, sigmaV, rho, x0, v0 ) : +import arrayfire as af + +def simulateHestonModel(T, N, R, mu, kappa, vBar, sigmaV, rho, x0, v0): deltaT = T / (float)(N - 1) x = [af.constant(x0, R, dtype=af.Dtype.f32), af.constant(0, R, dtype=af.Dtype.f32)] @@ -50,9 +51,9 @@ def simulateHestonModel( T, N, R, mu, kappa, vBar, sigmaV, rho, x0, v0 ) : m[1] = sqrtOneMinusRhoSquare zeroArray = af.constant(0, R, 1, dtype=af.Dtype.f32) - for t in range(1, N) : + for t in range(1, N): tPrevious = (t + 1) % 2 - tCurrent = t % 2 + tCurrent = t % 2 dBt = af.randn(R, 2, dtype=af.Dtype.f32) * sqrtDeltaT @@ -71,21 +72,21 @@ def main(): R_first = 1000 R = 5000000 - x0 = 0 # initial log stock price - v0 = 0.087**2 # initial volatility - r = math.log(1.0319) # risk-free rate - rho = -0.82 # instantaneous correlation between Brownian motions - sigmaV = 0.14 # variance of volatility - kappa = 3.46 # mean reversion speed - vBar = 0.008 # mean variance - k = math.log(0.95) # strike price + x0 = 0 # initial log stock price + v0 = 0.087**2 # initial volatility + r = math.log(1.0319) # risk-free rate + rho = -0.82 # instantaneous correlation between Brownian motions + sigmaV = 0.14 # variance of volatility + kappa = 3.46 # mean reversion speed + vBar = 0.008 # mean variance + k = math.log(0.95) # strike price # first run - ( x, v ) = simulateHestonModel( T, nT, R_first, r, kappa, vBar, sigmaV, rho, x0, v0 ) + x, v = simulateHestonModel(T, nT, R_first, r, kappa, vBar, sigmaV, rho, x0, v0) # Price plain vanilla call option tic = time.time() - ( x, v ) = simulateHestonModel( T, nT, R, r, kappa, vBar, sigmaV, rho, x0, v0 ) + x, v = simulateHestonModel(T, nT, R, r, kappa, vBar, sigmaV, rho, x0, v0) af.sync() toc = time.time() - tic K = math.exp(k) diff --git a/examples/financial/monte_carlo_options.py b/examples/financial/monte_carlo_options.py index 2c9bcc8ed..8c5f090d5 100644 --- a/examples/financial/monte_carlo_options.py +++ b/examples/financial/monte_carlo_options.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -9,29 +9,32 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -import arrayfire as af -from time import time import math import sys +from time import time + +import arrayfire as af + -def monte_carlo_options(N, K, t, vol, r, strike, steps, use_barrier = True, B = None, ty = af.Dtype.f32): - payoff = af.constant(0, N, 1, dtype = ty) +def monte_carlo_options(N, K, t, vol, r, strike, steps, use_barrier=True, B=None, ty=af.Dtype.f32): + payoff = af.constant(0, N, 1, dtype=ty) dt = t / float(steps - 1) - s = af.constant(strike, N, 1, dtype = ty) + s = af.constant(strike, N, 1, dtype=ty) - randmat = af.randn(N, steps - 1, dtype = ty) - randmat = af.exp((r - (vol * vol * 0.5)) * dt + vol * math.sqrt(dt) * randmat); + randmat = af.randn(N, steps - 1, dtype=ty) + randmat = af.exp((r - (vol * vol * 0.5)) * dt + vol * math.sqrt(dt) * randmat) S = af.product(af.join(1, s, randmat), 1) - if (use_barrier): + if use_barrier: S = S * af.all_true(S < B, 1) payoff = af.maxof(0, S - K) return af.mean(payoff) * math.exp(-r * t) -def monte_carlo_simulate(N, use_barrier, num_iter = 10): + +def monte_carlo_simulate(N, use_barrier, num_iter=10): steps = 180 stock_price = 100.0 maturity = 0.5 @@ -41,19 +44,19 @@ def monte_carlo_simulate(N, use_barrier, num_iter = 10): barrier = 115.0 start = time() - for i in range(num_iter): - monte_carlo_options(N, stock_price, maturity, volatility, rate, strike, steps, - use_barrier, barrier) + for _ in range(num_iter): + monte_carlo_options(N, stock_price, maturity, volatility, rate, strike, steps, use_barrier, barrier) return (time() - start) / num_iter + if __name__ == "__main__": - if (len(sys.argv) > 1): + if len(sys.argv) > 1: af.set_device(int(sys.argv[1])) af.info() - monte_carlo_simulate(1000, use_barrier = False) - monte_carlo_simulate(1000, use_barrier = True ) + monte_carlo_simulate(1000, use_barrier=False) + monte_carlo_simulate(1000, use_barrier=True) af.sync() for n in range(10000, 100001, 10000): diff --git a/examples/getting_started/convolve.py b/examples/getting_started/convolve.py index 6c9e2454d..5a2ccbb9e 100644 --- a/examples/getting_started/convolve.py +++ b/examples/getting_started/convolve.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -9,25 +9,27 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -import arrayfire as af import sys from array import array +import arrayfire as af + + def af_assert(left, right, eps=1E-6): - if (af.max(af.abs(left -right)) > eps): + if af.max(af.abs(left - right)) > eps: raise ValueError("Arrays not within dictated precision") - return + if __name__ == "__main__": - if (len(sys.argv) > 1): + if len(sys.argv) > 1: af.set_device(int(sys.argv[1])) af.info() - h_dx = array('f', (1.0/12, -8.0/12, 0, 8.0/12, 1.0/12)) - h_spread = array('f', (1.0/5, 1.0/5, 1.0/5, 1.0/5, 1.0/5)) + h_dx = array("f", (1.0/12, -8.0/12, 0, 8.0/12, 1.0/12)) + h_spread = array("f", (1.0/5, 1.0/5, 1.0/5, 1.0/5, 1.0/5)) img = af.randu(640, 480) - dx = af.Array(h_dx, (5,1)) + dx = af.Array(h_dx, (5, 1)) spread = af.Array(h_spread, (1, 5)) kernel = af.matmul(dx, spread) diff --git a/examples/getting_started/intro.py b/examples/getting_started/intro.py index 712343750..d03808738 100644 --- a/examples/getting_started/intro.py +++ b/examples/getting_started/intro.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -9,32 +9,33 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -import arrayfire as af import sys from array import array +import arrayfire as af + if __name__ == "__main__": - if (len(sys.argv) > 1): + if len(sys.argv) > 1: af.set_device(int(sys.argv[1])) af.info() print("\n---- Intro to ArrayFire using signed(s32) arrays ----\n") - h_A = array('i', ( 1, 2, 4, -1, 2, 0, 4, 2, 3)) - h_B = array('i', ( 2, 3, 5, 6, 0, 10,-12, 0, 1)) + h_A = array("i", (1, 2, 4, -1, 2, 0, 4, 2, 3)) + h_B = array("i", (2, 3, 5, 6, 0, 10, -12, 0, 1)) - A = af.Array(h_A, (3,3)) - B = af.Array(h_B, (3,3)) + A = af.Array(h_A, (3, 3)) + B = af.Array(h_B, (3, 3)) print("\n---- Sub referencing and sub assignment\n") af.display(A) - af.display(A[0,:]) - af.display(A[:,0]) - A[0,0] = 11 + af.display(A[0, :]) + af.display(A[:, 0]) + A[0, 0] = 11 A[1] = 100 af.display(A) af.display(B) - A[1,:] = B[2,:] + A[1, :] = B[2, :] af.display(A) print("\n---- Bitwise operations\n") @@ -61,6 +62,6 @@ af.display(af.max(A, 1)) print("\n---- Get minimum with index\n") - (min_val, min_idx) = af.imin(A, 0) + min_val, min_idx = af.imin(A, 0) af.display(min_val) af.display(min_idx) diff --git a/examples/graphics/conway.py b/examples/graphics/conway.py index 49ad43bb9..6e27b0472 100644 --- a/examples/graphics/conway.py +++ b/examples/graphics/conway.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -9,11 +9,12 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -import arrayfire as af import array from time import time -h_kernel = array.array('f', (1, 1, 1, 1, 0, 1, 1, 1, 1)) +import arrayfire as af + +h_kernel = array.array("f", (1, 1, 1, 1, 0, 1, 1, 1, 1)) reset = 500 game_w = 128 game_h = 128 @@ -21,10 +22,10 @@ print("Example demonstrating conway's game of life using arrayfire") print("The conway_pretty example visualizes all the states in Conway") -print("Red : Cells that have died due to under population" ) -print("Yellow: Cells that continue to live from previous state" ) -print("Green : Cells that are new as a result of reproduction" ) -print("Blue : Cells that have died due to over population" ) +print("Red : Cells that have died due to under population") +print("Yellow: Cells that continue to live from previous state") +print("Green : Cells that are new as a result of reproduction") +print("Blue : Cells that have died due to over population") print("This examples is throttled to 30 FPS so as to be a better visualization") simple_win = af.Window(512, 512, "Conway's Game of Life - Current State") @@ -35,21 +36,23 @@ frame_count = 0 # Copy kernel that specifies neighborhood conditions -kernel = af.Array(h_kernel, dims=(3,3)) +kernel = af.Array(h_kernel, dims=(3, 3)) # Generate the initial state with 0s and 1s state = (af.randu(game_h, game_w) > 0.4).as_type(af.Dtype.f32) # tile 3 times to display color -display = af.tile(state, 1, 1, 3, 1) +display = af.tile(state, 1, 1, 3, 1) -while (not simple_win.close()) and (not pretty_win.close()): +while not (simple_win.close() or pretty_win.close()): delay = time() - if (not simple_win.close()): simple_win.image(state) - if (not pretty_win.close()): pretty_win.image(display) + if not simple_win.close(): + simple_win.image(state) + if not pretty_win.close(): + pretty_win.image(display) frame_count += 1 - if (frame_count % reset == 0): + if frame_count % reset == 0: state = (af.randu(game_h, game_w) > 0.4).as_type(af.Dtype.f32) neighborhood = af.convolve(state, kernel) @@ -70,5 +73,5 @@ state = state * C0 + C1 - while(time() - delay < (1.0 / fps)): + while time() - delay < (1.0 / fps): pass diff --git a/examples/graphics/fractal.py b/examples/graphics/fractal.py index 37b35a63f..d1c468088 100644 --- a/examples/graphics/fractal.py +++ b/examples/graphics/fractal.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -9,18 +9,21 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -import arrayfire as af import sys from math import sqrt +import arrayfire as af + width = 400 height = 400 + def complex_grid(w, h, zoom, center): - x = (af.iota(d0 = 1, d1 = h, tile_dims = (w, 1)) - h/2) / zoom + center[0] - y = (af.iota(d0 = w, d1 = 1, tile_dims = (1, h)) - w/2) / zoom + center[1] + x = (af.iota(d0=1, d1=h, tile_dims=(w, 1)) - h/2) / zoom + center[0] + y = (af.iota(d0=w, d1=1, tile_dims=(1, h)) - w/2) / zoom + center[1] return af.cplx(x, y) + def mandelbrot(data, it, maxval): C = data Z = data @@ -42,13 +45,15 @@ def mandelbrot(data, it, maxval): return mag / maxval + def normalize(a): mx = af.max(a) mn = af.min(a) return (a - mn)/(mx - mn) + if __name__ == "__main__": - if (len(sys.argv) > 1): + if len(sys.argv) > 1: af.set_device(int(sys.argv[1])) af.info() @@ -62,13 +67,14 @@ def normalize(a): for i in range(10, 400): zoom = i * i - if not (i % 10): + if not i % 10: print("Iteration: %d zoom: %d" % (i, zoom)) c = complex_grid(width, height, zoom, center) it = sqrt(2*sqrt(abs(1-sqrt(5*zoom))))*100 - if (win.close()): break + if win.close(): + break mag = mandelbrot(c, int(it), 1000) win.image(normalize(mag)) diff --git a/examples/graphics/histogram.py b/examples/graphics/histogram.py index 9a15dcf30..ee9c0db1e 100644 --- a/examples/graphics/histogram.py +++ b/examples/graphics/histogram.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -9,29 +9,29 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -import arrayfire as af -import sys import os +import sys -if __name__ == "__main__": +import arrayfire as af - if (len(sys.argv) == 1): +if __name__ == "__main__": + if len(sys.argv) == 1: raise RuntimeError("Expected to the image as the first argument") if not os.path.isfile(sys.argv[1]): raise RuntimeError("File %s not found" % sys.argv[1]) - if (len(sys.argv) > 2): + if len(sys.argv) > 2: af.set_device(int(sys.argv[2])) af.info() hist_win = af.Window(512, 512, "3D Plot example using ArrayFire") - img_win = af.Window(480, 640, "Input Image") + img_win = af.Window(480, 640, "Input Image") 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()): + while not (hist_win.close() or img_win.close()): hist_win.hist(hist, 0, 255) img_win.image(img) diff --git a/examples/graphics/plot2d.py b/examples/graphics/plot2d.py index a7f7f8164..8115771bf 100755 --- a/examples/graphics/plot2d.py +++ b/examples/graphics/plot2d.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -9,9 +9,10 @@ # http://arrayfire.com/licenses/BSD-3-Clause ######################################################## -import arrayfire as af import math +import arrayfire as af + POINTS = 10000 PRECISION = 1.0 / float(POINTS) @@ -28,7 +29,7 @@ X += PRECISION * sign val += PRECISION * sign - if (val > math.pi): + if val > math.pi: sign = -1.0 - elif (val < -math.pi): + elif val < -math.pi: sign = 1.0 diff --git a/examples/graphics/plot3.py b/examples/graphics/plot3.py index 4957326a6..86565b432 100644 --- a/examples/graphics/plot3.py +++ b/examples/graphics/plot3.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. diff --git a/examples/graphics/surface.py b/examples/graphics/surface.py index 1af980e22..a51bf6161 100644 --- a/examples/graphics/surface.py +++ b/examples/graphics/surface.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -16,13 +16,13 @@ POINTS = 30 N = 2 * POINTS -x = (af.iota(d0 = N, d1 = 1, tile_dims = (1, N)) - POINTS) / POINTS -y = (af.iota(d0 = 1, d1 = N, tile_dims = (N, 1)) - POINTS) / POINTS +x = (af.iota(d0=N, d1=1, tile_dims=(1, N)) - POINTS) / POINTS +y = (af.iota(d0=1, d1=N, tile_dims=(N, 1)) - POINTS) / POINTS win = af.Window(800, 800, "3D Surface example using ArrayFire") t = 0 while not win.close(): t = t + 0.07 - z = 10*x*-af.abs(y) * af.cos(x*x*(y+t))+af.sin(y*(x+t))-1.5; + z = 10*x*-af.abs(y) * af.cos(x*x*(y+t))+af.sin(y*(x+t))-1.5 win.surface(x, y, z) diff --git a/examples/helloworld/helloworld.py b/examples/helloworld/helloworld.py index 2d76cf3ea..61b5f859c 100755 --- a/examples/helloworld/helloworld.py +++ b/examples/helloworld/helloworld.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -27,33 +27,33 @@ 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("Fourier transform the result\n") + C = af.fft(B) + af.display(C) - print("Grab last row\n"); - c = C[-1,:]; - 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 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("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 ] + 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("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); + 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) diff --git a/setup.cfg b/setup.cfg index 831f2063b..5f6ccf0ed 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = arrayfire -version = 3.7.20200213 +version = 3.7.20201113 description = Python bindings for ArrayFire licence = BSD long_description = file: README.md @@ -9,12 +9,14 @@ maintainer_email = technical@arrayfire.com url = http://arrayfire.com classifiers = Programming Language :: Python - Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 [options] packages = find: +python_requires = >=3.6.0 [options.packages.find] include = arrayfire diff --git a/setup.py b/setup.py index e4d485c30..5bc5472ca 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. diff --git a/tests/__init__.py b/tests/__init__.py index 24e9ac759..0c6d787de 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. diff --git a/tests/__main__.py b/tests/__main__.py index 6bed94278..190c5c8f8 100644 --- a/tests/__main__.py +++ b/tests/__main__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. diff --git a/tests/simple/__init__.py b/tests/simple/__init__.py index 4950136e3..abedbc4ba 100644 --- a/tests/simple/__init__.py +++ b/tests/simple/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. diff --git a/tests/simple/_util.py b/tests/simple/_util.py index 2275cf2fc..339bdd382 100644 --- a/tests/simple/_util.py +++ b/tests/simple/_util.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. diff --git a/tests/simple/algorithm.py b/tests/simple/algorithm.py index b9e42f138..d46b6d8cc 100644 --- a/tests/simple/algorithm.py +++ b/tests/simple/algorithm.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. diff --git a/tests/simple/arith.py b/tests/simple/arith.py index 5d4d83d00..05c5dd47a 100644 --- a/tests/simple/arith.py +++ b/tests/simple/arith.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -78,27 +78,25 @@ def simple_arith(verbose=False): display_func(a < b) display_func(a < 0.5) - display_func(0.5 < a) + display_func(a > 0.5) display_func(a <= b) display_func(a <= 0.5) - display_func(0.5 <= a) + display_func(a >= 0.5) display_func(a > b) display_func(a > 0.5) - display_func(0.5 > a) + display_func(a < 0.5) display_func(a >= b) display_func(a >= 0.5) - display_func(0.5 >= a) + display_func(a <= 0.5) display_func(a != b) display_func(a != 0.5) - display_func(0.5 != a) display_func(a == b) 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) diff --git a/tests/simple/array_test.py b/tests/simple/array_test.py index b2a787940..b1d9d1b18 100644 --- a/tests/simple/array_test.py +++ b/tests/simple/array_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -20,7 +20,7 @@ def simple_array(verbose=False): display_func = _util.display_func(verbose) print_func = _util.print_func(verbose) - a = af.Array([1, 2, 3]) + a = af.array.Array([1, 2, 3]) display_func(a) display_func(a.T) display_func(a.H) @@ -34,14 +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.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.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()) diff --git a/tests/simple/blas.py b/tests/simple/blas.py index f04049a93..ac4aa6166 100644 --- a/tests/simple/blas.py +++ b/tests/simple/blas.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. diff --git a/tests/simple/data.py b/tests/simple/data.py index d091497eb..3120aec09 100644 --- a/tests/simple/data.py +++ b/tests/simple/data.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. diff --git a/tests/simple/device.py b/tests/simple/device.py index f677c5e2a..f125ab862 100644 --- a/tests/simple/device.py +++ b/tests/simple/device.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -27,7 +27,7 @@ def simple_device(verbose=False): for k in range(af.get_device_count()): af.set_device(k) dev = af.get_device() - assert(k == dev) + assert k == dev print_func(af.is_dbl_supported(k)) @@ -38,8 +38,8 @@ 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) @@ -67,9 +67,9 @@ def simple_device(verbose=False): print_func(d) print_func(af.set_manual_eval_flag(True)) - assert(af.get_manual_eval_flag()) + assert af.get_manual_eval_flag() print_func(af.set_manual_eval_flag(False)) - assert(not af.get_manual_eval_flag()) + assert not af.get_manual_eval_flag() display_func(af.is_locked_array(a)) diff --git a/tests/simple/image.py b/tests/simple/image.py index 6f2e12186..c3bb48142 100644 --- a/tests/simple/image.py +++ b/tests/simple/image.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -86,7 +86,8 @@ 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)) + # FIXME: OpenCL Error (-11): Build Program Failure when calling clBuildProgram + # 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) diff --git a/tests/simple/index.py b/tests/simple/index.py index 8bb4b571a..1cd6229f2 100644 --- a/tests/simple/index.py +++ b/tests/simple/index.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -12,7 +12,6 @@ import array as host import arrayfire as af -from arrayfire import ParallelRange from . import _util @@ -57,12 +56,12 @@ def simple_index(verbose=False): b = af.randu(5, 1) display_func(a) display_func(b) - for ii in ParallelRange(1, 3): + for ii in af.ParallelRange(1, 3): a[ii] = b[ii] display_func(a) - for ii in ParallelRange(2, 5): + for ii in af.ParallelRange(2, 5): b[ii] = 2 display_func(b) diff --git a/tests/simple/interop.py b/tests/simple/interop.py index f07e6a770..75515f611 100644 --- a/tests/simple/interop.py +++ b/tests/simple/interop.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -13,41 +13,43 @@ from . import _util +# BUG: module 'arrayfire' has no 'to_array' member. -def simple_interop(verbose=False): + +def simple_interop(*args): 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)) 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)) 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)) 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.gpuarray as cudaArray @@ -55,28 +57,28 @@ def simple_interop(verbose=False): 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)) 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)) 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)) 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": - # TODO: This needs fixing upstream + # FIXME: This needs fixing upstream # https://github.com/arrayfire/arrayfire/issues/1728 # import pyopencl as cl @@ -88,25 +90,25 @@ def simple_interop(verbose=False): # c = cl.array.to_device(queue, n) # a = af.to_array(c) # n2 = np.array(a) - # assert((n==n2).all()) + # 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()) + # 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()) + # 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()) + # assert (n==n2).all() pass if af.AF_NUMBA_FOUND and af.get_active_backend() == "cuda": @@ -116,25 +118,25 @@ def simple_interop(verbose=False): 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)) 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)) 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)) 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 diff --git a/tests/simple/lapack.py b/tests/simple/lapack.py index 8cd3e9ac3..600e22605 100644 --- a/tests/simple/lapack.py +++ b/tests/simple/lapack.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. diff --git a/tests/simple/random.py b/tests/simple/random.py index 5152cb4e0..dcf7fbca6 100644 --- a/tests/simple/random.py +++ b/tests/simple/random.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -25,7 +25,7 @@ def simple_random(verbose=False): display_func(af.randn(3, 3, dtype=af.Dtype.c32)) af.set_seed(1024) - assert(af.get_seed() == 1024) + assert af.get_seed() == 1024 engine = af.Random_Engine(af.RANDOM_ENGINE.MERSENNE_GP11213, 100) @@ -35,7 +35,7 @@ def simple_random(verbose=False): display_func(af.randn(3, 3, engine=engine)) engine.set_seed(100) - assert(engine.get_seed() == 100) + assert engine.get_seed() == 100 _util.tests["random"] = simple_random diff --git a/tests/simple/signal.py b/tests/simple/signal.py index 0e3e8da9d..b2a337ed5 100644 --- a/tests/simple/signal.py +++ b/tests/simple/signal.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. diff --git a/tests/simple/sparse.py b/tests/simple/sparse.py index bda87dfb7..49253d97d 100644 --- a/tests/simple/sparse.py +++ b/tests/simple/sparse.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. diff --git a/tests/simple/statistics.py b/tests/simple/statistics.py index 174af0a5b..0da72cb0c 100644 --- a/tests/simple/statistics.py +++ b/tests/simple/statistics.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ####################################################### -# Copyright (c) 2015, ArrayFire +# Copyright (c) 2019, ArrayFire # All rights reserved. # # This file is distributed under 3-clause BSD license. @@ -58,7 +58,7 @@ def simple_statistics(verbose=False): k = 3 dim = 0 order = af.TOPK.DEFAULT # defaults to af.TOPK.MAX - assert(dim == 0) # topk currently supports first dim only + assert dim == 0 # topk currently supports first dim only values, indices = af.topk(data, k, dim, order) display_func(values) display_func(indices)