├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── COPYING ├── LICENSE ├── README.MD ├── config.m4 ├── config.w32 ├── docs ├── index.md ├── internals │ ├── carray_api.md │ └── explanation.md └── routines │ ├── arithmetic.md │ ├── carray_object.md │ ├── decompositions.md │ ├── dimensions.md │ ├── distributions.md │ ├── eigenvalues.md │ ├── equations_and_inverse.md │ ├── exponents_loga.md │ ├── hyperbolic.md │ ├── indexing.md │ ├── ma_norms.md │ ├── ma_products.md │ ├── numerical_ranges.md │ ├── ones_and_zeros.md │ ├── random.md │ ├── rearranging.md │ ├── rounding.md │ ├── searching.md │ ├── sorting.md │ ├── statistics.md │ ├── sum_products_and_diff.md │ ├── transpose.md │ └── trigonometric.md ├── kernel ├── alloc.c ├── alloc.h ├── arraytypes.c ├── arraytypes.h ├── assign.c ├── assign.h ├── assign_scalar.c ├── assign_scalar.h ├── buffer.c ├── buffer.h ├── calculation.c ├── calculation.h ├── carray.c ├── carray.h ├── casting.c ├── casting.h ├── clip.c ├── clip.h ├── common │ ├── ca_extint128.h │ ├── cblas_funcs.c │ ├── cblas_funcs.h │ ├── clblas_funcs.c │ ├── clblas_funcs.h │ ├── common.c │ ├── common.h │ ├── compare.c │ ├── compare.h │ ├── exceptions.c │ ├── exceptions.h │ ├── matmul.c │ ├── matmul.h │ ├── mem_overlap.c │ ├── mem_overlap.h │ ├── partition.h │ ├── sort.c │ ├── sort.h │ ├── strided_loops.c │ └── strided_loops.h ├── conversion_utils.c ├── conversion_utils.h ├── convert.c ├── convert.h ├── convert_datatype.c ├── convert_datatype.h ├── convert_type.c ├── convert_type.h ├── ctors.c ├── ctors.h ├── descriptor.c ├── descriptor.h ├── dtype_transfer.c ├── dtype_transfer.h ├── exp_logs.c ├── exp_logs.h ├── flagsobject.c ├── flagsobject.h ├── getset.c ├── getset.h ├── gpu.c ├── gpu.h ├── include │ └── cpu.h ├── interfaces │ ├── rubix.c │ └── rubix.h ├── item_selection.c ├── item_selection.h ├── iterators.c ├── iterators.h ├── join.c ├── join.h ├── linalg.c ├── linalg.h ├── matlib.c ├── matlib.h ├── number.c ├── number.h ├── random.c ├── random.h ├── random │ ├── distributions.c │ └── distributions.h ├── range.c ├── range.h ├── round.c ├── round.h ├── scalar.c ├── scalar.h ├── search.c ├── search.h ├── shape.c ├── shape.h ├── simd.c ├── simd.h ├── statistics.c ├── statistics.h ├── storage.c ├── storage.h ├── trigonometric.c └── trigonometric.h ├── mkdocs.yml ├── phpsci.c ├── phpsci.h ├── tests ├── arithmetics │ ├── arithmetics_dd_1d_add.phpt │ ├── arithmetics_di_1d_add.phpt │ ├── arithmetics_id_1d_add.phpt │ ├── arithmetics_ii_1d_add.phpt │ ├── arithmetics_ii_2d_1d_add.phpt │ └── arithmetics_ii_2d_1d_add_broadcastexception.phpt └── initializers │ ├── linspace.basicadd.phpt │ └── linspace.basicdump.phpt └── travis └── compile.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # TEST 2 | test.php 3 | 4 | # EDITOR 5 | .idea 6 | .libs 7 | 8 | # COMPILER 9 | .lo 10 | autom4te.cache 11 | *.lo 12 | .o 13 | .la 14 | *.la 15 | *.o 16 | ./modules/ 17 | ./include/ 18 | ./build/ 19 | config.h 20 | config.h.in 21 | Makefile 22 | config.log 23 | config.nice 24 | config.status 25 | configure 26 | configure.ac 27 | libtool 28 | Makefile 29 | Makefile.fragments 30 | Makefile.objects 31 | run-tests.php 32 | vgcore.* 33 | config.h* 34 | build* 35 | *.so 36 | *.gch 37 | 38 | 39 | # OS 40 | .DS_Store 41 | .DS_Store? 42 | ._* 43 | .Spotlight-V100 44 | .Trashes 45 | Icon? 46 | ehthumbs.db 47 | Thumbs.db 48 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | sudo: false 3 | 4 | addons: 5 | apt: 6 | packages: 7 | - libopenblas-dev 8 | - liblapacke-dev 9 | 10 | php: 11 | - 7.0 12 | - 7.1 13 | - 7.2 14 | - 7.3 15 | - 7.4 16 | - nightly 17 | 18 | matrix: 19 | allow_failures: 20 | - php: nightly 21 | 22 | cache: 23 | apt: true 24 | ccache: true 25 | 26 | before_script: 27 | - ccache --version 28 | - ccache --zero-stats 29 | - export USE_CCACHE=1 30 | - phpize 31 | - ./configure 32 | - make 33 | - make install 34 | - echo "extension=carray.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini 35 | 36 | script: 37 | - REPORT_EXIT_STATUS=1 php ./run-tests.php -P -q --show-diff 38 | 39 | after_success: 40 | - ccache --show-stats -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(carray C) 3 | 4 | add_compile_definitions(HAVE_SKELETON) 5 | 6 | set(SOURCE_FILES phpsci phpsci.c 7 | kernel/interfaces/rubix.c 8 | kernel/common/clblas_funcs.c 9 | kernel/common/exceptions.c 10 | ) 11 | 12 | execute_process ( 13 | COMMAND php-config --include-dir 14 | OUTPUT_VARIABLE PHP_SOURCE 15 | ) 16 | string(REGEX REPLACE "\n$" "" PHP_SOURCE "${PHP_SOURCE}") 17 | 18 | message("Using source directory: ${PHP_SOURCE}") 19 | 20 | include_directories(${PHP_SOURCE}) 21 | include_directories(${PHP_SOURCE}/main) 22 | include_directories(${PHP_SOURCE}/Zend) 23 | include_directories(${PHP_SOURCE}/TSRM) 24 | include_directories(${PROJECT_SOURCE_DIR}) 25 | 26 | add_custom_target(configure 27 | COMMAND phpize && ./configure 28 | DEPENDS ${SOURCE_FILES} 29 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) 30 | 31 | add_library(___ EXCLUDE_FROM_ALL ${SOURCE_FILES}) -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright © 2005-2019, NumPy Developers. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 5 | following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, this list of conditions 8 | and the following disclaimer. 9 | 10 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 11 | following disclaimer in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the NumPy Developers nor the names of any contributors may be used to endorse or promote 14 | products derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, 17 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 22 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 - Henrique Borba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | PHPSci CArray Logo 2 | 3 | # PHPSci CArray Extension 4 | 5 | PHPSci CArray is a high-performance scientific computing library for PHP developed in C and based on the original NumPy code. CArrays offer a solid alternative to PHP arrays as well as compatibility with codes developed using NumPy. 6 | 7 | - High Performance Indexing and Data Access 8 | - Low memory footprint compared to PHP Arrays 9 | - Efficient shape, initializers, linear algebra and mathematical methods. 10 | - Out of the box GPU integration (Cuda) 11 | 12 | -------------------------------------------------------------------------------- 13 | 14 | ## Installing 15 | 16 | It's really easy to compile this extension using Linux environments. 17 | 18 | ### Requirements 19 | 20 | - php-devel (php-dev) 21 | - PHP 7.2 22 | - OpenBLAS 23 | 24 | ### Optional 25 | 26 | - cuBLAS (For GPU Integration) 27 | 28 | ### Ubuntu 20.04 29 | 30 | ```commandline 31 | $ sudo add-apt-repository -y ppa:ondrej/php 32 | $ sudo apt-get update 33 | $ sudo apt-get install libopenblas-dev libatlas-base-dev liblapacke-dev php7.4-dev 34 | $ phpize 35 | $ ./configure 36 | $ make test 37 | $ sudo make install 38 | $ echo 'extension=carray' | sudo tee /etc/php/7.4/cli/conf.d/20-carray.ini 39 | $ echo 'extension=carray' | sudo tee /etc/php/7.4/fpm/conf.d/20-carray.ini 40 | $ echo 'extension=carray' | sudo tee /etc/php/7.4/cgi/conf.d/20-carray.ini 41 | $ echo 'extension=carray' | sudo tee /etc/php/7.4/apache2/conf.d/20-carray.ini 42 | ``` 43 | 44 | ### Ubuntu 16.04 45 | 46 | ```commandline 47 | $ add-apt-repository -y ppa:ondrej/php 48 | $ apt-get update 49 | $ apt-get install libblas-dev libatlas-base-dev liblapacke-dev php7.2-dev 50 | $ phpize 51 | $ ./configure 52 | $ make test 53 | $ make install 54 | ``` 55 | 56 | ### Ubuntu 14.04 57 | 58 | ```commandline 59 | $ add-apt-repository -y ppa:ondrej/php 60 | $ apt-get update 61 | $ apt-get install libopenblas-dev liblapacke-dev php7.2-dev 62 | $ phpize 63 | $ ./configure 64 | $ make test 65 | $ make install 66 | ``` 67 | 68 | > Don't forget to check if the extension is enabled in your php.ini file. 69 | 70 | > **Apache/NGINX Users:** Don't forget to restart your services. 71 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | PHP_ARG_WITH(carray, whether to enable CArray computing library, 2 | [ --with-carray Disable CArray computing library], yes) 3 | 4 | PHP_ARG_ENABLE(avx2, whether to enable AVX2 support, 5 | [ --enable-avx2 whether to enable AVX2 support], no, no) 6 | 7 | PHP_ARG_ENABLE(opencl, whether to enable OpenCL support, 8 | [ --enable-opencl whether to enable OpenCL support], no, no) 9 | 10 | if test "$PHP_CARRAY" != "no"; then 11 | AC_DEFINE([HAVE_CARRAY],1 ,[whether to enable CArray computing library]) 12 | 13 | AC_CHECK_HEADERS( 14 | [/opt/OpenBLAS/include/lapacke.h], 15 | [ 16 | PHP_ADD_INCLUDE(/opt/OpenBLAS/include/) 17 | ], 18 | , 19 | [[#include "/opt/OpenBLAS/include/lapacke.h"]] 20 | ) 21 | AC_CHECK_HEADERS( 22 | [/usr/include/openblas/lapacke.h], 23 | [ 24 | PHP_ADD_INCLUDE(/usr/include/openblas/) 25 | ], 26 | , 27 | [[#include "/usr/include/openblas/lapacke.h"]] 28 | ) 29 | AC_CHECK_HEADERS( 30 | [/usr/include/lapacke.h], 31 | [ 32 | PHP_ADD_INCLUDE(/usr/include/) 33 | ], 34 | , 35 | [[#include "/usr/include/lapacke.h"]] 36 | ) 37 | 38 | 39 | AC_CHECK_HEADERS( 40 | [/opt/OpenBLAS/include/cblas.h], 41 | [ 42 | PHP_ADD_INCLUDE(/opt/OpenBLAS/include/) 43 | ], 44 | , 45 | [[#include "/opt/OpenBLAS/include/cblas.h"]] 46 | ) 47 | AC_CHECK_HEADERS( 48 | [/usr/include/cblas.h], 49 | [ 50 | PHP_ADD_INCLUDE(/usr/include/) 51 | ], 52 | , 53 | [[#include "/usr/include/cblas.h"]] 54 | ) 55 | AC_CHECK_HEADERS( 56 | [/usr/include/atlas/cblas.h], 57 | [ 58 | PHP_ADD_INCLUDE(/usr/include/atlas/) 59 | ], 60 | , 61 | [[#include "/usr/include/atlas/cblas.h"]] 62 | ) 63 | AC_CHECK_HEADERS( 64 | [/usr/include/openblas/cblas.h], 65 | [ 66 | PHP_ADD_INCLUDE(/usr/include/openblas/) 67 | ], 68 | , 69 | [[#include "/usr/include/openblas/cblas.h"]] 70 | ) 71 | 72 | 73 | AC_CHECK_HEADERS( 74 | [/usr/include/clBLAS.h], 75 | [ 76 | PHP_ADD_INCLUDE(/usr/include/) 77 | ], 78 | , 79 | [[#include "/usr/include/clBLAS.h"]] 80 | ) 81 | 82 | if test "$PHP_OPENCL" != "no"; then 83 | PHP_CHECK_LIBRARY(clBLAS,clblasSgemm, 84 | [ 85 | PHP_ADD_LIBRARY(clBLAS,,CARRAY_SHARED_LIBADD) 86 | AC_DEFINE(HAVE_CLBLAS,1,[Have CLBLAS support]) 87 | 88 | PHP_CHECK_LIBRARY(OpenCL,clGetPlatformIDs, 89 | [ 90 | PHP_ADD_LIBRARY(OpenCL,,CARRAY_SHARED_LIBADD) 91 | AC_DEFINE(HAVE_OPENCL,1,[Have OpenCL support]) 92 | AC_MSG_RESULT([OpenCL detected ]) 93 | ],[ 94 | AC_MSG_WARN([OpenCL not detected (OpenCL BLAS not available).]) 95 | ],[ 96 | -lOpenCL 97 | ]) 98 | ],[ 99 | AC_MSG_RESULT([clBLAS not detected (OpenCL BLAS not available).]) 100 | ],[ 101 | -LclBLAS 102 | ]) 103 | fi 104 | 105 | if test "$PHP_AVX2" != "no"; then 106 | AC_CHECK_HEADER([immintrin.h], 107 | [ 108 | AC_DEFINE(CARRAY_HAVE_AVX2,1,[Have AV2/SSE support]) 109 | AC_MSG_RESULT([AVX2/SSE detected ]) 110 | CFLAGS+=" -mavx2 " 111 | ],[ 112 | AC_DEFINE(CARRAY_HAVE_AVX2,0,[Have AV2/SSE support]) 113 | AC_MSG_RESULT([AVX2/SSE not found ]) 114 | ], [ 115 | 116 | ] 117 | ) 118 | fi 119 | 120 | PHP_CHECK_LIBRARY(cblas,cblas_sdot, 121 | [ 122 | AC_DEFINE(HAVE_CBLAS,1,[ ]) 123 | AC_DEFINE(HAVE_BLAS,1,[ ]) 124 | PHP_ADD_LIBRARY(cblas,,CARRAY_SHARED_LIBADD) 125 | AC_MSG_RESULT([CBlas detected ]) 126 | ],[ 127 | PHP_CHECK_LIBRARY(openblas,cblas_sdot, 128 | [ 129 | PHP_ADD_LIBRARY(openblas,,CARRAY_SHARED_LIBADD) 130 | AC_MSG_RESULT([OpenBLAS detected ]) 131 | AC_DEFINE(HAVE_BLAS,1,[ ]) 132 | ],[ 133 | AC_MSG_RESULT([wrong openblas/blas version or library not found.]) 134 | ],[ 135 | -lopenblas 136 | ]) 137 | ],[ 138 | -lcblas 139 | ]) 140 | 141 | PHP_CHECK_LIBRARY(lapacke,LAPACKE_sgetrf, 142 | [ 143 | AC_DEFINE(HAVE_LAPACKE,1,[ ]) 144 | PHP_ADD_LIBRARY(lapacke,,CARRAY_SHARED_LIBADD) 145 | ],[ 146 | AC_MSG_RESULT([wrong lapacke version or library not found]) 147 | ],[ 148 | -llapacke 149 | ]) 150 | 151 | PHP_CHECK_LIBRARY(omp,omp_get_num_threads, 152 | [ 153 | AC_DEFINE(HAVE_OMP,1,[ ]) 154 | AC_MSG_RESULT([OpenMP found]) 155 | PHP_ADD_LIBRARY(omp,,CARRAY_SHARED_LIBADD) 156 | ],[ 157 | AC_MSG_RESULT([OpenMP not found]) 158 | ],[ 159 | -fopenmp 160 | ]) 161 | 162 | PHP_NEW_EXTENSION(carray, 163 | phpsci.c \ 164 | kernel/alloc.c \ 165 | kernel/carray.c \ 166 | kernel/iterators.c \ 167 | kernel/flagsobject.c \ 168 | kernel/assign.c \ 169 | kernel/convert.c \ 170 | kernel/casting.c \ 171 | kernel/linalg.c \ 172 | kernel/calculation.c \ 173 | kernel/shape.c \ 174 | kernel/common/common.c \ 175 | kernel/common/cblas_funcs.c \ 176 | kernel/common/clblas_funcs.c \ 177 | kernel/common/mem_overlap.c \ 178 | kernel/number.c \ 179 | kernel/convert_type.c \ 180 | kernel/trigonometric.c \ 181 | kernel/matlib.c \ 182 | kernel/statistics.c \ 183 | kernel/arraytypes.c \ 184 | kernel/join.c \ 185 | kernel/ctors.c \ 186 | kernel/simd.c \ 187 | kernel/scalar.c \ 188 | kernel/round.c \ 189 | kernel/getset.c \ 190 | kernel/common/strided_loops.c \ 191 | kernel/convert_datatype.c \ 192 | kernel/dtype_transfer.c \ 193 | kernel/assign_scalar.c \ 194 | kernel/gpu.c \ 195 | kernel/common/exceptions.c \ 196 | kernel/item_selection.c \ 197 | kernel/clip.c \ 198 | kernel/search.c \ 199 | kernel/common/sort.c \ 200 | kernel/interfaces/rubix.c \ 201 | kernel/common/compare.c \ 202 | kernel/exp_logs.c \ 203 | kernel/random.c \ 204 | kernel/storage.c \ 205 | kernel/range.c \ 206 | kernel/random/distributions.c \ 207 | kernel/conversion_utils.c \ 208 | kernel/buffer.c , 209 | $ext_shared) 210 | PHP_INSTALL_HEADERS([ext/carray], [phpsci.h, kernel/carray.h, kernel/types.h, kernel/buffer.h]) 211 | PHP_SUBST(CARRAY_SHARED_LIBADD) 212 | fi 213 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | ARG_ENABLE("carray", "enable carray", "no"); 2 | 3 | 4 | if (PHP_CARRAY != "no") { 5 | if (!CHECK_LIB("libopenblas_a.lib", "carray", PHP_PHP_BUILD + "\\libs")) { 6 | ERROR("Unable to find libopenblas.lib"); 7 | } 8 | if (CHECK_LIB("libopenblas_a.lib", "carray", PHP_PHP_BUILD + "\\libs") && 9 | CHECK_HEADER_ADD_INCLUDE("cblas.h", "CFLAGS_OPENBLAS", PHP_PHP_BUILD + "\\include") && 10 | CHECK_HEADER_ADD_INCLUDE("lapacke.h", "CFLAGS_LAPACKE", PHP_PHP_BUILD + "\\include")) { 11 | EXTENSION("carray", "phpsci.c", PHP_CARRAY_SHARED, "-I"+configure_module_dirname); 12 | ADD_SOURCES(configure_module_dirname + "/kernel", 13 | "exceptions.c" 14 | , "carray"); 15 | ADD_SOURCES(configure_module_dirname + "/kernel/carray", 16 | "carray.c tuple.c" 17 | , "carray"); 18 | ADD_SOURCES(configure_module_dirname + "/kernel/carray/utils", 19 | "carray_printer.c" 20 | , "carray"); 21 | ADD_SOURCES(configure_module_dirname + "/kernel/memory_pointer", 22 | "memory_pointer.c utils.c" 23 | , "carray"); 24 | ADD_SOURCES(configure_module_dirname + "/kernel/buffer", 25 | "memory_manager.c" 26 | , "carray"); 27 | ADD_SOURCES(configure_module_dirname + "/kernel/php", 28 | "php_array.c" 29 | , "carray"); 30 | ADD_SOURCES(configure_module_dirname + "/operations", 31 | "initializers.c linalg.c ranges.c basic_operations.c random.c arithmetic.c exponents.c logarithms.c trigonometric.c hyperbolic.c transformations.c magic_properties.c" 32 | , "carray"); 33 | ADD_SOURCES(configure_module_dirname + "/operations/linalg", 34 | "norms.c others.c eigenvalues.c equations.c" 35 | , "carray"); 36 | 37 | } else { 38 | ERROR( "OpenBlas not found! " ); 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # PHPSci CArray Extension 2 | 3 |

4 | 5 |

6 | 7 | PHPSci CArray is a high-performance scientific computing library for PHP developed in C and based on the original NumPy code. CArrays offer a solid alternative to PHP arrays as well as compatibility with codes developed using NumPy. 8 | 9 | - High Performance Indexing and Data Access 10 | - Low memory footprint compared to PHP Arrays 11 | - Efficient shape, initializers, linear algebra and mathematical methods. 12 | - Out of the box GPU integration (Cuda) 13 | 14 | --- 15 | 16 | ## Installing 17 | 18 | It's really easy to compile this extension using Linux environments. 19 | 20 | #### Requirements 21 | 22 | - php-devel (php-dev) 23 | - PHP 7.2 24 | - OpenBLAS 25 | 26 | #### Optional 27 | - cuBLAS (For GPU Integration) 28 | 29 | #### Ubuntu 16.04 30 | ```commandline 31 | $ add-apt-repository -y ppa:ondrej/php 32 | $ apt-get update 33 | $ apt-get install libblas-dev libatlas-base-dev php7.2-dev 34 | $ phpize 35 | $ ./configure 36 | $ make test 37 | $ make install 38 | ``` 39 | #### Ubuntu 14.04 40 | ```commandline 41 | $ add-apt-repository -y ppa:ondrej/php 42 | $ apt-get update 43 | $ apt-get install libopenblas-dev liblapacke-dev php7.2-dev 44 | $ phpize 45 | $ ./configure 46 | $ make test 47 | $ make install 48 | ``` 49 | 50 | > Don't forget to check if the extension is enabled in your php.ini file. 51 | 52 | > **Apache/NGINX Users:** Don't forget to restart your services. 53 | -------------------------------------------------------------------------------- /docs/internals/carray_api.md: -------------------------------------------------------------------------------- 1 | # CArray Internals C Reference 2 | 3 | ## Memory Stack 4 | 5 | The `MemoryStack` struct is a global buffer containing a set of `CArray` pointers. The global buffer 6 | can be accessed calling `PHPSCI_MAIN_MEM_STACK`. 7 | 8 | ```C 9 | struct MemoryStack { 10 | CArray * buffer; 11 | int size; 12 | int capacity; 13 | size_t bsize; 14 | } MemoryStack; 15 | ``` 16 | 17 | > #### `CArray *` MemoryStack.buffer 18 | > Dynamic allocated buffer containing all instances of **CArray** during runtime. 19 | 20 | > #### `int` MemoryStack.size 21 | > The number of CArray instances stored within the buffer. 22 | 23 | > #### `int` MemoryStack.capacity 24 | > The maximum capacity of the buffer. When **size** is equal **capacity** the buffer will be reallocated. 25 | 26 | > #### `size_t` MemoryStack.bsize 27 | > The current amount of bytes allocated within **buffer**. 28 | 29 | ## Memory Pointer 30 | 31 | The PHP interpreter performs operations using the MemoryPointer structure. This object contains the 32 | necessary information to relate the current PHP `zval` object with an instance of `CArray`. 33 | 34 | ```C 35 | typedef struct MemoryPointer { 36 | int uuid; 37 | } MemoryPointer; 38 | ``` 39 | 40 | > #### `int` MemoryPointer.uuid 41 | > Contains the `uuid` of the related CArray instance within the buffer. Ex: If `uuid`is 0, the CArray instance allocated within `MemoryStack.buffer[0]` is used. 42 | 43 | ## CArray Structure 44 | 45 | The `CArray` object contains all information required for our array. It keep track of the data buffer, and 46 | other array properties like strides, dimensions and so on. All instances of `CArray` within PHP points 47 | to this structure. 48 | 49 | ```C 50 | struct CArray { 51 | int * strides; 52 | int * dimensions; 53 | int ndim; 54 | char * data; 55 | CArray * base; 56 | int flags; 57 | CArrayDescriptor * descriptor; 58 | int refcount; 59 | }; 60 | ``` 61 | 62 | > #### `int *` CArray.strides 63 | > An vector of integers containing the amount of bytes that must be skipped to get to the next element of that dimension. 64 | 65 | > #### `int *` CArray.dimensions 66 | > An vector of integers containing the amount of elements within each dimension. This could be seen as the shape of this array. 67 | 68 | > #### `int` CArray.ndim 69 | > Integer describing the number of dimensions. 70 | 71 | > #### `char *` CArray.data 72 | > The pointer to the first element of this array 73 | 74 | > #### `CArray *` CArray.base 75 | > Points to the CArray containing the original data. This is useful when one CArray shares the same data 76 | with other (CArray Views). 77 | 78 | > #### `int` CArray.flags 79 | > Some properties are stored as flags. For example, if one CArray contains data from other CArray, them it won't have `CARRAY_ARRAY_OWNDATA` flag. 80 | 81 | > #### `CArrayDescriptor *` CArray.descriptor 82 | > Describes the memory layout and data properties of the CArray. One descriptor may be shared with multiples CArrays. 83 | 84 | > #### `int` CArray.refcount 85 | > CArray reference count. The reference count prevents PHP Gargage Collector from free shared data buffer across different CArray objects. 86 | 87 | 88 | ### CArrayDescriptor 89 | This structure describes the CArray memory layout and data type. CArrayDescriptor can be used for 90 | CArray initialization. 91 | 92 | ```C 93 | typedef struct CArrayDescriptor { 94 | char type; // b = boolean, d = double, i = signer integer, u = unsigned integer, f = floating point, c = char 95 | int flags; // Data related flags 96 | int type_num; // 0 = boolean, 1 = double, 2 = signed integer, 3 = unsigned integer, 4 = floating point, 5 = char 97 | int elsize; // Datatype size 98 | int numElements; // Number of elements 99 | int alignment; // Alignment Information 100 | int refcount; 101 | } CArrayDescriptor; 102 | ``` 103 | 104 | ## Creating CArrays 105 | 106 | 107 | #### `CArray *` CArray_NewFromDescr_int 108 | ```C 109 | CArray * CArray_NewFromDescr_int(CArray * self, CArrayDescriptor *descr, int nd, int *dims, int *strides, void *data, int flags, CArray *base, int zeroed, int allow_emptystring); 110 | ``` 111 | #### `CArray *` CArray_NewLikeArray 112 | ```C 113 | CArray * CArray_NewLikeArray(CArray *prototype, CARRAY_ORDER order, CArrayDescriptor *dtype, int subok); 114 | ``` 115 | 116 | ## CArray Iterators -------------------------------------------------------------------------------- /docs/internals/explanation.md: -------------------------------------------------------------------------------- 1 | # CArray Internals Explained 2 | 3 | ## Memory Layout 4 | 5 | CArrays are contiguous C arrays direct accessed and stored by the PHP interpreter. 6 | 7 | ```PHP 8 | $array_1d = new CArray([2, 3, 4, 5, 6, 7]); 9 | $array_2d = new CArray([[2, 3], [4, 5], [6, 7]]); 10 | $array_3d = new CArray([[[2, 3], [4, 5], [6, 7]]]); 11 | ``` 12 | 13 | In the example above, we allocated 3 `CArrays` with the following shapes `[6]`, `[3, 2]` and `[1, 3, 2]`. As all CArrays are contiguous allocated, the C memory layout for all the CArrays above is the same: 14 | 15 | ```C 16 | int * buffer = {2, 3, 4, 5, 6, 7} 17 | ``` 18 | 19 | The extension only knows where to look for your values because it has the dimensions and strides information for each CArray above. This is specially fast if we want to change our CArray shapes 20 | without loop (iterate) over the values. 21 | 22 | ## Data Access 23 | 24 | CArrays are internaly accessed using strides. The strides gives the amount of bytes to jump within 25 | our buffer to find next value for the Nth-dimension. 26 | 27 | ```PHP 28 | $array = new CArray([[[2, 3], [4, 5], [6, 7]], [[2, 3], [4, 5], [6, 7]]]); 29 | ``` 30 | 31 | The shape for this array is `[2, 3, 2]` and the type is `int`. Considering `int` as a 4 bytes type 32 | we have the following generated strides vector: `[24, 8 ,4]`. So for each value of the first dimension we jump 24 bytes, the second 2D matrix within this 3D tensor starts at index 6 `(24 bytes / 4 bytes)`. 33 | 34 | ```C 35 | int * buffer = {2, 3, 4, 5, 6, 7, -> 2, 3, 4, 5, 6, 7} 36 | ``` 37 | 38 | We jump two more indices `8 bytes / 4 bytes` so we get to the second row of the second internal matrice `[1, 1, 0]` 39 | 40 | ```C 41 | int * buffer = {2, 3, 4, 5, 6, 7, 2, 3, -> 4, 5, 6, 7} 42 | ``` 43 | 44 | -------------------------------------------------------------------------------- /docs/routines/arithmetic.md: -------------------------------------------------------------------------------- 1 | # Arithmetic Routines 2 | 3 | --- 4 | 5 | ## add 6 | ```php 7 | public static add($x1, $x2) : CArray 8 | ``` 9 | > Add arguments element-wise. 10 | 11 | ##### Parameters 12 | 13 | `CArray|Array` **$x1** **$x2** Input arrays. 14 | 15 | ##### Returns 16 | 17 | `CArray` The sum of `$x1` and `$x2`, element-wise. 18 | 19 | ##### Examples 20 | 21 | **Example 1** 22 | ```php 23 | $x1 = CArray::arange(9.0); 24 | $x1 = CArray::reshape($x1, [3, 3]); 25 | $x2 = CArray::arange(3.0); 26 | 27 | echo CArray::add($x1, $x2); 28 | ``` 29 | ``` 30 | [[ 0 2 4 ] 31 | [ 3 5 7 ] 32 | [ 6 8 10 ]] 33 | ``` 34 | 35 | **Example 2** 36 | ```php 37 | $a = new CArray([[1, 2], [3, 4]]); 38 | $b = new CArray([[5, 6], [7, 8]]); 39 | 40 | $c = $a + $b; // Same as CArray::add 41 | 42 | echo $c; 43 | ``` 44 | ``` 45 | [[ 6 8 ] 46 | [ 10 12 ]] 47 | ``` 48 | 49 | --- 50 | 51 | ## subtract 52 | ```php 53 | public static subtract($x1, $x2) : CArray 54 | ``` 55 | > Subtract arguments element-wise. 56 | 57 | ##### Parameters 58 | 59 | `CArray|Array` **$x1** **$x2** Input arrays. 60 | 61 | ##### Returns 62 | 63 | `CArray` The difference of `$x1` and `$x2`, element-wise. 64 | 65 | ##### Examples 66 | 67 | **Example 1** 68 | ```php 69 | $x1 = CArray::arange(9.0); 70 | $x1 = CArray::reshape($x1, [3, 3]); 71 | $x2 = CArray::arange(3.0); 72 | echo CArray::subtract($x1, $x2); 73 | ``` 74 | ``` 75 | [[ 0 0 0 ] 76 | [ 3 3 3 ] 77 | [ 6 6 6 ]] 78 | ``` 79 | 80 | **Example 2** 81 | ```php 82 | $x1 = CArray::arange(9.0); 83 | $x1 = CArray::reshape($x1, [3, 3]); 84 | $x2 = CArray::arange(3.0); 85 | echo ($x1 - $x2); 86 | ``` 87 | ``` 88 | [[ 0 0 0 ] 89 | [ 3 3 3 ] 90 | [ 6 6 6 ]] 91 | ``` 92 | 93 | --- 94 | 95 | ## multiply 96 | ```php 97 | public static multiply($x1, $x2) : CArray 98 | ``` 99 | > Multiply arguments element-wise. 100 | 101 | ##### Parameters 102 | 103 | `CArray|Array` **$x1** **$x2** Input arrays. 104 | 105 | ##### Returns 106 | 107 | `CArray` The multiplication of `$x1` and `$x2`, element-wise. 108 | 109 | ##### Examples 110 | 111 | **Example 1** 112 | ```php 113 | $x1 = CArray::arange(9.0); 114 | $x1 = CArray::reshape($x1, [3, 3]); 115 | $x2 = CArray::arange(3.0); 116 | echo CArray::multiply($x1, $x2); 117 | ``` 118 | ``` 119 | [[ 0 1 4 ] 120 | [ 0 4 10 ] 121 | [ 0 7 16 ]] 122 | ``` 123 | 124 | **Example 2** 125 | ```php 126 | $x1 = CArray::arange(9.0); 127 | $x1 = CArray::reshape($x1, [3, 3]); 128 | $x2 = CArray::arange(3.0); 129 | echo ($x1 * $x2); 130 | ``` 131 | ``` 132 | [[ 0 1 4 ] 133 | [ 0 4 10 ] 134 | [ 0 7 16 ]] 135 | ``` 136 | 137 | --- 138 | 139 | ## divide 140 | ```php 141 | public static divide($x1, $x2) : CArray 142 | ``` 143 | > Returns a true division of the inputs, element-wise. 144 | 145 | ##### Parameters 146 | 147 | `CArray|Array` **$x1** Dividend 148 | 149 | `CArray|Array` **$x2** Divisor 150 | 151 | ##### Returns 152 | 153 | `CArray` Return array. 154 | 155 | ##### Examples 156 | 157 | **Example 1** 158 | ```php 159 | echo CArray::divide([1, 2, 3, 4, 5], 4); 160 | ``` 161 | ``` 162 | [ 0.25000000 0.50000000 0.75000000 1.00000000 1.25000000 ] 163 | ``` 164 | 165 | **Example 2** 166 | ```php 167 | $a = new CArray([[1, 2], [3, 4]]); 168 | echo ($a / 4); 169 | ``` 170 | ``` 171 | [[ 0.25000000 0.50000000 ] 172 | [ 0.75000000 1.00000000 ]] 173 | ``` 174 | 175 | --- 176 | 177 | ## power 178 | ```php 179 | public static power($x1, $x2) : CArray 180 | ``` 181 | > `$x1` array elements raised to powers from `$x2` array, element-wise. 182 | 183 | ##### Parameters 184 | 185 | `CArray|Array` **$x1** Bases 186 | 187 | `CArray|Array` **$x2** Exponents 188 | 189 | ##### Returns 190 | 191 | `CArray` The bases in `$x1` raised to the exponents in `$x2`. 192 | 193 | ##### Examples 194 | 195 | **Example 1** 196 | ```php 197 | $x1 = CArray::arange(6); 198 | echo CArray::power($x1, 3); 199 | ``` 200 | ``` 201 | [ 0 1 8 27 64 125 ] 202 | ``` 203 | 204 | --- 205 | 206 | ## mod 207 | ```php 208 | public static mod($x1, $x2) : CArray 209 | ``` 210 | > Return element-wise remainder of division. 211 | 212 | ##### Parameters 213 | 214 | `CArray|Array` **$x1** Dividend 215 | 216 | `CArray|Array` **$x2** Divisor 217 | 218 | ##### Returns 219 | 220 | `CArray` The element-wise remainder 221 | 222 | ##### Examples 223 | 224 | **Example 1** 225 | ```php 226 | echo CArray::mod([4, 7], [2, 3]); 227 | ``` 228 | ``` 229 | [ 0. 1. ] 230 | ``` 231 | 232 | --- 233 | 234 | ## remainder 235 | ```php 236 | public static remainder($x1, $x2) : CArray 237 | ``` 238 | > Return element-wise remainder of division. 239 | 240 | ##### Parameters 241 | 242 | `CArray|Array` **$x1** Dividend 243 | 244 | `CArray|Array` **$x2** Divisor 245 | 246 | ##### Returns 247 | 248 | `CArray` The element-wise remainder 249 | 250 | ##### Examples 251 | 252 | **Example 1** 253 | ```php 254 | echo CArray::remainder([4, 7], [2, 3]); 255 | ``` 256 | ``` 257 | [ 0. 1. ] 258 | ``` 259 | 260 | --- 261 | 262 | ## negative 263 | ```php 264 | public static negative($x) : CArray 265 | ``` 266 | > Numerical negative, element-wise. 267 | 268 | ##### Parameters 269 | 270 | `CArray|Array` **$x** Input array. 271 | 272 | ##### Returns 273 | 274 | `CArray` Return array. 275 | 276 | ##### Examples 277 | 278 | **Example 1** 279 | ```php 280 | echo CArray::negative([1, -1]); 281 | ``` 282 | ``` 283 | [ -1. 1. ] 284 | ``` 285 | 286 | 287 | --- 288 | 289 | ## sqrt 290 | ```php 291 | public static sqrt($x) : CArray 292 | ``` 293 | 294 | --- 295 | 296 | ## reciprocal 297 | ```php 298 | public static reciprocal($x) : CArray 299 | ``` 300 | > Return `1/$x` of the argument, element-wise. 301 | 302 | ##### Parameters 303 | 304 | `CArray|Array` **$x** Input array. 305 | 306 | ##### Returns 307 | 308 | `CArray` Return array. 309 | 310 | ##### Examples 311 | 312 | **Example 1** 313 | ```php 314 | echo CArray::reciprocal([1, 2., 3.33]); 315 | ``` 316 | ``` 317 | [ 1.00000000 0.50000000 0.33333333 ] 318 | ``` 319 | 320 | 321 | 322 | 323 | -------------------------------------------------------------------------------- /docs/routines/carray_object.md: -------------------------------------------------------------------------------- 1 | # CArray Object 2 | 3 | --- 4 | 5 | ## fill 6 | ```php 7 | public fill($val) 8 | ``` 9 | > Fill the array with a scalar value. 10 | > 11 | ##### Parameters 12 | 13 | `int|double|float` **$val** All elements of the CArray will be assigned this value. -------------------------------------------------------------------------------- /docs/routines/decompositions.md: -------------------------------------------------------------------------------- 1 | # Decomposition Routines 2 | 3 | --- 4 | 5 | ## svd 6 | ```php 7 | public static svd($a) : CArray 8 | ``` 9 | > Singular Value Decomposition. 10 | 11 | ##### Parameters 12 | 13 | `CArray|Array` **$a** 2-D Input array. 14 | 15 | ##### Returns 16 | 17 | `Array` Array of CArrays containing the unitary arrays ([0] and [2]) and singular values ([1]). 18 | 19 | ##### Examples 20 | 21 | **Example 1** 22 | ```php 23 | $a = new CArray([[1, 4], [5, 6]]); 24 | $b = CArray::svd($a); 25 | 26 | 27 | print_r($b); 28 | echo "\nUNITARY ARRAYS\n"; 29 | echo $b[0]; 30 | echo "\nSINGULAR VALUES\n"; 31 | echo $b[1]; 32 | echo "\nUNITARY ARRAYS\n"; 33 | echo $b[2]; 34 | ``` 35 | ``` 36 | Array 37 | ( 38 | [0] => CArray Object 39 | ( 40 | [uuid] => 1 41 | [ndim] => 2 42 | ) 43 | 44 | [1] => CArray Object 45 | ( 46 | [uuid] => 2 47 | [ndim] => 1 48 | ) 49 | 50 | [2] => CArray Object 51 | ( 52 | [uuid] => 3 53 | [ndim] => 2 54 | ) 55 | 56 | ) 57 | 58 | UNITARY ARRAYS 59 | [[ -0.44475472 -0.89565241 ] 60 | [ -0.89565241 0.44475472 ]] 61 | 62 | SINGULAR VALUES 63 | [ 8.68334898 1.61228116 ] 64 | 65 | UNITARY ARRAYS 66 | [[ -0.56694909 -0.82375283 ] 67 | [ 0.82375283 -0.56694909 ]] 68 | ``` -------------------------------------------------------------------------------- /docs/routines/dimensions.md: -------------------------------------------------------------------------------- 1 | # Dimensions Routines 2 | 3 | --- 4 | 5 | ## atleast_1d 6 | ```php 7 | public static atleast_1d($a ...) : CArray | Array 8 | ``` 9 | > Convert inputs to arrays with at least one dimension. 10 | > Scalar inputs are converted to 1-dimensional arrays, whilst higher-dimensional inputs are preserved. 11 | 12 | ##### Parameters 13 | 14 | `CArray|Array` **$a ...** One or more input arrays. 15 | 16 | ##### Returns 17 | 18 | `CArray|Array` An CArray, or array of CArrays, each with NDIM >= 1. Copies are made only if necessary. 19 | 20 | --- 21 | 22 | ## atleast_2d 23 | 24 | ```php 25 | public static atleast_2d($a ...) : CArray | Array 26 | ``` 27 | > Convert inputs to arrays with at least two dimensions. 28 | 29 | ##### Parameters 30 | 31 | `CArray|Array` **$a ...** One or more input arrays. 32 | 33 | ##### Returns 34 | 35 | `CArray|Array` An CArray, or array of CArrays, each with NDIM >= 2. Copies are made only if necessary. 36 | 37 | --- 38 | 39 | ## atleast_3d 40 | 41 | ```php 42 | public static atleast_3d($a ...) : CArray | Array 43 | ``` 44 | > Convert inputs to arrays with at least three dimensions. 45 | 46 | ##### Parameters 47 | 48 | `CArray|Array` **$a ...** One or more input arrays. 49 | 50 | ##### Returns 51 | 52 | `CArray|Array` An CArray, or array of CArrays, each with NDIM >= 3. Copies are made only if necessary. 53 | 54 | --- 55 | 56 | ## squeeze 57 | 58 | ```php 59 | public static squeeze($a, $axis = NULL) : CArray 60 | ``` 61 | > Remove single-dimensional entries from the shape of an array. 62 | 63 | ##### Parameters 64 | 65 | `CArray|Array` **$a** Input data. 66 | 67 | `int` **$axis** Selects a subset of the single-dimensional entries in the shape. 68 | 69 | ##### Returns 70 | 71 | `CArray` The input array, but with all or a subset of the dimensions of length 1 removed. This is always a itself or a view into `$a`. 72 | 73 | --- 74 | 75 | ## expand_dims 76 | 77 | ```php 78 | public static expand_dims($a, $axis = NULL) : CArray 79 | ``` 80 | > Expand the shape of an array. 81 | 82 | > Insert a new axis that will appear at the `$axis` position in the expanded array shape. 83 | 84 | ##### Parameters 85 | 86 | `CArray|Array` **$a** Input data. 87 | 88 | `int` **$axis** Position in the expanded axes where the new axis is placed. 89 | 90 | ##### Returns 91 | 92 | `CArray` **View** of `$a` with the number of dimensions increased by one. 93 | -------------------------------------------------------------------------------- /docs/routines/distributions.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phpsci/phpsci-carray/192a92213200a80006793c932eb0effef1d24b8e/docs/routines/distributions.md -------------------------------------------------------------------------------- /docs/routines/eigenvalues.md: -------------------------------------------------------------------------------- 1 | ## eig 2 | 3 | ## eigh 4 | 5 | ## eigvals 6 | 7 | ## eigvalsh 8 | 9 | -------------------------------------------------------------------------------- /docs/routines/equations_and_inverse.md: -------------------------------------------------------------------------------- 1 | # Equations & Inverse Routines 2 | 3 | --- 4 | 5 | ## inv 6 | ```php 7 | public static inv($a) : CArray 8 | ``` 9 | > Compute the (multiplicative) inverse of a matrix. 10 | 11 | ##### Parameters 12 | 13 | `CArray|Array` **$a** Input array. 14 | 15 | ##### Returns 16 | 17 | `CArray` (Multiplicative) inverse of the matrix `$a`. 18 | 19 | ##### Examples 20 | 21 | **Example 1** 22 | ```php 23 | $a = new CArray([[1., 2.], [3., 4.]]); 24 | echo CArray::inv($a); 25 | ``` 26 | ``` 27 | [[ -2.00000000 1.00000000 ] 28 | [ 1.50000000 -0.50000000 ]] 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/routines/exponents_loga.md: -------------------------------------------------------------------------------- 1 | # Exponents and logarithms Routines 2 | 3 | --- 4 | 5 | ## exp 6 | ```php 7 | public static exp($x) : CArray 8 | ``` 9 | > Calculate the exponential of all elements. 10 | 11 | ##### Parameters 12 | 13 | `CArray|Array` **$x** Input array. 14 | 15 | ##### Returns 16 | 17 | `CArray` Output array, element-wise exponential of `$x`. 18 | 19 | --- 20 | 21 | ## expm1 22 | ```php 23 | public static expm1($x) : CArray 24 | ``` 25 | > Calculate `exp($x) - 1` for all elements in the array. 26 | 27 | ##### Parameters 28 | 29 | `CArray|Array` **$x** Input array. 30 | 31 | ##### Returns 32 | 33 | `CArray` Output array, element-wise `exp($x)-1` of `$x`. 34 | 35 | --- 36 | 37 | ## exp2 38 | ```php 39 | public static exp2($x) : CArray 40 | ``` 41 | > Calculate `2**p` for all `p` (value) in the input array. 42 | 43 | ##### Parameters 44 | 45 | `CArray|Array` **$x** Input array. 46 | 47 | ##### Returns 48 | 49 | `CArray` Output array, element-wise `2**p` of `$x`. 50 | 51 | --- 52 | 53 | ## log 54 | ```php 55 | public static log($x) : CArray 56 | ``` 57 | > Natural logarithm, element-wise. 58 | 59 | ##### Parameters 60 | 61 | `CArray|Array` **$x** Input array. 62 | 63 | ##### Returns 64 | 65 | `CArray` Output array, element-wise natural logarithm of `$x`. 66 | 67 | --- 68 | 69 | ## log10 70 | ```php 71 | public static log10($x) : CArray 72 | ``` 73 | > Return the base 10 logarithm of `$x`, element-wise. 74 | 75 | ##### Parameters 76 | 77 | `CArray|Array` **$x** Input array. 78 | 79 | ##### Returns 80 | 81 | `CArray` Output array, element-wise base 10 logarithm of `$x`. 82 | 83 | --- 84 | 85 | ## log2 86 | ```php 87 | public static log2($x) : CArray 88 | ``` 89 | > Base-2 logarithm of `$x`. 90 | 91 | ##### Parameters 92 | 93 | `CArray|Array` **$x** Input array. 94 | 95 | ##### Returns 96 | 97 | `CArray` Output array, element-wise base 2 logarithm of `$x`. 98 | 99 | --- 100 | 101 | ## log1p 102 | ```php 103 | public static log1p($x) : CArray 104 | ``` 105 | > Calculates `log(1 + $x)` of `$x` 106 | 107 | ##### Parameters 108 | 109 | `CArray|Array` **$x** Input array. 110 | 111 | ##### Returns 112 | 113 | `CArray` Output array, element-wise `log(1 + $x)` of `$x`. 114 | -------------------------------------------------------------------------------- /docs/routines/hyperbolic.md: -------------------------------------------------------------------------------- 1 | # Hyperbolic Routines 2 | 3 | --- 4 | 5 | ## sinh 6 | ```php 7 | public static sinh($x) : CArray 8 | ``` 9 | > Hyperbolic sine, element-wise. 10 | 11 | ##### Parameters 12 | 13 | `CArray|Array` **$x** Input array. 14 | 15 | ##### Returns 16 | 17 | `CArray` The hyperbolic sine of each element of `$x`. 18 | 19 | ##### Examples 20 | 21 | **Example 1** 22 | ```php 23 | echo CArray::sinh(0); 24 | ``` 25 | ``` 26 | 0.000000 27 | ``` 28 | 29 | --- 30 | 31 | ## cosh 32 | ```php 33 | public static cosh($x) : CArray 34 | ``` 35 | > Compute hyperbolic cosine element-wise. 36 | 37 | ##### Parameters 38 | 39 | `CArray|Array` **$x** Input array. 40 | 41 | ##### Returns 42 | 43 | `CArray` The hyperbolic cosine of each element of `$x`. 44 | 45 | ##### Examples 46 | 47 | **Example 1** 48 | ```php 49 | echo CArray::cosh([1, -1, 0]); 50 | ``` 51 | ``` 52 | [ 1.54308063 1.54308063 1.00000000 ] 53 | ``` 54 | 55 | --- 56 | 57 | ## tanh 58 | ```php 59 | public static tanh($x) : CArray 60 | ``` 61 | > Compute hyperbolic tangent element-wise. 62 | 63 | ##### Parameters 64 | 65 | `CArray|Array` **$x** Input array. 66 | 67 | ##### Returns 68 | 69 | `CArray` The hyperbolic tangent of each element of `$x`. 70 | 71 | ##### Examples 72 | 73 | **Example 1** 74 | ```php 75 | echo CArray::tanh([-1, 0, 1]); 76 | ``` 77 | ``` 78 | [ -0.76159416 0.00000000 0.76159416 ] 79 | ``` -------------------------------------------------------------------------------- /docs/routines/indexing.md: -------------------------------------------------------------------------------- 1 | # Indexing Routines 2 | 3 | --- 4 | 5 | ## diagonal 6 | 7 | ```php 8 | public static diagonal($a, int $offset = 0, int $axis1 = 0, int $axis2 = 0) : CArray 9 | ``` 10 | > Return specified diagonals. 11 | 12 | > If a is 2-D, returns the diagonal of a with the given offset, i.e., the collection of elements of the 13 | form `$a[i][i+offset]`. If a has more than two dimensions, then the axes specified by axis1 and axis2 are used to 14 | determine the 2-D sub-array whose diagonal is returned. The shape of the resulting array can be determined by 15 | removing axis1 and axis2 and appending an index to the right equal to the size of the resulting diagonals. 16 | 17 | ##### Parameters 18 | 19 | `CArray|Array` **$a** - Input array. 20 | 21 | `CArray|Array` **$offset** (optional) - Offset of the diagonal from the main diagonal. Can be positive or negative. Defaults to 22 | main diagonal (0). 23 | 24 | `CArray|Array` **$axis1** (optional) - Axis to be used as the first axis of the 2-D sub-arrays from which the diagonals should be taken. 25 | Defaults to first axis (0). 26 | 27 | `CArray|Array` **$axis2** (optional) - Axis to be used as the second axis of the 2-D sub-arrays from which the diagonals should be 28 | taken. Defaults to second axis (1). 29 | 30 | ##### Returns 31 | 32 | `CArray` Diagonals of `$a`. 33 | 34 | ##### Examples 35 | 36 | **Example 1** 37 | ```php 38 | $A = CArray::arange(4); 39 | $A = CArray::reshape($A, [2, 2]); 40 | echo CArray::diagonal($A); 41 | ``` 42 | ```` 43 | [ 0 3 ] 44 | ```` 45 | 46 | -------------------------------------------------------------------------------- /docs/routines/ma_norms.md: -------------------------------------------------------------------------------- 1 | # Matrix Norm Routines 2 | 3 | --- 4 | 5 | ## norm 6 | ```php 7 | public static norm($x) : CArray 8 | ``` 9 | > Matrix or vector Frobenius norm. 10 | 11 | ##### Parameters 12 | 13 | `CArray|Array` **$x** Input array. 14 | 15 | ##### Returns 16 | 17 | `CArray` Norm of the matrix or vector. 18 | 19 | ##### Examples 20 | 21 | **Example 1** 22 | ```php 23 | $a = CArray::arange(9) - 4; 24 | $b = CArray::reshape($a, [3, 3]); 25 | echo CArray::norm($b); 26 | ``` 27 | ``` 28 | 7.745967 29 | ``` 30 | 31 | --- 32 | 33 | ## det 34 | ```php 35 | public static det($a) : CArray 36 | ``` 37 | > Compute the determinant of an array. 38 | 39 | ##### Parameters 40 | 41 | `CArray|Array` **$a** Input array. 42 | 43 | ##### Returns 44 | 45 | `CArray` Determinant of `$a`. 46 | 47 | ##### Examples 48 | 49 | **Example 1** 50 | ```php 51 | $a = new CArray([[1, 2], [3, 4]]); 52 | echo CArray::det($a); 53 | ``` 54 | ``` 55 | -2.000000 56 | ``` -------------------------------------------------------------------------------- /docs/routines/ma_products.md: -------------------------------------------------------------------------------- 1 | # Matrix & Vector Products 2 | 3 | --- 4 | 5 | ## vdot 6 | ```php 7 | public static vdot($a, $b) : CArray 8 | ``` 9 | > Return the dot product of two vectors. 10 | 11 | > vdot does not perform a matrix product, but flattens input arguments to 1-D 12 | vectors first. Consequently, it should only be used for vectors. 13 | 14 | ##### Parameters 15 | 16 | `CArray|Array` **$a** Input array. 17 | 18 | `CArray|Array` **$b** Input array. 19 | 20 | ##### Returns 21 | 22 | `CArray` Dot product of `$a` and `$b`. 23 | 24 | ##### Examples 25 | 26 | **Example 1** 27 | ```php 28 | $a = new CArray([[1, 4], [5, 6]]); 29 | $b = new CArray([[4, 1], [2, 2]]); 30 | 31 | echo CArray::vdot($a, $b); 32 | ``` 33 | ``` 34 | 30.0000 35 | ``` 36 | 37 | --- 38 | 39 | ## matmul 40 | ```php 41 | public static matmul($a, $b) : CArray 42 | ``` 43 | > Matrix product of two arrays. 44 | 45 | ##### Parameters 46 | 47 | `CArray|Array` **$a** Input array. 48 | 49 | `CArray|Array` **$b** Input array. 50 | 51 | ##### Returns 52 | 53 | `CArray` The matrix product of the inputs. This is a scalar only when both `$x1`, `$x2` are 1-d vectors. 54 | 55 | ##### Examples 56 | 57 | **Example 1** 58 | ```php 59 | $a = new CArray([[1, 4], [5, 6]]); 60 | $b = new CArray([[4, 1], [2, 2]]); 61 | 62 | echo CArray::matmul($a, $b); 63 | ``` 64 | ``` 65 | [[ 12 9 ] 66 | [ 32 17 ]] 67 | ``` 68 | 69 | --- 70 | 71 | ## inner 72 | ```php 73 | public static inner($a, $b) : CArray 74 | ``` 75 | > Inner product of two arrays. 76 | 77 | ##### Parameters 78 | 79 | `CArray|Array` **$a** Input array. 80 | 81 | `CArray|Array` **$b** Input array. 82 | 83 | ##### Returns 84 | 85 | `CArray` Inner product of the input arrays. -------------------------------------------------------------------------------- /docs/routines/numerical_ranges.md: -------------------------------------------------------------------------------- 1 | # Numerical Range Methods 2 | 3 | --- 4 | 5 | ## arange 6 | 7 | ```php 8 | public static arange(int $start = 0, int $stop, int $step = 1) : CArray 9 | ``` 10 | > Return evenly spaced values within a given interval. 11 | 12 | ##### Parameters 13 | 14 | `int` **$start** (Optional) Start of interval. 15 | 16 | `int` **$stop** End of interval. 17 | 18 | `int` **$step** (Optional) Spacing between values. 19 | 20 | ##### Returns 21 | 22 | `CArray` CArray of evenly spaced values. 23 | 24 | --- 25 | 26 | ## linspace 27 | 28 | ```php 29 | public static linspace($start, $stop, $num = 50, $endpoint = True) : CArray 30 | ``` 31 | > Return evenly spaced numbers over a specified interval. 32 | 33 | > Returns `$num` evenly spaced samples, calculated over the interval `[$start, $stop]`. 34 | 35 | ##### Parameters 36 | 37 | `int` **$start** The starting value of the sequence. 38 | 39 | `int` **$stop** The end value of the sequence. 40 | 41 | `int` **$num** (Optional) Number of samples to generate. 42 | 43 | `bool` **$endpoint** (Optional) If True, stop is the last sample. Otherwise, it is not included. 44 | 45 | ##### Returns 46 | 47 | `CArray` There are `$num` equally spaced samples in the closed interval `[$start, $stop]`. 48 | 49 | --- 50 | 51 | ## logspace 52 | 53 | ```php 54 | public static logspace($start, $stop, $num=50, $endpoint=True, $base=10.0) : CArray 55 | ``` 56 | > Return numbers spaced evenly on a log scale. 57 | 58 | ##### Parameters 59 | 60 | `int` **$start** The starting value of the sequence. 61 | 62 | `int` **$stop** The end value of the sequence. 63 | 64 | `int` **$num** (Optional) Number of samples to generate. 65 | 66 | `bool` **$endpoint** (Optional) If True, stop is the last sample. Otherwise, it is not included. 67 | 68 | `int|double` **$base** (Optional) The base of the log space. 69 | 70 | ##### Returns 71 | 72 | `CArray` `$num` samples, equally spaced on a log scale. 73 | 74 | -------------------------------------------------------------------------------- /docs/routines/ones_and_zeros.md: -------------------------------------------------------------------------------- 1 | # Ones and Zeros Routines 2 | 3 | --- 4 | 5 | ## identity 6 | 7 | ```php 8 | public static identity($n) : CArray 9 | ``` 10 | > Return the identity array. 11 | 12 | > The identity array is a square array with ones on the main diagonal. 13 | 14 | ##### Parameters 15 | 16 | `CArray|Array` **$n** Number of rows (and columns) in `$n x $n` output. 17 | 18 | ##### Returns 19 | 20 | `CArray` `$n x $n` CArray with its main diagonal set to one, and all other elements 0. 21 | 22 | ##### Examples 23 | 24 | **Example 1** 25 | ```php 26 | echo CArray::identity(4); 27 | ``` 28 | ``` 29 | [[ 1. 0. 0. 0. ] 30 | [ 0. 1. 0. 0. ] 31 | [ 0. 0. 1. 0. ] 32 | [ 0. 0. 0. 1. ]] 33 | ``` 34 | 35 | --- 36 | 37 | ## eye 38 | 39 | ```php 40 | public static eye($n, $m = NULL, $k = 0) : CArray 41 | ``` 42 | 43 | > Return a 2-D array with ones on the diagonal and zeros elsewhere. 44 | 45 | ##### Parameters 46 | 47 | `CArray|Array` **$n** Number of rows in the output. 48 | 49 | `CArray|Array` **$m** Number of columns in the output. If NULL, defaults to `$n`. 50 | 51 | `CArray|Array` **$k** Index of the diagonal: 0 (the default) refers to the main diagonal, a positive value refers to 52 | an upper diagonal, and a negative value to a lower diagonal. 53 | 54 | ##### Returns 55 | 56 | `CArray` An array where all elements are equal to zero, except for the `$k`-th diagonal, whose values are equal to one. 57 | 58 | ##### Examples 59 | 60 | **Example 1** 61 | ```php 62 | echo CArray::eye(3, 3, 1); 63 | ``` 64 | ``` 65 | [[ 0. 1. 0. ] 66 | [ 0. 0. 1. ] 67 | [ 0. 0. 0. ]] 68 | ``` 69 | 70 | 71 | --- 72 | 73 | ## ones 74 | ```php 75 | public static ones(array $shape) : CArray 76 | ``` 77 | > Return a new CArray of given shape, filled with ones. 78 | 79 | ##### Parameters 80 | 81 | `Array` **$shape** Shape of the new array, e.g., `[2, 3]` or `[2]`. 82 | 83 | ##### Returns 84 | 85 | `CArray` CArray of ones with the given shape. 86 | 87 | 88 | --- 89 | 90 | ## zeros 91 | ```php 92 | public static zeros(array $shape) : CArray 93 | ``` 94 | 95 | > Return a new CArray of given shape, filled with zeros. 96 | 97 | ##### Parameters 98 | 99 | `Array` **$shape** Shape of the new array, e.g., `[2, 3]` or `[2]`. 100 | 101 | ##### Returns 102 | 103 | `CArray` CArray of zeros with the given shape. -------------------------------------------------------------------------------- /docs/routines/random.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phpsci/phpsci-carray/192a92213200a80006793c932eb0effef1d24b8e/docs/routines/random.md -------------------------------------------------------------------------------- /docs/routines/rearranging.md: -------------------------------------------------------------------------------- 1 | # Rearranging Routines 2 | 3 | --- 4 | 5 | ## reshape 6 | 7 | ```php 8 | public static reshape($a, $newshape) : CArray 9 | ``` 10 | > Gives a new shape to an array without changing its data. 11 | 12 | ##### Parameters 13 | 14 | `CArray|Array` **$a** Input array. 15 | 16 | `CArray|Array` **$newshape** The new shape should be compatible with the original shape. If an integer, then the result 17 | will be a 1-D array of that length. 18 | 19 | ##### Returns 20 | 21 | `CArray` This will be a new view of `$a` if possible; otherwise, it will be a copy. 22 | 23 | ##### Examples 24 | 25 | **Example 1** 26 | ```php 27 | $A = CArray::arange(8); 28 | echo CArray::reshape($A, [2, 4]); 29 | ``` 30 | ```` 31 | [[ 0 1 2 3 ] 32 | [ 4 5 6 7 ]] 33 | ```` 34 | 35 | --- 36 | 37 | ## flip 38 | 39 | ```php 40 | public static flip($a) : CArray 41 | ``` 42 | > Reverse the order of elements in an array 43 | 44 | ##### Parameters 45 | 46 | `CArray|Array` **$a** Input array. 47 | 48 | ##### Returns 49 | 50 | `CArray` A view of `$a` with the entries of axis reversed. 51 | 52 | ##### Examples 53 | 54 | **Example 1** 55 | ```php 56 | $A = CArray::arange(8); 57 | echo CArray::flip($A); 58 | ``` 59 | ``` 60 | [ 7 6 5 4 3 2 1 0 ] 61 | ``` -------------------------------------------------------------------------------- /docs/routines/rounding.md: -------------------------------------------------------------------------------- 1 | # Rounding Routines 2 | 3 | --- 4 | 5 | ## ceil 6 | ```php 7 | public static ceil($x) : CArray 8 | ``` 9 | > The ceiling of the input, element-wise. 10 | 11 | ##### Parameters 12 | 13 | `CArray|Array` **$x** Input array. 14 | 15 | ##### Returns 16 | 17 | `CArray` The ceiling of each element in `$x`. 18 | 19 | ##### Examples 20 | 21 | **Example 1** 22 | ```php 23 | $a = new CArray([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]); 24 | echo CArray::ceil($a); 25 | ``` 26 | ``` 27 | [ -1. -1. 0. 1. 2. 2. 2. ] 28 | ``` 29 | 30 | --- 31 | 32 | ## floor 33 | ```php 34 | public static floor($x) : CArray 35 | ``` 36 | > The floor of the input, element-wise. 37 | 38 | ##### Parameters 39 | 40 | `CArray|Array` **$x** Input array. 41 | 42 | ##### Returns 43 | 44 | `CArray` The floor of each element in `$x`. 45 | 46 | ##### Examples 47 | 48 | **Example 1** 49 | ```php 50 | $a = new CArray([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]); 51 | echo CArray::floor($a); 52 | ``` 53 | ``` 54 | [ -2. -2. -1. 0. 1. 1. 2. ] 55 | ``` 56 | 57 | 58 | --- 59 | 60 | ## around 61 | ```php 62 | public static around($x, int $decimals = 0) : CArray 63 | ``` 64 | > Evenly round to the given number of decimals. 65 | 66 | ##### Parameters 67 | 68 | `CArray|Array` **$x** Input array. 69 | 70 | `int` **$decimals** Number of decimal places to round to (default: 0). 71 | If decimals is negative, it specifies the number of positions to the 72 | left of the decimal point. 73 | 74 | ##### Returns 75 | 76 | `CArray` An array of the same type as `$a`, containing the rounded values. 77 | 78 | ##### Examples 79 | 80 | **Example 1** 81 | ```php 82 | $a = CArray::around([0.37, 1.64]); 83 | echo $a; 84 | ``` 85 | ``` 86 | [ 0. 2. ] 87 | ``` 88 | 89 | **Example 2** 90 | ```php 91 | $a = CArray::around([0.37, 1.64], 2); 92 | echo $a; 93 | ``` 94 | ``` 95 | [ 0.37000000 1.64000000 ] 96 | ``` -------------------------------------------------------------------------------- /docs/routines/searching.md: -------------------------------------------------------------------------------- 1 | # Search Routines 2 | 3 | --- 4 | 5 | ## argmax 6 | ```php 7 | public static argmax($x, $axis = NULL) : CArray 8 | ``` 9 | > Returns the indices of the maximum values along an axis. 10 | 11 | ##### Parameters 12 | 13 | `CArray|Array` **$x** Input array. 14 | 15 | `CArray|Array` **$axis** (Optional) The index is into the flattened array, otherwise along the specified axis. 16 | 17 | ##### Returns 18 | 19 | `CArray|Array` **$x** Array of indices into the array. It has the same shape as `$x` with the dimension along `$axis` removed. 20 | 21 | ##### Examples 22 | 23 | **Example 1** 24 | ```php 25 | $a = CArray::arange(6); 26 | $a = CArray::reshape($a, [2, 3]) + 10; 27 | echo CArray::argmax($a); 28 | ``` 29 | ``` 30 | 5 31 | ``` 32 | 33 | **Example 2** 34 | ```php 35 | $a = CArray::arange(6); 36 | $a = CArray::reshape($a, [2, 3]) + 10; 37 | echo CArray::argmax($a, 0); 38 | ``` 39 | ``` 40 | [ 1 1 1 ] 41 | ``` 42 | 43 | --- 44 | 45 | ## argmin 46 | ```php 47 | public static argmin($x, $axis = NULL) : CArray 48 | ``` 49 | > Returns the indices of the minimum values along an axis. 50 | 51 | ##### Parameters 52 | 53 | `CArray|Array` **$x** Input array. 54 | 55 | `CArray|Array` **$axis** (Optional) The index is into the flattened array, otherwise along the specified axis. 56 | 57 | ##### Returns 58 | 59 | `CArray|Array` **$x** Array of indices into the array. It has the same shape as `$x` with the dimension along `$axis` removed. 60 | 61 | ##### Examples 62 | 63 | **Example 1** 64 | ```php 65 | $a = CArray::arange(6); 66 | $a = CArray::reshape($a, [2, 3]) + 10; 67 | echo CArray::argmin($a); 68 | ``` 69 | ``` 70 | 0 71 | ``` 72 | 73 | **Example 2** 74 | ```php 75 | $a = CArray::arange(6); 76 | $a = CArray::reshape($a, [2, 3]) + 10; 77 | echo CArray::argmin($a, 0); 78 | ``` 79 | ``` 80 | [ 0 0 0 ] 81 | ``` -------------------------------------------------------------------------------- /docs/routines/sorting.md: -------------------------------------------------------------------------------- 1 | # Sorting Routines 2 | 3 | --- 4 | 5 | ## sort 6 | ```php 7 | public static sort($x, int $axis = -1, $kind = 'quicksort') : CArray 8 | ``` 9 | > Return a sorted copy of an array. 10 | 11 | ##### Parameters 12 | 13 | `CArray|Array` **$x** Input array. 14 | 15 | `int` **$axis** (Optional) Axis along which to sort. The default is -1, 16 | which sorts along the last axis. 17 | 18 | `string` **$kind** (Optional) Sorting Algorithm. Default is `quicksort`. Options: 19 | *quicksort*, *mergesort*, *heapsort* and *stable*. 20 | 21 | ##### Returns 22 | 23 | `CArray` Array of the same type and shape as `$x`. 24 | 25 | ##### Examples 26 | 27 | **Example 1** 28 | ```php 29 | echo CArray::sort([[1 ,4 ],[3 ,1]]); 30 | ``` 31 | ``` 32 | [[ 1 4 ] 33 | [ 1 3 ]] 34 | ``` 35 | 36 | **Example 2** 37 | ```php 38 | echo CArray::sort([[1 ,4 ],[3 ,1]], 0); 39 | ``` 40 | ``` 41 | [[ 1 1 ] 42 | [ 3 4 ]] 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/routines/statistics.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phpsci/phpsci-carray/192a92213200a80006793c932eb0effef1d24b8e/docs/routines/statistics.md -------------------------------------------------------------------------------- /docs/routines/sum_products_and_diff.md: -------------------------------------------------------------------------------- 1 | # Sums, products and differences Routines 2 | 3 | --- 4 | 5 | ## prod 6 | ```php 7 | public static prod($x, int $axis = NULL) : CArray 8 | ``` 9 | > Return the product of array elements over a given axis. 10 | 11 | ##### Parameters 12 | 13 | `CArray|Array` **$x** Input array. 14 | 15 | `int` **$axis** (optional) Axis or axes along which a product is performed. 16 | 17 | ##### Returns 18 | 19 | `CArray` An array shaped as `$x` but with the specified axis removed. 20 | . If `$axis` is NULL an 0-d CArray is returned. 21 | 22 | ##### Examples 23 | 24 | **Example 1** 25 | ```php 26 | echo CArray::prod([[1.,2.],[3.,4.]]); 27 | ``` 28 | ``` 29 | 24.000000 30 | ``` 31 | 32 | **Example 2** 33 | ```php 34 | echo CArray::prod([[1.,2.],[3.,4.]], 0); 35 | ``` 36 | ``` 37 | [ 3. 8. ] 38 | ``` 39 | 40 | 41 | 42 | 43 | --- 44 | 45 | ## sum 46 | ```php 47 | public static sum($x, int $axis = NULL) : CArray 48 | ``` 49 | > Sum of array elements over a given axis. 50 | 51 | ##### Parameters 52 | 53 | `CArray|Array` **$x** Input array. 54 | 55 | `int` **$axis** (optional) Axis or axes along which a sum is performed. 56 | 57 | ##### Returns 58 | 59 | `CArray` An array shaped as `$x` but with the specified axis removed. 60 | . If `$axis` is NULL an 0-d CArray is returned. 61 | 62 | ##### Examples 63 | 64 | **Example 1** 65 | ```php 66 | echo CArray::sum([[1.,2.],[3.,4.]]); 67 | ``` 68 | ``` 69 | 10.000000 70 | ``` 71 | 72 | **Example 2** 73 | ```php 74 | echo CArray::sum([[1.,2.],[3.,4.]]); 75 | ``` 76 | ``` 77 | [ 4. 6. ] 78 | ``` 79 | 80 | 81 | --- 82 | 83 | ## cumprod 84 | ```php 85 | public static cumprod($x, int $axis = 0) : CArray 86 | ``` 87 | > Return the cumulative product of elements along a given axis. 88 | 89 | ##### Parameters 90 | 91 | `CArray|Array` **$x** Input array. 92 | 93 | `int` **$axis** (optional) Axis along which the cumulative product is computed. 94 | 95 | ##### Returns 96 | 97 | `CArray` An array shaped as `$x`. If `$axis` is NULL an 0-d CArray is returned. 98 | 99 | ##### Examples 100 | 101 | **Example 1** 102 | ```php 103 | $a = new CArray([1, 2, 3]); 104 | echo CArray::cumprod($a); 105 | ``` 106 | ``` 107 | [ 1 2 6 ] 108 | ``` 109 | 110 | **Example 2** 111 | ```php 112 | $a = new CArray([[1, 2, 3], [4, 5, 6]]); 113 | echo CArray::cumprod($a); 114 | ``` 115 | ``` 116 | [ 1 2 6 24 120 720 ] 117 | ``` 118 | 119 | --- 120 | 121 | ## cumsum 122 | ```php 123 | public static cumsum($x) : CArray 124 | ``` 125 | > Return the cumulative sum of elements along a given axis. 126 | 127 | ##### Parameters 128 | 129 | `CArray|Array` **$x** Input array. 130 | 131 | `int` **$axis** (optional) Axis along which the cumulative sum is computed. 132 | 133 | ##### Returns 134 | 135 | `CArray` An array shaped as `$x`. If `$axis` is NULL an 0-d CArray is returned. 136 | 137 | ##### Examples 138 | 139 | **Example 1** 140 | ```php 141 | $a = new CArray([[1, 2, 3], [4, 5, 6]]); 142 | echo CArray::cumsum($a); 143 | ``` 144 | ``` 145 | [ 1 3 6 10 15 21 ] 146 | ``` 147 | 148 | **Example 2** 149 | ```php 150 | echo CArray::cumsum([1, 2, 3]); 151 | ``` 152 | ``` 153 | [ 1 3 6 ] 154 | ``` -------------------------------------------------------------------------------- /docs/routines/transpose.md: -------------------------------------------------------------------------------- 1 | # Transpose Routines 2 | 3 | --- 4 | 5 | ## moveaxis 6 | 7 | ```php 8 | public static moveaxis($a, $source, $destination) : CArray 9 | ``` 10 | > Move axes of an array to new positions. 11 | > Other axes remain in their original order. 12 | 13 | ##### Parameters 14 | 15 | `CArray|Array` **$a** The array whose axes should be reordered. 16 | 17 | `CArray|Array|Scalar` **$source** Original positions of the axes to move. These must be unique. 18 | 19 | `CArray|Array|Scalar` **$destination** Destination positions for each of the original axes. These must also be unique. 20 | 21 | 22 | ##### Returns 23 | 24 | `CArray` Array with moved axes. This array is a view of the input array. 25 | 26 | ##### Examples 27 | 28 | **Example 1** 29 | ```php 30 | echo CArray::moveaxis([[1, 2], [3, 4]], 0, 1); 31 | ``` 32 | ```php 33 | [[ 1.0000000000e+0 3.0000000000e+0 ] 34 | [ 2.0000000000e+0 4.0000000000e+0 ]] 35 | ``` 36 | 37 | **Example 2** 38 | ```php 39 | Roll the specified axis backwards, until it lies in a given position. 71 | 72 | ##### Parameters 73 | 74 | `CArray|Array` **$a** - Target array. 75 | 76 | `int` **$axis** - The axis to roll backwards. The positions of the other axes do not change relative to one another. 77 | 78 | `int` **$start** (optional) - The axis is rolled until it lies before this position. The default, 0, results in a “complete” roll. 79 | 80 | ##### Returns 81 | 82 | `CArray` A view of `$a` with rolled axis. 83 | 84 | 85 | ---- 86 | 87 | 88 | ## swapaxes 89 | ```php 90 | public static swapaxes($a, $axis1, $axis2) : CArray 91 | ``` 92 | > Interchange two axes of an array. 93 | 94 | ##### Parameters 95 | 96 | `CArray|Array` **$a** - Target array. 97 | 98 | `int` **$axis1** - First axis. 99 | 100 | `int` **$axis2** - Second axis. 101 | 102 | ##### Returns 103 | 104 | `CArray` A view of `$a` with interchanged axis. 105 | 106 | --- 107 | 108 | ## transpose 109 | ```php 110 | public static transpose($a, $axes = NULL) : CArray 111 | ``` 112 | > Permute the dimensions of an array. 113 | 114 | ##### Parameters 115 | 116 | `CArray|Array` **$a** - Target array. 117 | 118 | `CArray|Array|int` **$axes** (optional) - By default, reverse the dimensions, otherwise permute the axes according to 119 | the values given. 120 | 121 | ##### Returns 122 | 123 | `CArray` `$a` with its axes permuted. A view is returned whenever possible. -------------------------------------------------------------------------------- /docs/routines/trigonometric.md: -------------------------------------------------------------------------------- 1 | # Trigonometric Routines 2 | 3 | --- 4 | 5 | ## sin 6 | ```php 7 | public static sin($x) : CArray 8 | ``` 9 | > Trigonometric sine, element-wise. 10 | 11 | ##### Parameters 12 | 13 | `CArray|Array` **$x** Input array. 14 | 15 | ##### Returns 16 | 17 | `CArray` The sine of each element of `$x`. 18 | 19 | ##### Examples 20 | 21 | **Example 1** 22 | ```php 23 | $a = CArray::linspace(-pi(), pi(), 10); 24 | echo CArray::sin($a); 25 | ``` 26 | ``` 27 | [ -0.00000000 -1.00000000 0.00000000 1.00000000 0.00000000 ] 28 | ``` 29 | 30 | --- 31 | 32 | ## tan 33 | ```php 34 | public static tan($x) : CArray 35 | ``` 36 | > Compute tangent element-wise. 37 | > Equivalent to CArray::sin(x)/CArray::cos(x). 38 | 39 | ##### Parameters 40 | 41 | `CArray|Array` **$x** Input array. 42 | 43 | ##### Returns 44 | 45 | `CArray` The tangent of each element of `$x`. 46 | 47 | ##### Examples 48 | 49 | **Example 1** 50 | ```php 51 | echo CArray::tan([-pi(), pi()/2, pi()]); 52 | ``` 53 | ``` 54 | [ 1.224647e-16 1.633124e+16 -1.224647e-16 ] 55 | ``` 56 | 57 | --- 58 | 59 | ## arcsin 60 | ```php 61 | public static arcsin($x) : CArray 62 | ``` 63 | > Inverse sine, element-wise. 64 | 65 | ##### Parameters 66 | 67 | `CArray|Array` **$x** Input array. 68 | 69 | ##### Returns 70 | 71 | `CArray` The inverse sine of each element in `$x`. 72 | 73 | ##### Examples 74 | 75 | **Example 1** 76 | ```php 77 | echo CArray::arcsin(1); 78 | ``` 79 | ``` 80 | 1.570796 81 | ``` 82 | 83 | --- 84 | 85 | ## arccos 86 | ```php 87 | public static arccos($x) : CArray 88 | ``` 89 | > Trigonometric inverse cosine, element-wise. 90 | 91 | ##### Parameters 92 | 93 | `CArray|Array` **$x** Input array. 94 | 95 | ##### Returns 96 | 97 | `CArray` The inverse cosine of each element in `$x`. 98 | 99 | ##### Examples 100 | 101 | **Example 1** 102 | ```php 103 | echo CArray::arccos([1, -1]); 104 | ``` 105 | ``` 106 | [ 0.00000000 3.14159265 ] 107 | ``` 108 | 109 | --- 110 | 111 | ## arctan 112 | ```php 113 | public static arctan($x) : CArray 114 | ``` 115 | > Trigonometric inverse tangent, element-wise. 116 | 117 | ##### Parameters 118 | 119 | `CArray|Array` **$x** Input array. 120 | 121 | ##### Returns 122 | 123 | `CArray` The inverse tangent of each element in `$x`. 124 | 125 | ##### Examples 126 | 127 | **Example 1** 128 | ```php 129 | echo CArray::arctan([0, 1]); 130 | ``` 131 | ``` 132 | [ 0.00000000 0.78539816 ] 133 | ``` -------------------------------------------------------------------------------- /kernel/alloc.c: -------------------------------------------------------------------------------- 1 | #include "alloc.h" 2 | #include "carray.h" 3 | #include "buffer.h" 4 | 5 | /** 6 | * If CARRAY_GC_DEBUG env is True, CArray Garbage Collector 7 | * will print debug messages when destructing objects. 8 | */ 9 | static int 10 | CArrayGC_ISDEBUGON() 11 | { 12 | if (getenv("CARRAY_GC_DEBUG") == NULL) { 13 | return 0; 14 | } 15 | if (!strcmp(getenv("CARRAY_GC_DEBUG"), "0")) { 16 | return 0; 17 | } 18 | return 1; 19 | } 20 | 21 | void 22 | CArrayDescriptor_FREE(CArrayDescriptor * descr) 23 | { 24 | if (descr->refcount < 0) { 25 | if (descr->f != NULL) { 26 | efree(descr->f); 27 | descr->f = NULL; 28 | } 29 | 30 | efree(descr); 31 | descr = NULL; 32 | } 33 | } 34 | 35 | /** 36 | * @return 37 | */ 38 | void 39 | CArray_INCREF(CArray *target) 40 | { 41 | target->refcount++; 42 | } 43 | 44 | /** 45 | * @return 46 | */ 47 | void 48 | CArray_XDECREF(CArray *target) 49 | { 50 | target->refcount--; 51 | } 52 | 53 | /** 54 | * @return 55 | */ 56 | void 57 | CArray_DECREF(CArray *target) 58 | { 59 | target->refcount--; 60 | CArray_Free(target); 61 | } 62 | 63 | 64 | /** 65 | * Alocates CArray Data Buffer based on numElements and elsize from 66 | * CArray descriptor. 67 | **/ 68 | void 69 | CArray_Data_alloc(CArray * ca) 70 | { 71 | ca->data = emalloc((ca->descriptor->numElements * ca->descriptor->elsize)); 72 | } 73 | 74 | /** 75 | * @param size 76 | * @return 77 | */ 78 | void * 79 | carray_data_alloc_zeros(int num_elements, int size_element, char type) 80 | { 81 | return (void*)ecalloc(num_elements, size_element); 82 | } 83 | 84 | /** 85 | * @param size 86 | * @return 87 | */ 88 | void * 89 | carray_data_alloc(int num_elements, int size_element) 90 | { 91 | return (void*)emalloc(num_elements * size_element); 92 | } 93 | 94 | /** 95 | * @param descriptor 96 | */ 97 | void 98 | CArrayDescriptor_INCREF(CArrayDescriptor * descriptor) 99 | { 100 | descriptor->refcount++; 101 | } 102 | 103 | /** 104 | * @param descriptor 105 | */ 106 | void 107 | CArrayDescriptor_DECREF(CArrayDescriptor * descriptor) 108 | { 109 | if (descriptor != NULL) { 110 | descriptor->refcount--; 111 | } 112 | } 113 | 114 | void 115 | CArray_Free(CArray * self) 116 | { 117 | if(self->refcount <= 0) { 118 | efree(self->dimensions); 119 | efree(self->strides); 120 | efree(self->data); 121 | efree(self); 122 | } else { 123 | efree(self->dimensions); 124 | efree(self->strides); 125 | efree(self); 126 | } 127 | } 128 | 129 | /** 130 | * Free CArrays owning data buffer 131 | */ 132 | void 133 | _free_data_owner(MemoryPointer * ptr) 134 | { 135 | CArray * array = CArray_FromMemoryPointer(ptr); 136 | CArrayDescriptor_DECREF(array->descriptor); 137 | 138 | if(array->descriptor->refcount < 0) { 139 | if (CArrayGC_ISDEBUGON()) { 140 | php_printf("\n[CARRAY_GC_DEBUG][DESCR] Freeing Descriptor from CArray ID %d", ptr->uuid); 141 | } 142 | CArrayDescriptor_FREE(CArray_DESCR(array)); 143 | } 144 | 145 | CArray_XDECREF(array); 146 | if (CArrayGC_ISDEBUGON()) { 147 | php_printf("\n[CARRAY_GC_DEBUG] Freeing Dimensions and Strides from CArray ID %d", ptr->uuid); 148 | } 149 | efree(array->dimensions); 150 | efree(array->strides); 151 | if(array->refcount < 0) { 152 | if (CArrayGC_ISDEBUGON()) { 153 | php_printf("\n[CARRAY_GC_DEBUG] Freeing DATA from CArray ID %d", ptr->uuid); 154 | } 155 | efree(array->data); 156 | buffer_remove(ptr); 157 | } 158 | } 159 | 160 | /** 161 | * Free CArrays that refers others CArrays 162 | */ 163 | void 164 | _free_data_ref(MemoryPointer * ptr) 165 | { 166 | MemoryPointer tmp; 167 | 168 | CArray * array = CArray_FromMemoryPointer(ptr); 169 | 170 | CArray_XDECREF(array); 171 | CArray_XDECREF(array->base); 172 | CArrayDescriptor_DECREF(array->descriptor); 173 | if(array->descriptor->refcount < 0) { 174 | if (CArrayGC_ISDEBUGON()) { 175 | php_printf("\n[CARRAY_GC_DEBUG][DESCR][VIEW] Freeing Descriptor from CArray ID %d", ptr->uuid); 176 | } 177 | CArrayDescriptor_FREE(CArray_DESCR(array)); 178 | } 179 | efree(array->dimensions); 180 | efree(array->strides); 181 | 182 | if(array->refcount < 0 && array->base->refcount < 0) { 183 | if (CArrayGC_ISDEBUGON()) { 184 | php_printf("\n[CARRAY_GC_DEBUG][VIEW] Freeing CArray ID %d", ptr->uuid); 185 | } 186 | if(CArray_CHKFLAGS(array->base, CARRAY_ARRAY_OWNDATA)) { 187 | if (CArrayGC_ISDEBUGON()) { 188 | php_printf("\n[CARRAY_GC_DEBUG][VIEW] Freeing DATA from CArray ID %d", ptr->uuid); 189 | } 190 | efree(array->data); 191 | } 192 | tmp.uuid = array->base->uuid; 193 | buffer_remove(&tmp); 194 | } 195 | if(array->refcount < 0){ 196 | if (CArrayGC_ISDEBUGON()) { 197 | php_printf("\n[CARRAY_GC_DEBUG][VIEW] Freeing CArray ID %d", ptr->uuid); 198 | } 199 | buffer_remove(ptr); 200 | } 201 | } 202 | 203 | /** 204 | * Free CArray using MemoryPointer 205 | **/ 206 | void 207 | CArray_Alloc_FreeFromMemoryPointer(MemoryPointer * ptr) 208 | { 209 | CArray * array = CArray_FromMemoryPointer(ptr); 210 | if(CArray_CHKFLAGS(array, CARRAY_ARRAY_OWNDATA)){ 211 | _free_data_owner(ptr); 212 | } else { 213 | _free_data_ref(ptr); 214 | } 215 | return; 216 | } 217 | 218 | CArray * 219 | CArray_Alloc(CArrayDescriptor *descr, int nd, int* dims, 220 | int is_fortran, void *interfaceData) 221 | { 222 | CArray * target = emalloc(sizeof(CArray)); 223 | return CArray_NewFromDescr(target, descr, nd, dims, NULL, NULL, 224 | ( is_fortran ? CARRAY_ARRAY_F_CONTIGUOUS : 0), 225 | interfaceData); 226 | } 227 | -------------------------------------------------------------------------------- /kernel/alloc.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Henrique Borba on 19/11/2018. 3 | // 4 | 5 | #ifndef PHPSCI_EXT_ALLOC_H 6 | #define PHPSCI_EXT_ALLOC_H 7 | 8 | #include "carray.h" 9 | 10 | void CArray_Data_alloc(CArray * ca); 11 | void * carray_data_alloc_zeros(int num_elements, int size_element, char type); 12 | void * carray_data_alloc(int num_elements, int size_element); 13 | 14 | void CArray_INCREF(CArray * target); 15 | void CArray_XDECREF(CArray * target); 16 | void CArrayDescriptor_INCREF(CArrayDescriptor * descriptor); 17 | void CArrayDescriptor_DECREF(CArrayDescriptor * descriptor); 18 | void CArray_Alloc_FreeFromMemoryPointer(MemoryPointer * ptr); 19 | CArray * CArray_Alloc(CArrayDescriptor *descr, int nd, int* dims, int is_fortran, void *interfaceData); 20 | void CArray_Free(CArray * self); 21 | void CArrayDescriptor_FREE(CArrayDescriptor * descr); 22 | #endif //PHPSCI_EXT_ALLOC_H 23 | -------------------------------------------------------------------------------- /kernel/arraytypes.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_ARRAYTYPES_H 2 | #define CARRAY_ARRAYTYPES_H 3 | 4 | #include "carray.h" 5 | 6 | 7 | int 8 | small_correlate(const char * d_, int dstride, 9 | int nd, int dtype, 10 | const char * k_, int kstride, 11 | int nk, int ktype, 12 | char * out_, int ostride); 13 | #endif //CARRAY_ARRAYTYPES_H 14 | -------------------------------------------------------------------------------- /kernel/assign.c: -------------------------------------------------------------------------------- 1 | #include "assign.h" 2 | #include "carray.h" 3 | 4 | int 5 | raw_array_is_aligned(int ndim, int *shape, char *data, int *strides, int alignment) 6 | { 7 | 8 | /* 9 | * The code below expects the following: 10 | * * that alignment is a power of two, as required by the C standard. 11 | * * that casting from pointer to uintp gives a sensible representation 12 | * we can use bitwise operations on (perhaps *not* req. by C std, 13 | * but assumed by glibc so it should be fine) 14 | * * that casting stride from intp to uintp (to avoid dependence on the 15 | * signed int representation) preserves remainder wrt alignment, so 16 | * stride%a is the same as ((unsigned intp)stride)%a. Req. by C std. 17 | * 18 | * The code checks whether the lowest log2(alignment) bits of `data` 19 | * and all `strides` are 0, as this implies that 20 | * (data + n*stride)%alignment == 0 for all integers n. 21 | */ 22 | 23 | if (alignment > 1) { 24 | uintptr_t align_check = (uintptr_t)data; 25 | int i; 26 | 27 | for (i = 0; i < ndim; i++) { 28 | /* skip dim == 1 as it is not required to have stride 0 */ 29 | if (shape[i] > 1) { 30 | /* if shape[i] == 1, the stride is never used */ 31 | align_check |= (uintptr_t)strides[i]; 32 | } 33 | else if (shape[i] == 0) { 34 | /* an array with zero elements is always aligned */ 35 | return 1; 36 | } 37 | } 38 | 39 | return carray_is_aligned((void *)align_check, alignment); 40 | } 41 | else { 42 | return 1; 43 | } 44 | } 45 | 46 | 47 | int 48 | IsAligned(CArray * array) 49 | { 50 | if (CArray_DESCR(array) == NULL) { 51 | return 0; 52 | } 53 | 54 | return raw_array_is_aligned(CArray_NDIM(array), CArray_DIMS(array), 55 | CArray_DATA(array), CArray_STRIDES(array), 56 | CArray_DESCR(array)->alignment); 57 | } -------------------------------------------------------------------------------- /kernel/assign.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_ASSIGN_H 2 | #define PHPSCI_EXT_ASSIGN_H 3 | #include "carray.h" 4 | 5 | /* 6 | * return true if pointer is aligned to 'alignment' 7 | */ 8 | static inline int 9 | carray_is_aligned(void * p, int alignment) 10 | { 11 | /* 12 | * Assumes alignment is a power of two, as required by the C standard. 13 | * Assumes cast from pointer to unsigned integer gives a sensible representation we 14 | * can use bitwise & on (not required by C standard, but used by glibc). 15 | */ 16 | return ((uintptr_t)(p) & ((alignment) - 1)) == 0; 17 | } 18 | 19 | int IsAligned(CArray *array); 20 | int raw_array_is_aligned(int ndim, int *shape, char *data, int *strides, int alignment); 21 | #endif //PHPSCI_EXT_ASSIGN_H -------------------------------------------------------------------------------- /kernel/assign_scalar.c: -------------------------------------------------------------------------------- 1 | #include "carray.h" 2 | #include "assign_scalar.h" 3 | #include "convert_datatype.h" 4 | #include "assign.h" 5 | #include "common/exceptions.h" 6 | #include "common/common.h" 7 | #include "alloc.h" 8 | #include "dtype_transfer.h" 9 | 10 | /* 11 | * Assigns the scalar value to every element of the destination raw array. 12 | * 13 | * Returns 0 on success, -1 on failure. 14 | */ 15 | int 16 | raw_array_assign_scalar(int ndim, int *shape, 17 | CArrayDescriptor *dst_dtype, char *dst_data, int *dst_strides, 18 | CArrayDescriptor *src_dtype, char *src_data) 19 | { 20 | int idim; 21 | int * shape_it, * dst_strides_it; 22 | int * coord; 23 | 24 | CArray_StridedUnaryOp *stransfer = NULL; 25 | CArrayAuxData *transferdata = NULL; 26 | int aligned, needs_api = 0; 27 | int src_itemsize = src_dtype->elsize; 28 | 29 | shape_it = emalloc(sizeof(int) * ndim * 2); 30 | dst_strides_it = emalloc(sizeof(int) * ndim * 2); 31 | coord = emalloc(sizeof(int) * ndim * 2); 32 | 33 | /* Check both uint and true alignment */ 34 | aligned = raw_array_is_aligned(ndim, shape, dst_data, dst_strides, 35 | carray_uint_alignment(dst_dtype->elsize)) && 36 | raw_array_is_aligned(ndim, shape, dst_data, dst_strides, 37 | dst_dtype->alignment) && 38 | carray_is_aligned(src_data, carray_uint_alignment(src_dtype->elsize) && 39 | carray_is_aligned(src_data, src_dtype->alignment)); 40 | 41 | /* Use raw iteration with no heap allocation */ 42 | if (CArray_PrepareOneRawArrayIter( 43 | ndim, shape, 44 | dst_data, dst_strides, 45 | &ndim, shape_it, 46 | &dst_data, dst_strides_it) < 0) { 47 | return -1; 48 | } 49 | 50 | /* Get the function to do the casting */ 51 | if (CArray_GetDTypeTransferFunction(aligned, 52 | 0, dst_strides_it[0], 53 | src_dtype, dst_dtype, 54 | 0, 55 | &stransfer, &transferdata, 56 | &needs_api) != CARRAY_SUCCEED) { 57 | return -1; 58 | } 59 | 60 | if (!needs_api) { 61 | int nitems = 1, i; 62 | for (i = 0; i < ndim; i++) { 63 | nitems *= shape_it[i]; 64 | } 65 | } 66 | 67 | CARRAY_RAW_ITER_START(idim, ndim, coord, shape_it) { 68 | /* Process the innermost dimension */ 69 | stransfer(dst_data, dst_strides_it[0], src_data, 0, 70 | shape_it[0], src_itemsize, transferdata); 71 | } CARRAY_RAW_ITER_ONE_NEXT(idim, ndim, coord, 72 | shape_it, dst_data, dst_strides_it); 73 | 74 | 75 | CARRAY_AUXDATA_FREE(transferdata); 76 | 77 | efree(shape_it); 78 | efree(dst_strides_it); 79 | efree(coord); 80 | return (needs_api) ? -1 : 0; 81 | } 82 | 83 | /* 84 | * Assigns a scalar value specified by 'src_dtype' and 'src_data' 85 | * to elements of 'dst'. 86 | * 87 | * dst: The destination array. 88 | * src_dtype: The data type of the source scalar. 89 | * src_data: The memory element of the source scalar. 90 | * wheremask: If non-NULL, a boolean mask specifying where to copy. 91 | * casting: An exception is raised if the assignment violates this 92 | * casting rule. 93 | * 94 | * This function is implemented in array_assign_scalar.c. 95 | * 96 | * Returns 0 on success, -1 on failure. 97 | */ 98 | int 99 | CArray_AssignRawScalar(CArray *dst, CArrayDescriptor *src_dtype, char *src_data, CArray *wheremask, 100 | CARRAY_CASTING casting) 101 | { 102 | int allocated_src_data = 0; 103 | long long scalarbuffer[4]; 104 | 105 | if (CArray_FailUnlessWriteable(dst, "assignment destination") < 0) { 106 | return -1; 107 | } 108 | 109 | /* Check the casting rule */ 110 | if (!can_cast_scalar_to(src_dtype, src_data, 111 | CArray_DESCR(dst), casting)) { 112 | throw_typeerror_exception("Cannot cast scalar"); 113 | return -1; 114 | } 115 | 116 | /* 117 | * Make a copy of the src data if it's a different dtype than 'dst' 118 | * or isn't aligned, and the destination we're copying to has 119 | * more than one element. To avoid having to manage object lifetimes, 120 | * we also skip this if 'dst' has an object dtype. 121 | */ 122 | if ((!CArray_EquivTypes(CArray_DESCR(dst), src_dtype) || 123 | !(carray_is_aligned(src_data, carray_uint_alignment(src_dtype->elsize)) && 124 | carray_is_aligned(src_data, src_dtype->alignment))) && 125 | CArray_SIZE(dst) > 1) { 126 | char *tmp_src_data; 127 | /* 128 | * Use a static buffer to store the aligned/cast version, 129 | * or allocate some memory if more space is needed. 130 | */ 131 | if ((int)sizeof(scalarbuffer) >= CArray_DESCR(dst)->elsize) { 132 | tmp_src_data = (char *)&scalarbuffer[0]; 133 | } 134 | else { 135 | tmp_src_data = emalloc(CArray_DESCR(dst)->elsize); 136 | if (tmp_src_data == NULL) { 137 | throw_memory_exception("Memory Error"); 138 | goto fail; 139 | } 140 | allocated_src_data = 1; 141 | } 142 | if (CArrayDataType_FLAGCHK(CArray_DESCR(dst), CARRAY_NEEDS_INIT)) { 143 | memset(tmp_src_data, 0, CArray_DESCR(dst)->elsize); 144 | } 145 | 146 | if (CArray_CastRawArrays(1, src_data, tmp_src_data, 0, 0, 147 | src_dtype, CArray_DESCR(dst), 0) != CARRAY_SUCCEED) { 148 | src_data = tmp_src_data; 149 | goto fail; 150 | } 151 | 152 | /* Replace src_data/src_dtype */ 153 | src_data = tmp_src_data; 154 | src_dtype = CArray_DESCR(dst); 155 | } 156 | 157 | if (wheremask == NULL) { 158 | /* A straightforward value assignment */ 159 | /* Do the assignment with raw array iteration */ 160 | if (raw_array_assign_scalar(CArray_NDIM(dst), CArray_DIMS(dst), 161 | CArray_DESCR(dst), CArray_DATA(dst), CArray_STRIDES(dst), 162 | src_dtype, src_data) < 0) { 163 | 164 | goto fail; 165 | } 166 | } 167 | else { 168 | throw_notimplemented_exception(); 169 | } 170 | 171 | //if (allocated_src_data) { 172 | // free(src_data); 173 | //} 174 | 175 | return 0; 176 | fail: 177 | 178 | if (allocated_src_data) { 179 | free(src_data); 180 | } 181 | return -1; 182 | } -------------------------------------------------------------------------------- /kernel/assign_scalar.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_ASSIGN_SCALAR_H 2 | #define PHPSCI_EXT_ASSIGN_SCALAR_H 3 | 4 | #include "carray.h" 5 | 6 | int CArray_AssignRawScalar(CArray *dst, CArrayDescriptor *src_dtype, char *src_data, CArray *wheremask, 7 | CARRAY_CASTING casting); 8 | 9 | #endif -------------------------------------------------------------------------------- /kernel/buffer.c: -------------------------------------------------------------------------------- 1 | #include "../phpsci.h" 2 | #include "buffer.h" 3 | #include "carray.h" 4 | 5 | /** 6 | * MEMORY STACK 7 | * 8 | * CArrays Memory Buffer 9 | */ 10 | struct MemoryStack PHPSCI_MAIN_MEM_STACK; 11 | 12 | /** 13 | * If CARRAY_GC_DEBUG env is True, CArray Garbage Collector 14 | * will print debug messages when destructing objects. 15 | */ 16 | static int 17 | CArrayBuffer_ISDEBUGON() 18 | { 19 | if (getenv("CARRAY_BUFFER_DEBUG") == NULL) { 20 | return 0; 21 | } 22 | if (!strcmp(getenv("CARRAY_BUFFER_DEBUG"), "0")) { 23 | return 0; 24 | } 25 | return 1; 26 | } 27 | 28 | /** 29 | * Initialize MemoryStack Buffer 30 | * 31 | * @todo Same from buffer_to_capacity 32 | */ 33 | void buffer_init(size_t size) { 34 | PHPSCI_MAIN_MEM_STACK.freed = 0; 35 | PHPSCI_MAIN_MEM_STACK.size = 0; 36 | PHPSCI_MAIN_MEM_STACK.capacity = 1; 37 | PHPSCI_MAIN_MEM_STACK.bsize = size; 38 | PHPSCI_MAIN_MEM_STACK.last_free_uuid = -1; 39 | // Allocate first CArray struct to buffer 40 | PHPSCI_MAIN_MEM_STACK.buffer = (struct CArray**)emalloc(sizeof(CArray *)); 41 | if (CArrayBuffer_ISDEBUGON()) { 42 | php_printf("\n[CARRAY_BUFFER_DEBUG] Buffer Initialized"); 43 | } 44 | } 45 | 46 | void buffer_remove(MemoryPointer * ptr) 47 | { 48 | PHPSCI_MAIN_MEM_STACK.freed = PHPSCI_MAIN_MEM_STACK.freed + 1; 49 | efree(PHPSCI_MAIN_MEM_STACK.buffer[ptr->uuid]); 50 | PHPSCI_MAIN_MEM_STACK.last_free_uuid = ptr->uuid; 51 | 52 | } 53 | 54 | void buffer_free() { 55 | efree(PHPSCI_MAIN_MEM_STACK.buffer); 56 | PHPSCI_MAIN_MEM_STACK.buffer = NULL; 57 | } 58 | 59 | /** 60 | * Grow MemoryStack buffer to new_capacity. 61 | * 62 | * @param new_capacity int New capacity for MemoryStack (Buffer) 63 | * 64 | * @todo Check if this won't fck everything as the computing requirements grow up 65 | */ 66 | void buffer_to_capacity(int new_capacity, size_t size) { 67 | PHPSCI_MAIN_MEM_STACK.bsize += size; 68 | PHPSCI_MAIN_MEM_STACK.buffer = (struct CArray**)erealloc(PHPSCI_MAIN_MEM_STACK.buffer, (new_capacity * sizeof(CArray *))); 69 | // Set new capacity to MemoryStack 70 | PHPSCI_MAIN_MEM_STACK.capacity = new_capacity; 71 | } 72 | 73 | /** 74 | * Add CArray to MemoryStack (Buffer) and retrieve MemoryPointer 75 | * 76 | * @param array CArray CArray to add into the stack 77 | * @param size size_t Size of CArray in bytes 78 | */ 79 | void add_to_buffer(MemoryPointer * ptr, struct CArray * array, size_t size) { 80 | // If current MemoryStack buffer is empty, initialize it 81 | if(PHPSCI_MAIN_MEM_STACK.buffer == NULL) { 82 | buffer_init(size); 83 | } 84 | 85 | if (PHPSCI_MAIN_MEM_STACK.last_free_uuid == -1) { 86 | // If current capacity is smaller them the requested capacity, grow the MemoryStack 87 | if((PHPSCI_MAIN_MEM_STACK.size+1) > PHPSCI_MAIN_MEM_STACK.capacity) { 88 | buffer_to_capacity((PHPSCI_MAIN_MEM_STACK.capacity+1),size); 89 | } 90 | 91 | PHPSCI_MAIN_MEM_STACK.buffer[PHPSCI_MAIN_MEM_STACK.size] = array; 92 | 93 | // Associate CArray unique id 94 | ptr->uuid = (int)PHPSCI_MAIN_MEM_STACK.size; 95 | array->uuid = ptr->uuid; 96 | 97 | // Set new size for MemoryStack 98 | PHPSCI_MAIN_MEM_STACK.size++; 99 | } else { 100 | PHPSCI_MAIN_MEM_STACK.buffer[PHPSCI_MAIN_MEM_STACK.last_free_uuid] = array; 101 | 102 | // Associate CArray unique id 103 | ptr->uuid = (int)PHPSCI_MAIN_MEM_STACK.last_free_uuid; 104 | array->uuid = ptr->uuid; 105 | PHPSCI_MAIN_MEM_STACK.last_free_uuid = -1; 106 | } 107 | 108 | if (CArrayBuffer_ISDEBUGON()) { 109 | php_printf("\n[CARRAY_BUFFER_DEBUG] Added CArray ID %d", array->uuid); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /kernel/buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_BUFFER_H 2 | #define PHPSCI_EXT_BUFFER_H 3 | 4 | #include "carray.h" 5 | 6 | /** 7 | * MemoryStack : The memory buffer of CArrays 8 | */ 9 | struct MemoryStack { 10 | CArray ** buffer; 11 | int size; 12 | int capacity; 13 | int last_free_uuid; 14 | int freed; 15 | size_t bsize; 16 | }; 17 | 18 | extern struct MemoryStack PHPSCI_MAIN_MEM_STACK; 19 | 20 | void add_to_buffer(MemoryPointer * ptr, struct CArray * array, size_t size); 21 | void buffer_to_capacity(int new_capacity, size_t size); 22 | void remove_from_buffer(MemoryPointer * ptr); 23 | void buffer_init(); 24 | void buffer_remove(MemoryPointer * ptr); 25 | void buffer_free(); 26 | #endif //PHPSCI_EXT_BUFFER_H 27 | -------------------------------------------------------------------------------- /kernel/calculation.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_CALCULATION_H 2 | #define PHPSCI_EXT_CALCULATION_H 3 | 4 | #include "carray.h" 5 | 6 | #define CArray_MAX(a,b) (((a)>(b))?(a):(b)) 7 | #define CArray_MIN(a,b) (((a)<(b))?(a):(b)) 8 | 9 | 10 | CArray * CArray_Sum(CArray * self, int * axis, int rtype, MemoryPointer * out_ptr); 11 | CArray * CArray_Prod(CArray * self, int * axis, int rtype, MemoryPointer * out_ptr); 12 | CArray * CArray_CumProd(CArray * self, int * axis, int rtype, MemoryPointer * out_ptr); 13 | CArray * CArray_CumSum(CArray * self, int * axis, int rtype, MemoryPointer * out_ptr); 14 | CArray * CArray_Any(CArray * target, int * axis, MemoryPointer * out); 15 | #endif -------------------------------------------------------------------------------- /kernel/casting.c: -------------------------------------------------------------------------------- 1 | #include "carray.h" 2 | 3 | /** 4 | * COPYSWAPN 5 | */ 6 | static inline void 7 | _basic_copyn(void *dst, int dstride, void *src, int sstride, 8 | int n, int elsize) { 9 | if (src == NULL) { 10 | return; 11 | } 12 | if (sstride == elsize && dstride == elsize) { 13 | memcpy(dst, src, n*elsize); 14 | } 15 | else { 16 | _unaligned_strided_byte_copy(dst, dstride, src, sstride, 17 | n, elsize, NULL); 18 | } 19 | } 20 | 21 | 22 | /** 23 | * FILL INT 24 | */ 25 | int 26 | INT_fill(void * buffer, int length, struct CArray * ap) 27 | { 28 | int i; 29 | int start = ((int*)buffer)[0]; 30 | int delta = ((int*)buffer)[1]; 31 | 32 | delta -= start; 33 | for (i = 2; i < length; ++i) { 34 | ((int*)buffer)[i] = start + i*delta; 35 | } 36 | } 37 | 38 | /** 39 | * FILL DOUBLE 40 | */ 41 | int 42 | DOUBLE_fill(void * buffer, int length, struct CArray * ap) 43 | { 44 | int i; 45 | double start = ((double*)buffer)[0]; 46 | double delta = ((double*)buffer)[1]; 47 | 48 | delta -= start; 49 | for (i = 2; i < length; ++i) { 50 | ((double*)buffer)[i] = start + i*delta; 51 | } 52 | } 53 | 54 | /** 55 | * SETITEM INT 56 | */ 57 | int 58 | INT_setitem (void * op, void * ov, struct CArray * ap) 59 | { 60 | int temp; /* ensures alignment */ 61 | temp = *((int *)op); 62 | if (ap == NULL || CArray_ISBEHAVED(ap)) 63 | *((int *)ov)=temp; 64 | else { 65 | CArray_DESCR(ap)->f->copyswap(ov, &temp, !CArray_ISNOTSWAPPED(ap), ap); 66 | } 67 | return 0; 68 | } 69 | 70 | /** 71 | * GETITEM INT 72 | */ 73 | 74 | /** 75 | * SETITEM DOUBLE 76 | */ 77 | int 78 | DOUBLE_setitem (double * op, void * ov, struct CArray * ap) 79 | { 80 | double temp; /* ensures alignment */ 81 | 82 | temp = (double)*((double*)op); 83 | 84 | if (ap == NULL || CArray_ISBEHAVED(ap)) 85 | *((double *)ov)=temp; 86 | else { 87 | CArray_DESCR(ap)->f->copyswap(ov, &temp, !CArray_ISNOTSWAPPED(ap), ap); 88 | } 89 | return 0; 90 | } 91 | 92 | 93 | /** 94 | * COPYSWAP DOUBLE 95 | **/ 96 | void 97 | DOUBLE_copyswap (void *dst, void *src, int swap, void * arr) 98 | { 99 | if (src != NULL) { 100 | /* copy first if needed */ 101 | memcpy(dst, src, sizeof(double)); 102 | } 103 | /* ignore swap */ 104 | } 105 | 106 | /** 107 | * COPYSWAP INT 108 | **/ 109 | void 110 | INT_copyswap (void *dst, void *src, int swap, void * arr) 111 | { 112 | if (src != NULL) { 113 | /* copy first if needed */ 114 | memcpy(dst, src, sizeof(int)); 115 | } 116 | /* ignore swap */ 117 | } 118 | 119 | /** 120 | * CAST DOUBLE TO INT 121 | **/ 122 | void 123 | DOUBLE_TO_INT(double *ip, int *op, int n, 124 | CArray *aip, CArray *aop) { 125 | while (n--) { 126 | *(op++) = (int)*(ip++); 127 | } 128 | } 129 | 130 | /** 131 | * CAST INT TO DOUBLE 132 | */ 133 | void 134 | INT_TO_DOUBLE(int *ip, double *op, int n, 135 | CArray *aip, CArray *aop) { 136 | while (n--) { 137 | *(op++) = (double)*(ip++); 138 | } 139 | } 140 | 141 | void 142 | INT_TO_INT(int *ip, int *op, int n, 143 | CArray *aip, CArray *aop) { 144 | while (n--) { 145 | *op++ = (int)*ip++; 146 | } 147 | } 148 | 149 | 150 | /** 151 | * COPYSWAPN INT 152 | */ 153 | 154 | void 155 | INT_copyswapn (void *dst, int dstride, void *src, int sstride, 156 | int n, int swap, void *CARRAY_UNUSED(arr)) 157 | { 158 | /* copy first if needed */ 159 | _basic_copyn(dst, dstride, src, sstride, n, sizeof(int)); 160 | if (swap) { 161 | _strided_byte_swap(dst, dstride, n, sizeof(int)); 162 | } 163 | } 164 | 165 | /** 166 | * COPYSWAPN DOUBLE 167 | */ 168 | void 169 | DOUBLE_copyswapn (void *dst, int dstride, void *src, int sstride, 170 | int n, int swap, void *CARRAY_UNUSED(arr)) 171 | { 172 | /* copy first if needed */ 173 | _basic_copyn(dst, dstride, src, sstride, n, sizeof(double)); 174 | if (swap) { 175 | _strided_byte_swap(dst, dstride, n, sizeof(double)); 176 | } 177 | } -------------------------------------------------------------------------------- /kernel/casting.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_CASTING_H 2 | #define PHPSCI_EXT_CASTING_H 3 | 4 | #include "carray.h" 5 | 6 | void 7 | INT_copyswapn (void *dst, int dstride, void *src, int sstride, 8 | int n, int swap, void *CARRAY_UNUSED(arr)); 9 | void 10 | DOUBLE_copyswapn (void *dst, int dstride, void *src, int sstride, 11 | int n, int swap, void *CARRAY_UNUSED(arr)); 12 | 13 | void DOUBLE_copyswap (void *dst, void *src, int swap, void * arr); 14 | void INT_copyswap (void *dst, void *src, int swap, void * arr); 15 | 16 | void DOUBLE_TO_INT(int *ip, double *op, int n, CArray *aip, CArray *aop); 17 | void INT_TO_DOUBLE(int *ip, double *op, int n, CArray *aip, CArray *aop); 18 | void INT_TO_INT(int *ip, int *op, int n, CArray *aip, CArray *aop); 19 | 20 | int DOUBLE_setitem (void * op, void * ov, struct CArray * ap); 21 | int INT_setitem (int * op, void * ov, struct CArray * ap); 22 | 23 | int DOUBLE_fill(void * op, void * ov, struct CArray * ap); 24 | int INT_fill(int * op, void * ov, struct CArray * ap); 25 | #endif -------------------------------------------------------------------------------- /kernel/clip.c: -------------------------------------------------------------------------------- 1 | #include "clip.h" 2 | #include "carray.h" 3 | #include "calculation.h" 4 | #include "alloc.h" 5 | #include "ctors.h" 6 | #include "buffer.h" 7 | 8 | #define _CARRAY_DOUBLE_MIN(a, b) (isnan(a) ? (a) : CArray_MIN(a, b)) 9 | #define _CARRAY_DOUBLE_MAX(a, b) (isnan(a) ? (a) : CArray_MAX(a, b)) 10 | #define _CARRAY_DCLIP(x, min, max) \ 11 | _CARRAY_DOUBLE_MIN(_CARRAY_DOUBLE_MAX((x), (min)), (max)) 12 | 13 | 14 | #define _CARRAY_INT_MIN(a, b) CArray_MIN(a, b) 15 | #define _CARRAY_INT_MAX(a, b) CArray_MAX(a, b) 16 | #define _CARRAY_ICLIP(x, min, max) \ 17 | _CARRAY_INT_MIN(_CARRAY_INT_MAX((x), (min)), (max)) 18 | 19 | 20 | void 21 | INT_clip(int *in, int ni, int *min, int *max, int *out) 22 | { 23 | int i; 24 | int max_val = 0, min_val = 0; 25 | 26 | if (max != NULL) { 27 | max_val = *max; 28 | } 29 | if (min != NULL) { 30 | min_val = *min; 31 | } 32 | 33 | if (max == NULL) { 34 | for (i = 0; i < ni; i++) { 35 | if (in[i] < min_val) { 36 | out[i] = min_val; 37 | } 38 | else { 39 | out[i] = in[i]; 40 | } 41 | } 42 | } 43 | else if (min == NULL) { 44 | for (i = 0; i < ni; i++) { 45 | if (in[i] > max_val) { 46 | out[i] = max_val; 47 | } 48 | else { 49 | out[i] = in[i]; 50 | } 51 | } 52 | } 53 | else { 54 | /* 55 | * Visual Studio 2015 loop vectorizer handles NaN in an unexpected 56 | * manner, see: https://github.com/numpy/numpy/issues/7601 57 | */ 58 | #if (_MSC_VER == 1900) 59 | #pragma loop( no_vector ) 60 | #endif 61 | for (i = 0; i < ni; i++) { 62 | if (in[i] < min_val) { 63 | out[i] = min_val; 64 | } 65 | else if (in[i] > max_val) { 66 | out[i] = max_val; 67 | } 68 | else { 69 | out[i] = in[i]; 70 | } 71 | } 72 | } 73 | } 74 | 75 | void 76 | DOUBLE_clip(double *in, int ni, double *min, double *max, double *out) 77 | { 78 | int i; 79 | double max_val = 0, min_val = 0; 80 | 81 | if (max != NULL) { 82 | max_val = *max; 83 | } 84 | if (min != NULL) { 85 | min_val = *min; 86 | } 87 | 88 | if (max == NULL) { 89 | for (i = 0; i < ni; i++) { 90 | if (in[i] < min_val) { 91 | out[i] = min_val; 92 | } 93 | else { 94 | out[i] = in[i]; 95 | } 96 | } 97 | } 98 | else if (min == NULL) { 99 | for (i = 0; i < ni; i++) { 100 | if (in[i] > max_val) { 101 | out[i] = max_val; 102 | } 103 | else { 104 | out[i] = in[i]; 105 | } 106 | } 107 | } 108 | else { 109 | /* 110 | * Visual Studio 2015 loop vectorizer handles NaN in an unexpected 111 | * manner, see: https://github.com/numpy/numpy/issues/7601 112 | */ 113 | #if (_MSC_VER == 1900) 114 | #pragma loop( no_vector ) 115 | #endif 116 | for (i = 0; i < ni; i++) { 117 | if (in[i] < min_val) { 118 | out[i] = min_val; 119 | } 120 | else if (in[i] > max_val) { 121 | out[i] = max_val; 122 | } 123 | else { 124 | out[i] = in[i]; 125 | } 126 | } 127 | } 128 | } 129 | 130 | CArray * 131 | CArray_Clip(CArray * self, CArray * min, CArray * max, MemoryPointer * out_ptr) 132 | { 133 | CArray_FastClipFunc *func; 134 | int outgood = 0, ingood = 0; 135 | CArray *maxa = NULL; 136 | CArray *mina = NULL; 137 | CArray *newout = NULL, *out = NULL, *newin = NULL; 138 | CArrayDescriptor *indescr = NULL, *newdescr = NULL; 139 | char *max_data, *min_data; 140 | CArray *zero; 141 | 142 | if ((max == NULL) && (min == NULL)) { 143 | throw_valueerror_exception("array_clip: must set either max or min"); 144 | return NULL; 145 | } 146 | 147 | func = CArray_DESCR(self)->f->fastclip; 148 | 149 | /* First we need to figure out the correct type */ 150 | if (min != NULL) { 151 | indescr = CArray_DESCR(min); 152 | if (indescr == NULL) { 153 | goto fail; 154 | } 155 | } 156 | if (max != NULL) { 157 | newdescr = CArray_DESCR(max); 158 | indescr = NULL; 159 | if (newdescr == NULL) { 160 | goto fail; 161 | } 162 | } 163 | else { 164 | /* Steal the reference */ 165 | newdescr = indescr; 166 | indescr = NULL; 167 | } 168 | 169 | /* 170 | * Use the scalar descriptor only if it is of a bigger 171 | * KIND than the input array (and then find the 172 | * type that matches both). 173 | */ 174 | if (newdescr->type_num > CArray_DESCR(self)->type_num, NULL) { 175 | indescr = CArray_DescrFromType(newdescr->type_num); 176 | 177 | if (indescr == NULL) { 178 | goto fail; 179 | } 180 | func = indescr->f->fastclip; 181 | } 182 | else { 183 | indescr = CArray_DESCR(self); 184 | CArrayDescriptor_INCREF(indescr); 185 | } 186 | newdescr = NULL; 187 | 188 | 189 | if (CArray_ISONESEGMENT(self) && 190 | CArray_CHKFLAGS(self, CARRAY_ARRAY_ALIGNED) && 191 | CArray_ISNOTSWAPPED(self) && 192 | (CArray_DESCR(self) == indescr)) { 193 | ingood = 1; 194 | } 195 | 196 | if (!ingood) { 197 | int flags; 198 | 199 | if (CArray_ISFORTRAN(self)) { 200 | flags = CARRAY_ARRAY_FARRAY; 201 | } 202 | else { 203 | flags = CARRAY_ARRAY_CARRAY; 204 | } 205 | 206 | newin = CArray_FromArray(self, indescr, flags); 207 | 208 | if (newin == NULL) { 209 | goto fail; 210 | } 211 | } 212 | else { 213 | newin = self; 214 | CArray_INCREF(newin); 215 | } 216 | 217 | 218 | /* 219 | * If we have already made a copy of the data, then use 220 | * that as the output array 221 | */ 222 | if (out == NULL && !ingood) { 223 | out = newin; 224 | } 225 | 226 | if (out == NULL) { 227 | 228 | out = emalloc(sizeof(CArray)); 229 | out = CArray_NewFromDescr(out, 230 | CArray_DESCR(self), CArray_NDIM(self), 231 | CArray_DIMS(self), 232 | NULL, NULL, 233 | CArray_ISFORTRAN(self), 234 | NULL); 235 | 236 | if (out == NULL) { 237 | goto fail; 238 | } 239 | 240 | outgood = 1; 241 | } 242 | 243 | maxa = max; 244 | mina = min; 245 | 246 | /* Now we can call the fast-clip function */ 247 | min_data = max_data = NULL; 248 | if (mina != NULL) { 249 | min_data = CArray_DATA(mina); 250 | } 251 | if (maxa != NULL) { 252 | max_data = CArray_DATA(maxa); 253 | } 254 | 255 | func(CArray_DATA(newin), CArray_SIZE(newin), min_data, max_data, CArray_DATA(out)); 256 | 257 | if (out_ptr != NULL) { 258 | add_to_buffer(out_ptr, out, sizeof(CArray)); 259 | } 260 | 261 | CArray_XDECREF(self); 262 | return out; 263 | fail: 264 | return NULL; 265 | } 266 | -------------------------------------------------------------------------------- /kernel/clip.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_CLIP_H 2 | #define CARRAY_CLIP_H 3 | 4 | #include "carray.h" 5 | 6 | CArray * CArray_Clip(CArray * self, CArray * min, CArray * max, MemoryPointer * out); 7 | void DOUBLE_clip(double *in, int ni, double *min, double *max, double *out); 8 | void INT_clip(int *in, int ni, int *min, int *max, int *out); 9 | 10 | #endif //CARRAY_CLIP_H 11 | -------------------------------------------------------------------------------- /kernel/common/cblas_funcs.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_CBLAS_FUNC_H 2 | #define PHPSCI_EXT_CBLAS_FUNC_H 3 | 4 | #include "../carray.h" 5 | 6 | typedef enum { 7 | _scalar, 8 | _column, 9 | _row, 10 | _matrix 11 | } MatrixShape; 12 | 13 | CArray * cblas_matrixproduct(int typenum, CArray * ap1, CArray *ap2, CArray *out, MemoryPointer * ptr); 14 | 15 | #endif //PHPSCI_EXT_CBLAS_FUNC_H -------------------------------------------------------------------------------- /kernel/common/clblas_funcs.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_CLBLAS_FUNC_H 2 | #define PHPSCI_EXT_CLBLAS_FUNC_H 3 | 4 | #include "../carray.h" 5 | 6 | CArray * clblas_matrixproduct(int typenum, CArray * ap1, CArray *ap2, CArray *out, MemoryPointer * ptr); 7 | 8 | #endif //PHPSCI_EXT_CLBLAS_FUNC_H -------------------------------------------------------------------------------- /kernel/common/common.c: -------------------------------------------------------------------------------- 1 | #include "../carray.h" 2 | #include "common.h" 3 | #include "exceptions.h" 4 | #include "../alloc.h" 5 | #include "mem_overlap.h" 6 | 7 | /** 8 | * @param ap 9 | * @return 10 | */ 11 | int 12 | _IsWriteable(CArray *ap) 13 | { 14 | CArray * base = CArray_BASE(ap); 15 | 16 | /* If we own our own data, then no-problem */ 17 | if ((base == NULL) || (CArray_FLAGS(ap) & CARRAY_ARRAY_OWNDATA)) { 18 | return 1; 19 | } 20 | 21 | /* 22 | * Get to the final base object 23 | * If it is a writeable array, then return TRUE 24 | * If we can find an array object 25 | * or a writeable buffer object as the final base object 26 | */ 27 | return 0; 28 | } 29 | 30 | /* 31 | * Make a new empty array, of the passed size, of a type that takes the 32 | * priority of ap1 and ap2 into account. 33 | * 34 | * If `out` is non-NULL, memory overlap is checked with ap1 and ap2, and an 35 | * updateifcopy temporary array may be returned. If `result` is non-NULL, the 36 | * output array to be returned (`out` if non-NULL and the newly allocated array 37 | * otherwise) is incref'd and put to *result. 38 | */ 39 | CArray * 40 | new_array_for_sum(CArray *ap1, CArray *ap2, CArray* out, 41 | int nd, int dimensions[], int typenum, CArray **result) 42 | { 43 | CArray *out_buf; 44 | if (out != NULL) { 45 | int d; 46 | 47 | /* verify that out is usable */ 48 | if (CArray_NDIM(out) != nd || 49 | CArray_TYPE(out) != typenum) { 50 | throw_valueerror_exception( 51 | "output array is not acceptable (must have the right datatype, " 52 | "number of dimensions, and be a C-Array)"); 53 | return 0; 54 | } 55 | for (d = 0; d < nd; ++d) { 56 | if (dimensions[d] != CArray_DIM(out, d)) { 57 | throw_valueerror_exception( 58 | "output array has wrong dimensions"); 59 | return 0; 60 | } 61 | } 62 | 63 | /* check for memory overlap */ 64 | if (!(solve_may_share_memory(out, ap1, 1) == 0 && 65 | solve_may_share_memory(out, ap2, 1) == 0)) { 66 | /* allocate temporary output array */ 67 | out_buf = CArray_NewLikeArray(out, CARRAY_CORDER, NULL, 0); 68 | if (out_buf == NULL) { 69 | return NULL; 70 | } 71 | 72 | /* set copy-back */ 73 | CArray_INCREF(out); 74 | if (CArray_SetWritebackIfCopyBase(out_buf, out) < 0) { 75 | CArray_XDECREF(out); 76 | CArray_XDECREF(out_buf); 77 | return NULL; 78 | } 79 | } 80 | else { 81 | CArray_INCREF(out); 82 | out_buf = out; 83 | } 84 | 85 | if (result) { 86 | CArray_INCREF(out); 87 | *result = out; 88 | } 89 | 90 | return out_buf; 91 | } 92 | else { 93 | CArray * subtype; 94 | double prior1, prior2; 95 | out_buf = (CArray *)emalloc(sizeof(CArray)); 96 | 97 | prior1 = prior2 = 0.0; 98 | subtype = ap1; 99 | 100 | out_buf = CArray_New(out_buf, nd, dimensions, 101 | typenum, NULL, NULL, 0, 0, 102 | NULL); 103 | 104 | return out_buf; 105 | } 106 | } 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /kernel/common/common.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_COMMON_H 2 | #define PHPSCI_EXT_COMMON_H 3 | 4 | #include "../carray.h" 5 | #include "../assign.h" 6 | 7 | # define CARRAY_LONGLONG_SUFFIX(x) (x##L) 8 | # define CARRAY_ULONGLONG_SUFFIX(x) (x##UL) 9 | 10 | /* 11 | * numarray-style bit-width typedefs 12 | */ 13 | #define CARRAY_MAX_INT8 127 14 | #define CARRAY_MIN_INT8 -128 15 | #define CARRAY_MAX_UINT8 255 16 | #define CARRAY_MAX_INT16 32767 17 | #define CARRAY_MIN_INT16 -32768 18 | #define CARRAY_MAX_UINT16 65535 19 | #define CARRAY_MAX_INT32 2147483647 20 | #define CARRAY_MIN_INT32 (-CARRAY_MAX_INT32 - 1) 21 | #define CARRAY_MAX_UINT32 4294967295U 22 | #define CARRAY_MAX_INT64 CARRAY_LONGLONG_SUFFIX(9223372036854775807) 23 | #define CARRAY_MIN_INT64 (-CARRAY_MAX_INT64 - CARRAY_LONGLONG_SUFFIX(1)) 24 | #define CARRAY_MAX_UINT64 CARRAY_ULONGLONG_SUFFIX(18446744073709551615) 25 | #define CARRAY_MAX_INT128 CARRAY_LONGLONG_SUFFIX(85070591730234615865843651857942052864) 26 | #define CARRAY_MIN_INT128 (-CARRAY_MAX_INT128 - CARRAY_LONGLONG_SUFFIX(1)) 27 | #define CARRAY_MAX_UINT128 CARRAY_ULONGLONG_SUFFIX(170141183460469231731687303715884105728) 28 | #define CARRAY_MAX_INT256 CARRAY_LONGLONG_SUFFIX(57896044618658097711785492504343953926634992332820282019728792003956564819967) 29 | #define CARRAY_MIN_INT256 (-CARRAY_MAX_INT256 - CARRAY_LONGLONG_SUFFIX(1)) 30 | #define CARRAY_MAX_UINT256 CARRAY_ULONGLONG_SUFFIX(115792089237316195423570985008687907853269984665640564039457584007913129639935) 31 | #define CARRAY_MIN_DATETIME CARRAY_MIN_INT64 32 | #define CARRAY_MAX_DATETIME CARRAY_MAX_INT64 33 | #define CARRAY_MIN_TIMEDELTA CARRAY_MIN_INT64 34 | #define CARRAY_MAX_TIMEDELTA CARRAY_MAX_INT64 35 | #define CARRAY_MAX_INT INT_MAX 36 | #define CARRAY_MAX_INTP CARRAY_MAX_INT 37 | 38 | 39 | #if CARRAY_MAX_INTP > INT_MAX 40 | # define CARRAY_CBLAS_CHUNK (INT_MAX / 2 + 1) 41 | #else 42 | # define CARRAY_CBLAS_CHUNK CARRAY_MAX_INTP 43 | #endif 44 | 45 | 46 | /* 47 | * Convert CArray stride to BLAS stride. Returns 0 if conversion cannot be done 48 | * (BLAS won't handle negative or zero strides the way we want). 49 | */ 50 | static inline int 51 | blas_stride(int stride, unsigned itemsize) 52 | { 53 | if (stride > 0 && carray_is_aligned((void*)&stride, itemsize)) { 54 | stride /= itemsize; 55 | if (stride <= INT_MAX) { 56 | return stride; 57 | } 58 | } 59 | return 0; 60 | } 61 | 62 | /* used for some alignment checks */ 63 | #define _ALIGN(type) offsetof(struct {char c; type v;}, v) 64 | #define _UINT_ALIGN(type) carray_uint_alignment(sizeof(type)) 65 | 66 | /* Get equivalent "uint" alignment given an itemsize, for use in copy code */ 67 | static inline int 68 | carray_uint_alignment(int itemsize) 69 | { 70 | int alignment = 0; /* return value of 0 means unaligned */ 71 | 72 | switch(itemsize){ 73 | case 1: 74 | return 1; 75 | case 2: 76 | alignment = _ALIGN(uint16_t); 77 | break; 78 | case 4: 79 | alignment = _ALIGN(uint32_t); 80 | break; 81 | case 8: 82 | alignment = _ALIGN(uint64_t); 83 | break; 84 | case 16: 85 | /* 86 | * 16 byte types are copied using 2 uint64 assignments. 87 | * See the strided copy function in lowlevel_strided_loops.c. 88 | */ 89 | alignment = _ALIGN(uint64_t); 90 | break; 91 | default: 92 | break; 93 | } 94 | return alignment; 95 | } 96 | 97 | /* 98 | * Returns -1 and sets an exception if *index is an invalid index for 99 | * an array of size max_item, otherwise adjusts it in place to be 100 | * 0 <= *index < max_item, and returns 0. 101 | * 'axis' should be the array axis that is being indexed over, if known. If 102 | * unknown, use -1. 103 | * If _save is NULL it is assumed the GIL is taken 104 | * If _save is not NULL it is assumed the GIL is not taken and it 105 | * is acquired in the case of an error 106 | */ 107 | static inline int 108 | check_and_adjust_index(int *index, int max_item, int axis) 109 | { 110 | /* Check that index is valid, taking into account negative indices */ 111 | if (CARRAY_UNLIKELY((*index < -max_item) || (*index >= max_item))) { 112 | /* Try to be as clear as possible about what went wrong. */ 113 | if (axis >= 0) { 114 | throw_indexerror_exception("index is out of bounds for axis"); 115 | } else { 116 | throw_indexerror_exception("index is out of bounds for size"); 117 | } 118 | return -1; 119 | } 120 | /* adjust negative indices */ 121 | if (*index < 0) { 122 | *index += max_item; 123 | } 124 | return 0; 125 | } 126 | 127 | 128 | 129 | 130 | CArray * new_array_for_sum(CArray *ap1, CArray *ap2, CArray* out, 131 | int nd, int dimensions[], int typenum, CArray **result); 132 | int _IsWriteable(CArray *ap); 133 | #endif //PHPSCI_EXT_COMMON_H -------------------------------------------------------------------------------- /kernel/common/compare.c: -------------------------------------------------------------------------------- 1 | #include "compare.h" 2 | #include "../carray.h" 3 | 4 | int 5 | INT_compare (int *pa, int *pb, CArray *CARRAY_UNUSED(ap)) 6 | { 7 | const int a = *pa; 8 | const int b = *pb; 9 | 10 | return a < b ? -1 : a == b ? 0 : 1; 11 | } 12 | 13 | #define LT(a,b) ((a) < (b) || ((b) != (b) && (a) ==(a))) 14 | 15 | int 16 | DOUBLE_compare(double *pa, double *pb) 17 | { 18 | const double a = *pa; 19 | const double b = *pb; 20 | int ret; 21 | 22 | if (LT(a,b)) { 23 | ret = -1; 24 | } 25 | else if (LT(b,a)) { 26 | ret = 1; 27 | } 28 | else { 29 | ret = 0; 30 | } 31 | return ret; 32 | } 33 | -------------------------------------------------------------------------------- /kernel/common/compare.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_COMPARE_H 2 | #define CARRAY_COMPARE_H 3 | 4 | #include "../carray.h" 5 | 6 | int DOUBLE_compare(double *pa, double *pb); 7 | int INT_compare (int *pa, int *pb, CArray *CARRAY_UNUSED(ap)); 8 | 9 | #endif //CARRAY_COMPARE_H 10 | -------------------------------------------------------------------------------- /kernel/common/exceptions.c: -------------------------------------------------------------------------------- 1 | #include "php.h" 2 | #include "exceptions.h" 3 | #include "Zend/zend_exceptions.h" 4 | 5 | static zend_class_entry * phpsci_ce_CArrayAxisException; 6 | static zend_class_entry * phpsci_ce_CArrayValueErrorException; 7 | static zend_class_entry * phpsci_ce_CArrayTypeErrorException; 8 | static zend_class_entry * phpsci_ce_CArrayOverflowException; 9 | static zend_class_entry * phpsci_ce_CArrayMemoryException; 10 | static zend_class_entry * phpsci_ce_CArrayNotImplementedException; 11 | static zend_class_entry * phpsci_ce_CArrayIndexErrorException; 12 | 13 | static const zend_function_entry phpsci_ce_CArrayAxisException_methods[] = { 14 | PHP_FE_END 15 | }; 16 | static const zend_function_entry phpsci_ce_CArrayValueErrorException_methods[] = { 17 | PHP_FE_END 18 | }; 19 | static const zend_function_entry phpsci_ce_CArrayTypeErrorException_methods[] = { 20 | PHP_FE_END 21 | }; 22 | 23 | static const zend_function_entry phpsci_ce_CArrayOverflowException_methods[] = { 24 | PHP_FE_END 25 | }; 26 | 27 | static const zend_function_entry phpsci_ce_CArrayMemoryException_methods[] = { 28 | PHP_FE_END 29 | }; 30 | 31 | static const zend_function_entry phpsci_ce_CArrayNotImplementedException_methods[] = { 32 | PHP_FE_END 33 | }; 34 | 35 | static const zend_function_entry phpsci_ce_CArrayIndexErrorException_methods[] = { 36 | PHP_FE_END 37 | }; 38 | 39 | /** 40 | * Initialize Exception Classes 41 | */ 42 | void 43 | init_exception_objects() 44 | { 45 | zend_class_entry ce; 46 | INIT_CLASS_ENTRY(ce, "CArrayAxisException", phpsci_ce_CArrayAxisException_methods); 47 | phpsci_ce_CArrayAxisException = zend_register_internal_class_ex(&ce, zend_ce_exception); 48 | INIT_CLASS_ENTRY(ce, "CArrayValueErrorException", phpsci_ce_CArrayAxisException_methods); 49 | phpsci_ce_CArrayValueErrorException = zend_register_internal_class_ex(&ce, zend_ce_exception); 50 | INIT_CLASS_ENTRY(ce, "CArrayTypeErrorException", phpsci_ce_CArrayAxisException_methods); 51 | phpsci_ce_CArrayTypeErrorException = zend_register_internal_class_ex(&ce, zend_ce_exception); 52 | INIT_CLASS_ENTRY(ce, "CArrayOverflowException", phpsci_ce_CArrayOverflowException_methods); 53 | phpsci_ce_CArrayTypeErrorException = zend_register_internal_class_ex(&ce, zend_ce_exception); 54 | INIT_CLASS_ENTRY(ce, "CArrayMemoryException", phpsci_ce_CArrayMemoryException_methods); 55 | phpsci_ce_CArrayMemoryException = zend_register_internal_class_ex(&ce, zend_ce_exception); 56 | INIT_CLASS_ENTRY(ce, "CArrayNotImplementedException", phpsci_ce_CArrayNotImplementedException_methods); 57 | phpsci_ce_CArrayNotImplementedException = zend_register_internal_class_ex(&ce, zend_ce_exception); 58 | INIT_CLASS_ENTRY(ce, "CArrayIndexErrorException", phpsci_ce_CArrayIndexErrorException_methods); 59 | phpsci_ce_CArrayIndexErrorException = zend_register_internal_class_ex(&ce, zend_ce_exception); 60 | } 61 | 62 | /** 63 | * Throw CArrayAxisException 64 | */ 65 | void 66 | throw_notimplemented_exception() 67 | { 68 | zend_throw_exception_ex(phpsci_ce_CArrayNotImplementedException, NOTIMPLEMENTED_EXCEPTION, "%s", 69 | "Whoops! Looks like this situation was unexpected."); 70 | } 71 | 72 | /** 73 | * Throw CArrayAxisException 74 | */ 75 | void 76 | throw_memory_exception(char * msg) 77 | { 78 | zend_throw_exception_ex(phpsci_ce_CArrayMemoryException, MEMORY_EXCEPTION, "%s", msg); 79 | } 80 | 81 | /** 82 | * Throw CArrayAxisException 83 | */ 84 | void 85 | throw_axis_exception(char * msg) 86 | { 87 | zend_throw_exception_ex(phpsci_ce_CArrayAxisException, AXIS_EXCEPTION, "%s", msg); 88 | } 89 | 90 | /** 91 | * Throw ValueErrorException 92 | */ 93 | void 94 | throw_valueerror_exception(char * msg) 95 | { 96 | zend_throw_exception_ex(phpsci_ce_CArrayValueErrorException, VALUEERROR_EXCEPTION, "%s", msg); 97 | } 98 | 99 | /** 100 | * Throw TypeErrorException 101 | */ 102 | void 103 | throw_typeerror_exception(char * msg) 104 | { 105 | zend_throw_exception_ex(phpsci_ce_CArrayTypeErrorException, TYPEERROR_EXCEPTION, "%s", msg); 106 | } 107 | 108 | /** 109 | * Throw OverflowException 110 | * @param msg 111 | */ 112 | void 113 | throw_overflow_exception(char * msg) 114 | { 115 | zend_throw_exception_ex(phpsci_ce_CArrayOverflowException, OVERFLOW_EXCEPTION, "%s", msg); 116 | } 117 | 118 | /** 119 | * Throw IndexErrorException 120 | * @param msg 121 | */ 122 | void 123 | throw_indexerror_exception(char * msg) 124 | { 125 | zend_throw_exception_ex(phpsci_ce_CArrayIndexErrorException, INDEXERROR_EXCEPTION, "%s", msg); 126 | } 127 | 128 | -------------------------------------------------------------------------------- /kernel/common/exceptions.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_EXCEPTIONS_H 2 | #define PHPSCI_EXT_EXCEPTIONS_H 3 | 4 | #define AXIS_EXCEPTION 5000 5 | #define VALUEERROR_EXCEPTION 5001 6 | #define TYPEERROR_EXCEPTION 5002 7 | #define OVERFLOW_EXCEPTION 5003 8 | #define MEMORY_EXCEPTION 5004 9 | #define NOTIMPLEMENTED_EXCEPTION 5005 10 | #define INDEXERROR_EXCEPTION 5006 11 | 12 | void init_exception_objects(); 13 | void throw_axis_exception(char * msg); 14 | void throw_valueerror_exception(char * msg); 15 | void throw_typeerror_exception(char * msg); 16 | void throw_overflow_exception(char * msg); 17 | void throw_memory_exception(char * msg); 18 | void throw_notimplemented_exception(); 19 | void throw_indexerror_exception(char * msg); 20 | #endif //PHPSCI_EXT_EXCEPTIONS_H -------------------------------------------------------------------------------- /kernel/common/matmul.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_MATMUL_H 2 | #define CARRAY_MATMUL_H 3 | 4 | #include "../carray.h" 5 | 6 | void DOUBLE_matmul(char **args, int *dimensions, int *steps, void *CARRAY_UNUSED(func)); 7 | void INT_matmul(char **args, int *dimensions, int *steps, void *CARRAY_UNUSED(func)); 8 | #endif //CARRAY_MATMUL_H 9 | -------------------------------------------------------------------------------- /kernel/common/mem_overlap.h: -------------------------------------------------------------------------------- 1 | /* 2 | Original File 3 | Copyright (c) NumPy (/numpy/core/src/common/mem_overlap.c) 4 | 5 | Edited for CArrays in 2018 6 | Henrique Borba 7 | henrique.borba.dev@gmail.com 8 | 9 | Solving memory overlap integer programs and bounded Diophantine equations with 10 | positive coefficients. 11 | Asking whether two strided arrays `a` and `b` overlap is equivalent to 12 | asking whether there is a solution to the following problem:: 13 | sum(stride_a[i] * x_a[i] for i in range(ndim_a)) 14 | - 15 | sum(stride_b[i] * x_b[i] for i in range(ndim_b)) 16 | == 17 | base_b - base_a 18 | 19 | 0 <= x_a[i] < shape_a[i] 20 | 21 | 0 <= x_b[i] < shape_b[i] 22 | 23 | for some integer x_a, x_b. Itemsize needs to be considered as an additional 24 | dimension with stride 1 and size itemsize. 25 | Negative strides can be changed to positive (and vice versa) by changing 26 | variables x[i] -> shape[i] - 1 - x[i], and zero strides can be dropped, so 27 | that the problem can be recast into a bounded Diophantine equation with 28 | positive coefficients:: 29 | 30 | sum(a[i] * x[i] for i in range(n)) == b 31 | 32 | a[i] > 0 33 | 34 | 0 <= x[i] <= ub[i] 35 | 36 | This problem is NP-hard --- runtime of algorithms grows exponentially with 37 | increasing ndim. 38 | *Algorithm description* 39 | A straightforward algorithm that excludes infeasible solutions using GCD-based 40 | pruning is outlined in Ref. [1]. It is implemented below. A number of other 41 | algorithms exist in the literature; however, this one seems to have 42 | performance satisfactory for the present purpose. 43 | The idea is that an equation:: 44 | 45 | a_1 x_1 + a_2 x_2 + ... + a_n x_n = b 46 | 47 | 0 <= x_i <= ub_i, i = 1...n 48 | 49 | implies:: 50 | 51 | a_2' x_2' + a_3 x_3 + ... + a_n x_n = b 52 | 53 | 0 <= x_i <= ub_i, i = 2...n 54 | 55 | 0 <= x_1' <= c_1 ub_1 + c_2 ub_2 56 | 57 | with a_2' = gcd(a_1, a_2) and x_2' = c_1 x_1 + c_2 x_2 with c_1 = (a_1/a_1'), 58 | and c_2 = (a_2/a_1'). This procedure can be repeated to obtain:: 59 | 60 | a_{n-1}' x_{n-1}' + a_n x_n = b 61 | 62 | 0 <= x_{n-1}' <= ub_{n-1}' 63 | 64 | 0 <= x_n <= ub_n 65 | 66 | Now, one can enumerate all candidate solutions for x_n. For each, one can use 67 | the previous-level equation to enumerate potential solutions for x_{n-1}, with 68 | transformed right-hand side b -> b - a_n x_n. And so forth, until after n-1 69 | nested for loops we either arrive at a candidate solution for x_1 (in which 70 | case we have found one solution to the problem), or find that the equations do 71 | not allow any solutions either for x_1 or one of the intermediate x_i (in 72 | which case we have proved there is no solution for the upper-level candidates 73 | chosen). If no solution is found for any candidate x_n, we have proved the 74 | problem is infeasible --- which for the memory overlap problem means there is 75 | no overlap. 76 | */ 77 | 78 | #ifndef PHPSCI_EXT_MEM_OVERLAP_H 79 | #define PHPSCI_EXT_MEM_OVERLAP_H 80 | 81 | #include "../carray.h" 82 | 83 | /* Bounds check only */ 84 | #define CARRAY_MAY_SHARE_BOUNDS 0 85 | 86 | /* Exact solution */ 87 | #define CARRAY_MAY_SHARE_EXACT -1 88 | 89 | 90 | typedef enum { 91 | MEM_OVERLAP_NO = 0, /* no solution exists */ 92 | MEM_OVERLAP_YES = 1, /* solution found */ 93 | MEM_OVERLAP_TOO_HARD = -1, /* max_work exceeded */ 94 | MEM_OVERLAP_OVERFLOW = -2, /* algorithm failed due to integer overflow */ 95 | MEM_OVERLAP_ERROR = -3 /* invalid input */ 96 | } mem_overlap_t; 97 | 98 | 99 | typedef struct { 100 | int64_t a; 101 | int64_t ub; 102 | } diophantine_term_t; 103 | 104 | mem_overlap_t solve_may_share_memory(CArray *a, CArray *b, size_t max_work); 105 | 106 | #endif //PHPSCI_EXT_MEM_OVERLAP_H -------------------------------------------------------------------------------- /kernel/common/partition.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_PARTITION_H 2 | #define CARRAY_PARTITION_H 3 | 4 | #define CARRAY_MAX_PIVOT_STACK 50 5 | 6 | #endif //CARRAY_PARTITION_H 7 | -------------------------------------------------------------------------------- /kernel/common/sort.c: -------------------------------------------------------------------------------- 1 | #include "sort.h" 2 | #include "../carray.h" 3 | 4 | int 5 | carray_heapsort(void *start, int num, void *varr) 6 | { 7 | CArray *arr = varr; 8 | int elsize = CArray_ITEMSIZE(arr); 9 | CArray_CompareFunc *cmp = CArray_DESCR(arr)->f->compare; 10 | char *tmp = emalloc(elsize); 11 | char *a = (char *)start - elsize; 12 | int i, j, l; 13 | 14 | if (tmp == NULL) { 15 | return -CARRAY_ENOMEM; 16 | } 17 | 18 | for (l = num >> 1; l > 0; --l) { 19 | GENERIC_COPY(tmp, a + l*elsize, elsize); 20 | for (i = l, j = l << 1; j <= num;) { 21 | if (j < num && cmp(a + j*elsize, a + (j+1)*elsize, arr) < 0) { 22 | ++j; 23 | } 24 | if (cmp(tmp, a + j*elsize, arr) < 0) { 25 | GENERIC_COPY(a + i*elsize, a + j*elsize, elsize); 26 | i = j; 27 | j += j; 28 | } 29 | else { 30 | break; 31 | } 32 | } 33 | GENERIC_COPY(a + i*elsize, tmp, elsize); 34 | } 35 | 36 | for (; num > 1;) { 37 | GENERIC_COPY(tmp, a + num*elsize, elsize); 38 | GENERIC_COPY(a + num*elsize, a + elsize, elsize); 39 | num -= 1; 40 | for (i = 1, j = 2; j <= num;) { 41 | if (j < num && cmp(a + j*elsize, a + (j+1)*elsize, arr) < 0) { 42 | ++j; 43 | } 44 | if (cmp(tmp, a + j*elsize, arr) < 0) { 45 | GENERIC_COPY(a + i*elsize, a + j*elsize, elsize); 46 | i = j; 47 | j += j; 48 | } 49 | else { 50 | break; 51 | } 52 | } 53 | GENERIC_COPY(a + i*elsize, tmp, elsize); 54 | } 55 | 56 | efree(tmp); 57 | return 0; 58 | } 59 | 60 | int 61 | carray_quicksort(void *start, int num, void *varr) 62 | { 63 | CArray *arr = varr; 64 | int elsize = CArray_ITEMSIZE(arr); 65 | CArray_CompareFunc *cmp = CArray_DESCR(arr)->f->compare; 66 | char *vp; 67 | char *pl = start; 68 | char *pr = pl + (num - 1)*elsize; 69 | char *stack[QS_STACK]; 70 | char **sptr = stack; 71 | char *pm, *pi, *pj, *pk; 72 | int depth[QS_STACK]; 73 | int * psdepth = depth; 74 | int cdepth = carray_get_msb(num) * 2; 75 | 76 | /* Items that have zero size don't make sense to sort */ 77 | if (elsize == 0) { 78 | return 0; 79 | } 80 | 81 | vp = emalloc(elsize); 82 | if (vp == NULL) { 83 | return -CARRAY_ENOMEM; 84 | } 85 | 86 | for (;;) { 87 | 88 | if (CARRAY_UNLIKELY(cdepth < 0)) { 89 | carray_heapsort(pl, (pr - pl) / elsize + 1, varr); 90 | goto stack_pop; 91 | } 92 | while(pr - pl > SMALL_QUICKSORT*elsize) { 93 | 94 | /* quicksort partition */ 95 | pm = pl + (((pr - pl) / elsize) >> 1) * elsize; 96 | if (cmp(pm, pl, arr) < 0) { 97 | GENERIC_SWAP(pm, pl, elsize); 98 | } 99 | if (cmp(pr, pm, arr) < 0) { 100 | GENERIC_SWAP(pr, pm, elsize); 101 | } 102 | if (cmp(pm, pl, arr) < 0) { 103 | GENERIC_SWAP(pm, pl, elsize); 104 | } 105 | GENERIC_COPY(vp, pm, elsize); 106 | pi = pl; 107 | pj = pr - elsize; 108 | GENERIC_SWAP(pm, pj, elsize); 109 | /* 110 | * Generic comparisons may be buggy, so don't rely on the sentinels 111 | * to keep the pointers from going out of bounds. 112 | */ 113 | for (;;) { 114 | do { 115 | pi += elsize; 116 | } while (cmp(pi, vp, arr) < 0 && pi < pj); 117 | do { 118 | pj -= elsize; 119 | } while (cmp(vp, pj, arr) < 0 && pi < pj); 120 | if (pi >= pj) { 121 | break; 122 | } 123 | GENERIC_SWAP(pi, pj, elsize); 124 | } 125 | pk = pr - elsize; 126 | GENERIC_SWAP(pi, pk, elsize); 127 | /* push largest partition on stack */ 128 | if (pi - pl < pr - pi) { 129 | *sptr++ = pi + elsize; 130 | *sptr++ = pr; 131 | pr = pi - elsize; 132 | } 133 | else { 134 | *sptr++ = pl; 135 | *sptr++ = pi - elsize; 136 | pl = pi + elsize; 137 | } 138 | *psdepth++ = --cdepth; 139 | } 140 | 141 | /* insertion sort */ 142 | for (pi = pl + elsize; pi <= pr; pi += elsize) { 143 | GENERIC_COPY(vp, pi, elsize); 144 | pj = pi; 145 | pk = pi - elsize; 146 | while (pj > pl && cmp(vp, pk, arr) < 0) { 147 | GENERIC_COPY(pj, pk, elsize); 148 | pj -= elsize; 149 | pk -= elsize; 150 | } 151 | GENERIC_COPY(pj, vp, elsize); 152 | } 153 | stack_pop: 154 | if (sptr == stack) { 155 | break; 156 | } 157 | pr = *(--sptr); 158 | pl = *(--sptr); 159 | cdepth = *(--psdepth); 160 | } 161 | 162 | efree(vp); 163 | return 0; 164 | } 165 | 166 | static void 167 | carray_mergesort0(char *pl, char *pr, char *pw, char *vp, int elsize, 168 | CArray_CompareFunc *cmp, CArray *arr) 169 | { 170 | char *pi, *pj, *pk, *pm; 171 | 172 | if (pr - pl > SMALL_MERGESORT*elsize) { 173 | /* merge sort */ 174 | pm = pl + (((pr - pl)/elsize) >> 1)*elsize; 175 | carray_mergesort0(pl, pm, pw, vp, elsize, cmp, arr); 176 | carray_mergesort0(pm, pr, pw, vp, elsize, cmp, arr); 177 | GENERIC_COPY(pw, pl, pm - pl); 178 | pi = pw + (pm - pl); 179 | pj = pw; 180 | pk = pl; 181 | while (pj < pi && pm < pr) { 182 | if (cmp(pm, pj, arr) < 0) { 183 | GENERIC_COPY(pk, pm, elsize); 184 | pm += elsize; 185 | pk += elsize; 186 | } 187 | else { 188 | GENERIC_COPY(pk, pj, elsize); 189 | pj += elsize; 190 | pk += elsize; 191 | } 192 | } 193 | GENERIC_COPY(pk, pj, pi - pj); 194 | } 195 | else { 196 | /* insertion sort */ 197 | for (pi = pl + elsize; pi < pr; pi += elsize) { 198 | GENERIC_COPY(vp, pi, elsize); 199 | pj = pi; 200 | pk = pi - elsize; 201 | while (pj > pl && cmp(vp, pk, arr) < 0) { 202 | GENERIC_COPY(pj, pk, elsize); 203 | pj -= elsize; 204 | pk -= elsize; 205 | } 206 | GENERIC_COPY(pj, vp, elsize); 207 | } 208 | } 209 | } 210 | 211 | int 212 | carray_mergesort(void *start, int num, void *varr) 213 | { 214 | CArray *arr = varr; 215 | int elsize = CArray_ITEMSIZE(arr); 216 | CArray_CompareFunc *cmp = CArray_DESCR(arr)->f->compare; 217 | char *pl = start; 218 | char *pr = pl + num*elsize; 219 | char *pw; 220 | char *vp; 221 | int err = -CARRAY_ENOMEM; 222 | 223 | /* Items that have zero size don't make sense to sort */ 224 | if (elsize == 0) { 225 | return 0; 226 | } 227 | 228 | pw = emalloc((num >> 1) *elsize); 229 | vp = emalloc(elsize); 230 | 231 | if (pw != NULL && vp != NULL) { 232 | carray_mergesort0(pl, pr, pw, vp, elsize, cmp, arr); 233 | err = 0; 234 | } 235 | 236 | efree(vp); 237 | efree(pw); 238 | 239 | return err; 240 | } 241 | -------------------------------------------------------------------------------- /kernel/common/sort.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_SORT_H 2 | #define CARRAY_SORT_H 3 | 4 | #include "stdio.h" 5 | #include "string.h" 6 | 7 | #define QS_STACK 100 8 | #define SMALL_QUICKSORT 15 9 | #define SMALL_MERGESORT 20 10 | #define SMALL_STRING 16 11 | 12 | #define CARRAY_ENOMEM 1 13 | #define CARRAY_ECOMP 2 14 | 15 | static inline int carray_get_msb(int unum) 16 | { 17 | int depth_limit = 0; 18 | while (unum >>= 1) { 19 | depth_limit++; 20 | } 21 | return depth_limit; 22 | } 23 | 24 | inline static void 25 | GENERIC_SWAP(char *a, char *b, size_t len) 26 | { 27 | while(len--) { 28 | const char t = *a; 29 | *a++ = *b; 30 | *b++ = t; 31 | } 32 | } 33 | 34 | inline static void 35 | GENERIC_COPY(char *a, char *b, size_t len) 36 | { 37 | memcpy(a, b, len); 38 | } 39 | 40 | 41 | /* 42 | ***************************************************************************** 43 | ** GENERIC SORT ** 44 | ***************************************************************************** 45 | */ 46 | int carray_quicksort(void *vec, int cnt, void *arr); 47 | int carray_heapsort(void *vec, int cnt, void *arr); 48 | int carray_mergesort(void *vec, int cnt, void *arr); 49 | int carray_timsort(void *vec, int cnt, void *arr); 50 | int carray_aquicksort(void *vec, int *ind, int cnt, void *arr); 51 | int carray_aheapsort(void *vec, int *ind, int cnt, void *arr); 52 | int carray_amergesort(void *vec, int *ind, int cnt, void *arr); 53 | int carray_atimsort(void *vec, int *ind, int cnt, void *arr); 54 | 55 | #endif //CARRAY_SORT_H 56 | -------------------------------------------------------------------------------- /kernel/common/strided_loops.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_STRIDE_LOOPS_H 2 | #define PHPSCI_EXT_STRIDE_LOOPS_H 3 | 4 | #include "../carray.h" 5 | #include "common.h" 6 | 7 | /* byte swapping functions */ 8 | static inline uint16_t 9 | carray_bswap2(uint16_t x) 10 | { 11 | return ((x & 0xffu) << 8) | (x >> 8); 12 | } 13 | 14 | /* 15 | * treat as int16 and byteswap unaligned memory, 16 | * some cpus don't support unaligned access 17 | */ 18 | static inline void 19 | carray_bswap2_unaligned(char * x) 20 | { 21 | char a = x[0]; 22 | x[0] = x[1]; 23 | x[1] = a; 24 | } 25 | 26 | static inline uint32_t 27 | carray_bswap4(uint32_t x) 28 | { 29 | #ifdef HAVE___BUILTIN_BSWAP32 30 | return __builtin_bswap32(x); 31 | #else 32 | return ((x & 0xffu) << 24) | ((x & 0xff00u) << 8) | 33 | ((x & 0xff0000u) >> 8) | (x >> 24); 34 | #endif 35 | } 36 | 37 | static inline void 38 | carray_bswap4_unaligned(char * x) 39 | { 40 | char a = x[0]; 41 | x[0] = x[3]; 42 | x[3] = a; 43 | a = x[1]; 44 | x[1] = x[2]; 45 | x[2] = a; 46 | } 47 | 48 | static inline uint64_t 49 | carray_bswap8(uint64_t x) 50 | { 51 | #ifdef HAVE___BUILTIN_BSWAP64 52 | return __builtin_bswap64(x); 53 | #else 54 | return ((x & 0xffULL) << 56) | 55 | ((x & 0xff00ULL) << 40) | 56 | ((x & 0xff0000ULL) << 24) | 57 | ((x & 0xff000000ULL) << 8) | 58 | ((x & 0xff00000000ULL) >> 8) | 59 | ((x & 0xff0000000000ULL) >> 24) | 60 | ((x & 0xff000000000000ULL) >> 40) | 61 | ( x >> 56); 62 | #endif 63 | } 64 | 65 | static inline void 66 | carray_bswap8_unaligned(char * x) 67 | { 68 | char a = x[0]; x[0] = x[7]; x[7] = a; 69 | a = x[1]; x[1] = x[6]; x[6] = a; 70 | a = x[2]; x[2] = x[5]; x[5] = a; 71 | a = x[3]; x[3] = x[4]; x[4] = a; 72 | } 73 | 74 | /* Start raw iteration */ 75 | #define CARRAY_RAW_ITER_START(idim, ndim, coord, shape) \ 76 | memset((coord), 0, (ndim) * sizeof(coord[0])); \ 77 | do { 78 | 79 | 80 | /* Increment to the next n-dimensional coordinate for one raw array */ 81 | #define CARRAY_RAW_ITER_ONE_NEXT(idim, ndim, coord, shape, data, strides) \ 82 | for ((idim) = 1; (idim) < (ndim); ++(idim)) { \ 83 | if (++(coord)[idim] == (shape)[idim]) { \ 84 | (coord)[idim] = 0; \ 85 | (data) -= ((shape)[idim] - 1) * (strides)[idim]; \ 86 | } \ 87 | else { \ 88 | (data) += (strides)[idim]; \ 89 | break; \ 90 | } \ 91 | } \ 92 | } while ((idim) < (ndim)) 93 | 94 | /* 95 | * This function pointer is for unary operations that input an 96 | * arbitrarily strided one-dimensional array segment and output 97 | * an arbitrarily strided array segment of the same size. 98 | * It may be a fully general function, or a specialized function 99 | * when the strides or item size have particular known values. 100 | * 101 | * Examples of unary operations are a straight copy, a byte-swap, 102 | * and a casting operation, 103 | * 104 | * The 'transferdata' parameter is slightly special, following a 105 | * generic auxiliary data pattern defined in carray.h 106 | * Use CARRAY_AUXDATA_CLONE and CARRAY_AUXDATA_FREE to deal with this data. 107 | * 108 | */ 109 | typedef void (CArray_StridedUnaryOp)(char *dst, int dst_stride, 110 | char *src, int src_stride, 111 | int N, int src_itemsize, 112 | CArrayAuxData *transferdata); 113 | 114 | 115 | /* 116 | * Gives back a function pointer to a specialized function for copying 117 | * strided memory. Returns NULL if there is a problem with the inputs. 118 | * 119 | * aligned: 120 | * Should be 1 if the src and dst pointers always point to 121 | * locations at which a uint of equal size to dtype->elsize 122 | * would be aligned, 0 otherwise. 123 | * src_stride: 124 | * Should be the src stride if it will always be the same, 125 | * MAX_INT otherwise. 126 | * dst_stride: 127 | * Should be the dst stride if it will always be the same, 128 | * MAX_INT otherwise. 129 | * itemsize: 130 | * Should be the item size if it will always be the same, 0 otherwise. 131 | * 132 | */ 133 | CArray_StridedUnaryOp * CArray_GetStridedCopyFn(int aligned, int src_stride, int dst_stride, int itemsize); 134 | CArray_StridedUnaryOp * CArray_GetStridedNumericCastFn(int aligned, int src_stride, 135 | int dst_stride, 136 | int src_type_num, int dst_type_num); 137 | #endif //PHPSCI_EXT_STRIDE_LOOPS_H -------------------------------------------------------------------------------- /kernel/conversion_utils.c: -------------------------------------------------------------------------------- 1 | #include "carray.h" 2 | #include "conversion_utils.h" 3 | 4 | /* 5 | * Converts an axis parameter into an ndim-length C-array of 6 | * boolean flags, True for each axis specified. 7 | * 8 | * If obj is None or NULL, everything is set to True. If obj is a tuple, 9 | * each axis within the tuple is set to True. If obj is an integer, 10 | * just that axis is set to True. 11 | */ 12 | int 13 | CArray_ConvertMultiAxis(int *axis_in, int ndim, int *out_axis_flags) 14 | { 15 | /* INT_MAX means all of the axes */ 16 | if (*axis_in == INT_MAX || axis_in == NULL) { 17 | memset(out_axis_flags, 1, ndim); 18 | return CARRAY_SUCCEED; 19 | } 20 | /* Try to interpret axis as an integer */ 21 | else { 22 | int axis; 23 | axis = axis_in[0]; 24 | 25 | memset(out_axis_flags, 0, ndim); 26 | 27 | /* 28 | * Special case letting axis={-1,0} slip through for scalars, 29 | * for backwards compatibility reasons. 30 | */ 31 | if (ndim == 0 && (axis == 0 || axis == -1)) { 32 | return CARRAY_SUCCEED; 33 | } 34 | 35 | if (check_and_adjust_axis(&axis, ndim) < 0) { 36 | return CARRAY_FAIL; 37 | } 38 | 39 | out_axis_flags[axis] = 1; 40 | 41 | return CARRAY_SUCCEED; 42 | } 43 | } -------------------------------------------------------------------------------- /kernel/conversion_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_CONVERSION_UTILS_H 2 | #define PHPSCI_EXT_CONVERSION_UTILS_H 3 | 4 | #include "carray.h" 5 | 6 | int CArray_ConvertMultiAxis(int *axis_in, int ndim, int *out_axis_flags); 7 | 8 | #endif -------------------------------------------------------------------------------- /kernel/convert.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_CONVERT_H 2 | #define PHPSCI_EXT_CONVERT_H 3 | 4 | #include "carray.h" 5 | #include "scalar.h" 6 | 7 | CArray * CArray_Slice_Index(CArray * self, int index, MemoryPointer * out); 8 | CArray * CArray_Slice_Str(CArray * self, char * index, MemoryPointer * out); 9 | 10 | CArray * CArray_View(CArray *self); 11 | CArray * CArray_NewCopy(CArray *obj, CARRAY_ORDER order); 12 | int CArray_CanCastTo(CArrayDescriptor *from, CArrayDescriptor *to); 13 | int CArray_CanCastSafely(int fromtype, int totype); 14 | int CArray_CastTo(CArray *out, CArray *mp); 15 | int CArray_FillWithScalar(CArray * arr, CArrayScalar * sc); 16 | #endif //PHPSCI_EXT_CONVERT_H 17 | -------------------------------------------------------------------------------- /kernel/convert_datatype.c: -------------------------------------------------------------------------------- 1 | #include "carray.h" 2 | #include "convert_datatype.h" 3 | #include "common/exceptions.h" 4 | #include "convert_type.h" 5 | 6 | int 7 | can_cast_scalar_to(CArrayDescriptor *scal_type, char *scal_data, 8 | CArrayDescriptor *to, CARRAY_CASTING casting) 9 | { 10 | int swap; 11 | int is_small_unsigned = 0, type_num; 12 | int ret; 13 | CArrayDescriptor *dtype; 14 | 15 | /* An aligned memory buffer large enough to hold any type */ 16 | long long value[4]; 17 | 18 | /* 19 | * If the two dtypes are actually references to the same object 20 | * or if casting type is forced unsafe then always OK. 21 | */ 22 | if (scal_type == to || casting == CARRAY_UNSAFE_CASTING ) { 23 | return 1; 24 | } 25 | 26 | swap = !CArray_ISNBO(scal_type->byteorder); 27 | scal_type->f->copyswap(&value, scal_data, swap, NULL); 28 | 29 | type_num = min_scalar_type_num((char *)&value, scal_type->type_num, 30 | &is_small_unsigned); 31 | 32 | /* 33 | * If we've got a small unsigned scalar, and the 'to' type 34 | * is not unsigned, then make it signed to allow the value 35 | * to be cast more appropriately. 36 | */ 37 | if (is_small_unsigned && !(CArrayTypeNum_ISUNSIGNED(to->type_num))) { 38 | type_num = type_num_unsigned_to_signed(type_num); 39 | } 40 | 41 | dtype = CArray_DescrFromType(type_num); 42 | if (dtype == NULL) { 43 | return 0; 44 | } 45 | 46 | ret = CArray_CanCastTypeTo(dtype, to, casting); 47 | return ret; 48 | } 49 | -------------------------------------------------------------------------------- /kernel/convert_datatype.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_CONVERT_DATATYPE_H 2 | #define PHPSCI_EXT_CONVERT_DATATYPE_H 3 | 4 | #include "carray.h" 5 | 6 | int can_cast_scalar_to(CArrayDescriptor *scal_type, char *scal_data, 7 | CArrayDescriptor *to, CARRAY_CASTING casting); 8 | 9 | #endif //PHPSCI_EXT_CONVERT_DATATYPE_H 10 | -------------------------------------------------------------------------------- /kernel/convert_type.c: -------------------------------------------------------------------------------- 1 | #include "convert_type.h" 2 | #include "alloc.h" 3 | #include "carray.h" 4 | #include "convert.h" 5 | #include "convert_datatype.h" 6 | 7 | /** 8 | * @param op 9 | * @param minimum_type 10 | * @return 11 | */ 12 | int 13 | CArray_ObjectType(CArray * op, int minimum_type) 14 | { 15 | CArrayDescriptor *dtype = NULL; 16 | int ret; 17 | 18 | if (minimum_type >= 0) { 19 | if (CArray_TYPE(op) <= minimum_type) { 20 | dtype = CArray_DescrFromType(minimum_type); 21 | } 22 | if (CArray_TYPE(op) > minimum_type) { 23 | dtype = CArray_DescrFromType(CArray_TYPE(op)); 24 | } 25 | 26 | if (dtype == NULL) { 27 | return TYPE_NOTYPE_INT; 28 | } 29 | } 30 | 31 | if (dtype == NULL) { 32 | ret = TYPE_DEFAULT_INT; 33 | } 34 | else { 35 | ret = dtype->type_num; 36 | } 37 | 38 | if (dtype != NULL) { 39 | CArrayDescriptor_FREE(dtype); 40 | } 41 | return ret; 42 | } 43 | 44 | /* 45 | * Returns true if data of type 'from' may be cast to data of type 46 | * 'to' according to the rule 'casting'. 47 | */ 48 | int 49 | CArray_CanCastTypeTo(CArrayDescriptor *from, CArrayDescriptor *to, 50 | CARRAY_CASTING casting) 51 | { 52 | /* Fast path for unsafe casts or basic types */ 53 | if (casting == CARRAY_UNSAFE_CASTING || 54 | (CARRAY_LIKELY(from->type_num == to->type_num) && 55 | CARRAY_LIKELY(from->byteorder == to->byteorder))) { 56 | return 1; 57 | } 58 | /* Equivalent types can be cast with any value of 'casting' */ 59 | else if (CArray_EquivTypes(from, to)) { 60 | switch (from->type_num) { 61 | default: 62 | switch (casting) { 63 | case CARRAY_NO_CASTING: 64 | return CArray_EquivTypes(from, to); 65 | case CARRAY_EQUIV_CASTING: 66 | return (from->elsize == to->elsize); 67 | case CARRAY_SAFE_CASTING: 68 | return (from->elsize <= to->elsize); 69 | default: 70 | return 1; 71 | } 72 | break; 73 | } 74 | } 75 | /* If safe or same-kind casts are allowed */ 76 | else if (casting == CARRAY_SAFE_CASTING || casting == CARRAY_SAME_KIND_CASTING) { 77 | if (CArray_CanCastTo(from, to)) { 78 | return 1; 79 | } 80 | else if(casting == CARRAY_SAME_KIND_CASTING) { 81 | throw_notimplemented_exception(); 82 | } 83 | else { 84 | return 0; 85 | } 86 | } 87 | /* NPY_NO_CASTING or NPY_EQUIV_CASTING was specified */ 88 | else { 89 | return 0; 90 | } 91 | 92 | } 93 | 94 | 95 | 96 | /* 97 | * Returns 1 if the array object may be cast to the given data type using 98 | * the casting rule, 0 otherwise. This differs from CArray_CanCastTo in 99 | * that it handles scalar arrays (0 dimensions) specially, by checking 100 | * their value. 101 | */ 102 | int 103 | CArray_CanCastArrayTo(CArray *arr, CArrayDescriptor *to, 104 | CARRAY_CASTING casting) 105 | { 106 | CArrayDescriptor *from = CArray_DESCR(arr); 107 | 108 | /* If it's a scalar, check the value */ 109 | if (CArray_NDIM(arr) == 0) { 110 | return can_cast_scalar_to(from, CArray_DATA(arr), to, casting); 111 | } 112 | 113 | /* Otherwise, use the standard rules */ 114 | return CArray_CanCastTypeTo(from, to, casting); 115 | } -------------------------------------------------------------------------------- /kernel/convert_type.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_CONVERT_TYPE_H 2 | #define PHPSCI_EXT_CONVERT_TYPE_H 3 | 4 | #include "carray.h" 5 | 6 | /* Converts a type number from unsigned to signed */ 7 | static int 8 | type_num_unsigned_to_signed(int type_num) 9 | { 10 | switch (type_num) { 11 | default: 12 | return type_num; 13 | } 14 | } 15 | 16 | /* 17 | * The is_small_unsigned output flag indicates whether it's an unsigned integer, 18 | * and would fit in a signed integer of the same bit size. 19 | */ 20 | static 21 | int min_scalar_type_num(char *valueptr, int type_num, 22 | int *is_small_unsigned) 23 | { 24 | switch (type_num) { 25 | case TYPE_INTEGER_INT: { 26 | break; 27 | } 28 | case TYPE_DOUBLE_INT: { 29 | double value = *(double *)valueptr; 30 | if (value > -3.4e38 && value < 3.4e38) { 31 | return TYPE_FLOAT_INT; 32 | } 33 | break; 34 | } 35 | } 36 | return type_num; 37 | } 38 | 39 | int CArray_ObjectType(CArray * op, int minimum_type); 40 | int CArray_CanCastTypeTo(CArrayDescriptor *from, CArrayDescriptor *to, CARRAY_CASTING casting); 41 | int CArray_CanCastArrayTo(CArray *arr, CArrayDescriptor *to, CARRAY_CASTING casting); 42 | #endif //PHPSCI_EXT_CONVERT_TYPE_H 43 | -------------------------------------------------------------------------------- /kernel/ctors.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_CTORS_H 2 | #define CARRAY_CTORS_H 3 | 4 | #include "carray.h" 5 | 6 | int setArrayFromSequence(CArray *a, CArray *s, int dim, int offset); 7 | CArray * CArray_FromArray(CArray *arr, CArrayDescriptor *newtype, int flags); 8 | void CArray_ToArray(CArray *a, zval * rtn); 9 | #endif //CARRAY_CTORS_H 10 | -------------------------------------------------------------------------------- /kernel/descriptor.c: -------------------------------------------------------------------------------- 1 | #include "carray.h" 2 | #include "descriptor.h" 3 | -------------------------------------------------------------------------------- /kernel/descriptor.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_DESCRIPTOR_H 2 | #define PHPSCI_EXT_DESCRIPTOR_H 3 | 4 | #include "carray.h" 5 | 6 | 7 | 8 | #endif //PHPSCI_EXT_MATLIB_H 9 | -------------------------------------------------------------------------------- /kernel/dtype_transfer.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_DTYPE_TRANSFER_H 2 | #define PHPSCI_EXT_DTYPE_TRANSFER_H 3 | 4 | #include "carray.h" 5 | #include "common/common.h" 6 | #include "common/strided_loops.h" 7 | 8 | int CArray_CastRawArrays(int count, char *src, char *dst, 9 | int src_stride, int dst_stride, 10 | CArrayDescriptor *src_dtype, CArrayDescriptor *dst_dtype, 11 | int move_references); 12 | 13 | int CArray_GetDTypeTransferFunction(int aligned, 14 | int src_stride, int dst_stride, 15 | CArrayDescriptor *src_dtype, CArrayDescriptor *dst_dtype, 16 | int move_references, 17 | CArray_StridedUnaryOp **out_stransfer, 18 | CArrayAuxData **out_transferdata, 19 | int *out_needs_api); 20 | 21 | int 22 | CArray_PrepareOneRawArrayIter(int ndim, int *shape, 23 | char *data, int *strides, 24 | int *out_ndim, int *out_shape, 25 | char **out_data, int *out_strides); 26 | #endif //PHPSCI_EXT_DTYPE_TRANSFER_H 27 | -------------------------------------------------------------------------------- /kernel/exp_logs.c: -------------------------------------------------------------------------------- 1 | #include "exp_logs.h" 2 | #include "carray.h" 3 | #include "trigonometric.h" 4 | #include "alloc.h" 5 | #include "buffer.h" 6 | 7 | CArray * 8 | CArray_Exp(CArray * target, MemoryPointer * out) 9 | { 10 | CArray * result; 11 | CArrayDescriptor * descr; 12 | int * new_strides; 13 | result = emalloc(sizeof(CArray)); 14 | 15 | descr = CArray_DescrFromType(TYPE_DOUBLE_INT); 16 | 17 | result = CArray_NewFromDescr_int(result, descr, CArray_NDIM(target), 18 | CArray_DIMS(target), NULL, NULL, 19 | CArray_FLAGS(target), NULL, 1, 0); 20 | result->flags = ~CARRAY_ARRAY_F_CONTIGUOUS; 21 | 22 | CArray_ElementWise_CFunc(target, result, &exp); 23 | 24 | if(out != NULL) { 25 | add_to_buffer(out, result, sizeof(CArray *)); 26 | } 27 | } 28 | 29 | CArray * 30 | CArray_Expm1(CArray * target, MemoryPointer * out) 31 | { 32 | CArray * result; 33 | CArrayDescriptor * descr; 34 | int * new_strides; 35 | result = emalloc(sizeof(CArray)); 36 | 37 | descr = CArray_DescrFromType(TYPE_DOUBLE_INT); 38 | 39 | result = CArray_NewFromDescr_int(result, descr, CArray_NDIM(target), 40 | CArray_DIMS(target), NULL, NULL, 41 | CArray_FLAGS(target), NULL, 1, 0); 42 | result->flags = ~CARRAY_ARRAY_F_CONTIGUOUS; 43 | 44 | CArray_ElementWise_CFunc(target, result, &expm1); 45 | 46 | if(out != NULL) { 47 | add_to_buffer(out, result, sizeof(CArray *)); 48 | } 49 | } 50 | 51 | CArray * 52 | CArray_Exp2(CArray * target, MemoryPointer * out) 53 | { 54 | CArray * result; 55 | CArrayDescriptor * descr; 56 | int * new_strides; 57 | result = emalloc(sizeof(CArray)); 58 | 59 | descr = CArray_DescrFromType(TYPE_DOUBLE_INT); 60 | 61 | result = CArray_NewFromDescr_int(result, descr, CArray_NDIM(target), 62 | CArray_DIMS(target), NULL, NULL, 63 | CArray_FLAGS(target), NULL, 1, 0); 64 | result->flags = ~CARRAY_ARRAY_F_CONTIGUOUS; 65 | 66 | CArray_ElementWise_CFunc(target, result, &exp2); 67 | 68 | if(out != NULL) { 69 | add_to_buffer(out, result, sizeof(CArray *)); 70 | } 71 | } 72 | 73 | CArray * 74 | CArray_Log(CArray * target, MemoryPointer * out) 75 | { 76 | CArray * result; 77 | CArrayDescriptor * descr; 78 | int * new_strides; 79 | result = emalloc(sizeof(CArray)); 80 | 81 | descr = CArray_DescrFromType(TYPE_DOUBLE_INT); 82 | 83 | result = CArray_NewFromDescr_int(result, descr, CArray_NDIM(target), 84 | CArray_DIMS(target), NULL, NULL, 85 | CArray_FLAGS(target), NULL, 1, 0); 86 | result->flags = ~CARRAY_ARRAY_F_CONTIGUOUS; 87 | 88 | CArray_ElementWise_CFunc(target, result, &log); 89 | 90 | if(out != NULL) { 91 | add_to_buffer(out, result, sizeof(CArray *)); 92 | } 93 | } 94 | 95 | CArray * 96 | CArray_Log10(CArray * target, MemoryPointer * out) 97 | { 98 | CArray * result; 99 | CArrayDescriptor * descr; 100 | int * new_strides; 101 | result = emalloc(sizeof(CArray)); 102 | 103 | descr = CArray_DescrFromType(TYPE_DOUBLE_INT); 104 | 105 | result = CArray_NewFromDescr_int(result, descr, CArray_NDIM(target), 106 | CArray_DIMS(target), NULL, NULL, 107 | CArray_FLAGS(target), NULL, 1, 0); 108 | result->flags = ~CARRAY_ARRAY_F_CONTIGUOUS; 109 | 110 | CArray_ElementWise_CFunc(target, result, &log10); 111 | 112 | if(out != NULL) { 113 | add_to_buffer(out, result, sizeof(CArray *)); 114 | } 115 | } 116 | 117 | CArray * 118 | CArray_Log2(CArray * target, MemoryPointer * out) 119 | { 120 | CArray * result; 121 | CArrayDescriptor * descr; 122 | int * new_strides; 123 | result = emalloc(sizeof(CArray)); 124 | 125 | descr = CArray_DescrFromType(TYPE_DOUBLE_INT); 126 | 127 | result = CArray_NewFromDescr_int(result, descr, CArray_NDIM(target), 128 | CArray_DIMS(target), NULL, NULL, 129 | CArray_FLAGS(target), NULL, 1, 0); 130 | result->flags = ~CARRAY_ARRAY_F_CONTIGUOUS; 131 | 132 | CArray_ElementWise_CFunc(target, result, &log2); 133 | 134 | if(out != NULL) { 135 | add_to_buffer(out, result, sizeof(CArray *)); 136 | } 137 | } 138 | 139 | CArray * 140 | CArray_Log1p(CArray * target, MemoryPointer * out) 141 | { 142 | CArray * result; 143 | CArrayDescriptor * descr; 144 | int * new_strides; 145 | result = emalloc(sizeof(CArray)); 146 | 147 | descr = CArray_DescrFromType(TYPE_DOUBLE_INT); 148 | 149 | result = CArray_NewFromDescr_int(result, descr, CArray_NDIM(target), 150 | CArray_DIMS(target), NULL, NULL, 151 | CArray_FLAGS(target), NULL, 1, 0); 152 | result->flags = ~CARRAY_ARRAY_F_CONTIGUOUS; 153 | 154 | CArray_ElementWise_CFunc(target, result, &log1p); 155 | 156 | if(out != NULL) { 157 | add_to_buffer(out, result, sizeof(CArray *)); 158 | } 159 | } -------------------------------------------------------------------------------- /kernel/exp_logs.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_EXP_LOGS_H 2 | #define CARRAY_EXP_LOGS_H 3 | 4 | #include "carray.h" 5 | 6 | CArray * CArray_Exp(CArray * target, MemoryPointer * out); 7 | CArray * CArray_Expm1(CArray * target, MemoryPointer * out); 8 | CArray * CArray_Exp2(CArray * target, MemoryPointer * out); 9 | CArray * CArray_Log(CArray * target, MemoryPointer * out); 10 | CArray * CArray_Log10(CArray * target, MemoryPointer * out); 11 | CArray * CArray_Log2(CArray * target, MemoryPointer * out); 12 | CArray * CArray_Log1p(CArray * target, MemoryPointer * out); 13 | #endif //CARRAY_EXP_LOGS_H 14 | -------------------------------------------------------------------------------- /kernel/flagsobject.c: -------------------------------------------------------------------------------- 1 | #include "flagsobject.h" 2 | #include "carray.h" 3 | #include "assign.h" 4 | #include "common/common.h" 5 | 6 | /** 7 | * Check whether the given array is stored contiguously 8 | **/ 9 | static void 10 | _UpdateContiguousFlags(CArray * array) 11 | { 12 | int sd; 13 | int dim; 14 | int i; 15 | int is_c_contig = 1; 16 | 17 | sd = CArray_ITEMSIZE(array); 18 | for (i = CArray_NDIM(array) - 1; i >= 0; --i) { 19 | dim = CArray_DIMS(array)[i]; 20 | 21 | if (CArray_STRIDES(array)[i] != sd) { 22 | is_c_contig = 0; 23 | break; 24 | } 25 | /* contiguous, if it got this far */ 26 | if (dim == 0) { 27 | break; 28 | } 29 | sd *= dim; 30 | } 31 | if (is_c_contig) { 32 | CArray_ENABLEFLAGS(array, CARRAY_ARRAY_C_CONTIGUOUS); 33 | } 34 | else { 35 | CArray_CLEARFLAGS(array, CARRAY_ARRAY_C_CONTIGUOUS); 36 | } 37 | } 38 | 39 | /** 40 | * Update CArray flags 41 | **/ 42 | void 43 | CArray_UpdateFlags(CArray * array, int flagmask) 44 | { 45 | /* Always update both, as its not trivial to guess one from the other */ 46 | if (flagmask & (CARRAY_ARRAY_F_CONTIGUOUS | CARRAY_ARRAY_C_CONTIGUOUS)) { 47 | _UpdateContiguousFlags(array); 48 | } 49 | 50 | if (flagmask & CARRAY_ARRAY_ALIGNED) { 51 | if (IsAligned(array)) { 52 | CArray_ENABLEFLAGS(array, CARRAY_ARRAY_ALIGNED); 53 | } 54 | else { 55 | CArray_CLEARFLAGS(array, CARRAY_ARRAY_ALIGNED); 56 | } 57 | } 58 | 59 | if (flagmask & CARRAY_ARRAY_WRITEABLE) { 60 | if (_IsWriteable(array)) { 61 | CArray_ENABLEFLAGS(array, CARRAY_ARRAY_WRITEABLE); 62 | } 63 | else { 64 | CArray_CLEARFLAGS(array, CARRAY_ARRAY_WRITEABLE); 65 | } 66 | } 67 | return; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /kernel/flagsobject.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_FLAGSOBJECT_H 2 | #define PHPSCI_EXT_FLAGSOBJECT_H 3 | 4 | #include "carray.h" 5 | 6 | /* 7 | * Enables the specified array flags. 8 | */ 9 | static void 10 | CArray_ENABLEFLAGS(CArray * arr, int flags) 11 | { 12 | (arr)->flags |= flags; 13 | } 14 | 15 | /* 16 | * Clears the specified array flags. Does no checking, 17 | * assumes you know what you're doing. 18 | */ 19 | static void 20 | CArray_CLEARFLAGS(CArray *arr, int flags) 21 | { 22 | (arr)->flags &= ~flags; 23 | } 24 | 25 | void CArray_UpdateFlags(CArray * array, int flagmask); 26 | 27 | #endif //PHPSCI_EXT_FLAGSOBJECT_H -------------------------------------------------------------------------------- /kernel/getset.c: -------------------------------------------------------------------------------- 1 | #include "getset.h" 2 | #include "iterators.h" 3 | #include "carray.h" 4 | #include "alloc.h" 5 | 6 | int 7 | array_flat_set(CArray * self, CArray * val) 8 | { 9 | CArray * arr = NULL; 10 | int retval = -1; 11 | CArrayIterator *self_it, *arr_it; 12 | CArrayDescriptor *typecode; 13 | int swap; 14 | CArray_CopySwapFunc *copyswap; 15 | 16 | typecode = emalloc(sizeof(CArrayDescriptor)); 17 | memcpy(typecode, CArray_DESCR(self), sizeof(CArrayDescriptor)); 18 | CArrayDescriptor_INCREF(typecode); 19 | 20 | CArrayDescriptor_INCREF(CArray_DESCR(val)); 21 | arr = CArray_FromAnyUnwrap(val, typecode, 0, 0, CARRAY_ARRAY_FORCECAST, NULL); 22 | 23 | if(arr == NULL) { 24 | return -1; 25 | } 26 | 27 | arr_it = CArray_NewIter(arr); 28 | if (arr_it == NULL) { 29 | goto exit; 30 | } 31 | 32 | self_it = CArray_NewIter(self); 33 | if (self_it == NULL) { 34 | goto exit; 35 | } 36 | 37 | if (arr_it->size == 0) { 38 | retval = 0; 39 | goto exit; 40 | } 41 | 42 | swap = CArray_ISNOTSWAPPED(self) != CArray_ISNOTSWAPPED(arr); 43 | copyswap = CArray_DESCR(self)->f->copyswap; 44 | 45 | if (CArray_DESCR(self)->refcount) { 46 | while (self_it->index < self_it->size) { 47 | memmove(self_it->data_pointer, arr_it->data_pointer, CArray_SIZE(self)); 48 | CArrayIterator_NEXT(self_it); 49 | CArrayIterator_NEXT(arr_it); 50 | if (arr_it->index == arr_it->size) { 51 | CArrayIterator_RESET(arr_it); 52 | } 53 | } 54 | retval = 0; 55 | goto exit; 56 | } 57 | 58 | while(self_it->index < self_it->size) { 59 | memmove(self_it->data_pointer, arr_it->data_pointer, CArray_ITEMSIZE(self)); 60 | if (swap) { 61 | copyswap(self_it->data_pointer, NULL, swap, self); 62 | } 63 | CArrayIterator_NEXT(self_it); 64 | CArrayIterator_NEXT(arr_it); 65 | 66 | if (arr_it->index == arr_it->size) { 67 | CArrayIterator_RESET(arr_it); 68 | } 69 | } 70 | retval = 0; 71 | CArrayIterator_FREE(arr_it); 72 | CArrayIterator_FREE(self_it); 73 | efree(typecode); 74 | return retval; 75 | exit: 76 | CArray_XDECREF(arr); 77 | return retval; 78 | } 79 | -------------------------------------------------------------------------------- /kernel/getset.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_GETSET_H 2 | #define PHPSCI_EXT_GETSET_H 3 | 4 | #include "carray.h" 5 | 6 | int array_flat_set(CArray * self, CArray * val); 7 | 8 | 9 | #endif -------------------------------------------------------------------------------- /kernel/gpu.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #ifdef HAVE_CLBLAS 4 | #include "gpu.h" 5 | #include "clBLAS.h" 6 | 7 | cl_context ctx; 8 | cl_command_queue queue; 9 | 10 | void 11 | start_clblas_context() { 12 | cl_context_properties props[3] = { CL_CONTEXT_PLATFORM, 0, 0 }; 13 | cl_platform_id platform = 0; 14 | cl_device_id device = 0; 15 | cl_int err; 16 | 17 | 18 | /* Setup OpenCL environment. */ 19 | err = clGetPlatformIDs( 1, &platform, NULL ); 20 | err = clGetDeviceIDs( platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL ); 21 | 22 | props[1] = (cl_context_properties)platform; 23 | 24 | ctx = clCreateContext( props, 1, &device, NULL, NULL, &err ); 25 | queue = clCreateCommandQueue( ctx, device, 0, &err ); 26 | 27 | /* Setup clBLAS */ 28 | err = clblasSetup( ); 29 | } 30 | 31 | 32 | cl_context 33 | getCLContext() { 34 | return ctx; 35 | } 36 | 37 | cl_command_queue 38 | getCLQueue() { 39 | return queue; 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /kernel/gpu.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_GPU_H 2 | #define PHPSCI_EXT_GPU_H 3 | 4 | #include "config.h" 5 | 6 | #ifdef HAVE_CLBLAS 7 | #include "clBLAS.h" 8 | 9 | void start_clblas_context(); 10 | cl_command_queue getCLQueue(); 11 | cl_context getCLContext(); 12 | #endif 13 | 14 | 15 | #endif //PHPSCI_EXT_GPU_H 16 | -------------------------------------------------------------------------------- /kernel/include/cpu.h: -------------------------------------------------------------------------------- 1 | #if defined( __i386__ ) || defined(i386) || defined(_M_IX86) 2 | /* 3 | * __i386__ is defined by gcc and Intel compiler on Linux, 4 | * _M_IX86 by VS compiler, 5 | * i386 by Sun compilers on opensolaris at least 6 | */ 7 | #define CARRAY_CPU_X86 8 | #elif defined(__x86_64__) || defined(__amd64__) || defined(__x86_64) || defined(_M_AMD64) 9 | /* 10 | * both __x86_64__ and __amd64__ are defined by gcc 11 | * __x86_64 defined by sun compiler on opensolaris at least 12 | * _M_AMD64 defined by MS compiler 13 | */ 14 | #define CARRAY_CPU_AMD64 15 | #endif 16 | 17 | #if (defined(CARRAY_CPU_X86) || defined(CARRAY_CPU_AMD64)) 18 | #define CARRAY_CPU_HAVE_UNALIGNED_ACCESS 1 19 | #else 20 | #define CARRAY_CPU_HAVE_UNALIGNED_ACCESS 0 21 | #endif -------------------------------------------------------------------------------- /kernel/item_selection.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_ITEM_SELECTION_H 2 | #define PHPSCI_EXT_ITEM_SELECTION_H 3 | 4 | #include "carray.h" 5 | 6 | int 7 | INT_fasttake(int *dest, int *src, int *indarray, 8 | int nindarray, int n_outer, 9 | int m_middle, int nelem, 10 | CARRAY_CLIPMODE clipmode); 11 | int 12 | DOUBLE_fasttake(double *dest, double *src, int *indarray, 13 | int nindarray, int n_outer, 14 | int m_middle, int nelem, 15 | CARRAY_CLIPMODE clipmode); 16 | 17 | 18 | CArray * CArray_Diagonal(CArray *self, int offset, int axis1, int axis2, MemoryPointer * rtn); 19 | CArray * CArray_TakeFrom(CArray * target, CArray * indices0, int axis, MemoryPointer * out, CARRAY_CLIPMODE clipmode); 20 | CArray * CArray_Sort(CArray * target, int * axis, CARRAY_SORTKIND which, int inplace, MemoryPointer * out); 21 | #endif //PHPSCI_EXT_ITEM_SELECTION_H -------------------------------------------------------------------------------- /kernel/iterators.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_ITERATORS_H 2 | #define PHPSCI_EXT_ITERATORS_H 3 | 4 | #include "carray.h" 5 | 6 | /*** Global flags that may be passed to the iterator constructors ***/ 7 | 8 | /* Track an index representing C order */ 9 | #define CARRAY_ITER_C_INDEX 0x00000001 10 | /* Track an index representing Fortran order */ 11 | #define CARRAY_ITER_F_INDEX 0x00000002 12 | /* Track a multi-index */ 13 | #define CARRAY_ITER_MULTI_INDEX 0x00000004 14 | /* User code external to the iterator does the 1-dimensional innermost loop */ 15 | #define CARRAY_ITER_EXTERNAL_LOOP 0x00000008 16 | /* Convert all the operands to a common data type */ 17 | #define CARRAY_ITER_COMMON_DTYPE 0x00000010 18 | /* Operands may hold references, requiring API access during iteration */ 19 | #define CARRAY_ITER_REFS_OK 0x00000020 20 | /* Zero-sized operands should be permitted, iteration checks IterSize for 0 */ 21 | #define CARRAY_ITER_ZEROSIZE_OK 0x00000040 22 | /* Permits reductions (size-0 stride with dimension size > 1) */ 23 | #define CARRAY_ITER_REDUCE_OK 0x00000080 24 | /* Enables sub-range iteration */ 25 | #define CARRAY_ITER_RANGED 0x00000100 26 | /* Enables buffering */ 27 | #define CARRAY_ITER_BUFFERED 0x00000200 28 | /* When buffering is enabled, grows the inner loop if possible */ 29 | #define CARRAY_ITER_GROWINNER 0x00000400 30 | /* Delay allocation of buffers until first Reset* call */ 31 | #define CARRAY_ITER_DELAY_BUFALLOC 0x00000800 32 | /* When CARRAY_KEEPORDER is specified, disable reversing negative-stride axes */ 33 | #define CARRAY_ITER_DONT_NEGATE_STRIDES 0x00001000 34 | /* 35 | * If output operands overlap with other operands (based on heuristics that 36 | * has false positives but no false negatives), make temporary copies to 37 | * eliminate overlap. 38 | */ 39 | #define CARRAY_ITER_COPY_IF_OVERLAP 0x00002000 40 | 41 | /*** Per-operand flags that may be passed to the iterator constructors ***/ 42 | 43 | /* The operand will be read from and written to */ 44 | #define CARRAY_ITER_READWRITE 0x00010000 45 | /* The operand will only be read from */ 46 | #define CARRAY_ITER_READONLY 0x00020000 47 | /* The operand will only be written to */ 48 | #define CARRAY_ITER_WRITEONLY 0x00040000 49 | /* The operand's data must be in native byte order */ 50 | #define CARRAY_ITER_NBO 0x00080000 51 | /* The operand's data must be aligned */ 52 | #define CARRAY_ITER_ALIGNED 0x00100000 53 | /* The operand's data must be contiguous (within the inner loop) */ 54 | #define CARRAY_ITER_CONTIG 0x00200000 55 | /* The operand may be copied to satisfy requirements */ 56 | #define CARRAY_ITER_COPY 0x00400000 57 | /* The operand may be copied with WRITEBACKIFCOPY to satisfy requirements */ 58 | #define CARRAY_ITER_UPDATEIFCOPY 0x00800000 59 | /* Allocate the operand if it is NULL */ 60 | #define CARRAY_ITER_ALLOCATE 0x01000000 61 | /* If an operand is allocated, don't use any subtype */ 62 | #define CARRAY_ITER_NO_SUBTYPE 0x02000000 63 | /* This is a virtual array slot, operand is NULL but temporary data is there */ 64 | #define CARRAY_ITER_VIRTUAL 0x04000000 65 | /* Require that the dimension match the iterator dimensions exactly */ 66 | #define CARRAY_ITER_NO_BROADCAST 0x08000000 67 | /* A mask is being used on this array, affects buffer -> array copy */ 68 | #define CARRAY_ITER_WRITEMASKED 0x10000000 69 | /* This array is the mask for all WRITEMASKED operands */ 70 | #define CARRAY_ITER_ARRAYMASK 0x20000000 71 | /* Assume iterator order data access for COPY_IF_OVERLAP */ 72 | #define CARRAY_ITER_OVERLAP_ASSUME_ELEMENTWISE 0x40000000 73 | 74 | #define CARRAY_ITER_GLOBAL_FLAGS 0x0000ffff 75 | #define CARRAY_ITER_PER_OP_FLAGS 0xffff0000 76 | 77 | typedef struct CArrayIterator 78 | { 79 | int index; // Current 1-d index 80 | int size; 81 | int * coordinates; // Coordinate vectors of index 82 | int * dims_m1; // Size of array minus 1 for each dimension 83 | int ndims_m1; 84 | int * factors; // Factor for ND-index to 1D-index 85 | int * strides; // Array Strides 86 | int * backstrides; // Backstrides 87 | char * data_pointer; // Data pointer to element defined by index 88 | int contiguous; // 1 = Contiguous, 0 = Non-contiguous 89 | int ** bounds; 90 | int ** limits; 91 | int * limits_sizes; 92 | CArray * array; // Pointer to represented CArray 93 | } CArrayIterator; 94 | 95 | typedef int (CArrayIterator_IterNextFunc)(CArrayIterator *iter); 96 | 97 | #define IT_IDATA(it) ((int *)((it)->data_pointer)) 98 | #define IT_DDATA(it) ((double *)((it)->data_pointer)) 99 | #define CArrayIterator_DATA(it) ((void *)((it)->data_pointer)) 100 | #define CArrayIterator_NOTDONE(it) ((it)->index < (it)->size) 101 | 102 | CArrayIterator * CArray_NewIter(CArray * array); 103 | static char* get_ptr(CArrayIterator * iter, uintptr_t * coordinates); 104 | void CArrayIterator_Dump(CArrayIterator * iterator); 105 | void CArrayIterator_GOTO(CArrayIterator * iterator, int * destination); 106 | void CArrayIterator_NEXT(CArrayIterator * iterator); 107 | void CArrayIterator_RESET(CArrayIterator * iterator); 108 | void CArrayIterator_FREE(CArrayIterator * it); 109 | 110 | CArrayIterator * CArray_BroadcastToShape(CArray * target, int * dims, int nd); 111 | CArrayIterator * CArray_IterAllButAxis(CArray *obj, int *inaxis); 112 | #endif //PHPSCI_EXT_ITERATORS_H -------------------------------------------------------------------------------- /kernel/join.c: -------------------------------------------------------------------------------- 1 | #include "join.h" 2 | #include "carray.h" 3 | #include "alloc.h" 4 | #include "stdio.h" 5 | #include "shape.h" 6 | #include "buffer.h" 7 | 8 | static CArray * 9 | _swap_and_concat(CArray **op, int axis, int n, MemoryPointer * out) 10 | { 11 | CArray **newtup = NULL; 12 | CArray *otmp, *arr; 13 | int i; 14 | int axis2 = 0; 15 | 16 | newtup = emalloc(sizeof(CArray) * n); 17 | if (newtup==NULL) return NULL; 18 | for (i=0; i= CARRAY_MAXDIMS) { 73 | otmp = CArray_Ravel(mps[i],0); 74 | CArray_XDECREF(mps[i]); 75 | mps[i] = otmp; 76 | } 77 | prior2 = 0.0; 78 | if (prior2 > prior1) { 79 | prior1 = prior2; 80 | } 81 | } 82 | 83 | new_dim = 0; 84 | for(i=0; indim; 87 | else { 88 | if (nd != mps[i]->ndim) { 89 | throw_valueerror_exception("arrays must have same " 90 | "number of dimensions"); 91 | goto fail; 92 | } 93 | if (!CArray_CompareLists(mps[0]->dimensions+1, 94 | mps[i]->dimensions+1, 95 | nd-1)) { 96 | throw_valueerror_exception("array dimensions must " 97 | "agree except for d_0"); 98 | goto fail; 99 | } 100 | } 101 | if (nd == 0) { 102 | throw_valueerror_exception("0-d arrays can't be concatenated"); 103 | goto fail; 104 | } 105 | new_dim += mps[i]->dimensions[0]; 106 | } 107 | 108 | tmp = mps[0]->dimensions[0]; 109 | mps[0]->dimensions[0] = new_dim; 110 | CArrayDescriptor_INCREF(CArray_DESCR(mps[0])); 111 | 112 | ret = (CArray *)CArray_NewFromDescr(ret, CArray_DESCR(mps[0]), nd, 113 | CArray_DIMS(mps[0]),NULL, NULL, 0, 114 | NULL); 115 | mps[0]->dimensions[0] = tmp; 116 | 117 | if (ret == NULL) goto fail; 118 | 119 | data = ret->data; 120 | for(i=0; idata, numbytes); 123 | data += numbytes; 124 | } 125 | 126 | CArray_INCREF(ret); 127 | for(i=0; iobval = emalloc(new_descr->elsize); 32 | sc->type = CHAR_TYPE_INT(type); 33 | 34 | if(type == TYPE_DOUBLE){ 35 | *((double *)sc->obval) = (double)0.00; 36 | } 37 | if(type == TYPE_INTEGER){ 38 | *((int *)sc->obval) = (int)0; 39 | } 40 | if(type == TYPE_FLOAT){ 41 | *((float *)sc->obval) = (float)0; 42 | } 43 | 44 | CArray_FillWithScalar(rtn, sc); 45 | 46 | efree(sc->obval); 47 | efree(sc); 48 | 49 | if(allocated) { 50 | efree(order); 51 | } 52 | return rtn; 53 | } 54 | 55 | 56 | CArray * 57 | CArray_Ones(int * shape, int nd, char * type, char * order, MemoryPointer * rtn_ptr) 58 | { 59 | int is_fortran = 0, order_allocated = 0; 60 | CArrayDescriptor * new_descr; 61 | CArrayScalar * sc = emalloc(sizeof(CArrayScalar)); 62 | CArray * rtn; 63 | 64 | if (order == NULL) { 65 | order = emalloc(sizeof(char)); 66 | *order = 'C'; 67 | order_allocated = 1; 68 | } 69 | 70 | if (*order == 'F') { 71 | is_fortran = 1; 72 | } 73 | 74 | new_descr = CArray_DescrFromType(CHAR_TYPE_INT(*type)); 75 | rtn = CArray_Empty(nd, shape, new_descr, is_fortran, rtn_ptr); 76 | 77 | sc->obval = emalloc(new_descr->elsize); 78 | sc->type = CHAR_TYPE_INT(*type); 79 | 80 | if(*type == TYPE_DOUBLE){ 81 | *((double *)sc->obval) = (double)1.00; 82 | } 83 | if(*type == TYPE_INTEGER){ 84 | *((int *)sc->obval) = (int)1; 85 | } 86 | if(*type == TYPE_FLOAT){ 87 | *((float *)sc->obval) = (float)1; 88 | } 89 | 90 | CArray_FillWithScalar(rtn, sc); 91 | 92 | efree(sc->obval); 93 | efree(sc); 94 | 95 | if (order_allocated) { 96 | efree(order); 97 | } 98 | return rtn; 99 | } 100 | 101 | CArray * 102 | CArray_Flip(CArray *a, int * axis, MemoryPointer * out) 103 | { 104 | CArrayIterator * it; 105 | CArray * rtn; 106 | 107 | it = CArray_NewIter(a); 108 | rtn = CArray_NewLikeArray(a, CARRAY_KEEPORDER, CArray_DESCR(a), 0); 109 | CArrayDescriptor_INCREF(CArray_DESCR(a)); 110 | 111 | if (axis == NULL) { 112 | switch(CArray_TYPE(a)) { 113 | case TYPE_DOUBLE_INT: 114 | do { 115 | DDATA(rtn)[CArray_DESCR(a)->numElements - it->index - 1] = *IT_DDATA(it); 116 | CArrayIterator_NEXT(it); 117 | } while(CArrayIterator_NOTDONE(it)); 118 | break; 119 | case TYPE_INTEGER_INT: 120 | do { 121 | IDATA(rtn)[CArray_DESCR(a)->numElements - it->index - 1] = *IT_IDATA(it); 122 | CArrayIterator_NEXT(it); 123 | } while(CArrayIterator_NOTDONE(it)); 124 | break; 125 | } 126 | } 127 | else { 128 | throw_notimplemented_exception(); 129 | CArrayIterator_FREE(it); 130 | return NULL; 131 | } 132 | 133 | if (out != NULL) { 134 | add_to_buffer(out, rtn, sizeof(CArray)); 135 | } 136 | 137 | CArrayIterator_FREE(it); 138 | return rtn; 139 | } -------------------------------------------------------------------------------- /kernel/matlib.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_MATLIB_H 2 | #define PHPSCI_EXT_MATLIB_H 3 | 4 | #include "carray.h" 5 | 6 | CArray * CArray_Zeros(int * shape, int nd, char type, char * order, MemoryPointer * rtn_ptr); 7 | CArray * CArray_Ones(int * shape, int nd, char * type, char * order, MemoryPointer * rtn_ptr); 8 | CArray * CArray_Flip(CArray *a, int * axis, MemoryPointer * out); 9 | #endif //PHPSCI_EXT_MATLIB_H 10 | -------------------------------------------------------------------------------- /kernel/number.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_NUMBER_H 2 | #define PHPSCI_EXT_NUMBER_H 3 | 4 | #include "carray.h" 5 | 6 | CArray * CArray_Add(CArray *m1, CArray *m2, MemoryPointer * ptr); 7 | CArray * CArray_Subtract(CArray *m1, CArray *m2, MemoryPointer * ptr); 8 | CArray * CArray_Multiply(CArray *m1, CArray *m2, MemoryPointer * ptr); 9 | CArray * CArray_Divide(CArray *m1, CArray *m2, MemoryPointer * ptr); 10 | CArray * CArray_Power(CArray *m1, CArray *m2, MemoryPointer * ptr); 11 | CArray * CArray_Mod(CArray *m1, CArray *m2, MemoryPointer * ptr); 12 | CArray * CArray_Negative(CArray * a, MemoryPointer * out); 13 | CArray * CArray_Sqrt(CArray *a, MemoryPointer *out); 14 | CArray * CArray_Reciprocal(CArray *a, MemoryPointer *out); 15 | CArray * CArray_Absolute(CArray *a, MemoryPointer *out); 16 | #endif //PHPSCI_EXT_NUMBER_H 17 | -------------------------------------------------------------------------------- /kernel/random.c: -------------------------------------------------------------------------------- 1 | #include "carray.h" 2 | #include "random.h" 3 | #include "matlib.h" 4 | 5 | #ifndef RK_DEV_URANDOM 6 | #define RK_DEV_URANDOM "/dev/urandom" 7 | #endif 8 | 9 | #ifndef RK_DEV_RANDOM 10 | #define RK_DEV_RANDOM "/dev/random" 11 | #endif 12 | 13 | /* Magic Mersenne Twister constants */ 14 | #define N 624 15 | #define M 397 16 | #define MATRIX_A 0x9908b0dfUL 17 | #define UPPER_MASK 0x80000000UL 18 | #define LOWER_MASK 0x7fffffffUL 19 | 20 | /* Thomas Wang 32 bits integer hash function */ 21 | unsigned long 22 | rk_hash(unsigned long key) 23 | { 24 | key += ~(key << 15); 25 | key ^= (key >> 10); 26 | key += (key << 3); 27 | key ^= (key >> 6); 28 | key += ~(key << 11); 29 | key ^= (key >> 16); 30 | return key; 31 | } 32 | 33 | rk_error 34 | rk_devfill(void *buffer, size_t size, int strong) 35 | { 36 | #ifndef _WIN32 37 | FILE *rfile; 38 | int done; 39 | 40 | if (strong) { 41 | rfile = fopen(RK_DEV_RANDOM, "rb"); 42 | } 43 | else { 44 | rfile = fopen(RK_DEV_URANDOM, "rb"); 45 | } 46 | if (rfile == NULL) { 47 | return RK_ENODEV; 48 | } 49 | done = fread(buffer, size, 1, rfile); 50 | fclose(rfile); 51 | if (done) { 52 | return RK_NOERR; 53 | } 54 | #else 55 | 56 | #ifndef RK_NO_WINCRYPT 57 | HCRYPTPROV hCryptProv; 58 | BOOL done; 59 | 60 | if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 61 | CRYPT_VERIFYCONTEXT) || !hCryptProv) { 62 | return RK_ENODEV; 63 | } 64 | done = CryptGenRandom(hCryptProv, size, (unsigned char *)buffer); 65 | CryptReleaseContext(hCryptProv, 0); 66 | if (done) { 67 | return RK_NOERR; 68 | } 69 | #endif 70 | 71 | #endif 72 | return RK_ENODEV; 73 | } 74 | 75 | /* 76 | * Slightly optimised reference implementation of the Mersenne Twister 77 | * Note that regardless of the precision of long, only 32 bit random 78 | * integers are produced 79 | */ 80 | unsigned long 81 | rk_random(rk_state *state) 82 | { 83 | unsigned long y; 84 | 85 | if (state->pos == RK_STATE_LEN) { 86 | int i; 87 | 88 | for (i = 0; i < N - M; i++) { 89 | y = (state->key[i] & UPPER_MASK) | (state->key[i+1] & LOWER_MASK); 90 | state->key[i] = state->key[i+M] ^ (y>>1) ^ (-(y & 1) & MATRIX_A); 91 | } 92 | for (; i < N - 1; i++) { 93 | y = (state->key[i] & UPPER_MASK) | (state->key[i+1] & LOWER_MASK); 94 | state->key[i] = state->key[i+(M-N)] ^ (y>>1) ^ (-(y & 1) & MATRIX_A); 95 | } 96 | y = (state->key[N - 1] & UPPER_MASK) | (state->key[0] & LOWER_MASK); 97 | state->key[N - 1] = state->key[M - 1] ^ (y >> 1) ^ (-(y & 1) & MATRIX_A); 98 | 99 | state->pos = 0; 100 | } 101 | y = state->key[state->pos++]; 102 | 103 | /* Tempering */ 104 | y ^= (y >> 11); 105 | y ^= (y << 7) & 0x9d2c5680UL; 106 | y ^= (y << 15) & 0xefc60000UL; 107 | y ^= (y >> 18); 108 | 109 | return y; 110 | } 111 | 112 | double 113 | rk_double(rk_state *state) 114 | { 115 | /* shifts : 67108864 = 0x4000000, 9007199254740992 = 0x20000000000000 */ 116 | long a = rk_random(state) >> 5, b = rk_random(state) >> 6; 117 | return (a * 67108864.0 + b) / 9007199254740992.0; 118 | } 119 | 120 | void 121 | rk_seed(unsigned long seed, rk_state *state) 122 | { 123 | int pos; 124 | seed &= 0xffffffffUL; 125 | 126 | /* Knuth's PRNG as used in the Mersenne Twister reference implementation */ 127 | for (pos = 0; pos < RK_STATE_LEN; pos++) { 128 | state->key[pos] = seed; 129 | seed = (1812433253UL * (seed ^ (seed >> 30)) + pos + 1) & 0xffffffffUL; 130 | } 131 | state->pos = RK_STATE_LEN; 132 | state->gauss = 0; 133 | state->has_gauss = 0; 134 | state->has_binomial = 0; 135 | } 136 | 137 | 138 | rk_error 139 | rk_randomseed(rk_state *state) 140 | { 141 | #ifndef _WIN32 142 | struct timeval tv; 143 | #else 144 | struct _timeb tv; 145 | #endif 146 | int i; 147 | 148 | if (rk_devfill(state->key, sizeof(state->key), 0) == RK_NOERR) { 149 | /* ensures non-zero key */ 150 | state->key[0] |= 0x80000000UL; 151 | state->pos = RK_STATE_LEN; 152 | state->gauss = 0; 153 | state->has_gauss = 0; 154 | state->has_binomial = 0; 155 | 156 | for (i = 0; i < 624; i++) { 157 | state->key[i] &= 0xffffffffUL; 158 | } 159 | return RK_NOERR; 160 | } 161 | 162 | #ifndef _WIN32 163 | gettimeofday(&tv, NULL); 164 | rk_seed(rk_hash(getpid()) ^ rk_hash(tv.tv_sec) ^ rk_hash(tv.tv_usec) 165 | ^ rk_hash(clock()), state); 166 | #else 167 | _FTIME(&tv); 168 | rk_seed(rk_hash(tv.time) ^ rk_hash(tv.millitm) ^ rk_hash(clock()), state); 169 | #endif 170 | 171 | return RK_ENODEV; 172 | } 173 | 174 | CArray * 175 | CArray_Rand(int * size, int nd, MemoryPointer * out) 176 | { 177 | rk_state * state = emalloc(sizeof(rk_state)); 178 | double * array_data; 179 | CArray * target; 180 | int length; 181 | int i; 182 | target = CArray_Zeros(size, nd, TYPE_DOUBLE, NULL, out); 183 | 184 | length = CArray_SIZE(target); 185 | array_data = (double *)CArray_DATA(target); 186 | 187 | rk_randomseed(state); 188 | for(i = 0; i < length; i++) { 189 | array_data[i] = rk_double(state); 190 | } 191 | efree(state); 192 | return target; 193 | } -------------------------------------------------------------------------------- /kernel/random.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_RANDOM_H 2 | #define PHPSCI_EXT_RANDOM_H 3 | 4 | #include "carray.h" 5 | 6 | #define RK_STATE_LEN 624 7 | 8 | typedef struct rk_state_ 9 | { 10 | unsigned long key[RK_STATE_LEN]; 11 | int pos; 12 | int has_gauss; /* !=0: gauss contains a gaussian deviate */ 13 | double gauss; 14 | 15 | /* The rk_state structure has been extended to store the following 16 | * information for the binomial generator. If the input values of n or p 17 | * are different than nsave and psave, then the other parameters will be 18 | * recomputed. RTK 2005-09-02 */ 19 | 20 | int has_binomial; /* !=0: following parameters initialized for 21 | binomial */ 22 | double psave; 23 | long nsave; 24 | double r; 25 | double q; 26 | double fm; 27 | long m; 28 | double p1; 29 | double xm; 30 | double xl; 31 | double xr; 32 | double c; 33 | double laml; 34 | double lamr; 35 | double p2; 36 | double p3; 37 | double p4; 38 | 39 | } 40 | rk_state; 41 | 42 | typedef enum { 43 | RK_NOERR = 0, /* no error */ 44 | RK_ENODEV = 1, /* no RK_DEV_RANDOM device */ 45 | RK_ERR_MAX = 2 46 | } rk_error; 47 | 48 | unsigned long rk_random(rk_state *state); 49 | 50 | /* 51 | * Returns a random double between 0.0 and 1.0, 1.0 excluded. 52 | */ 53 | double rk_double(rk_state *state); 54 | 55 | void rk_seed(unsigned long seed, rk_state *state); 56 | CArray * CArray_Rand(int * size, int nd, MemoryPointer * out); 57 | 58 | #endif //PHPSCI_EXT_RANDOM_H 59 | -------------------------------------------------------------------------------- /kernel/random/distributions.c: -------------------------------------------------------------------------------- 1 | #include "../carray.h" 2 | #include "distributions.h" 3 | #include "../buffer.h" 4 | 5 | /** 6 | * Poisson Random Distribution 7 | * 8 | * @param m 9 | * @param n 10 | * @param lambda 11 | * @return 12 | */ 13 | CArray* 14 | CArray_Poisson(int *shape, double lambda, MemoryPointer *out) 15 | { 16 | CArray *result; 17 | CArrayDescriptor *descr; 18 | double max = INT_MAX; 19 | time_t t; 20 | double l = exp(-lambda); 21 | double k; 22 | double p; 23 | int i; 24 | 25 | result = emalloc(sizeof(CArray)); 26 | descr = CArray_DescrFromType(TYPE_DOUBLE_INT); 27 | result = CArray_NewFromDescr_int(result, descr, 2, shape, NULL, NULL, 28 | CARRAY_ARRAY_C_CONTIGUOUS, NULL, 1, 0); 29 | 30 | // Random Seed 31 | srand((unsigned) time(&t)); 32 | 33 | for (i = 0; i < CArray_DESCR(result)->numElements; i++) { 34 | k = 0.0; 35 | p = 1.0; 36 | 37 | while (p > l) { 38 | k = k + 1.0; 39 | p *= rand() / max; 40 | } 41 | DDATA(result)[i] = (double) k - 1; 42 | } 43 | 44 | if (out != NULL) { 45 | add_to_buffer(out, result, sizeof(result)); 46 | } 47 | 48 | return result; 49 | } 50 | -------------------------------------------------------------------------------- /kernel/random/distributions.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_CARRAY_DISTRIBUTIONS_H 2 | #define PHPSCI_CARRAY_DISTRIBUTIONS_H 3 | 4 | #include "../carray.h" 5 | 6 | CArray* CArray_Poisson(int *shape, double lambda, MemoryPointer *out); 7 | 8 | #endif //PHPSCI_CARRAY_DISTRIBUTIONS_H 9 | -------------------------------------------------------------------------------- /kernel/range.c: -------------------------------------------------------------------------------- 1 | #include "carray.h" 2 | #include "alloc.h" 3 | #include "buffer.h" 4 | #include "range.h" 5 | #include "convert.h" 6 | #include "number.h" 7 | #include "shape.h" 8 | 9 | /** 10 | * @param start 11 | * @param stop 12 | * @param step 13 | * @param type_num 14 | * @param ptr 15 | * @todo Fix leak 16 | * @return 17 | */ 18 | CArray * 19 | CArray_Arange(double start, double stop, double step, int type_num, MemoryPointer * ptr) 20 | { 21 | int length; 22 | CArray * range; 23 | CArray_ArrFuncs *funcs; 24 | int start_plus_step_i, start_i; 25 | double start_plus_step_d, start_d; 26 | int ret; 27 | 28 | range = emalloc(sizeof(CArray)); 29 | 30 | if (_safe_ceil_to_int((stop - start) / step, &length)) { 31 | throw_overflow_exception("arange: overflow while computing length"); 32 | } 33 | 34 | if (length <= 0) { 35 | length = 0; 36 | if(ptr != NULL) { 37 | add_to_buffer(ptr, range, sizeof(CArray)); 38 | } 39 | return CArray_New(range, 1, &length, type_num, 40 | NULL, NULL, 0, 0, NULL); 41 | } 42 | 43 | range = CArray_New(range, 1, &length, type_num, 44 | NULL, NULL, 0, 0, NULL); 45 | 46 | if (range == NULL) { 47 | return NULL; 48 | } 49 | 50 | funcs = CArray_DESCR(range)->f; 51 | 52 | if(type_num == TYPE_DOUBLE_INT) { 53 | start_d = (double)(start); 54 | ret = funcs->setitem(((double *) &start_d), CArray_BYTES(range), range); 55 | } 56 | if(type_num == TYPE_INTEGER_INT) { 57 | start_i = (int)(start); 58 | ret = funcs->setitem(((int *) &start_i), CArray_BYTES(range), range); 59 | } 60 | 61 | if (ret < 0) { 62 | goto fail; 63 | } 64 | 65 | if(ptr != NULL) { 66 | add_to_buffer(ptr, range, sizeof(CArray)); 67 | } 68 | 69 | if (length == 1) { 70 | return range; 71 | } 72 | 73 | if(type_num == TYPE_DOUBLE_INT) { 74 | start_plus_step_d = (double)(start + step); 75 | ret = funcs->setitem(&start_plus_step_d, (CArray_BYTES(range) + CArray_ITEMSIZE(range)), range); 76 | } 77 | if(type_num == TYPE_INTEGER_INT) { 78 | start_plus_step_i = (int)(start + step); 79 | ret = funcs->setitem(&start_plus_step_i, (CArray_BYTES(range) + CArray_ITEMSIZE(range)), range); 80 | } 81 | 82 | if (ret < 0) { 83 | goto fail; 84 | } 85 | 86 | if (length == 2) { 87 | return range; 88 | } 89 | 90 | if (funcs->fill == NULL) { 91 | throw_valueerror_exception("no fill-function for data-type."); 92 | return NULL; 93 | } 94 | 95 | funcs->fill(CArray_BYTES(range), length, range); 96 | return range; 97 | fail: 98 | return NULL; 99 | } 100 | 101 | 102 | CArray * 103 | CArray_Linspace(double start, double stop, int num, int endpoint, int retstep, int * axis, int type, MemoryPointer * out) 104 | { 105 | CArray * y, * tempc = emalloc(sizeof(CArray)), * freec, * rtn; 106 | double div, delta; 107 | CArrayDescriptor * dtype; 108 | double step; 109 | if(num < 0) { 110 | throw_valueerror_exception("Number of samples must be non-negative."); 111 | return NULL; 112 | } 113 | 114 | if(endpoint) { 115 | div = (num - 1); 116 | } else { 117 | div = num; 118 | } 119 | 120 | dtype = CArray_DescrFromType(TYPE_DOUBLE_INT); 121 | tempc = CArray_NewFromDescr(tempc, dtype, 0, NULL, NULL, NULL, 122 | 0, NULL); 123 | 124 | DDATA(tempc)[0] = div; 125 | 126 | delta = stop - start; 127 | y = CArray_Arange(0.0, num, 1.0, type, NULL); 128 | freec = y; 129 | 130 | if(num > 1) { 131 | step = delta / div; 132 | if (step == 0) { 133 | y = CArray_Divide(y, tempc, NULL); 134 | DDATA(tempc)[0] = delta; 135 | y = CArray_Multiply(y, tempc, NULL); 136 | } else { 137 | DDATA(tempc)[0] = step; 138 | y = CArray_Multiply(y, tempc, NULL); 139 | CArray_Free(freec); 140 | } 141 | } else { 142 | DDATA(tempc)[0] = delta; 143 | y = CArray_Multiply(y, tempc, NULL); 144 | } 145 | 146 | freec = y; 147 | DDATA(tempc)[0] = start; 148 | 149 | y = CArray_Add(y, tempc, NULL); 150 | CArray_Free(freec); 151 | 152 | if (endpoint && num > 1) { 153 | if (CArray_TYPE(y) == TYPE_INTEGER_INT) { 154 | IDATA(y)[CArray_DESCR(y)->numElements-1] = (int)stop; 155 | } 156 | if (CArray_TYPE(y) == TYPE_DOUBLE_INT) { 157 | DDATA(y)[CArray_DESCR(y)->numElements-1] = (double)stop; 158 | } 159 | } 160 | 161 | if (axis != NULL) { 162 | if (*axis != 0) { 163 | dtype = CArray_DescrFromType(TYPE_INTEGER_INT); 164 | CArray *axisc = emalloc(sizeof(CArray)); 165 | axisc = CArray_NewFromDescr(axisc, dtype, 0, NULL, NULL, NULL, 0, NULL); 166 | IDATA(axisc)[0] = *axis; 167 | 168 | dtype = CArray_DescrFromType(TYPE_INTEGER_INT); 169 | CArray *dst = emalloc(sizeof(CArray)); 170 | dst = CArray_NewFromDescr(dst, dtype, 0, NULL, NULL, NULL, 0, NULL); 171 | IDATA(dst)[0] = 0; 172 | y = CArray_Moveaxis(y, dst, axisc, NULL); 173 | } 174 | } 175 | 176 | CArrayDescriptor_FREE(dtype); 177 | 178 | 179 | if (type != TYPE_DOUBLE_INT) { 180 | CArrayDescriptor *descr = CArray_DescrFromType(type); 181 | rtn = CArray_NewLikeArray(y, CARRAY_CORDER, descr, 0); 182 | if(CArray_CastTo(rtn, y) < 0) { 183 | return NULL; 184 | } 185 | CArray_Free(y); 186 | } else { 187 | rtn = y; 188 | } 189 | 190 | if (out != NULL) { 191 | add_to_buffer(out, rtn, sizeof(CArray)); 192 | } 193 | efree(tempc->data); 194 | efree(tempc); 195 | return rtn; 196 | } 197 | 198 | CArray * 199 | CArray_Logspace(double start, double stop, int num, int endpoint, double base, int typenum, MemoryPointer * out) 200 | { 201 | int axis = 0; 202 | CArray * baseca, * y, * rtn, * tmp; 203 | 204 | 205 | baseca = emalloc(sizeof(CArray)); 206 | 207 | CArrayDescriptor * dtype = CArray_DescrFromType(TYPE_DOUBLE_INT); 208 | baseca = CArray_NewFromDescr(baseca, dtype, 0, NULL, NULL, NULL, 0, NULL); 209 | DDATA(baseca)[0] = base; 210 | 211 | tmp = CArray_Linspace(start, stop, num, endpoint, 1, &axis, TYPE_DOUBLE_INT, NULL); 212 | 213 | y = CArray_Power(baseca, tmp, NULL); 214 | 215 | CArray_Free(tmp); 216 | CArray_Free(baseca); 217 | 218 | if (typenum != TYPE_DOUBLE_INT) { 219 | CArrayDescriptor *descr = CArray_DescrFromType(typenum); 220 | rtn = CArray_NewLikeArray(y, CARRAY_CORDER, descr, 0); 221 | if(CArray_CastTo(rtn, y) < 0) { 222 | return NULL; 223 | } 224 | CArray_Free(y); 225 | } else { 226 | rtn = y; 227 | } 228 | 229 | if (out != NULL) { 230 | add_to_buffer(out, rtn, sizeof(CArray)); 231 | } 232 | 233 | return rtn; 234 | } 235 | 236 | CArray * 237 | CArray_Geomspace(double start, double stop, int num, int endpoint, int typenum, MemoryPointer * out) 238 | { 239 | 240 | } 241 | 242 | -------------------------------------------------------------------------------- /kernel/range.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_RANGE_H 2 | #define CARRAY_RANGE_H 3 | 4 | #include "carray.h" 5 | 6 | CArray * CArray_Linspace(double start, double stop, int num, int endpoint, int retstep, int * axis, int type, MemoryPointer * out); 7 | CArray * CArray_Arange(double start, double stop, double step, int type_num, MemoryPointer * ptr); 8 | CArray * CArray_Logspace(double start, double stop, int num, int endpoint, double base, int typenum, MemoryPointer * out); 9 | CArray * CArray_Geomspace(double start, double stop, int num, int endpoint, int typenum, MemoryPointer * out); 10 | 11 | #endif //CARRAY_RANGE_H 12 | -------------------------------------------------------------------------------- /kernel/round.c: -------------------------------------------------------------------------------- 1 | #include "carray.h" 2 | #include "round.h" 3 | #include "alloc.h" 4 | #include "buffer.h" 5 | #include "iterators.h" 6 | 7 | CArray * 8 | CArray_Floor(CArray *a, MemoryPointer *out) 9 | { 10 | CArrayIterator * it1, * it2; 11 | CArray * rtn; 12 | 13 | rtn = CArray_NewLikeArray(a, CARRAY_KEEPORDER, NULL, 0); 14 | 15 | it1 = CArray_NewIter(a); 16 | it2 = CArray_NewIter(rtn); 17 | 18 | switch(CArray_TYPE(rtn)) { 19 | case TYPE_DOUBLE_INT: 20 | do { 21 | *IT_DDATA(it2) = floor(*IT_DDATA(it1)); 22 | CArrayIterator_NEXT(it1); 23 | CArrayIterator_NEXT(it2); 24 | } while (CArrayIterator_NOTDONE(it1)); 25 | break; 26 | case TYPE_INTEGER_INT: 27 | do { 28 | *IT_IDATA(it2) = *IT_IDATA(it1); 29 | CArrayIterator_NEXT(it1); 30 | CArrayIterator_NEXT(it2); 31 | } while (CArrayIterator_NOTDONE(it1)); 32 | break; 33 | default: 34 | throw_notimplemented_exception(); 35 | goto fail; 36 | } 37 | 38 | if (out != NULL) { 39 | add_to_buffer(out, rtn, sizeof(CArray)); 40 | } 41 | 42 | CArrayIterator_FREE(it1); 43 | CArrayIterator_FREE(it2); 44 | return rtn; 45 | fail: 46 | CArrayIterator_FREE(it1); 47 | CArrayIterator_FREE(it2); 48 | return NULL; 49 | } 50 | 51 | CArray * 52 | CArray_Ceil(CArray *a, MemoryPointer *out) 53 | { 54 | CArrayIterator * it1, * it2; 55 | CArray * rtn; 56 | 57 | rtn = CArray_NewLikeArray(a, CARRAY_KEEPORDER, NULL, 0); 58 | 59 | it1 = CArray_NewIter(a); 60 | it2 = CArray_NewIter(rtn); 61 | 62 | switch(CArray_TYPE(rtn)) { 63 | case TYPE_DOUBLE_INT: 64 | do { 65 | *IT_DDATA(it2) = ceil(*IT_DDATA(it1)); 66 | CArrayIterator_NEXT(it1); 67 | CArrayIterator_NEXT(it2); 68 | } while (CArrayIterator_NOTDONE(it1)); 69 | break; 70 | case TYPE_INTEGER_INT: 71 | do { 72 | *IT_IDATA(it2) = (int)ceil((double)*IT_IDATA(it1)); 73 | CArrayIterator_NEXT(it1); 74 | CArrayIterator_NEXT(it2); 75 | } while (CArrayIterator_NOTDONE(it1)); 76 | break; 77 | default: 78 | throw_notimplemented_exception(); 79 | goto fail; 80 | } 81 | 82 | if (out != NULL) { 83 | add_to_buffer(out, rtn, sizeof(CArray)); 84 | } 85 | 86 | CArrayIterator_FREE(it1); 87 | CArrayIterator_FREE(it2); 88 | return rtn; 89 | fail: 90 | CArrayIterator_FREE(it1); 91 | CArrayIterator_FREE(it2); 92 | return NULL; 93 | } 94 | 95 | CArray * 96 | CArray_Round(CArray *a, int decimals, MemoryPointer *out) 97 | { 98 | CArrayIterator * it1, * it2; 99 | CArray * rtn; 100 | int multiplier = 1, negative_decimals = 0, i; 101 | 102 | rtn = CArray_NewLikeArray(a, CARRAY_KEEPORDER, NULL, 0); 103 | 104 | it1 = CArray_NewIter(a); 105 | it2 = CArray_NewIter(rtn); 106 | 107 | if (decimals >= 0) { 108 | for (i = 0; i <= decimals; i++) { 109 | multiplier = multiplier * 10; 110 | } 111 | } else { 112 | negative_decimals = 1; 113 | for (i = 0; i > decimals; i--) { 114 | multiplier = multiplier * 10; 115 | } 116 | } 117 | 118 | switch(CArray_TYPE(rtn)) { 119 | case TYPE_DOUBLE_INT: 120 | if (negative_decimals) { 121 | do { 122 | *IT_DDATA(it2) = ceil(*IT_DDATA(it1) / multiplier) * multiplier; 123 | CArrayIterator_NEXT(it1); 124 | CArrayIterator_NEXT(it2); 125 | } while (CArrayIterator_NOTDONE(it1)); 126 | } else { 127 | do { 128 | if ((*IT_DDATA(it1) - (int)*IT_DDATA(it1)) >= 0.5) { 129 | *IT_DDATA(it2) = ceil(pow(10,decimals)* *IT_DDATA(it1))/pow(10,decimals); 130 | } else { 131 | *IT_DDATA(it2) = floor(pow(10,decimals)* *IT_DDATA(it1))/pow(10,decimals); 132 | } 133 | 134 | CArrayIterator_NEXT(it1); 135 | CArrayIterator_NEXT(it2); 136 | } while (CArrayIterator_NOTDONE(it1)); 137 | } 138 | break; 139 | case TYPE_INTEGER_INT: 140 | if (negative_decimals) { 141 | do { 142 | *IT_IDATA(it2) = (int)(ceil(((double)(*IT_IDATA(it1))/multiplier)) * multiplier); 143 | CArrayIterator_NEXT(it1); 144 | CArrayIterator_NEXT(it2); 145 | } while (CArrayIterator_NOTDONE(it1)); 146 | } else { 147 | do { 148 | *IT_IDATA(it2) = *IT_IDATA(it1); 149 | CArrayIterator_NEXT(it1); 150 | CArrayIterator_NEXT(it2); 151 | } while (CArrayIterator_NOTDONE(it1)); 152 | } 153 | break; 154 | default: 155 | throw_notimplemented_exception(); 156 | goto fail; 157 | } 158 | 159 | if (out != NULL) { 160 | add_to_buffer(out, rtn, sizeof(CArray)); 161 | } 162 | 163 | CArrayIterator_FREE(it1); 164 | CArrayIterator_FREE(it2); 165 | return rtn; 166 | fail: 167 | CArrayIterator_FREE(it1); 168 | CArrayIterator_FREE(it2); 169 | return NULL; 170 | } 171 | -------------------------------------------------------------------------------- /kernel/round.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_ROUND_H 2 | #define CARRAY_ROUND_H 3 | 4 | #include "carray.h" 5 | 6 | CArray * CArray_Floor(CArray *a, MemoryPointer *out); 7 | CArray * CArray_Ceil(CArray *a, MemoryPointer *out); 8 | CArray * CArray_Round(CArray *a, int decimals, MemoryPointer *out); 9 | 10 | #endif //CARRAY_ROUND_H 11 | -------------------------------------------------------------------------------- /kernel/scalar.c: -------------------------------------------------------------------------------- 1 | #include "carray.h" 2 | #include "scalar.h" 3 | #include "php.h" 4 | #include "alloc.h" 5 | #include "buffer.h" 6 | 7 | CArrayScalar * 8 | CArrayScalar_NewLong(long sc) 9 | { 10 | CArrayScalar * ret = NULL; 11 | ret = emalloc(sizeof(CArrayScalar)); 12 | ret->obval = emalloc(sizeof(long)); 13 | ret->type = TYPE_LONG_INT; 14 | *((long*)ret->obval) = sc; 15 | return ret; 16 | } 17 | 18 | CArrayScalar * 19 | CArrayScalar_NewFloat(float sc) 20 | { 21 | CArrayScalar * ret = NULL; 22 | ret = emalloc(sizeof(CArrayScalar)); 23 | ret->obval = emalloc(sizeof(float)); 24 | ret->type = TYPE_FLOAT_INT; 25 | *((float*)ret->obval) = sc; 26 | return ret; 27 | } 28 | 29 | CArrayScalar * 30 | CArrayScalar_NewDouble(double sc) 31 | { 32 | CArrayScalar * ret = NULL; 33 | ret = emalloc(sizeof(CArrayScalar)); 34 | ret->obval = emalloc(sizeof(double)); 35 | ret->type = TYPE_DOUBLE_INT; 36 | *((double*)ret->obval) = sc; 37 | return ret; 38 | } 39 | 40 | CArrayScalar * 41 | CArrayScalar_NewInt(int sc) 42 | { 43 | CArrayScalar * ret = NULL; 44 | ret = emalloc(sizeof(CArrayScalar)); 45 | ret->obval = emalloc(sizeof(int)); 46 | ret->type = TYPE_INTEGER_INT; 47 | *((int*)ret->obval) = sc; 48 | return ret; 49 | } 50 | 51 | void 52 | CArrayScalar_FREE(CArrayScalar * sc) 53 | { 54 | efree(sc->obval); 55 | efree(sc); 56 | } 57 | 58 | CArrayScalar * 59 | CArrayScalar_FromZval(PHPObject * obj, int is_double, int is_long) 60 | { 61 | if(Z_TYPE_P(obj) == IS_DOUBLE) { 62 | /** 63 | * PHP assumes FLOAT and DOUBLE as same type, user 64 | * must identify wich one will be used. 65 | **/ 66 | if(!is_double) { 67 | return CArrayScalar_NewFloat((float)Z_DVAL_P(obj)); 68 | } 69 | return CArrayScalar_NewDouble(Z_DVAL_P(obj)); 70 | } 71 | if(Z_TYPE_P(obj) == IS_LONG) { 72 | /** 73 | * PHP assumes LONG and INTEGER as same type, user 74 | * must identify wich one will be used. 75 | */ 76 | if(!is_long) { 77 | return CArrayScalar_NewInt((int)Z_LVAL_P(obj)); 78 | } 79 | return CArrayScalar_NewLong((long)Z_LVAL_P(obj)); 80 | } 81 | } 82 | 83 | void * 84 | scalar_value(CArrayScalar *scalar, CArrayDescriptor *descr) 85 | { 86 | int type_num; 87 | int align; 88 | int memloc; 89 | 90 | if (descr == NULL) { 91 | descr = CArray_DescrFromScalar(scalar); 92 | type_num = descr->type_num; 93 | CArrayDescriptor_DECREF(descr); 94 | } 95 | else { 96 | type_num = descr->type_num; 97 | } 98 | 99 | switch(type_num) 100 | { 101 | case TYPE_DOUBLE_INT: 102 | return (double *) scalar->obval; 103 | break; 104 | case TYPE_INTEGER_INT: 105 | return (int *) scalar->obval; 106 | break; 107 | case TYPE_FLOAT_INT: 108 | return (float *) scalar->obval; 109 | break; 110 | } 111 | 112 | /**switch (type_num) { 113 | #define CASE(ut,lt) case TYPE_##ut: return &(((CArray##lt##ScalarObject *)scalar)->obval) 114 | CASE(INTEGER, Integer); 115 | CASE(LONG, Long); 116 | CASE(FLOAT, Float); 117 | CASE(DOUBLE, Double); 118 | }**/ 119 | } 120 | 121 | CArrayDescriptor * 122 | CArray_DescrFromScalar(CArrayScalar *sc) 123 | { 124 | return CArray_DescrFromType(sc->type); 125 | } -------------------------------------------------------------------------------- /kernel/scalar.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_SCALAR_H 2 | #define PHPSCI_EXT_SCALAR_H 3 | 4 | #include "carray.h" 5 | 6 | /** 7 | * SCALARS STRUCTURES 8 | */ 9 | typedef struct { 10 | int type; 11 | int obval; 12 | } CArrayIntegerScalarObject; 13 | 14 | typedef struct { 15 | int type; 16 | float obval; 17 | } CArrayFloatScalarObject; 18 | 19 | typedef struct { 20 | int type; 21 | double obval; 22 | } CArrayDoubleScalarObject; 23 | 24 | typedef struct { 25 | int type; 26 | double obval; 27 | } CArrayLongScalarObject; 28 | 29 | typedef struct { 30 | int type; 31 | char * obval; 32 | } CArrayScalar; 33 | 34 | CArrayDescriptor * CArray_DescrFromScalar(CArrayScalar *sc); 35 | CArrayScalar * CArrayScalar_FromZval(PHPObject * obj, int is_double, int is_long); 36 | void CArrayScalar_FREE(CArrayScalar * sc); 37 | CArrayScalar * CArrayScalar_NewInt(int sc); 38 | CArrayScalar * CArrayScalar_NewDouble(double sc); 39 | CArrayScalar * CArrayScalar_NewFloat(float sc); 40 | CArrayScalar * CArrayScalar_NewLong(long sc); 41 | void * scalar_value(CArrayScalar *scalar, CArrayDescriptor *descr); 42 | #endif //PHPSCI_EXT_SCALAR_H 43 | -------------------------------------------------------------------------------- /kernel/search.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_SEARCH_H 2 | #define CARRAY_SEARCH_H 3 | 4 | #include "carray.h" 5 | 6 | int INT_argmax(int *ip, int n, int *max_ind, CArray *CARRAY_UNUSED(aip)); 7 | int DOUBLE_argmax(double *ip, int n, int *max_ind, CArray *CARRAY_UNUSED(aip)); 8 | int INT_argmin(int *ip, int n, int *max_ind, CArray *CARRAY_UNUSED(aip)); 9 | int DOUBLE_argmin(double *ip, int n, int *max_ind, CArray *CARRAY_UNUSED(aip)); 10 | 11 | 12 | CArray * CArray_Argmax(CArray * target, int * axis, MemoryPointer * out); 13 | CArray * CArray_Argmin(CArray * target, int * axis, MemoryPointer * out); 14 | #endif //CARRAY_SEARCH_H 15 | -------------------------------------------------------------------------------- /kernel/shape.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_SHAPE_H 2 | #define PHPSCI_EXT_SHAPE_H 3 | 4 | #include "carray.h" 5 | 6 | CArray * normalize_axis_tuple(CArray * axis, int ndim, int allow_duplicate); 7 | 8 | CArray * CArray_Newshape(CArray * self, int *newdims, int new_ndim, CARRAY_ORDER order, MemoryPointer * ptr); 9 | CArray * CArray_Transpose(CArray * target, CArray_Dims * permute, MemoryPointer * ptr); 10 | CArray * CArray_SwapAxes(CArray * ap, int a1, int a2, MemoryPointer * out); 11 | CArray * CArray_Rollaxis(CArray * arr, int axis, int start, MemoryPointer * out); 12 | CArray * CArray_Moveaxis(CArray * target, CArray * source, CArray * destination, MemoryPointer * out); 13 | void CArray_CreateSortedStridePerm(int ndim, int *strides, ca_stride_sort_item *out_strideperm); 14 | CArray * CArray_Ravel(CArray *arr, CARRAY_ORDER order); 15 | CArray * CArray_atleast1d(CArray * self, MemoryPointer * out); 16 | CArray * CArray_atleast2d(CArray * self, MemoryPointer * out); 17 | CArray * CArray_atleast3d(CArray * self, MemoryPointer * out); 18 | CArray * CArray_Squeeze(CArray * self, int * axis, MemoryPointer * out); 19 | CArray * CArray_SqueezeSelected(CArray * self, int *axis_flags, int n_axis); 20 | void CArray_RemoveAxesInPlace(CArray *arr, int *flags); 21 | CArray * CArray_ExpandDims(CArray * target, int axis, MemoryPointer * out); 22 | #endif //PHPSCI_EXT_SHAPE_H 23 | -------------------------------------------------------------------------------- /kernel/simd.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_SIMD_H 2 | #define CARRAY_SIMD_H 3 | 4 | 5 | int run_binary_simd_multiply_DOUBLE(char **args, int const *dimensions, int const *steps); 6 | int run_unary_simd_sqrt_DOUBLE(char **args, int const *dimensions, int const *steps); 7 | 8 | #endif //CARRAY_SIMD_H 9 | -------------------------------------------------------------------------------- /kernel/statistics.c: -------------------------------------------------------------------------------- 1 | #include "statistics.h" 2 | #include "carray.h" 3 | #include "convert_type.h" 4 | #include "alloc.h" 5 | #include "buffer.h" 6 | #include "common/common.h" 7 | #include "arraytypes.h" 8 | 9 | /* 10 | * Implementation which is common between CArray_Correlate 11 | * and CArray_Correlate2. 12 | * 13 | * inverted is set to 1 if computed correlate(ap2, ap1), 0 otherwise 14 | */ 15 | static CArray* 16 | _carray_correlate(CArray *ap1, CArray *ap2, int typenum, 17 | int mode, int *inverted) 18 | { 19 | CArray *ret; 20 | int length; 21 | int i, n1, n2, n, n_left, n_right; 22 | int is1, is2, os; 23 | char *ip1, *ip2, *op; 24 | CArray_DotFunc *dot; 25 | 26 | n1 = CArray_DIMS(ap1)[0]; 27 | n2 = CArray_DIMS(ap2)[0]; 28 | if (n1 < n2) { 29 | ret = ap1; 30 | ap1 = ap2; 31 | ap2 = ret; 32 | ret = NULL; 33 | i = n1; 34 | n1 = n2; 35 | n2 = i; 36 | *inverted = 1; 37 | } else { 38 | *inverted = 0; 39 | } 40 | 41 | length = n1; 42 | n = n2; 43 | switch(mode) { 44 | case 0: 45 | length = length - n + 1; 46 | n_left = n_right = 0; 47 | break; 48 | case 1: 49 | n_left = (int)(n/2); 50 | n_right = n - n_left - 1; 51 | break; 52 | case 2: 53 | n_right = n - 1; 54 | n_left = n - 1; 55 | length = length + n - 1; 56 | break; 57 | default: 58 | throw_valueerror_exception("mode must be 0, 1, or 2"); 59 | return NULL; 60 | } 61 | 62 | /* 63 | * Need to choose an output array that can hold a sum 64 | * -- use priority to determine which subtype. 65 | */ 66 | ret = new_array_for_sum(ap1, ap2, NULL, 1, &length, typenum, NULL); 67 | if (ret == NULL) { 68 | return NULL; 69 | } 70 | dot = CArray_DESCR(ret)->f->dotfunc; 71 | if (dot == NULL) { 72 | throw_valueerror_exception("function not available for this data type"); 73 | goto clean_ret; 74 | } 75 | 76 | is1 = CArray_STRIDES(ap1)[0]; 77 | is2 = CArray_STRIDES(ap2)[0]; 78 | op = CArray_DATA(ret); 79 | os = CArray_DESCR(ret)->elsize; 80 | ip1 = CArray_DATA(ap1); 81 | ip2 = CArray_BYTES(ap2) + n_left*is2; 82 | n = n - n_left; 83 | for (i = 0; i < n_left; i++) { 84 | dot(ip1, is1, ip2, is2, op, n); 85 | n++; 86 | ip2 -= is2; 87 | op += os; 88 | } 89 | if (small_correlate(ip1, is1, n1 - n2 + 1, CArray_TYPE(ap1), 90 | ip2, is2, n, CArray_TYPE(ap2), 91 | op, os)) { 92 | ip1 += is1 * (n1 - n2 + 1); 93 | op += os * (n1 - n2 + 1); 94 | } 95 | else { 96 | for (i = 0; i < (n1 - n2 + 1); i++) { 97 | dot(ip1, is1, ip2, is2, op, n); 98 | ip1 += is1; 99 | op += os; 100 | } 101 | } 102 | for (i = 0; i < n_right; i++) { 103 | n--; 104 | dot(ip1, is1, ip2, is2, op, n); 105 | ip1 += is1; 106 | op += os; 107 | } 108 | 109 | return ret; 110 | 111 | clean_ret: 112 | CArray_XDECREF(ret); 113 | return NULL; 114 | } 115 | 116 | 117 | CArray * 118 | CArray_Correlate(CArray * op1, CArray * op2, int mode, MemoryPointer * out) 119 | { 120 | CArray *ap1, *ap2, *ret = NULL; 121 | int typenum; 122 | int unused; 123 | CArrayDescriptor *typec; 124 | 125 | typenum = CArray_ObjectType(op1, 0); 126 | typenum = CArray_ObjectType(op2, typenum); 127 | 128 | typec = CArray_DescrFromType(typenum); 129 | CArrayDescriptor_INCREF(typec); 130 | 131 | ap1 = CArray_FromAny(op1, typec, 1, 1, CARRAY_ARRAY_DEFAULT); 132 | if (ap1 == NULL) { 133 | CArrayDescriptor_DECREF(typec); 134 | return NULL; 135 | } 136 | ap2 = CArray_FromAny(op2, typec, 1, 1, CARRAY_ARRAY_DEFAULT); 137 | if (ap2 == NULL) { 138 | goto fail; 139 | } 140 | 141 | ret = _carray_correlate(ap1, ap2, typenum, mode, &unused); 142 | if (ret == NULL) { 143 | goto fail; 144 | } 145 | 146 | if (out != NULL) { 147 | add_to_buffer(out, ret, sizeof(CArray)); 148 | } 149 | 150 | CArrayDescriptor_FREE(typec); 151 | return ret; 152 | 153 | fail: 154 | CArray_XDECREF(ap1); 155 | CArray_XDECREF(ap2); 156 | CArray_XDECREF(ret); 157 | return NULL; 158 | } 159 | 160 | 161 | CArray * 162 | CArray_Correlate2(CArray * op1, CArray * op2, int mode, MemoryPointer * out) 163 | { 164 | CArray *ap1, *ap2, *ret = NULL; 165 | int typenum; 166 | CArrayDescriptor *typec; 167 | int inverted; 168 | int st; 169 | 170 | typenum = CArray_ObjectType(op1, 0); 171 | typenum = CArray_ObjectType(op2, typenum); 172 | 173 | typec = CArray_DescrFromType(typenum); 174 | CArrayDescriptor_INCREF(typec); 175 | 176 | ap1 = CArray_FromAny(op1, typec, 1, 1, CARRAY_ARRAY_DEFAULT); 177 | if (ap1 == NULL) { 178 | CArrayDescriptor_DECREF(typec); 179 | CArrayDescriptor_FREE(typec); 180 | return NULL; 181 | } 182 | ap2 = CArray_FromAny(op2, typec, 1, 1, CARRAY_ARRAY_DEFAULT); 183 | if (ap2 == NULL) { 184 | goto clean_ap1; 185 | } 186 | 187 | ret = _carray_correlate(ap1, ap2, typenum, mode, &inverted); 188 | if (ret == NULL) { 189 | goto clean_ap2; 190 | } 191 | 192 | /* 193 | * If we inverted input orders, we need to reverse the output array (i.e. 194 | * ret = ret[::-1]) 195 | */ 196 | if (inverted) { 197 | //st = _carray_revert(ret); 198 | if (st) { 199 | goto clean_ret; 200 | } 201 | } 202 | 203 | if (out != NULL) { 204 | add_to_buffer(out, ret, sizeof(CArray)); 205 | } 206 | 207 | CArrayDescriptor_DECREF(typec); 208 | 209 | if (ap1->data != op1->data) { 210 | CArray_Free(ap1); 211 | } 212 | 213 | if (ap2->data != op2->data) { 214 | CArray_Free(ap2); 215 | } 216 | 217 | return ret; 218 | clean_ret: 219 | CArray_XDECREF(ret); 220 | clean_ap2: 221 | CArray_XDECREF(ap2); 222 | clean_ap1: 223 | CArray_XDECREF(ap1); 224 | return NULL; 225 | } -------------------------------------------------------------------------------- /kernel/statistics.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_STATISTICS_H 2 | #define CARRAY_STATISTICS_H 3 | 4 | #include "carray.h" 5 | 6 | CArray * CArray_Correlate2(CArray * op1, CArray * op2, int mode, MemoryPointer * out); 7 | CArray * CArray_Correlate(CArray * op1, CArray * op2, int mode, MemoryPointer * out); 8 | 9 | #endif //CARRAY_STATISTICS_H 10 | -------------------------------------------------------------------------------- /kernel/storage.c: -------------------------------------------------------------------------------- 1 | #include "carray.h" 2 | #include "storage.h" 3 | #include "buffer.h" 4 | 5 | /** 6 | * Save CArrray to binary file 7 | * 8 | * @param filename 9 | * @param target 10 | * @return 1 - Success or 0 error 11 | */ 12 | int 13 | CArrayStorage_SaveBin(char * filename, CArray *target) 14 | { 15 | char * fullname = emalloc(sizeof(char) * (strlen(filename) + 4)); 16 | 17 | strcpy(fullname, filename); 18 | strcat(fullname, ".carray"); 19 | 20 | FILE* fp = fopen(fullname, "wb"); 21 | 22 | if (fp == NULL || fp == 0) { 23 | return 0; 24 | } 25 | 26 | assert(fp != 0); 27 | 28 | fwrite(&(target->ndim), sizeof(int), 1, fp); 29 | fwrite(target->dimensions, sizeof(int) * CArray_NDIM(target), 1, fp); 30 | fwrite(target->strides, sizeof(int), CArray_NDIM(target), fp); 31 | fwrite(&(target->flags), sizeof(int), 1, fp); 32 | fwrite(&(target->descriptor->type_num), sizeof(int), 1, fp); 33 | fwrite(target->data, CArray_DESCR(target)->elsize, CArray_MultiplyList(CArray_DIMS(target), CArray_NDIM(target)), fp); 34 | 35 | fclose(fp); 36 | efree(fullname); 37 | 38 | return 1; 39 | } 40 | 41 | int 42 | CArrayStorage_LoadBin(char *filename, MemoryPointer *out) 43 | { 44 | CArrayDescriptor *descr; 45 | CArray *array; 46 | char * fullname = emalloc(sizeof(char) * (strlen(filename) + 4)); 47 | int type_num; 48 | 49 | strcpy(fullname, filename); 50 | strcat(fullname, ".carray"); 51 | 52 | FILE* fp = fopen(fullname, "r"); 53 | 54 | if (fp == NULL || fp == 0) { 55 | return 0; 56 | } 57 | 58 | assert(fp != 0); 59 | 60 | array = emalloc(sizeof(CArray)); 61 | fread(&(array->ndim), sizeof(int), 1, fp); 62 | 63 | array->dimensions = emalloc(sizeof(int) * array->ndim); 64 | fread(array->dimensions, sizeof(int) * array->ndim, 1, fp); 65 | 66 | array->strides = emalloc(sizeof(int) * array->ndim); 67 | fread(array->strides, sizeof(int), array->ndim, fp); 68 | fread(&(array->flags), sizeof(int), 1, fp); 69 | fread(&type_num, sizeof(int), 1, fp); 70 | 71 | descr = CArray_DescrFromType(type_num); 72 | array->descriptor = descr; 73 | 74 | array->data = emalloc(array->descriptor->elsize * CArray_MultiplyList(CArray_DIMS(array), CArray_NDIM(array))); 75 | fread(array->data, array->descriptor->elsize, CArray_MultiplyList(CArray_DIMS(array), CArray_NDIM(array)), fp); 76 | 77 | array->descriptor->numElements = CArray_MultiplyList(CArray_DIMS(array), CArray_NDIM(array)); 78 | array->refcount = 0; 79 | 80 | 81 | array->flags |= CARRAY_ARRAY_OWNDATA; 82 | 83 | add_to_buffer(out, array, sizeof(CArray)); 84 | efree(fullname); 85 | return 1; 86 | } -------------------------------------------------------------------------------- /kernel/storage.h: -------------------------------------------------------------------------------- 1 | #ifndef CARRAY_STORAGE_H 2 | #define CARRAY_STORAGE_H 3 | 4 | #include "carray.h" 5 | 6 | int CArrayStorage_SaveBin(char * filename, CArray *target); 7 | int CArrayStorage_LoadBin(char * filename, MemoryPointer * out); 8 | #endif //CARRAY_STORAGE_H 9 | -------------------------------------------------------------------------------- /kernel/trigonometric.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPSCI_EXT_TRIGONOMETRIC_H 2 | #define PHPSCI_EXT_TRIGONOMETRIC_H 3 | 4 | #include "carray.h" 5 | 6 | typedef double (CArray_CFunc_ElementWise) (double x); 7 | void CArray_ElementWise_CFunc_Int(CArray * target, CArray * result, CArray_CFunc_ElementWise * func); 8 | void CArray_ElementWise_CFunc_Double(CArray * target, CArray * result, CArray_CFunc_ElementWise * func); 9 | void CArray_ElementWise_CFunc(CArray * target, CArray * result, CArray_CFunc_ElementWise * func); 10 | 11 | CArray * CArray_Sin(CArray * target, MemoryPointer * out); 12 | CArray * CArray_Cos(CArray * target, MemoryPointer * out); 13 | CArray * CArray_Tan(CArray * target, MemoryPointer * out); 14 | CArray * CArray_Arcsin(CArray * target, MemoryPointer * out); 15 | CArray * CArray_Arccos(CArray * target, MemoryPointer * out); 16 | CArray * CArray_Arctan(CArray * target, MemoryPointer * out); 17 | CArray * CArray_Sinh(CArray * target, MemoryPointer * out); 18 | CArray * CArray_Cosh(CArray * target, MemoryPointer * out); 19 | CArray * CArray_Tanh(CArray * target, MemoryPointer * out); 20 | CArray * CArray_Arcsinh(CArray * target, MemoryPointer * out); 21 | CArray * CArray_Arccosh(CArray * target, MemoryPointer * out); 22 | CArray * CArray_Arctanh(CArray * target, MemoryPointer * out); 23 | #endif //PHPSCI_EXT_TRIGONOMETRIC_H 24 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: PHPSci CArray 2 | theme: readthedocs 3 | repo_url: http://github.com/phpsci/phpsci-ext 4 | site_url: http://phpsci-carray.readthedocs.io/ 5 | site_description: 'Documentation for PHPSci CArray Extension for PHP.' 6 | docs_dir: docs/ 7 | dev_addr: '0.0.0.0:8000' 8 | 9 | pages: 10 | - Home: index.md 11 | - Routines: 12 | - CArray Object: routines/carray_object.md 13 | - Ones and Zeros: routines/ones_and_zeros.md 14 | - Numerical Ranges: routines/numerical_ranges.md 15 | - Transpose: routines/transpose.md 16 | - Dimensions: routines/dimensions.md 17 | - Indexing: routines/indexing.md 18 | - Matrix & Vector Products: routines/ma_products.md 19 | - Decompositions: routines/decompositions.md 20 | - Matrix Norms: routines/ma_norms.md 21 | - Equations & Inverse: routines/equations_and_inverse.md 22 | - Trigonometric: routines/trigonometric.md 23 | - Hyperbolic: routines/hyperbolic.md 24 | - Rounding: routines/rounding.md 25 | - Sums, products, differences: routines/sum_products_and_diff.md 26 | - Exponents and logarithms: routines/exponents_loga.md 27 | - Arithmetic: routines/arithmetic.md 28 | - Sorting: routines/sorting.md 29 | - Searching: routines/searching.md 30 | - Random Sampling: routines/random.md 31 | - Rearranging: routines/rearranging.md 32 | - Distributions: routines/distributions.md 33 | - Statistics: routines/statistics.md 34 | - CArray Internals: 35 | - Internals Explanation: internals/explanation.md 36 | - C Reference: internals/carray_api.md 37 | -------------------------------------------------------------------------------- /phpsci.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHPSci CArray | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2018 PHPSci Team | 6 | +----------------------------------------------------------------------+ 7 | | Licensed under the Apache License, Version 2.0 (the "License"); | 8 | | you may not use this file except in compliance with the License. | 9 | | You may obtain a copy of the License at | 10 | | | 11 | | http://www.apache.org/licenses/LICENSE-2.0 | 12 | | | 13 | | Unless required by applicable law or agreed to in writing, software | 14 | | distributed under the License is distributed on an "AS IS" BASIS, | 15 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | 16 | | implied. | 17 | | See the License for the specific language governing permissions and | 18 | | limitations under the License. | 19 | +----------------------------------------------------------------------+ 20 | | Authors: Henrique Borba | 21 | +----------------------------------------------------------------------+ 22 | */ 23 | 24 | #ifndef CARRAY_EXT_PHPSCI_H 25 | #define CARRAY_EXT_PHPSCI_H 26 | 27 | #define PHP_CARRAY_EXTNAME "CArray" 28 | #define PHP_CARRAY_VERSION "0.0.1" 29 | 30 | #ifdef ZTS 31 | #include "TSRM.h" 32 | #endif 33 | #include "php.h" 34 | #include "kernel/carray.h" 35 | 36 | 37 | static zend_class_entry *carray_sc_entry; 38 | static zend_object_handlers carray_object_handlers; 39 | static zend_class_entry *carray_exception_sc_entry; 40 | static zend_class_entry *carray_iterator_sc_entry; 41 | 42 | extern zend_module_entry carray_module_entry; 43 | 44 | #define phpext_carray_ptr &carray_module_entry 45 | 46 | void RETURN_MEMORYPOINTER(zval * return_value, MemoryPointer * ptr); 47 | int * ZVAL_TO_TUPLE(zval * obj, int * size); 48 | void ZVAL_TO_MEMORYPOINTER(zval * obj, MemoryPointer * ptr, char * type); 49 | void RETURN_RUBIX_MEMORYPOINTER(zval * return_value, MemoryPointer * ptr); 50 | void FREE_FROM_MEMORYPOINTER(MemoryPointer * ptr); 51 | void * FREE_TUPLE(int * tuple); 52 | zval * MEMORYPOINTER_TO_ZVAL(MemoryPointer * ptr); 53 | #endif //PHPSCI_EXT_PHPSCI_H 54 | -------------------------------------------------------------------------------- /tests/arithmetics/arithmetics_dd_1d_add.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | CArray Arithmetics ([DOUBLE] + DOUBLE): new CArray([1.0, 2.0, 3.0]) plus 1.5 3 | --FILE-- 4 | getMessage(); 11 | } 12 | --EXPECT-- 13 | array is not broadcastable to correct shape -------------------------------------------------------------------------------- /tests/initializers/linspace.basicadd.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | CArray::linspace(2.0, 3.0, 5) plus 1 3 | --FILE-- 4 | 11 | int(2) 12 | ["ndim"]=> 13 | int(1) 14 | } -------------------------------------------------------------------------------- /tests/initializers/linspace.basicdump.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | CArray::linspace(2.0, 3.0, 5) basic dump 3 | --FILE-- 4 | 0 11 | [ndim] => 1 12 | ) 13 | -------------------------------------------------------------------------------- /travis/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | phpize 5 | ./configure 6 | make clean 7 | make 8 | make install --------------------------------------------------------------------------------