├── conf └── 20-rindow_openblas.ini ├── CREDITS ├── phpunit ├── test.php ├── Bootstrap.php ├── phpunit.xml ├── AbstractNDArrayPhp.php ├── Utils.php └── BufferTest.php ├── .vscode ├── settings.json └── c_cpp_properties.json ├── testPHP ├── NDArrayPhp7.php ├── HostBuffer.php └── NDArrayPhp8.php ├── tests ├── 001.phpt ├── 002.phpt ├── 003.phpt ├── sample_math.phpt ├── sample_buffer.phpt └── sample_blas.phpt ├── composer.json ├── debian └── control ├── .gitignore ├── matlib.c ├── LICENSE ├── packaging.sh ├── .github └── workflows │ └── tests.yml ├── lapacke_client.c ├── php_rindow_openblas.h ├── config.w32 ├── config.m4 ├── src └── Rindow │ └── OpenBLAS │ ├── Math_repeat.c │ ├── Math_slice.c │ ├── Math_random.c │ ├── Math_reduction.c │ ├── Lapack.c │ ├── Math_im2col1d.c │ ├── Math_im2col2d.c │ ├── Math_gather.c │ ├── Buffer.c │ └── Math_im2col3d.c ├── README.md ├── rindow_openblas.c └── client_generator.php /conf/20-rindow_openblas.ini: -------------------------------------------------------------------------------- 1 | extension=rindow_openblas -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | Rindow OpenBLAS PHP extension 2 | Yuichi Ishikawa 3 | -------------------------------------------------------------------------------- /phpunit/test.php: -------------------------------------------------------------------------------- 1 | doOffsetGet( $offset ); 9 | } 10 | } -------------------------------------------------------------------------------- /testPHP/HostBuffer.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | . 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testPHP/NDArrayPhp8.php: -------------------------------------------------------------------------------- 1 | doOffsetGet( $offset ); 11 | } 12 | } -------------------------------------------------------------------------------- /tests/001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check if rindow_openblas is loaded 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | 13 | --EXPECT-- 14 | The extension "rindow_openblas" is available 15 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rindow/rindow-openblas-dev", 3 | "type": "project", 4 | "description": "Universal Buffer for N-dimension and OpenBLAS and Math library", 5 | "keywords": ["rindow","math","NDArray","blas","openblas"], 6 | "license": "BSD-3-Clause", 7 | "require": { 8 | "php": ">=7.2", 9 | "interop-phpobjects/polite-math": ">=1.0.6" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Buffer 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | 22 | --EXPECT-- 23 | 41234 24 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Package: rindow-openblas-php%PHP_VERSION% 2 | Maintainer: Rindow Developers 3 | Architecture: amd64 4 | Depends: libopenblas-base, liblapacke, php%PHP_VERSION%-common 5 | Version: %PHP_RINDOW_OPENBLAS_VERSION% 6 | Homepage: https://rindow.github.io/ 7 | Description: Rindow OpenBLAS PHP extension 8 | The Rindow OpenBLAS PHP extension is universal Buffer for N-dimension and OpenBLAS 9 | and Mathematical library. 10 | 11 | -------------------------------------------------------------------------------- /tests/003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Blas 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | asum(4,$buf,0,1); 23 | ?> 24 | --EXPECT-- 25 | 10 26 | -------------------------------------------------------------------------------- /tests/sample_math.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Sample BLAS 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | array([1,2],NDArray::float32); 22 | $math->increment($a->size(),$alpha=2.0,$a->buffer(),0,1,$beta=1.0); 23 | var_dump($a[0]); 24 | var_dump($a[1]); 25 | ?> 26 | --EXPECT-- 27 | float(3) 28 | float(5) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.lo 2 | *.la 3 | *.dep 4 | *.out 5 | *.obj 6 | *.exe 7 | .libs 8 | acinclude.m4 9 | aclocal.m4 10 | autom4te.cache 11 | build 12 | config.guess 13 | config.h 14 | config.h.in 15 | config.h.in~ 16 | config.log 17 | config.nice 18 | config.nice.bat 19 | config.status 20 | config.sub 21 | configure 22 | configure~ 23 | configure.ac 24 | configure.in 25 | configure.bat 26 | configure.js 27 | install-sh 28 | libtool 29 | ltmain.sh 30 | Makefile 31 | Makefile.fragments 32 | Makefile.global 33 | Makefile.objects 34 | missing 35 | mkinstalldirs 36 | modules 37 | run-tests.php 38 | phpunit/.phpunit.* 39 | tests/*.diff 40 | tests/*.out 41 | tests/*.php 42 | tests/*.exp 43 | tests/*.log 44 | tests/*.sh 45 | x64 46 | pkgwork/ 47 | *.deb 48 | composer.lock 49 | vendor/ 50 | /.vscode -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "C:/php/php-8.2.1-devel-vs16-x64/include", 8 | "C:/php/php-8.2.1-devel-vs16-x64/include/main", 9 | "C:/OpenBLAS/OpenBLAS-0.3.20-x64/include" 10 | ], 11 | "defines": [ 12 | "_DEBUG", 13 | "UNICODE", 14 | "_UNICODE" 15 | ], 16 | "windowsSdkVersion": "10.0.19041.0", 17 | "compilerPath": "cl.exe", 18 | "cStandard": "c17", 19 | "cppStandard": "c++17", 20 | "intelliSenseMode": "windows-msvc-x64", 21 | "compilerArgs": [ 22 | "/openmp:experimental" 23 | ] 24 | } 25 | ], 26 | "version": 4 27 | } -------------------------------------------------------------------------------- /matlib.c: -------------------------------------------------------------------------------- 1 | #include "common.c" 2 | #include "sum.c" 3 | #include "imax.c" 4 | #include "imin.c" 5 | #include "increment.c" 6 | #include "reciprocal.c" 7 | #include "maximum.c" 8 | #include "minimum.c" 9 | #include "greater.c" 10 | #include "greater_eq.c" 11 | #include "less.c" 12 | #include "less_eq.c" 13 | #include "multiply.c" 14 | #include "add.c" 15 | #include "duplicate.c" 16 | #include "square.c" 17 | #include "sqrt.c" 18 | #include "rsqrt.c" 19 | #include "pow.c" 20 | #include "exp.c" 21 | #include "log.c" 22 | #include "tanh.c" 23 | #include "sin.c" 24 | #include "cos.c" 25 | #include "tan.c" 26 | #include "zeros.c" 27 | #include "onehot.c" 28 | #include "softmax.c" 29 | #include "equal.c" 30 | #include "not_equal.c" 31 | #include "not.c" 32 | #include "astype.c" 33 | #include "matrixcopy.c" 34 | #include "imagecopy.c" 35 | #include "fill.c" 36 | #include "nan2num.c" 37 | #include "isnan.c" 38 | #include "searchsorted.c" 39 | #include "cumsum.c" 40 | #include "transpose.c" 41 | #include "bandpart.c" 42 | #include "gather.c" 43 | #include "reduce_gather.c" 44 | #include "slice.c" 45 | #include "repeat.c" 46 | #include "reduce_sum.c" 47 | #include "reduce_max.c" 48 | #include "reduce_argmax.c" 49 | #include "random_uniform.c" 50 | #include "random_normal.c" 51 | #include "random_sequence.c" 52 | #include "im2col1d.c" 53 | #include "im2col2d.c" 54 | #include "im2col3d.c" 55 | 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, rindow 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /packaging.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | PHP_CONFIG=`which php-config$1` 4 | if [ -z "$1" ] 5 | then 6 | echo "Argument 1 must be the php version" 7 | exit 8 | fi 9 | if [ ! -x "$PHP_CONFIG" ] 10 | then 11 | echo "Invalid version $1"; 12 | exit 13 | fi 14 | PHP_VERSION=$1 15 | PKG_WORK=pkgwork 16 | EXTENSION_DIR=`$PHP_CONFIG --extension-dir` 17 | if [ `echo $PHP_VERSION | awk -F. '{printf "%2d%02d%02d", $1,$2,$3}'` -lt "070400" ] 18 | then 19 | INI_DIR=/etc/php/$PHP_VERSION/cli/conf.d 20 | else 21 | INI_DIR=`$PHP_CONFIG --ini-dir` 22 | fi 23 | RINDOW_OPENBLAS_VERSION=`fgrep "# define PHP_RINDOW_OPENBLAS_VERSION" php_rindow_openblas.h | cut -d " " -f 4 | cut -d "\"" -f 2` 24 | #. /etc/os-release 25 | #OS_VERSION=$ID$VERSION_ID 26 | echo EXTENSION_DIR=$EXTENSION_DIR 27 | echo INI_DIR=$INI_DIR 28 | echo RINDOW_OPENBLAS_VERSION=$RINDOW_OPENBLAS_VERSION 29 | #echo OS_VERSION=$OS_VERSION 30 | rm -rf $PKG_WORK 31 | mkdir -p $PKG_WORK$EXTENSION_DIR 32 | mkdir -p $PKG_WORK$INI_DIR 33 | mkdir -p $PKG_WORK/DEBIAN 34 | cp modules/rindow_openblas.so $PKG_WORK$EXTENSION_DIR/. 35 | chmod 744 $PKG_WORK$EXTENSION_DIR/rindow_openblas.so 36 | cp conf/20-rindow_openblas.ini $PKG_WORK$INI_DIR/. 37 | chmod 744 $PKG_WORK$INI_DIR/20-rindow_openblas.ini 38 | sed -e s/%PHP_RINDOW_OPENBLAS_VERSION%/$RINDOW_OPENBLAS_VERSION/g debian/control | \ 39 | #sed -e s/%OS_VERSION%/$OS_VERSION/g | \ 40 | sed -e s/%PHP_VERSION%/$PHP_VERSION/g > $PKG_WORK/DEBIAN/control 41 | #sed -e s@%EXTENSION_DIR%@$EXTENSION_DIR@ debian/rules | \ 42 | #sed -e s@%INI_DIR%@$INI_DIR@ debian/rules | \ 43 | # > $PKG_WORK/DEBIAN/rules 44 | #cp debian/changelog $PKG_WORK/DEBIAN/. 45 | #cp debian/copyright $PKG_WORK/DEBIAN/. 46 | 47 | rm -f rindow-openblas*.deb 48 | fakeroot dpkg-deb --build pkgwork . 49 | -------------------------------------------------------------------------------- /tests/sample_buffer.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Blas 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | dtype()==NDArray::float32,'dtype'); 51 | 52 | $binary = $x->dump(); 53 | assert(strlen($binary)==32/8*2,'dump binary'); 54 | $y = new Rindow\OpenBlas\Buffer(2,NDArray::float32); 55 | $y->load($binary); 56 | assert($y[0]==10.0,'load binary'); 57 | assert($y[1]==20.0,'load binary'); 58 | echo "done" 59 | ?> 60 | --EXPECT-- 61 | done 62 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | tests: 10 | runs-on: ubuntu-22.04 11 | env: 12 | matlib: 1.0.0 13 | 14 | strategy: 15 | fail-fast: true 16 | matrix: 17 | php: ['7.2','8.2','8.3'] 18 | 19 | steps: 20 | - name: Checkout codes 21 | uses: "actions/checkout@v4" 22 | 23 | - name: Setup PHP ${{ matrix.php }} 24 | uses: shivammathur/setup-php@v2 25 | with: 26 | php-version: ${{ matrix.php }} 27 | # PHP Extras 28 | coverage: none 29 | tools: composer, phpunit:8.5 30 | ini-values: "memory_limit=512M" 31 | # extensions: ${{ matrix.ffi }} 32 | 33 | - name: setup OpenBLAS 34 | run: | 35 | sudo apt install libopenblas-dev 36 | sudo apt install liblapacke-dev 37 | 38 | - name: Download rindow-matlib 39 | run: | 40 | wget https://github.com/rindow/rindow-matlib/archive/refs/tags/${matlib}.tar.gz 41 | tar xvf ${matlib}.tar.gz 42 | ( cd rindow-matlib-${matlib} && cmake -S . -B build ) 43 | 44 | - name: Build 45 | run: | 46 | composer update 47 | phpize${{ matrix.php }} 48 | ./configure --enable-rindow_openblas --with-rindow_matlib=./rindow-matlib-${matlib} --with-php-config=php-config${{ matrix.php }} 49 | make clean 50 | make 51 | 52 | - name: Install rindow_openblas 53 | run: | 54 | sh ./packaging.sh ${{ matrix.php }} 55 | RINDOW_OPENBLAS_VERSION=`fgrep "# define PHP_RINDOW_OPENBLAS_VERSION" php_rindow_openblas.h | cut -d " " -f 4 | cut -d "\"" -f 2` 56 | . /etc/os-release 57 | sudo apt install -y ./rindow-openblas-php${{ matrix.php }}_${RINDOW_OPENBLAS_VERSION}_amd64.deb 58 | 59 | - name: Tests 60 | run: | 61 | phpunit -c phpunit 62 | 63 | 64 | -------------------------------------------------------------------------------- /lapacke_client.c: -------------------------------------------------------------------------------- 1 | typedef lapack_int (CALLBACK* PFNLAPACKE_sgesvd)( /* LAPACKE_sgesvd */ 2 | int /* matrix_layout */, 3 | char /* jobu */, 4 | char /* jobvt */, 5 | lapack_int /* m */, 6 | lapack_int /* n */, 7 | float * /* a */, 8 | lapack_int /* lda */, 9 | float * /* s */, 10 | float * /* u */, 11 | lapack_int /* ldu */, 12 | float * /* vt */, 13 | lapack_int /* ldvt */, 14 | float * /* superb */ 15 | ); 16 | static PFNLAPACKE_sgesvd _g_LAPACKE_sgesvd = NULL; 17 | lapack_int LAPACKE_sgesvd( 18 | int matrix_layout, 19 | char jobu, 20 | char jobvt, 21 | lapack_int m, 22 | lapack_int n, 23 | float * a, 24 | lapack_int lda, 25 | float * s, 26 | float * u, 27 | lapack_int ldu, 28 | float * vt, 29 | lapack_int ldvt, 30 | float * superb 31 | ) 32 | { 33 | if(_h_openblas==NULL || _g_LAPACKE_sgesvd==NULL) { 34 | return 0; 35 | } 36 | return _g_LAPACKE_sgesvd( 37 | matrix_layout, 38 | jobu, 39 | jobvt, 40 | m, 41 | n, 42 | a, 43 | lda, 44 | s, 45 | u, 46 | ldu, 47 | vt, 48 | ldvt, 49 | superb 50 | ); 51 | } 52 | typedef lapack_int (CALLBACK* PFNLAPACKE_dgesvd)( /* LAPACKE_dgesvd */ 53 | int /* matrix_layout */, 54 | char /* jobu */, 55 | char /* jobvt */, 56 | lapack_int /* m */, 57 | lapack_int /* n */, 58 | double * /* a */, 59 | lapack_int /* lda */, 60 | double * /* s */, 61 | double * /* u */, 62 | lapack_int /* ldu */, 63 | double * /* vt */, 64 | lapack_int /* ldvt */, 65 | double * /* superb */ 66 | ); 67 | static PFNLAPACKE_dgesvd _g_LAPACKE_dgesvd = NULL; 68 | lapack_int LAPACKE_dgesvd( 69 | int matrix_layout, 70 | char jobu, 71 | char jobvt, 72 | lapack_int m, 73 | lapack_int n, 74 | double * a, 75 | lapack_int lda, 76 | double * s, 77 | double * u, 78 | lapack_int ldu, 79 | double * vt, 80 | lapack_int ldvt, 81 | double * superb 82 | ) 83 | { 84 | if(_h_openblas==NULL || _g_LAPACKE_dgesvd==NULL) { 85 | return 0; 86 | } 87 | return _g_LAPACKE_dgesvd( 88 | matrix_layout, 89 | jobu, 90 | jobvt, 91 | m, 92 | n, 93 | a, 94 | lda, 95 | s, 96 | u, 97 | ldu, 98 | vt, 99 | ldvt, 100 | superb 101 | ); 102 | } 103 | -------------------------------------------------------------------------------- /php_rindow_openblas.h: -------------------------------------------------------------------------------- 1 | /* rindow_openblas extension for PHP */ 2 | 3 | #ifndef PHP_RINDOW_OPENBLAS_H 4 | # define PHP_RINDOW_OPENBLAS_H 5 | 6 | # define phpext_rindow_openblas_ptr &rindow_openblas_module_entry 7 | 8 | # define PHP_RINDOW_OPENBLAS_VERSION "0.4.1" 9 | 10 | # if defined(ZTS) && defined(COMPILE_DL_RINDOW_OPENBLAS) 11 | ZEND_TSRMLS_CACHE_EXTERN() 12 | # endif 13 | 14 | 15 | // Rindow\OpenBLAS\Blas object structures 16 | typedef struct { 17 | zend_object std; 18 | } php_rindow_openblas_blas_t; 19 | static inline php_rindow_openblas_blas_t* php_rindow_openblas_blas_fetch_object(zend_object* obj) 20 | { 21 | return (php_rindow_openblas_blas_t*) ((char*) obj - XtOffsetOf(php_rindow_openblas_blas_t, std)); 22 | } 23 | #define Z_RINDOW_OPENBLAS_BLAS_OBJ_P(zv) (php_rindow_openblas_blas_fetch_object(Z_OBJ_P(zv))) 24 | 25 | // Rindow\OpenBLAS\Lapack object structures 26 | typedef struct { 27 | zend_object std; 28 | } php_rindow_openblas_lapack_t; 29 | static inline php_rindow_openblas_lapack_t* php_rindow_openblas_lapack_fetch_object(zend_object* obj) 30 | { 31 | return (php_rindow_openblas_lapack_t*) ((char*) obj - XtOffsetOf(php_rindow_openblas_lapack_t, std)); 32 | } 33 | #define Z_RINDOW_OPENBLAS_LAPACK_OBJ_P(zv) (php_rindow_openblas_lapack_fetch_object(Z_OBJ_P(zv))) 34 | 35 | // Rindow\OpenBLAS\Math object structures 36 | typedef struct { 37 | zend_object std; 38 | } php_rindow_openblas_math_t; 39 | static inline php_rindow_openblas_math_t* php_rindow_openblas_math_fetch_object(zend_object* obj) 40 | { 41 | return (php_rindow_openblas_math_t*) ((char*) obj - XtOffsetOf(php_rindow_openblas_math_t, std)); 42 | } 43 | #define Z_RINDOW_OPENBLAS_MATH_OBJ_P(zv) (php_rindow_openblas_math_fetch_object(Z_OBJ_P(zv))) 44 | 45 | static inline void *php_rindow_openblas_get_address( 46 | php_interop_polite_math_matrix_linear_buffer_t* buffer,zend_long offset,int valueSize) 47 | { 48 | return (uint8_t *)(buffer->data)+(offset*valueSize); 49 | } 50 | 51 | 52 | extern int php_rindow_openblas_common_dtype_to_valuesize(zend_long dtype); 53 | extern int php_rindow_openblas_common_dtype_is_int(zend_long dtype); 54 | extern int php_rindow_openblas_common_dtype_is_float(zend_long dtype); 55 | extern int php_rindow_openblas_common_dtype_is_bool(zend_long dtype); 56 | 57 | extern void php_rindow_openblas_buffer_init_ce(INIT_FUNC_ARGS); 58 | extern void php_rindow_openblas_blas_init_ce(INIT_FUNC_ARGS); 59 | extern void php_rindow_openblas_lapack_init_ce(INIT_FUNC_ARGS); 60 | extern void php_rindow_openblas_math_init_ce(INIT_FUNC_ARGS); 61 | extern zend_class_entry* php_rindow_openblas_buffer_ce; 62 | extern zend_module_entry rindow_openblas_module_entry; 63 | 64 | extern int php_rindow_openblas_assert_shape_parameter( 65 | char* name, zend_long n); 66 | extern int php_rindow_openblas_assert_vector_buffer_spec( 67 | char* name,php_interop_polite_math_matrix_linear_buffer_t *buffer, 68 | zend_long n, zend_long offset, zend_long inc); 69 | extern int php_rindow_openblas_assert_matrix_buffer_spec( 70 | char *name,php_interop_polite_math_matrix_linear_buffer_t *buffer, 71 | zend_long m, zend_long n, zend_long offset, zend_long ld); 72 | extern int php_rindow_openblas_assert_buffer_size( 73 | php_interop_polite_math_matrix_linear_buffer_t *buffer, 74 | zend_long offset,zend_long size, 75 | char* message); 76 | extern int php_rindow_openblas_assert_buffer_type( 77 | php_interop_polite_math_matrix_linear_buffer_t *buffer, 78 | char* name); 79 | 80 | #endif /* PHP_RINDOW_OPENBLAS_H */ 81 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // vim:ft=javascript 2 | 3 | ARG_ENABLE('rindow_openblas', 'rindow_openblas support', 'no'); 4 | 5 | ARG_WITH('openblas', 'openblas support', 'no'); 6 | ARG_WITH('flang', 'flang support', 'no'); 7 | ARG_WITH('matlib', 'matlib support', 'no'); 8 | 9 | // OpenMP compile option 10 | // /openmp:experimental 11 | 12 | if (PHP_RINDOW_OPENBLAS != 'no') { 13 | var PHP_RINDOW_OPENBLAS_CFLAGS="\ 14 | /Qvec-report:1 \ 15 | /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 \ 16 | /openmp:experimental \ 17 | /I" + configure_module_dirname + " \ 18 | "; 19 | if(CHECK_HEADER_ADD_INCLUDE("cblas.h", "rindow_openblas", PHP_OPENBLAS + '/build/build/generated')) { 20 | PHP_RINDOW_OPENBLAS_CFLAGS = PHP_RINDOW_OPENBLAS_CFLAGS + "\ 21 | /I" + PHP_OPENBLAS + "/build \ 22 | /I" + PHP_OPENBLAS + "/build/generated \ 23 | "; 24 | } else if(CHECK_HEADER_ADD_INCLUDE("cblas.h", "rindow_openblas", PHP_OPENBLAS + '/include')) { 25 | PHP_RINDOW_OPENBLAS_CFLAGS = PHP_RINDOW_OPENBLAS_CFLAGS + "\ 26 | /I" + PHP_OPENBLAS + "/include \ 27 | "; 28 | } else { 29 | ERROR("NOT FOUND: OpenBLAS header files. Please set --with-openblas=/some/directory/path"); 30 | } 31 | if(CHECK_HEADER_ADD_INCLUDE("Interop/Polite/Math/Matrix.h", "rindow_openblas", configure_module_dirname + '/vendor/interop-phpobjects/polite-math/include')) { 32 | PHP_RINDOW_OPENBLAS_CFLAGS = PHP_RINDOW_OPENBLAS_CFLAGS + "\ 33 | /I" + configure_module_dirname + "/vendor/interop-phpobjects/polite-math/include \ 34 | "; 35 | } else { 36 | ERROR("NOT FOUND: LinearBuffer interface header files. Please execute \"composer update\" on development directory."); 37 | } 38 | if(CHECK_HEADER_ADD_INCLUDE("rindow/matlib.h", "rindow_openblas", PHP_MATLIB + '/include')) { 39 | PHP_RINDOW_OPENBLAS_CFLAGS = PHP_RINDOW_OPENBLAS_CFLAGS + "\ 40 | /I" + PHP_MATLIB + "/include \ 41 | /I" + PHP_MATLIB + "/src \ 42 | /I" + PHP_MATLIB + "/build/src \ 43 | "; 44 | } else { 45 | ERROR("NOT FOUND: Rindow Matlib header files. Please set --with-matlib=/some/directory/path"); 46 | } 47 | 48 | // Condense whitespace in CFLAGS 49 | PHP_RINDOW_OPENBLAS_CFLAGS = PHP_RINDOW_OPENBLAS_CFLAGS.replace(/\s+/g, ' '); 50 | 51 | AC_DEFINE('HAVE_RINDOW_OPENBLAS', 1, 'rindow_openblas support enabled'); 52 | AC_DEFINE('OPENBLAS_HAVE_IAMIN', 1, 'openblas have iamin'); 53 | 54 | EXTENSION('rindow_openblas', 'rindow_openblas.c openblas_client.c', null, PHP_RINDOW_OPENBLAS_CFLAGS); 55 | ADD_SOURCES(configure_module_dirname + "/src/Rindow/OpenBLAS", "Buffer.c Blas.c Lapack.c Math.c", "rindow_openblas"); 56 | // if (CHECK_LIB("openblas.lib", "rindow_openblas", PHP_OPENBLAS + '/build/lib/Release')) { 57 | // ADD_FLAG("LIBS_OPENBLAS", "openblas.lib"); 58 | // ADD_FLAG("LDFLAGS", '/libpath:"\\"' + PHP_OPENBLAS + '/build/lib/Release' + '\\"" '); 59 | // } else if (CHECK_LIB("openblas.lib", "rindow_openblas", PHP_OPENBLAS + '/lib')) { 60 | // ADD_FLAG("LIBS_OPENBLAS", "openblas.lib"); 61 | // ADD_FLAG("LDFLAGS", '/libpath:"\\"' + PHP_OPENBLAS + '/lib' + '\\"" '); 62 | // } else if (CHECK_LIB("libopenblas.lib", "rindow_openblas", PHP_OPENBLAS + '/lib')) { 63 | // ADD_FLAG("LIBS_OPENBLAS", "libopenblas.lib"); 64 | // ADD_FLAG("LDFLAGS", '/libpath:"\\"' + PHP_OPENBLAS + '/lib' + '\\"" '); 65 | // } else { 66 | // ERROR("NOT FOUND: OpenBLAS library files. Please set --with-openblas=/some/directory/path"); 67 | // } 68 | if (CHECK_LIB("flang.lib", "rindow_openblas", PHP_FLANG + '/lib')) { 69 | ADD_FLAG("LDFLAGS", '/libpath:"\\"' + PHP_FLANG + '/lib' + '\\"" '); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tests/sample_blas.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Sample BLAS 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | array([1,2],NDArray::float32); 23 | 24 | $blas->scal(2,10,$a->buffer(),0,1); 25 | var_dump($a[0]); 26 | var_dump($a[1]); 27 | 28 | $a = $mo->array([1,2],NDArray::float32); 29 | $b = $mo->array([50,60],NDArray::float32); 30 | 31 | $blas->scal($a->size(),2.0,$a->buffer(),0,1); 32 | var_dump($a->toArray()); 33 | 34 | $blas->axpy($a->size(),2.0,$a->buffer(),0,1,$b->buffer(),0,1); 35 | var_dump($b->toArray()); 36 | 37 | $a = $mo->array([1,2,3,4,5,6],NDArray::float32); 38 | $b = $mo->array([3,4,5,6,7,8],NDArray::float32); 39 | var_dump($blas->dot($a->size(),$a->buffer(),0,1,$b->buffer(),0,1)); 40 | 41 | $a = $mo->array([-1,2,3,4,5,6],NDArray::float32); 42 | var_dump($blas->asum($a->size(),$a->buffer(),0,1)); 43 | 44 | $a = $mo->array([-1,2,3,4,5,-6],NDArray::float32); 45 | var_dump($blas->iamax($a->size(),$a->buffer(),0,1)); 46 | 47 | $a = $mo->array([-1,2,3,4,-5,6],NDArray::float32); 48 | var_dump($blas->iamin($a->size(),$a->buffer(),0,1)); 49 | 50 | $a = $mo->array([-1,2,3,4,-5,6],NDArray::float32); 51 | $b = $mo->zerosLike($a); 52 | $blas->copy($a->size(),$a->buffer(),0,1,$b->buffer(),0,1); 53 | var_dump($b->toArray()); 54 | 55 | // Use BLAS 56 | // Use BLAS 57 | // 3x3 * 3 58 | // y := alpha * Ax + beta * y 59 | $A = $mo->array([[1,2,3],[4,5,6],[7,8,9]],NDArray::float32); 60 | $X = $mo->array([2,3,4],NDArray::float32); 61 | $Y = $mo->zeros([3],NDArray::float32); 62 | // [ 20, 47, 74], 63 | $blas->gemv(BLAS::RowMajor,BLAS::NoTrans,$Y->size(),$X->size(), 64 | 1.0,$A->buffer(),0,$Y->size(),$X->buffer(),0,1,0.0,$Y->buffer(),0,1); 65 | echo 'gemv='; 66 | var_dump($Y->toArray()); 67 | 68 | // Use BLAS 69 | // 3x3 * 3x3 70 | // C := alpha * AB + beta * C 71 | $A = $mo->array([[1,2,3],[4,5,6],[7,8,9]],NDArray::float32); 72 | $B = $mo->array([[2,3,4],[5,6,7],[8,9,1]],NDArray::float32); 73 | $C = $mo->zeros([3,3],NDArray::float32); 74 | // [[ 36, 42, 21], 75 | // [ 81, 96, 57], 76 | // [126, 150, 93]], 77 | //var_dump($A->shape()); 78 | //var_dump($B->shape()); 79 | //var_dump($C->shape()); 80 | $blas->gemm( 81 | BLAS::RowMajor,BLAS::NoTrans,BLAS::NoTrans, 82 | 3,3,3, 83 | 1.0, 84 | $A->buffer(),0,3, 85 | $B->buffer(),0,3, 86 | 0.0, 87 | $C->buffer(),0,3); 88 | echo 'gemm='; 89 | var_dump($C->toArray()); 90 | ?> 91 | --EXPECT-- 92 | float(10) 93 | float(20) 94 | array(2) { 95 | [0]=> 96 | float(2) 97 | [1]=> 98 | float(4) 99 | } 100 | array(2) { 101 | [0]=> 102 | float(54) 103 | [1]=> 104 | float(68) 105 | } 106 | float(133) 107 | float(21) 108 | int(5) 109 | int(0) 110 | array(6) { 111 | [0]=> 112 | float(-1) 113 | [1]=> 114 | float(2) 115 | [2]=> 116 | float(3) 117 | [3]=> 118 | float(4) 119 | [4]=> 120 | float(-5) 121 | [5]=> 122 | float(6) 123 | } 124 | gemv=array(3) { 125 | [0]=> 126 | float(20) 127 | [1]=> 128 | float(47) 129 | [2]=> 130 | float(74) 131 | } 132 | gemm=array(3) { 133 | [0]=> 134 | array(3) { 135 | [0]=> 136 | float(36) 137 | [1]=> 138 | float(42) 139 | [2]=> 140 | float(21) 141 | } 142 | [1]=> 143 | array(3) { 144 | [0]=> 145 | float(81) 146 | [1]=> 147 | float(96) 148 | [2]=> 149 | float(57) 150 | } 151 | [2]=> 152 | array(3) { 153 | [0]=> 154 | float(126) 155 | [1]=> 156 | float(150) 157 | [2]=> 158 | float(93) 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl config.m4 for extension rindow_openblas 2 | 3 | PHP_ARG_ENABLE(rindow_openblas, whether to enable rindow_openblas support, 4 | dnl Make sure that the comment is aligned: 5 | [ --enable-rindow_openblas Enable rindow_openblas support], no) 6 | PHP_ARG_WITH(rindow_matlib, rindow_matlib support, 7 | [ --with-rindow_matlib=DIR Specify rindow_matlib path]) 8 | 9 | if test "$PHP_RINDOW_OPENBLAS" != "no"; then 10 | 11 | dnl # get library OpenBLAS build options from pkg-config output 12 | AC_PATH_PROG(PKG_CONFIG, pkg-config, no) 13 | AC_MSG_CHECKING(for openblas) 14 | if test -x "$PKG_CONFIG"; then 15 | if $PKG_CONFIG --exists openblas; then 16 | if $PKG_CONFIG --exists lapacke; then 17 | if $PKG_CONFIG openblas --atleast-version 0.2.0; then 18 | LIBBLAS_CFLAGS="`$PKG_CONFIG openblas --cflags` `$PKG_CONFIG lapacke --libs`" 19 | LIBBLAS_LIBDIR="`$PKG_CONFIG openblas --libs` `$PKG_CONFIG lapacke --libs`" 20 | LIBBLAS_VERSON=`$PKG_CONFIG openblas --modversion` 21 | AC_MSG_RESULT(from pkgconfig: version $LIBBLAS_VERSON) 22 | if $PKG_CONFIG openblas --atleast-version 0.3.6; then 23 | AC_DEFINE(OPENBLAS_HAVE_IAMIN, 1, [openblas have iamin]) 24 | fi 25 | else 26 | AC_MSG_ERROR(system openblas is too old: version 0.2.0 required) 27 | fi 28 | else 29 | AC_MSG_ERROR(lapacke not found) 30 | fi 31 | else 32 | AC_MSG_ERROR(openblas not found) 33 | fi 34 | else 35 | AC_MSG_ERROR(pkg-config not found) 36 | fi 37 | LIBMATLIB_LIBDIR=PHP_EXT_SRCDIR(rindow_openblas)[/lib] 38 | dnl # LIBBLAS_LIBDIR="-L$LIBMATLIB_LIBDIR -lrindowmatlib $LIBBLAS_LIBDIR" 39 | PHP_EVAL_LIBLINE($LIBBLAS_LIBDIR, RINDOW_OPENBLAS_SHARED_LIBADD) 40 | PHP_EVAL_INCLINE($LIBBLAS_CFLAGS) 41 | dnl # RINDOW_OPENBLAS_SHARED_LIBADD="-fopenmp $RINDOW_OPENBLAS_SHARED_LIBADD" 42 | AC_MSG_CHECKING([LIBBLAS_LIBDIR]) 43 | AC_MSG_RESULT($LIBBLAS_LIBDIR) 44 | 45 | AC_DEFINE(CL_TARGET_OPENCL_VERSION, 120, [ Target OpenCL version 1.2 ]) 46 | PHP_EVAL_LIBLINE($LIBOPENCL_LIBDIR" "$LIBCLBLAST_LIBDIR, RINDOW_CLBLAST_SHARED_LIBADD) 47 | PHP_EVAL_INCLINE($LIBOPENCL_CFLAGS" "$LIBCLBLAST_CFLAGS) 48 | 49 | dnl # PHP_ADD_INCLUDE($RINDOW_OPENBLAS_DIR/include) 50 | AC_MSG_CHECKING(for Interop/Polite/Math/Matrix.h) 51 | if test -f "PHP_EXT_SRCDIR(rindow_openblas)/vendor/interop-phpobjects/polite-math/include/Interop/Polite/Math/Matrix.h" ; then 52 | AC_MSG_RESULT(ok) 53 | PHP_ADD_INCLUDE(PHP_EXT_SRCDIR(rindow_openblas)[/vendor/interop-phpobjects/polite-math/include]) 54 | else 55 | AC_MSG_RESULT(no) 56 | AC_MSG_ERROR(Interop/Polite/Math/Matrix.h not found. Please type "composer update") 57 | fi 58 | 59 | if test "$PHP_RINDOW_MATLIB" != "no"; then 60 | if test "$PHP_RINDOW_MATLIB" == "yes"; then 61 | AC_MSG_ERROR([You must specify a path when using --with-rindow_matlib]) 62 | fi 63 | AC_MSG_CHECKING(for rindow/matlib.h) 64 | if test -f "$PHP_RINDOW_MATLIB/include/rindow/matlib.h" ; then 65 | AC_MSG_RESULT(ok) 66 | PHP_ADD_INCLUDE($PHP_RINDOW_MATLIB/include) 67 | PHP_ADD_INCLUDE($PHP_RINDOW_MATLIB/src) 68 | PHP_ADD_INCLUDE($PHP_RINDOW_MATLIB/build/src) 69 | else 70 | AC_MSG_RESULT(no) 71 | AC_MSG_ERROR(rindow/matlib.h not found. Please specify directory by --with-rindow_matlib option) 72 | fi 73 | fi 74 | 75 | PHP_SUBST(RINDOW_OPENBLAS_SHARED_LIBADD) 76 | 77 | 78 | dnl # In case of no dependencies 79 | AC_DEFINE(HAVE_RINDOW_OPENBLAS, 1, [ Have rindow_openblas support ]) 80 | 81 | RINDOW_OPENBLAS_SOURCES="\ 82 | rindow_openblas.c \ 83 | src/Rindow/OpenBLAS/Buffer.c \ 84 | src/Rindow/OpenBLAS/Blas.c \ 85 | src/Rindow/OpenBLAS/Lapack.c \ 86 | src/Rindow/OpenBLAS/Math.c \ 87 | " 88 | 89 | dnl # PHP_NEW_EXTENSION(rindow_openblas, $RINDOW_OPENBLAS_SOURCES, $ext_shared,, -fopenmp -msse2) 90 | PHP_NEW_EXTENSION(rindow_openblas, $RINDOW_OPENBLAS_SOURCES, $ext_shared) 91 | fi 92 | -------------------------------------------------------------------------------- /src/Rindow/OpenBLAS/Math_repeat.c: -------------------------------------------------------------------------------- 1 | /* 2 | B(n,repeats,k) := A(n,k) 3 | 4 | Method Rindow\OpenBLAS\Math:: 5 | public function repeat( 6 | int $m, 7 | int $k, 8 | int $repeats, 9 | Buffer $A, int $offsetA, 10 | Buffer $B, int $offsetB 11 | ) : void 12 | {{{ */ 13 | static PHP_METHOD(Math, repeat) 14 | { 15 | zend_long m; 16 | zend_long k; 17 | zend_long repeats; 18 | zval* a; 19 | zend_long offsetA; 20 | zval* b; 21 | zend_long offsetB; 22 | php_interop_polite_math_matrix_linear_buffer_t* bufferA; 23 | php_interop_polite_math_matrix_linear_buffer_t* bufferB; 24 | 25 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 7, 7) 26 | Z_PARAM_LONG(m) 27 | Z_PARAM_LONG(k) 28 | Z_PARAM_LONG(repeats) 29 | Z_PARAM_OBJECT(a) // Interop\Polite\Math\Matrix\LinearBuffer 30 | Z_PARAM_LONG(offsetA) 31 | Z_PARAM_OBJECT(b) // Interop\Polite\Math\Matrix\LinearBuffer 32 | Z_PARAM_LONG(offsetB) 33 | ZEND_PARSE_PARAMETERS_END(); 34 | 35 | if(php_rindow_openblas_assert_shape_parameter( 36 | "m", m)) { 37 | return; 38 | } 39 | if(php_rindow_openblas_assert_shape_parameter( 40 | "k", k)) { 41 | return; 42 | } 43 | if(repeats<=0) { 44 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument repeats must be greater than or equal 0.", 0); 45 | return; 46 | } 47 | 48 | // Check Buffer A 49 | bufferA = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(a); 50 | if(php_rindow_openblas_assert_buffer_type(bufferA,"a")) { 51 | return; 52 | } 53 | if(offsetA+m*k > bufferA->size) { 54 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix A specification too large for buffer.", 0); 55 | return; 56 | } 57 | 58 | // Check Buffer B 59 | bufferB = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(b); 60 | if(php_rindow_openblas_assert_buffer_type(bufferB,"b")) { 61 | return; 62 | } 63 | if(offsetB+m*repeats*k > bufferB->size) { 64 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix B specification too large for buffer.", 0); 65 | return; 66 | } 67 | 68 | // Check Buffer A and Y 69 | if(bufferA->dtype!=bufferB->dtype) { 70 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch data type for A and B", 0); 71 | return; 72 | } 73 | 74 | switch (bufferA->dtype) { 75 | case php_interop_polite_math_matrix_dtype_float32: { 76 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataA,bufferA,offsetA) 77 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataB,bufferB,offsetB) 78 | rindow_matlib_s_repeat((index_t)m,(index_t)k,(index_t)repeats,pDataA,pDataB); 79 | break; 80 | } 81 | case php_interop_polite_math_matrix_dtype_float64: { 82 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataA,bufferA,offsetA) 83 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataB,bufferB,offsetB) 84 | rindow_matlib_d_repeat((index_t)m,(index_t)k,(index_t)repeats,pDataA,pDataB); 85 | break; 86 | } 87 | default:{ 88 | if(!php_rindow_openblas_common_dtype_is_int(bufferA->dtype)&& 89 | !php_rindow_openblas_common_dtype_is_bool(bufferA->dtype)) { 90 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 91 | return; 92 | } 93 | void *pDataA = rindow_matlib_common_get_address((dtype_t)bufferA->dtype, bufferA->data,(index_t)offsetA); 94 | void *pDataB = rindow_matlib_common_get_address((dtype_t)bufferB->dtype, bufferB->data,(index_t)offsetB); 95 | rindow_matlib_i_repeat((index_t)m,(index_t)k,(index_t)repeats,(dtype_t)bufferA->dtype,pDataA,pDataB); 96 | break; 97 | } 98 | } 99 | } 100 | /* }}} */ 101 | -------------------------------------------------------------------------------- /src/Rindow/OpenBLAS/Math_slice.c: -------------------------------------------------------------------------------- 1 | /* 2 | Y(i,j) := A(is,js) 3 | 4 | Method Rindow\OpenBLAS\Math:: 5 | public function slice( 6 | bool $reverse, 7 | bool $addMode, 8 | int $m, 9 | int $n, 10 | int $k, 11 | int $size, 12 | Buffer $A, int $offsetA, int $incA, 13 | Buffer $Y, int $offsetY, int $incY, 14 | int $startAxis0, 15 | int $sizeAxis0, 16 | int $startAxis1, 17 | int $sizeAxis1, 18 | int $startAxis2, 19 | int $sizeAxis2 20 | ) : void 21 | {{{ */ 22 | static PHP_METHOD(Math, slice) 23 | { 24 | php_interop_polite_math_matrix_linear_buffer_t* bufferA; 25 | php_interop_polite_math_matrix_linear_buffer_t* bufferY; 26 | zend_bool reverse; 27 | zend_bool addMode; 28 | zend_long m; 29 | zend_long n; 30 | zend_long k; 31 | zend_long size; 32 | zval* obja=NULL; 33 | zend_long offsetA; 34 | zend_long incA; 35 | zval* objy=NULL; 36 | zend_long offsetY; 37 | zend_long incY; 38 | zend_long startAxis0; 39 | zend_long sizeAxis0; 40 | zend_long startAxis1; 41 | zend_long sizeAxis1; 42 | zend_long startAxis2; 43 | zend_long sizeAxis2; 44 | 45 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 18, 18) 46 | Z_PARAM_BOOL(reverse) 47 | Z_PARAM_BOOL(addMode) 48 | Z_PARAM_LONG(m) 49 | Z_PARAM_LONG(n) 50 | Z_PARAM_LONG(k) 51 | 52 | Z_PARAM_LONG(size) 53 | Z_PARAM_OBJECT(obja) // Interop\Polite\Math\Matrix\LinearBuffer 54 | Z_PARAM_LONG(offsetA) 55 | Z_PARAM_LONG(incA) 56 | Z_PARAM_OBJECT(objy) // Interop\Polite\Math\Matrix\LinearBuffer 57 | 58 | Z_PARAM_LONG(offsetY) 59 | Z_PARAM_LONG(incY) 60 | Z_PARAM_LONG(startAxis0) 61 | Z_PARAM_LONG(sizeAxis0) 62 | Z_PARAM_LONG(startAxis1) 63 | 64 | Z_PARAM_LONG(sizeAxis1) 65 | Z_PARAM_LONG(startAxis2) 66 | Z_PARAM_LONG(sizeAxis2) 67 | ZEND_PARSE_PARAMETERS_END(); 68 | 69 | if(php_rindow_openblas_assert_shape_parameter( 70 | "m", m)) { 71 | return; 72 | } 73 | if(php_rindow_openblas_assert_shape_parameter( 74 | "n", n)) { 75 | return; 76 | } 77 | if(php_rindow_openblas_assert_shape_parameter( 78 | "k", k)) { 79 | return; 80 | } 81 | if(size<=0){ 82 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument size must be greater than or equal 0.", 0); 83 | return; 84 | } 85 | if(startAxis0<0){ 86 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument startAxis0 must be greater than or equal 0.", 0); 87 | return; 88 | } 89 | if(sizeAxis0<=0){ 90 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument sizeAxis0 must be greater than 0.", 0); 91 | return; 92 | } 93 | if(startAxis1<0){ 94 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument startAxis1 must be greater than or equal 0.", 0); 95 | return; 96 | } 97 | if(sizeAxis1<=0){ 98 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument sizeAxis1 must be greater than 0.", 0); 99 | return; 100 | } 101 | if(startAxis2<0){ 102 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument startAxis2 must be greater than or equal 0.", 0); 103 | return; 104 | } 105 | if(sizeAxis2<=0){ 106 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument sizeAxis2 must be greater than 0.", 0); 107 | return; 108 | } 109 | // Check Buffer A 110 | bufferA = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(obja); 111 | if(php_rindow_openblas_assert_buffer_type(bufferA,"a")) { 112 | return; 113 | } 114 | if(m*n*k*size*incA+offsetA > bufferA->size) { 115 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch BufferA size and m,n,k,size", 0); 116 | return; 117 | } 118 | // Check Buffer Y 119 | bufferY = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(objy); 120 | if(php_rindow_openblas_assert_buffer_type(bufferY,"y")) { 121 | return; 122 | } 123 | if(sizeAxis0*sizeAxis1*size*incY+offsetY > bufferY->size) { 124 | zend_throw_exception(spl_ce_InvalidArgumentException, "BufferY size is too small", 0); 125 | return; 126 | } 127 | 128 | if(startAxis0>=m|| 129 | sizeAxis0+startAxis0>m){ 130 | zend_throw_exception(spl_ce_InvalidArgumentException, "Axis0 range is too large for source array.",0); 131 | return; 132 | } 133 | if(startAxis1>=n|| 134 | sizeAxis1+startAxis1>n){ 135 | zend_throw_exception(spl_ce_InvalidArgumentException, "Axis1 range is too large for source array.",0); 136 | return; 137 | } 138 | if(startAxis2>=k|| 139 | sizeAxis2+startAxis2>k){ 140 | zend_throw_exception(spl_ce_InvalidArgumentException, "Axis2 range is too large for source array.",0); 141 | return; 142 | } 143 | if(bufferA->dtype != bufferY->dtype) { 144 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch data type", 0); 145 | return; 146 | } 147 | 148 | switch (bufferA->dtype) { 149 | case php_interop_polite_math_matrix_dtype_float32: { 150 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataA,bufferA,offsetA) 151 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataY,bufferY,offsetY) 152 | rindow_matlib_s_slice(reverse,addMode,(index_t)m,(index_t)n,(index_t)k,(index_t)size,pDataA,(index_t)incA,pDataY,(index_t)incY,(index_t)startAxis0,(index_t)sizeAxis0,(index_t)startAxis1,(index_t)sizeAxis1,(index_t)startAxis2,(index_t)sizeAxis2); 153 | break; 154 | } 155 | case php_interop_polite_math_matrix_dtype_float64: { 156 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataA,bufferA,offsetA) 157 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataY,bufferY,offsetY) 158 | rindow_matlib_d_slice(reverse,addMode,(index_t)m,(index_t)n,(index_t)k,(index_t)size,pDataA,(index_t)incA,pDataY,(index_t)incY,(index_t)startAxis0,(index_t)sizeAxis0,(index_t)startAxis1,(index_t)sizeAxis1,(index_t)startAxis2,(index_t)sizeAxis2); 159 | break; 160 | } 161 | default:{ 162 | if(!php_rindow_openblas_common_dtype_is_int(bufferA->dtype)&& 163 | !php_rindow_openblas_common_dtype_is_bool(bufferA->dtype)) { 164 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 165 | return; 166 | } 167 | void *pDataA = rindow_matlib_common_get_address((dtype_t)bufferA->dtype, bufferA->data,(index_t)offsetA); 168 | void *pDataY = rindow_matlib_common_get_address((dtype_t)bufferY->dtype, bufferY->data,(index_t)offsetY); 169 | rindow_matlib_i_slice(reverse,addMode,(index_t)m,(index_t)n,(index_t)k,(index_t)size,(dtype_t)bufferA->dtype,pDataA,(index_t)incA,pDataY,(index_t)incY,(index_t)startAxis0,(index_t)sizeAxis0,(index_t)startAxis1,(index_t)sizeAxis1,(index_t)startAxis2,(index_t)sizeAxis2); 170 | break; 171 | } 172 | } 173 | } 174 | /* }}} */ 175 | -------------------------------------------------------------------------------- /src/Rindow/OpenBLAS/Math_random.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | /* 5 | X(i) := rand(seed) 6 | 7 | Method Rindow\OpenBLAS\Math:: 8 | public function randomUniform( 9 | int $n, 10 | Buffer $X, int $offsetX, int $incX, 11 | float $low, 12 | float $high, 13 | int $seed 14 | ) : void 15 | {{{ */ 16 | 17 | static PHP_METHOD(Math, randomUniform) 18 | { 19 | php_interop_polite_math_matrix_linear_buffer_t* bufferX; 20 | zend_long n; 21 | zval* x=NULL; 22 | zend_long offsetX; 23 | zend_long incX; 24 | zval* low_val=NULL; 25 | zval* high_val=NULL; 26 | zend_long low_int; 27 | zend_long high_int; 28 | double low_float; 29 | double high_float; 30 | zend_long seed; 31 | 32 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 7, 7) 33 | Z_PARAM_LONG(n) 34 | Z_PARAM_OBJECT(x) // Interop\Polite\Math\Matrix\LinearBuffer 35 | Z_PARAM_LONG(offsetX) 36 | Z_PARAM_LONG(incX) 37 | Z_PARAM_ZVAL(low_val) 38 | Z_PARAM_ZVAL(high_val) 39 | Z_PARAM_LONG(seed) 40 | ZEND_PARSE_PARAMETERS_END(); 41 | 42 | // Check Buffer X 43 | bufferX = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(x); 44 | if(php_rindow_openblas_assert_buffer_type(bufferX,"x")) { 45 | return; 46 | } 47 | if(php_rindow_openblas_assert_vector_buffer_spec( 48 | "X", bufferX,n,offsetX,incX)) { 49 | return; 50 | } 51 | 52 | if(php_rindow_openblas_common_dtype_is_float(bufferX->dtype)) { 53 | if(php_rindow_openblas_val2float(low_val,&low_float,"low must be float or int")) { 54 | return; 55 | } 56 | if(php_rindow_openblas_val2float(high_val,&high_float,"high must be float or int")) { 57 | return; 58 | } 59 | } else if(php_rindow_openblas_common_dtype_is_int(bufferX->dtype)) { 60 | if(php_rindow_openblas_val2int(low_val,&low_int,"low must be float or int")) { 61 | return; 62 | } 63 | if(php_rindow_openblas_val2int(high_val,&high_int,"high must be float or int")) { 64 | return; 65 | } 66 | } else { 67 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 68 | return; 69 | } 70 | 71 | switch(bufferX->dtype) { 72 | case php_interop_polite_math_matrix_dtype_float32: { 73 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataX,bufferX,offsetX) 74 | rindow_matlib_s_randomuniform((index_t)n,pDataX,(index_t)incX,(float)low_float,(float)high_float,(int32_t)seed); 75 | break; 76 | } 77 | case php_interop_polite_math_matrix_dtype_float64: { 78 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataX,bufferX,offsetX) 79 | rindow_matlib_d_randomuniform((index_t)n,pDataX,(index_t)incX,(double)low_float,(double)high_float,(int32_t)seed); 80 | break; 81 | } 82 | default: { 83 | void *pDataX = rindow_matlib_common_get_address((dtype_t)bufferX->dtype, bufferX->data,(index_t)offsetX); 84 | rindow_matlib_i_randomuniform((index_t)n,(dtype_t)bufferX->dtype,pDataX,(index_t)incX,(int32_t)low_int,(int32_t)high_int,(int32_t)seed); 85 | break; 86 | } 87 | } 88 | } 89 | /* }}} */ 90 | 91 | /* 92 | X(i) := rand(seed) 93 | 94 | Method Rindow\OpenBLAS\Math:: 95 | public function randomNormal( 96 | int $n, 97 | Buffer $X, int $offsetX, int $incX, 98 | float $mean, 99 | float $scale, 100 | int $seed 101 | ) : void 102 | {{{ */ 103 | 104 | static PHP_METHOD(Math, randomNormal) 105 | { 106 | php_interop_polite_math_matrix_linear_buffer_t* bufferX; 107 | zend_long n; 108 | zval* x=NULL; 109 | zend_long offsetX; 110 | zend_long incX; 111 | zval* low_val=NULL; 112 | zval* high_val=NULL; 113 | double mean; 114 | double scale; 115 | zend_long seed; 116 | 117 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 7, 7) 118 | Z_PARAM_LONG(n) 119 | Z_PARAM_OBJECT(x) // Interop\Polite\Math\Matrix\LinearBuffer 120 | Z_PARAM_LONG(offsetX) 121 | Z_PARAM_LONG(incX) 122 | Z_PARAM_DOUBLE(mean) 123 | Z_PARAM_DOUBLE(scale) 124 | Z_PARAM_LONG(seed) 125 | ZEND_PARSE_PARAMETERS_END(); 126 | 127 | // Check Buffer X 128 | bufferX = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(x); 129 | if(php_rindow_openblas_assert_buffer_type(bufferX,"x")) { 130 | return; 131 | } 132 | if(php_rindow_openblas_assert_vector_buffer_spec( 133 | "X", bufferX,n,offsetX,incX)) { 134 | return; 135 | } 136 | 137 | switch(bufferX->dtype) { 138 | case php_interop_polite_math_matrix_dtype_float32: { 139 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataX,bufferX,offsetX) 140 | rindow_matlib_s_randomnormal((index_t)n,pDataX,(index_t)incX,(float)mean,(float)scale,(int32_t)seed); 141 | break; 142 | } 143 | case php_interop_polite_math_matrix_dtype_float64: { 144 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataX,bufferX,offsetX) 145 | rindow_matlib_d_randomnormal((index_t)n,pDataX,(index_t)incX,(double)mean,(double)scale,(int32_t)seed); 146 | break; 147 | } 148 | default: { 149 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 150 | return; 151 | } 152 | } 153 | } 154 | /* }}} */ 155 | /* 156 | X(i) := rand(seed) 157 | 158 | Method Rindow\OpenBLAS\Math:: 159 | public function randomSequence( 160 | int $n, 161 | int $size, 162 | Buffer $X, int $offsetX, int $incX 163 | int $seed 164 | ) : void 165 | {{{ */ 166 | 167 | static PHP_METHOD(Math, randomSequence) 168 | { 169 | php_interop_polite_math_matrix_linear_buffer_t* bufferX; 170 | zend_long n; 171 | zend_long size; 172 | zval* x=NULL; 173 | zend_long offsetX; 174 | zend_long incX; 175 | zend_long seed; 176 | 177 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 6, 6) 178 | Z_PARAM_LONG(n) 179 | Z_PARAM_LONG(size) 180 | Z_PARAM_OBJECT(x) // Interop\Polite\Math\Matrix\LinearBuffer 181 | Z_PARAM_LONG(offsetX) 182 | Z_PARAM_LONG(incX) 183 | Z_PARAM_LONG(seed) 184 | ZEND_PARSE_PARAMETERS_END(); 185 | 186 | // Check Buffer X 187 | bufferX = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(x); 188 | if(php_rindow_openblas_assert_buffer_type(bufferX,"x")) { 189 | return; 190 | } 191 | if(php_rindow_openblas_assert_vector_buffer_spec( 192 | "X", bufferX,n,offsetX,incX)) { 193 | return; 194 | } 195 | if(ndtype!=php_interop_polite_math_matrix_dtype_int64&& 200 | bufferX->dtype!=php_interop_polite_math_matrix_dtype_int32) { 201 | zend_throw_exception(spl_ce_InvalidArgumentException, "dtype must be int32 or int64.", 0); 202 | return; 203 | } 204 | 205 | void *pDataX = rindow_matlib_common_get_address((dtype_t)bufferX->dtype, bufferX->data,(index_t)offsetX); 206 | rindow_matlib_i_randomsequence((index_t)n,(index_t)size,(dtype_t)bufferX->dtype,pDataX,(index_t)incX,(int32_t)seed); 207 | } 208 | /* }}} */ 209 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | IMPORTANT 2 | ========= 3 | Development of this program has ended. 4 | Please migrate to the program below instead. 5 | 6 | - https://github.com/rindow/rindow-openblas-ffi 7 | 8 | We stopped using PHP extensions because it was too difficult to prepare binary files for each PHP version and Linux version. 9 | 10 | Rindow OpenBLAS PHP extension 11 | ============================= 12 | The Rindow OpenBLAS PHP extension is universal Buffer for N-dimension and OpenBLAS and Mathematical library. 13 | 14 | - Provides Universal Buffer for 1-dimension for data exchange between C,C+ language and PHP. 15 | - The OpenBLAS library available to PHP. Only the commonly used functions in OpenBLAS are provided. 16 | - Provides commonly used Mathematical libraries not included in OpenBLAS. 17 | 18 | You can do very fast N-dimensional array operations in conjunction with the [Rindow Math Matrix](https://github.com/rindow/rindow-math-matrix). 19 | 20 | Very useful when you want to do deep learning with PHP! 21 | 22 | Requirements 23 | ============ 24 | 25 | - PHP7.2 or PHP7.3 or PHP7.4 or PHP8.0 or PHP8.1 or PHP8.2 or PHP8.3 26 | - Linux or Windows 10 27 | - [OpenBLAS](https://github.com/OpenMathLib/OpenBLAS) 28 | - [Rindow-Matlib](https://github.com/rindow/rindow-matlib) 29 | 30 | Recommend environment 31 | ===================== 32 | 33 | - PHP8.1 or PHP8.2 or PHP8.3 34 | - OpenCL binding for PHP - rindow-opencl 0.2.0. [sources](https://github.com/rindow/rindow-opencl), [binaries](https://github.com/rindow-opencl/releases) 35 | - BLAS libray for OpenCL implements - rindow-clblast 0.2.0. [sources](https://github.com/rindow/rindow-clblast), [binaries](https://github.com/rindow-clblast/releases) 36 | - Matrix PHP library - rindow-math-matrix 2.0.0 or later. [sources](https://github.com/rindow/rindow-math-matrix) 37 | - Driver Pack - rindow-math-matrix-matlibext 1.0.0 or later. [sources](https://github.com/rindow/rindow-math-matrix-matlibext) 38 | 39 | How to build from source code on Linux 40 | ====================================== 41 | You can also build and use from source code. 42 | (Please change the notation of the php version number according to your environment.) 43 | 44 | Install build tools and OpenBLAS libray 45 | --------------------------------------- 46 | Install gcc development environment and openblas library. 47 | Then install the php development environment according to the target php version. 48 | 49 | ```shell 50 | $ sudo apt install build-essential autoconf automake libtool bison re2c 51 | $ sudo apt install pkg-config 52 | $ sudo apt install libopenblas-dev 53 | $ sudo apt install liblapacke-dev 54 | $ sudo apt install phpX.X-dev (ex. php8.1-dev) 55 | ``` 56 | If you want to use the latest version of openblas, download the source code from [the site](https://github.com/xianyi/OpenBLAS/releases), build it, and set the installation location of openblas in PKG_CONFIG_PATH 57 | 58 | ### Build 59 | Run the target php version of phpize and build. 60 | 61 | ```shell 62 | $ cd /path/to/build/directory 63 | $ git clone https://github.com/rindow/rindow-matlib 64 | $ cd rindow-matlib 65 | $ cmake -S . -B build 66 | $ cd .. 67 | $ git clone https://github.com/rindow/rindow-openblas 68 | $ cd rindow-openblas 69 | $ composer update 70 | $ phpizeX.X (ex. phpize8.1) 71 | $ ./configure --enable-rindow_openblas --with-rindow_matlib=/path/to/rindow-matlib --with-php-config=php-configX.X (ex. php-config8.1) 72 | $ make clean 73 | $ make 74 | $ make test 75 | ``` 76 | 77 | ### Install from built directory 78 | 79 | ```shell 80 | $ sudo make install 81 | ``` 82 | Add the "extension=rindow_openblas" entry to php.ini or Make the file rindow_openblas.ini. 83 | 84 | If you want an easier install, use the following spell instead of "make install" and creating an ini file. 85 | 86 | ```shell 87 | $ sh ./packaging.sh X.X (ex. sh ./packaging.sh 8.1) 88 | $ sudo apt install ./rindow-openblas-phpX.X_X.X.X_amd64.deb (ex. ./rindow-openblas-php8.1_...) 89 | ``` 90 | 91 | How to build from source code on Windows 92 | ======================================== 93 | You can also build and use from source code. 94 | 95 | 96 | Download or Build OpenBLAS for MSVC on Windows 97 | ---------------------------------------------- 98 | ### Download binaries for the OpenBLAS libray 99 | You need to build OpenBLAS libray for MSVC or download built binaries of libray for MSVC. 100 | 101 | If you want to use the pre-built OpenBLAS libray, you need OpenBLAS release 0.3.10 or later. 102 | 103 | - https://github.com/xianyi/OpenBLAS/releases 104 | 105 | ### Install VC15 or VC16 106 | Developing PHP extensions for php7.x requires VC15 instead of the latest VC. 107 | 108 | - Install Microsoft Visual Studio 2019 or later installer 109 | - Run Installer with vs2017 build tools option. 110 | 111 | Developing PHP extensions from php8.x, requires VS16. You can use Visual Studio 2019. 112 | 113 | ### Build OpenBLAS for pure MSVC from sources 114 | If you want to build the OpenBLAS on MSVC with static library instead you use pre-build binary on our site, you can build it yourself. 115 | 116 | https://github.com/xianyi/OpenBLAS/wiki/How-to-use-OpenBLAS-in-Microsoft-Visual-Studio 117 | > 1. Native (MSVC) ABI 118 | > Install Miniconda3 for 64 bits. And then follow the procedure described on the above page. 119 | 120 | You want to build a DLL of OpenBLAS, you can run cmake with shared libray option -DBUILD_SHARED_LIBS=ON 121 | 122 | ```shell 123 | Anaconda3>vcvars64 -vcvars_ver=14.16 124 | 125 | ...... omission 126 | 127 | Anaconda3>cmake .. -G "Ninja" -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER=clang-cl -DCMAKE_Fortran_COMPILER=flang -DBUILD_WITHOUT_LAPACK=no -DNOFORTRAN=0 -DDYNAMIC_ARCH=ON -DCMAKE_BUILD_TYPE=Release 128 | Anaconda3>cmake --build . --config Release 129 | ``` 130 | 131 | Build the extension for Windows 132 | ------------------------------- 133 | 134 | Please refer to the following URL for details. 135 | 136 | https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2 137 | 138 | ### php sdk and devel-pack binaries for windows 139 | 140 | - You must know that PHP 7.x needs environment for the MSVC version vc15 (that means Visual Studio 2017). php-sdk releases 2.1.9 supports vc15. 141 | - For PHP 7.x, Download the php-sdk from https://github.com/microsoft/php-sdk-binary-tools/releases/tag/php-sdk-2.1.9 142 | - If you want to build extensions for PHP 8.x, You have to use php-sdk release 2.2.0. It supports vs16. 143 | - For PHP 8.x, Download the php-sdk from https://github.com/microsoft/php-sdk-binary-tools/releases/tag/php-sdk-2.2.0 144 | - Extract to c:\php-sdk 145 | - Download target Development package from https://windows.php.net/download 146 | - Extract to /path/to/php-devel-pack-x.x.x-Win32-Vxxx-x64/ 147 | 148 | ### start php-sdk for target PHP version 149 | 150 | Open Visual Studio Command Prompt for VS for the target PHP version(see stepbystepbuild.) 151 | Note that you must explicitly specify the version of vc15 for which php.exe was built. 152 | The -vcvars_ver=14.16 means vc15. 153 | 154 | If you want to build for PHP 8.x, No options required. 155 | 156 | ```shell 157 | C:\visual\studio\path>vcvars64 -vcvars_ver=14.16 158 | or 159 | C:\visual\studio\path>vcvars64 160 | 161 | C:\tmp>cd c:\php-sdk-x.x.x 162 | 163 | C:\php-sdk-2.1.9>phpsdk-vc15-x64.bat 164 | or 165 | C:\php-sdk-2.2.0>phpsdk-vs16-x64.bat 166 | 167 | ``` 168 | 169 | ### Build 170 | 171 | ```shell 172 | $ cd /path/to/Rindow-Matlib-project-directory 173 | $ cmake -S . -B build 174 | $ PATH %PATH%;/path/to/OpenBLAS/bin 175 | $ cd /path/to/here 176 | $ composer update 177 | $ /path/to/php-devel-pack-x.x.x-Win32-VXXX-x64/phpize.bat 178 | $ configure --enable-rindow_openblas --with-prefix=/path/to/php-installation-path --with-openblas=/path/to/OpenBLAS-libray-built-directory --with-matlib=/path/to/Rindow-Matlib-project-directory 179 | ``` 180 | Edit "#define PHP_BUILD_SYSTEM" line in the "/php-devel-pack-xxx/include/main/config.w32.h" 181 | Change the PHP_BUILD_SYSTEM definition to the same value as in "/php-devel-pack-xxx/include/main/config.pickle.h". If the values are not the same, a warning error will occur during build. 182 | 183 | And then Build. 184 | 185 | ```shell 186 | $ nmake clean 187 | $ nmake 188 | $ nmake test 189 | ``` 190 | 191 | ### Install from built directory 192 | 193 | - Copy the php extension binary(.dll) to the php/ext directory from here/arch/Releases_TS/php_rindow_openblas.dll 194 | - Add the "extension=php_rindow_openblas" entry to php.ini 195 | -------------------------------------------------------------------------------- /rindow_openblas.c: -------------------------------------------------------------------------------- 1 | /* rindow_openblas extension for PHP */ 2 | 3 | #ifdef HAVE_CONFIG_H 4 | # include "config.h" 5 | #endif 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "ext/standard/info.h" 13 | #include 14 | #include "php_rindow_openblas.h" 15 | 16 | #if _MSC_VER 17 | extern int rindow_load_openblas_dll(); 18 | extern void rindow_unload_openblas_dll(); 19 | #endif 20 | 21 | /* For compatibility with older PHP versions */ 22 | #ifndef ZEND_PARSE_PARAMETERS_NONE 23 | #define ZEND_PARSE_PARAMETERS_NONE() \ 24 | ZEND_PARSE_PARAMETERS_START(0, 0) \ 25 | ZEND_PARSE_PARAMETERS_END() 26 | #endif 27 | 28 | int php_rindow_openblas_common_dtype_to_valuesize(zend_long dtype) 29 | { 30 | switch (dtype) { 31 | case php_interop_polite_math_matrix_dtype_bool: 32 | case php_interop_polite_math_matrix_dtype_int8: 33 | case php_interop_polite_math_matrix_dtype_uint8: 34 | case php_interop_polite_math_matrix_dtype_float8: 35 | return 1; 36 | case php_interop_polite_math_matrix_dtype_int16: 37 | case php_interop_polite_math_matrix_dtype_uint16: 38 | case php_interop_polite_math_matrix_dtype_float16: 39 | return 2; 40 | case php_interop_polite_math_matrix_dtype_int32: 41 | case php_interop_polite_math_matrix_dtype_uint32: 42 | case php_interop_polite_math_matrix_dtype_float32: 43 | return 4; 44 | case php_interop_polite_math_matrix_dtype_int64: 45 | case php_interop_polite_math_matrix_dtype_uint64: 46 | case php_interop_polite_math_matrix_dtype_float64: 47 | return 8; 48 | } 49 | return 0; 50 | } 51 | 52 | 53 | int php_rindow_openblas_common_dtype_is_int(zend_long dtype) 54 | { 55 | switch (dtype) { 56 | case php_interop_polite_math_matrix_dtype_int8: 57 | case php_interop_polite_math_matrix_dtype_uint8: 58 | case php_interop_polite_math_matrix_dtype_int16: 59 | case php_interop_polite_math_matrix_dtype_uint16: 60 | case php_interop_polite_math_matrix_dtype_int32: 61 | case php_interop_polite_math_matrix_dtype_uint32: 62 | case php_interop_polite_math_matrix_dtype_int64: 63 | case php_interop_polite_math_matrix_dtype_uint64: 64 | return 1; 65 | } 66 | return 0; 67 | } 68 | 69 | int php_rindow_openblas_common_dtype_is_float(zend_long dtype) 70 | { 71 | switch (dtype) { 72 | case php_interop_polite_math_matrix_dtype_float8: 73 | case php_interop_polite_math_matrix_dtype_float16: 74 | case php_interop_polite_math_matrix_dtype_float32: 75 | case php_interop_polite_math_matrix_dtype_float64: 76 | return 1; 77 | } 78 | return 0; 79 | } 80 | 81 | int php_rindow_openblas_common_dtype_is_bool(zend_long dtype) 82 | { 83 | switch (dtype) { 84 | case php_interop_polite_math_matrix_dtype_bool: 85 | return 1; 86 | } 87 | return 0; 88 | } 89 | 90 | int php_rindow_openblas_assert_shape_parameter( 91 | char* name, zend_long n) 92 | { 93 | if(n<1) { 94 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Argument %s must be greater than 0.",name); 95 | return -1; 96 | } 97 | return 0; 98 | } 99 | 100 | int php_rindow_openblas_assert_vector_buffer_spec( 101 | char* name,php_interop_polite_math_matrix_linear_buffer_t *buffer, 102 | zend_long n, zend_long offset, zend_long inc) 103 | { 104 | if(buffer->data==NULL) { 105 | zend_throw_exception_ex(spl_ce_DomainException, 0, "buffer%s is not initialized",name); 106 | return -1; 107 | } 108 | if(offset<0) { 109 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Argument offset%s must be greater than or equals 0.",name); 110 | return -1; 111 | } 112 | if(inc<1) { 113 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Argument inc%s must be greater than 0.",name); 114 | return -1; 115 | } 116 | if(offset+(n-1)*inc >= buffer->size) { 117 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Vector specification too large for buffer%s.",name); 118 | return -1; 119 | } 120 | 121 | return 0; 122 | } 123 | 124 | int php_rindow_openblas_assert_matrix_buffer_spec( 125 | char* name, php_interop_polite_math_matrix_linear_buffer_t *buffer, 126 | zend_long m,zend_long n, zend_long offset, zend_long ld) 127 | { 128 | if(buffer->data==NULL) { 129 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "uninitialized array: %s",name); 130 | return -1; 131 | } 132 | if(offset<0) { 133 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Argument offset%s must be greater than or equals 0.",name); 134 | return -1; 135 | } 136 | if(ld<1) { 137 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Argument ld%s must be greater than 0.",name); 138 | return -1; 139 | } 140 | if(offset+(m-1)*ld+(n-1) >= buffer->size) { 141 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Matrix specification too large for buffer%s.",name); 142 | return -1; 143 | } 144 | 145 | return 0; 146 | } 147 | 148 | int php_rindow_openblas_assert_buffer_size( 149 | php_interop_polite_math_matrix_linear_buffer_t *buffer, 150 | zend_long offset,zend_long size, 151 | char* message) 152 | { 153 | if(size<1 || offset<0 || 154 | buffer->size < offset+size) { 155 | zend_throw_exception(spl_ce_InvalidArgumentException, message, 0); 156 | return -1; 157 | } 158 | return 0; 159 | } 160 | 161 | int php_rindow_openblas_assert_buffer_type( 162 | php_interop_polite_math_matrix_linear_buffer_t *buffer, 163 | char* name) 164 | { 165 | if(!php_interop_polite_math_matrix_is_linear_buffer(buffer)) { 166 | zend_throw_exception_ex(zend_ce_type_error, 0, "%s must implement interface %s", 167 | name,PHP_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_CLASSNAME); 168 | return 1; 169 | } 170 | return 0; 171 | } 172 | 173 | /* {{{ PHP_RINIT_FUNCTION 174 | */ 175 | PHP_RINIT_FUNCTION(rindow_openblas) 176 | { 177 | #if defined(ZTS) && defined(COMPILE_DL_RINDOW_OPENBLAS) 178 | ZEND_TSRMLS_CACHE_UPDATE(); 179 | #endif 180 | 181 | return SUCCESS; 182 | } 183 | /* }}} */ 184 | 185 | /* {{{ PHP_MINFO_FUNCTION 186 | */ 187 | PHP_MINFO_FUNCTION(rindow_openblas) 188 | { 189 | php_info_print_table_start(); 190 | php_info_print_table_header(2, "rindow_openblas support", "enabled"); 191 | php_info_print_table_end(); 192 | } 193 | /* }}} */ 194 | 195 | /* {{{ rindow_openblas_functions[] 196 | */ 197 | //static const zend_function_entry rindow_openblas_functions[] = { 198 | //}; 199 | /* }}} */ 200 | 201 | PHP_MINIT_FUNCTION(rindow_openblas) 202 | { 203 | #if _MSC_VER 204 | int rc=rindow_load_openblas_dll(); 205 | if(rc!=0) { 206 | rindow_unload_openblas_dll(); 207 | return FAILURE; 208 | } 209 | #endif 210 | php_rindow_openblas_buffer_init_ce(INIT_FUNC_ARGS_PASSTHRU); 211 | php_rindow_openblas_blas_init_ce(INIT_FUNC_ARGS_PASSTHRU); 212 | php_rindow_openblas_lapack_init_ce(INIT_FUNC_ARGS_PASSTHRU); 213 | php_rindow_openblas_math_init_ce(INIT_FUNC_ARGS_PASSTHRU); 214 | return SUCCESS; 215 | } 216 | 217 | PHP_MSHUTDOWN_FUNCTION(rindow_openblas) 218 | { 219 | #if _MSC_VER 220 | rindow_unload_openblas_dll(); 221 | #endif 222 | return SUCCESS; 223 | } 224 | 225 | /* {{{ php_rindow_openblas_module_entry 226 | */ 227 | zend_module_entry rindow_openblas_module_entry = { 228 | STANDARD_MODULE_HEADER, 229 | "rindow_openblas", /* Extension name */ 230 | NULL, /* zend_function_entry */ 231 | PHP_MINIT(rindow_openblas), /* PHP_MINIT - Module initialization */ 232 | PHP_MSHUTDOWN(rindow_openblas), /* PHP_MSHUTDOWN - Module shutdown */ 233 | PHP_RINIT(rindow_openblas), /* PHP_RINIT - Request initialization */ 234 | NULL, /* PHP_RSHUTDOWN - Request shutdown */ 235 | PHP_MINFO(rindow_openblas), /* PHP_MINFO - Module info */ 236 | PHP_RINDOW_OPENBLAS_VERSION, /* Version */ 237 | STANDARD_MODULE_PROPERTIES 238 | }; 239 | /* }}} */ 240 | 241 | #ifdef COMPILE_DL_RINDOW_OPENBLAS 242 | # ifdef ZTS 243 | ZEND_TSRMLS_CACHE_DEFINE() 244 | # endif 245 | ZEND_GET_MODULE(rindow_openblas) 246 | #endif 247 | -------------------------------------------------------------------------------- /phpunit/AbstractNDArrayPhp.php: -------------------------------------------------------------------------------- 1 | array2Flat($array,$dummyBuffer,$idx,$prepare=true); 31 | $buffer = $this->newBuffer($idx,$dtype); 32 | $idx = 0; 33 | $this->array2Flat($array,$buffer,$idx,$prepare=false); 34 | if($shape===null) { 35 | $shape = $this->genShape($array); 36 | } 37 | } elseif(is_numeric($array)||is_bool($array)) { 38 | if(is_bool($array)&&$dtype!=NDArray::bool) { 39 | throw new InvalidArgumentException("unmatch dtype with bool value"); 40 | } 41 | $buffer = $this->newBuffer(1,$dtype); 42 | $buffer[0] = $array; 43 | if($shape===null) { 44 | $shape = []; 45 | } 46 | $this->checkShape($shape); 47 | if(array_product($shape)!=1) 48 | throw new InvalidArgumentException("Invalid dimension size"); 49 | } elseif($array===null && $shape!==null) { 50 | $this->checkShape($shape); 51 | $size = (int)array_product($shape); 52 | $buffer = $this->newBuffer($size,$dtype); 53 | } elseif($array===null && $shape!==null) { 54 | $this->checkShape($shape); 55 | $size = (int)array_product($shape); 56 | $buffer = $this->newBuffer($size,$dtype); 57 | } elseif($this->isBuffer($array)) { 58 | if($offset===null||!is_int($offset)) 59 | throw new InvalidArgumentException("Must specify offset with the buffer"); 60 | if($shape===null) 61 | throw new InvalidArgumentException("Invalid dimension size"); 62 | $buffer = $array; 63 | } else { 64 | var_dump($array);var_dump($shape); 65 | throw new \Exception("Illegal array type"); 66 | } 67 | $this->buffer = $buffer; 68 | $this->size = $buffer->count(); 69 | $this->dtype = $buffer->dtype(); 70 | $this->shape = $shape; 71 | $this->offset = $offset; 72 | } 73 | 74 | function newBuffer($size,$dtype) 75 | { 76 | return new HostBuffer($size,$dtype); 77 | } 78 | 79 | protected function isBuffer($buffer) 80 | { 81 | if($buffer instanceof SplFixedArray || $buffer instanceof Buffer) { 82 | return true; 83 | } else { 84 | return false; 85 | } 86 | } 87 | 88 | protected function array2Flat($A, $F, &$idx, $prepare) 89 | { 90 | if(is_array($A)) { 91 | ksort($A); 92 | } elseif($A instanceof ArrayObject) { 93 | $A->ksort(); 94 | } 95 | 96 | $num = null; 97 | foreach ($A as $key => $value) { 98 | if(!is_int($key)) 99 | throw new InvalidArgumentException("Dimension must be integer"); 100 | if(is_array($value)||$value instanceof ArrayObject) { 101 | $num2 = $this->array2Flat($value, $F, $idx, $prepare); 102 | if($num===null) { 103 | $num = $num2; 104 | } else { 105 | if($num!=$num2) 106 | throw new InvalidArgumentException("The shape of the dimension is broken"); 107 | } 108 | } else { 109 | if($num!==null) 110 | throw new InvalidArgumentException("The shape of the dimension is broken"); 111 | if(!$prepare) 112 | $F[$idx] = $value; 113 | $idx++; 114 | } 115 | } 116 | return count($A); 117 | } 118 | 119 | protected function flat2Array($F, &$idx, array $shape) 120 | { 121 | $size = array_shift($shape); 122 | if(count($shape)) { 123 | $A = []; 124 | for($i=0; $i<$size; $i++) { 125 | $A[$i] = $this->flat2Array($F,$idx,$shape); 126 | } 127 | } else { 128 | $A = []; 129 | for($i=0; $i<$size; $i++) { 130 | $A[$i] = $F[$idx]; 131 | $idx++; 132 | } 133 | } 134 | return $A; 135 | } 136 | 137 | protected function genShape($A) 138 | { 139 | $shape = []; 140 | while(is_array($A) || $A instanceof ArrayObject) { 141 | $shape[] = count($A); 142 | $A = $A[0]; 143 | } 144 | return $shape; 145 | } 146 | 147 | protected function checkShape(array $shape) 148 | { 149 | foreach($shape as $num) { 150 | if(!is_int($num)) { 151 | throw new InvalidArgumentException( 152 | "Invalid shape numbers. It gives ".gettype($num)); 153 | } 154 | if($num<=0) { 155 | throw new InvalidArgumentException( 156 | "Invalid shape numbers. It gives ".$num); 157 | } 158 | } 159 | } 160 | 161 | public function toArray() 162 | { 163 | if(count($this->shape)==0) { 164 | return $this->buffer[$this->offset]; 165 | } 166 | $idx = $this->offset; 167 | return $this->flat2Array($this->buffer, $idx, $this->shape); 168 | } 169 | 170 | public function shape() : array { return $this->shape; } 171 | 172 | public function ndim() : int { return count($this->shape); } 173 | 174 | public function dtype() { return $this->dtype; } 175 | 176 | public function buffer() : ArrayAccess { return $this->buffer; } 177 | 178 | public function offset() : int { return $this->offset; } 179 | 180 | public function size() : int { return $this->buffer->count(); } 181 | 182 | public function reshape(array $shape) : NDArray 183 | { 184 | if(array_product($shape)==array_product($this->shape)) { 185 | $this->shape = $shape; 186 | } else { 187 | throw new \Exception("unmatch shape"); 188 | } 189 | return $this; 190 | } 191 | public function offsetExists( $offset ) : bool { throw new \Excpetion('not implement'); } 192 | protected function doOffsetGet( $offset ) 193 | { 194 | if(is_array($offset)) { 195 | throw new InvalidArgumentException("offset style is old renge style."); 196 | } 197 | // for single index specification 198 | if(is_numeric($offset)) { 199 | $shape = $this->shape; 200 | $max = array_shift($shape); 201 | if(count($shape)==0) { 202 | return $this->buffer[$this->offset+$offset]; 203 | } 204 | $size = (int)array_product($shape); 205 | $new = new static($this->buffer,$this->dtype,$shape,$this->offset+$offset*$size); 206 | return $new; 207 | } 208 | 209 | // for range spesification 210 | $shape = $this->shape; 211 | array_shift($shape); 212 | if(is_array($offset)) { 213 | $start = $offset[0]; 214 | $limit = $offset[1]+1; 215 | } else { 216 | $start = $offset->start(); 217 | $limit = $offset->limit(); 218 | } 219 | $rowsCount = $limit-$start; 220 | if(count($shape)>0) { 221 | $itemSize = (int)array_product($shape); 222 | } else { 223 | $itemSize = 1; 224 | } 225 | if($rowsCount<0) { 226 | throw new OutOfRangeException('Invalid range'); 227 | } 228 | array_unshift($shape,$rowsCount); 229 | $size = (int)array_product($shape); 230 | $new = new static($this->buffer,$this->dtype,$shape,$this->offset+$start*$itemSize); 231 | return $new; 232 | } 233 | public function offsetSet( $offset , $value ) : void { throw new \Exception('not implement'); } 234 | public function offsetUnset( $offset ) : void { throw new \Exception('not implement'); } 235 | public function count() : int 236 | { 237 | return $this->buffer->count(); 238 | } 239 | public function getIterator() : Traversable { throw new \Exception('not implement'); } 240 | } 241 | -------------------------------------------------------------------------------- /phpunit/Utils.php: -------------------------------------------------------------------------------- 1 | limit = $limit; 40 | $this->start = $start ?? 0; 41 | $this->delta = $delta ?? (($limit>=$start)? 1 : -1); 42 | } 43 | 44 | public function start() 45 | { 46 | return $this->start; 47 | } 48 | 49 | public function limit() 50 | { 51 | return $this->limit; 52 | } 53 | 54 | public function delta() 55 | { 56 | return $this->delta; 57 | } 58 | } 59 | 60 | trait Utils 61 | { 62 | public function alloc(array $shape,int $dtype=null) 63 | { 64 | $ndarray = $this->array(null,$dtype,$shape); 65 | return $ndarray; 66 | } 67 | 68 | public function zeros(array $shape,int $dtype=null) 69 | { 70 | $ndarray = $this->array(null,$dtype,$shape); 71 | $buffer = $ndarray->buffer(); 72 | $size = $buffer->count(); 73 | for($i=0;$i<$size;$i++) { 74 | $buffer[$i] = 0; 75 | } 76 | return $ndarray; 77 | } 78 | 79 | public function ones(array $shape,int $dtype=null) 80 | { 81 | $ndarray = $this->array(null,$dtype,$shape); 82 | $buffer = $ndarray->buffer(); 83 | $size = $buffer->count(); 84 | for($i=0;$i<$size;$i++) { 85 | $buffer[$i] = 1; 86 | } 87 | return $ndarray; 88 | } 89 | 90 | public function zerosLike(object $ndarray) 91 | { 92 | return $this->zeros($ndarray->shape(),$ndarray->dtype()); 93 | } 94 | 95 | public function arange(int $count ,$start=null, $step=null, $dtype=null) 96 | { 97 | if($start===null) 98 | $start = 0; 99 | if($step===null) 100 | $step = 1; 101 | if($dtype===null) { 102 | if(is_int($start)) 103 | $dtype = NDArray::int32; 104 | else 105 | $dtype = NDArray::float32; 106 | } 107 | $array = $this->zeros([$count], $dtype); 108 | $buffer = $array->buffer(); 109 | $n = $start; 110 | for($i=0; $i<$count; $i++) { 111 | $buffer[$i] = $n; 112 | $n += $step; 113 | } 114 | return $array; 115 | } 116 | 117 | public function array($array=null, int $dtype=null, array $shape=null) : object 118 | { 119 | $ndarray = new NDArrayPhp($array, $dtype, $shape); 120 | return $ndarray; 121 | } 122 | 123 | 124 | public function getMatlibVersion($matlib) 125 | { 126 | $config = $matlib->getConfig(); 127 | if(strpos($config,'Matlib')===0) { 128 | $config = explode(' ',$config); 129 | return $config[1]; 130 | } else { 131 | return '0.0.0'; 132 | } 133 | } 134 | 135 | public function checkSkip($mark) 136 | { 137 | if(!in_array($mark,[ 138 | //'multiply', 139 | //'duplicate' 140 | ])) { 141 | return false; 142 | } 143 | $this->markTestSkipped($mark); 144 | return true; 145 | } 146 | 147 | 148 | public function sum($n,$X,$offsetX,$incX) 149 | { 150 | $a = 0; 151 | for($i=0;$i<$n;$i++) { 152 | $a += $X[$offsetX+$i*$incX]; 153 | } 154 | return $a; 155 | } 156 | 157 | protected function printableShapes($values) 158 | { 159 | if(!is_array($values)) { 160 | if($values instanceof NDArray) 161 | return '('.implode(',',$values->shape()).')'; 162 | if(is_object($values)) 163 | return '"'.get_class($values).'"'; 164 | if(is_numeric($values) || is_string($values)) 165 | return strval($values); 166 | return gettype($values); 167 | } 168 | $string = '['; 169 | foreach($values as $value) { 170 | if($string!='[') { 171 | $string .= ','; 172 | } 173 | $string .= $this->printableShapes($value); 174 | } 175 | $string .= ']'; 176 | return $string; 177 | } 178 | 179 | protected function copy(NDArray $x,NDArray $y=null) : NDArray 180 | { 181 | $blas = $this->getBlas(); 182 | 183 | if($y==null) { 184 | $y = $this->zeros($x->shape(),$x->dtype()); 185 | } 186 | $N = $x->size(); 187 | $XX = $x->buffer(); 188 | $offX = $x->offset(); 189 | $YY = $y->buffer(); 190 | $offY = $y->offset(); 191 | $blas->copy($N,$XX,$offX,1,$YY,$offY,1); 192 | return $y; 193 | } 194 | 195 | protected function axpy(NDArray $x,NDArray $y=null,$alpha=null) : NDArray 196 | { 197 | $blas = $this->getBlas(); 198 | 199 | if($y==null) { 200 | $y = $this->zeros($x->shape(),$x->dtype()); 201 | } 202 | if($alpha===null) { 203 | $alpha = 1.0; 204 | } 205 | $N = $x->size(); 206 | $XX = $x->buffer(); 207 | $offX = $x->offset(); 208 | $YY = $y->buffer(); 209 | $offY = $y->offset(); 210 | 211 | $blas->axpy($N,$alpha,$XX,$offX,1,$YY,$offY,1); 212 | return $y; 213 | } 214 | 215 | protected function iamax(NDArray $x) : int 216 | { 217 | $blas = $this->getBlas(); 218 | 219 | $N = $x->size(); 220 | $XX = $x->buffer(); 221 | $offX = $x->offset(); 222 | 223 | $y = $blas->iamax($N,$XX,$offX,1); 224 | return $y; 225 | } 226 | 227 | protected function scal(float $a,NDArray $x) : NDArray 228 | { 229 | $blas = $this->getBlas(); 230 | 231 | $N = $x->size(); 232 | $XX = $x->buffer(); 233 | $offX = $x->offset(); 234 | 235 | $blas->scal($N,$a,$XX,$offX,1); 236 | return $x; 237 | } 238 | 239 | protected function isComplex($dtype) : bool 240 | { 241 | return $dtype==NDArray::complex64||$dtype==NDArray::complex128; 242 | } 243 | 244 | protected function buildValByType($value, int $dtype) 245 | { 246 | if($this->isComplex($dtype)) { 247 | throw new InvalidArgumentException('complex value is not supported.'); 248 | } 249 | return $value; 250 | } 251 | 252 | protected function transToCode(bool $trans,bool $conj) : int 253 | { 254 | if($trans) { 255 | return $conj ? BLAS::ConjTrans : BLAS::Trans; 256 | } else { 257 | return $conj ? BLAS::ConjNoTrans : BLAS::NoTrans; 258 | } 259 | } 260 | 261 | protected function complementTrans(?bool $trans,?bool $conj,int $dtype) : array 262 | { 263 | $trans = $trans ?? false; 264 | if($this->isComplex($dtype)) { 265 | $conj = $conj ?? $trans; 266 | } else { 267 | $conj = $conj ?? false; 268 | } 269 | return [$trans,$conj]; 270 | } 271 | 272 | protected function abs($value) : float 273 | { 274 | if(is_numeric($value)) { 275 | return abs($value); 276 | } 277 | throw new InvalidArgumentException('complex value is not supported.'); 278 | //$abs = sqrt(($value->real)**2+($value->imag)**2); 279 | //return $abs; 280 | } 281 | 282 | protected function isclose(NDArray $a, NDArray $b, $rtol=null, $atol=null) : bool 283 | { 284 | $blas = $this->getBlas(); 285 | 286 | $isCpx = $this->isComplex($a->dtype()); 287 | if($rtol===null) { 288 | //$rtol = $isCpx?C(1e-04):1e-04; 289 | $rtol = 1e-04; 290 | } 291 | if($atol===null) { 292 | $atol = 1e-07; 293 | } 294 | if($a->shape()!=$b->shape()) { 295 | return false; 296 | } 297 | // diff = b - a 298 | //$alpha = $isCpx?C(-1):-1; 299 | $alpha = -1; 300 | $diffs = $this->copy($b); 301 | $this->axpy($a,$diffs,$alpha); 302 | $iDiffMax = $this->iamax($diffs); 303 | $diff = $this->abs($diffs->buffer()[$iDiffMax]); 304 | 305 | // close = atol + rtol * b 306 | $scalB = $this->copy($b); 307 | $this->scal($rtol,$scalB); 308 | $iCloseMax = $this->iamax($scalB); 309 | $close = $atol+$this->abs($scalB->buffer()[$iCloseMax]); 310 | 311 | return $diff < $close; 312 | } 313 | 314 | protected function argExpectException($class) 315 | { 316 | if(version_compare(phpversion(),'8.0.0','<')) { 317 | $this->expectException(TypeError::class); 318 | } else { 319 | $this->expectException($class); 320 | } 321 | } 322 | 323 | protected function argExpectExceptionMessage($message) 324 | { 325 | if(version_compare(phpversion(),'8.0.0','<')) { 326 | $this->expectExceptionMessage('Argument '); 327 | } else { 328 | $this->expectExceptionMessage($message); 329 | } 330 | } 331 | } -------------------------------------------------------------------------------- /client_generator.php: -------------------------------------------------------------------------------- 1 | preg_types = implode('|',array_map(fn($x) => str_replace('*','\\*',$x),$this->funcDecrWord)); 34 | } 35 | 36 | public function generator($argv) 37 | { 38 | $dummy = array_shift($argv); 39 | $outputfile = array_shift($argv); 40 | $fpi = null; 41 | $fpo = null; 42 | $funcs = []; 43 | try { 44 | $fpo = fopen($outputfile,'w'); 45 | if($fpo==null) { 46 | throw new RuntimeException("Error opening input file: $outputfile"); 47 | } 48 | $code = $this->beginTemplate(); 49 | if(!fwrite($fpo,$code)) { 50 | throw new RuntimeException("fwrite error"); 51 | } 52 | while($inputfile=array_shift($argv)) { 53 | $fpi = fopen($inputfile,'r'); 54 | if($fpi==null) { 55 | throw new RuntimeException("Error opening input file: $inputfile"); 56 | } 57 | $funcs = array_merge($funcs,$this->generate($fpo,$fpi)); 58 | } 59 | $code = $this->endTemplate($funcs); 60 | if(!fwrite($fpo,$code)) { 61 | throw new RuntimeException("fwrite error"); 62 | } 63 | } finally { 64 | if($fpi) { 65 | fclose($fpi); 66 | } 67 | if($fpo) { 68 | fclose($fpo); 69 | } 70 | } 71 | } 72 | 73 | public function generate($fpo,$fpi) : array 74 | { 75 | $excludeFuncs = $this->excludeFuncs; 76 | $eof = false; 77 | $funcs = []; 78 | while(!$eof) { 79 | $line=''; 80 | while(true) { 81 | $next=fgets($fpi); 82 | if(!$next) { 83 | $eof = true; 84 | break; 85 | } 86 | $next = trim($next); 87 | if(substr($next,0,1)=='#') { 88 | break; 89 | } 90 | if(substr($next,0,2)=='/*') { 91 | break; 92 | } 93 | if(substr($next,0,2)=='//') { 94 | break; 95 | } 96 | $line .= trim($next); 97 | if(substr($next,-1,1)==';') { 98 | break; 99 | } 100 | } 101 | $declare = $this->parser($line); 102 | //var_dump($line); 103 | //var_dump($declare); 104 | //echo "PAUSE>"; 105 | //fgets(STDIN); 106 | if($declare==null) { 107 | continue; 108 | } 109 | if(in_array($declare['func'],$excludeFuncs)) { 110 | continue; 111 | } 112 | $code = $this->funcTemplate($declare); 113 | if(!fwrite($fpo,$code)) { 114 | throw new RuntimeException("fwrite error"); 115 | } 116 | $funcs[] = $declare; 117 | } 118 | return $funcs; 119 | } 120 | 121 | public function parser(string $line) : ?array 122 | { 123 | $funcDecrWord = $this->funcDecrWord; 124 | $tmp = explode(' ',$line); 125 | $head = $tmp[0]; 126 | if(!in_array($head,$funcDecrWord)) { 127 | return null; 128 | } 129 | $pattern = "/^(".$this->preg_types.") *([A-Za-z0-9_]+) *\\(([^)]+)/"; 130 | //var_dump($pattern); 131 | preg_match($pattern,$line,$match); 132 | if(array_key_exists(1,$match)) { 133 | $return = $match[1]; 134 | } else { 135 | var_dump("unmatch return $line"); 136 | $return = "unknown"; 137 | } 138 | if(array_key_exists(2,$match)) { 139 | $func = $match[2]; 140 | } else { 141 | var_dump("unmatch func $line"); 142 | $func = "unknown"; 143 | } 144 | if(array_key_exists(3,$match)) { 145 | $args = $match[3]; 146 | } else { 147 | var_dump("unmatch args $line"); 148 | $args = ["unknown","unknown"]; 149 | } 150 | $args = explode(',',$args); 151 | $strargs = array_map('trim',$args); 152 | $args = []; 153 | foreach($strargs as $arg) { 154 | $var = null; 155 | $arg = str_replace('*',' *',$arg); 156 | $types2 = explode(' ',$arg); 157 | $types = []; 158 | foreach($types2 as $t) { 159 | if($t) { 160 | $types[] = $t; 161 | } 162 | } 163 | $types = array_map('trim',$types); 164 | if(count($types)>1) { 165 | $var = array_pop($types); 166 | $var = trim($var); 167 | if(substr($var,0,1)=='*') { 168 | $var = substr($var,1); 169 | array_push($types,'*'); 170 | } 171 | } 172 | $type = implode(' ',$types); 173 | $args[] = ['type'=>$type,'var'=>$var]; 174 | } 175 | //var_dump("$return $func"); 176 | //echo "args:"; 177 | //var_dump($args); 178 | //if($func=='cblas_xerbla') { 179 | // var_dump(['return' => $return, 'func'=>$func, 'args'=>$args]); 180 | //} 181 | 182 | return ['return' => $return, 'func'=>$func, 'args'=>$args]; 183 | } 184 | public function funcTemplate($declare) 185 | { 186 | $return = $declare['return']; 187 | $funcname = $declare['func']; 188 | // typedef 189 | $code = "typedef {$return} (CALLBACK* PFN{$funcname})( /* {$funcname} */"; 190 | $isNext = false; 191 | foreach($declare['args'] as $arg) { 192 | $type = $arg['type']; 193 | $var = $arg['var']; 194 | if($isNext) { 195 | $code .= ","; 196 | } 197 | $code .= "\n"; 198 | $code .= " {$type} /* {$var} */"; 199 | $isNext = true; 200 | } 201 | $code .= "\n"; 202 | $code .= ");\n"; 203 | 204 | // static function pointer 205 | $code .= "static PFN{$funcname} _g_{$funcname} = NULL;\n"; 206 | 207 | // proxy function 208 | $code .= "{$return} {$funcname}("; 209 | $isNext = false; 210 | foreach($declare['args'] as $arg) { 211 | $type = $arg['type']; 212 | $var = $arg['var']; 213 | if($isNext) { 214 | $code .= ","; 215 | } 216 | $code .= "\n"; 217 | $code .= " {$type} {$var}"; 218 | $isNext = true; 219 | } 220 | $code .= "\n"; 221 | $code .= ")\n"; 222 | $code .= "{\n"; 223 | $code .= " if(_h_openblas==NULL || _g_{$funcname}==NULL) {\n"; 224 | if($return=='void') { 225 | $code .= " return;\n"; 226 | } else { 227 | $code .= " return 0;\n"; 228 | } 229 | $code .= " }\n"; 230 | if($return=='void') { 231 | $code .= " _g_{$funcname}("; 232 | } else { 233 | $code .= " return _g_{$funcname}("; 234 | } 235 | $isNext = false; 236 | foreach($declare['args'] as $arg) { 237 | $type = $arg['type']; 238 | $var = $arg['var']; 239 | if($isNext) { 240 | $code .= ","; 241 | } 242 | $code .= "\n"; 243 | if($var) { 244 | $code .= " {$var}"; 245 | } 246 | $isNext = true; 247 | } 248 | $code .= " \n"; 249 | $code .= " );\n"; 250 | $code .= "}\n"; 251 | return $code; 252 | } 253 | 254 | function beginTemplate() 255 | { 256 | $code = "#include \n"; 257 | $code .= "#include \n"; 258 | $code .= "#include \n"; 259 | $code .= "\n"; 260 | $code .= "#define LOADFUNC(funcname) \\\n"; 261 | $code .= "_g_##funcname = (PFN##funcname)GetProcAddress( _h_openblas, #funcname ); \\\n"; 262 | $code .= "if(_g_##funcname==NULL) { \\\n"; 263 | $code .= " printf(\"load error: %s\\n\", #funcname); \\\n"; 264 | $code .= " return -1; \\\n"; 265 | $code .= "} \\\n"; 266 | $code .= "\n"; 267 | $code .= "static HMODULE _h_openblas = NULL;\n"; 268 | return $code; 269 | } 270 | 271 | public function endTemplate($funcs) 272 | { 273 | $code = "int rindow_load_openblas_dll()\n"; 274 | $code .= "{\n"; 275 | $code .= " if(_h_openblas!=NULL) {\n"; 276 | $code .= " return 0;\n"; 277 | $code .= " }\n"; 278 | $code .= " _h_openblas = LoadLibraryA( \"libopenblas.dll\" );\n"; 279 | $code .= " if(_h_openblas==NULL) {\n"; 280 | $code .= " printf(\"load error: libopenblas\\n\");\n"; 281 | $code .= " return -1;\n"; 282 | $code .= " }\n"; 283 | foreach($funcs as $declare) { 284 | $funcname = $declare['func']; 285 | $code .= " LOADFUNC({$funcname})\n"; 286 | } 287 | $code .= " return 0;\n"; 288 | $code .= "}\n"; 289 | $code .= "void rindow_unload_openblas_dll()\n"; 290 | $code .= "{\n"; 291 | $code .= " FreeLibrary( _h_openblas );\n"; 292 | $code .= " _h_openblas = NULL;\n"; 293 | $code .= "}\n"; 294 | return $code; 295 | } 296 | } 297 | 298 | $generator = new OpenBLASClientGenerator(); 299 | $generator->generator($argv); 300 | -------------------------------------------------------------------------------- /src/Rindow/OpenBLAS/Math_reduction.c: -------------------------------------------------------------------------------- 1 | /* 2 | X(m) := sum( A(m,n) ) 3 | 4 | Method Rindow\OpenBLAS\Math:: 5 | public function reduceSum( 6 | int $m, 7 | int $n, 8 | int $k, 9 | Buffer $A, int $offsetA, 10 | Buffer $B, int $offsetB ) : void 11 | {{{ */ 12 | static PHP_METHOD(Math, reduceSum) 13 | { 14 | php_interop_polite_math_matrix_linear_buffer_t* bufferA; 15 | php_interop_polite_math_matrix_linear_buffer_t* bufferB; 16 | zend_long m; 17 | zend_long n; 18 | zend_long k; 19 | zval* a=NULL; 20 | zend_long offsetA; 21 | zval* b=NULL; 22 | zend_long offsetB; 23 | 24 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 7, 7) 25 | Z_PARAM_LONG(m) 26 | Z_PARAM_LONG(n) 27 | Z_PARAM_LONG(k) 28 | Z_PARAM_OBJECT(a) // Interop\Polite\Math\Matrix\LinearBuffer 29 | Z_PARAM_LONG(offsetA) 30 | Z_PARAM_OBJECT(b) // Interop\Polite\Math\Matrix\LinearBuffer 31 | Z_PARAM_LONG(offsetB) 32 | ZEND_PARSE_PARAMETERS_END(); 33 | 34 | if(php_rindow_openblas_assert_shape_parameter( 35 | "m", m)) { 36 | return; 37 | } 38 | if(php_rindow_openblas_assert_shape_parameter( 39 | "n", n)) { 40 | return; 41 | } 42 | if(php_rindow_openblas_assert_shape_parameter( 43 | "k", k)) { 44 | return; 45 | } 46 | // Check Buffer A 47 | bufferA = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(a); 48 | if(php_rindow_openblas_assert_buffer_type(bufferA,"a")) { 49 | return; 50 | } 51 | if(offsetA<0) { 52 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument offsetA must be greater than or equals 0.", 0); 53 | return; 54 | } 55 | if(offsetA+m*n*k>bufferA->size) { 56 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix specification too large for bufferA.", 0); 57 | return; 58 | } 59 | 60 | // Check Buffer B 61 | bufferB = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(b); 62 | if(php_rindow_openblas_assert_buffer_type(bufferB,"b")) { 63 | return; 64 | } 65 | if(offsetB<0) { 66 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument offsetB must be greater than or equals 0.", 0); 67 | return; 68 | } 69 | if(offsetB+m*k>bufferB->size) { 70 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix specification too large for bufferB.", 0); 71 | return; 72 | } 73 | 74 | // Check Buffer A and B 75 | if(bufferA->dtype!=bufferB->dtype) { 76 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch data type for A and B", 0); 77 | return; 78 | } 79 | 80 | switch (bufferA->dtype) { 81 | case php_interop_polite_math_matrix_dtype_float32: { 82 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataA,bufferA,offsetA) 83 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataB,bufferB,offsetB) 84 | rindow_matlib_s_reducesum((index_t)m,(index_t)n,(index_t)k,pDataA,pDataB); 85 | break; 86 | } 87 | case php_interop_polite_math_matrix_dtype_float64: { 88 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataA,bufferA,offsetA) 89 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataB,bufferB,offsetB) 90 | rindow_matlib_d_reducesum((index_t)m,(index_t)n,(index_t)k,pDataA,pDataB); 91 | break; 92 | } 93 | default: { 94 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 95 | return; 96 | } 97 | } 98 | } 99 | /* }}} */ 100 | 101 | /* 102 | X(m) := max( A(m,n) ) 103 | 104 | Method Rindow\OpenBLAS\Math:: 105 | public function reduceMax( 106 | int $m, 107 | int $n, 108 | int $k, 109 | Buffer $A, int $offsetA, 110 | Buffer $B, int $offsetB ) : void 111 | {{{ */ 112 | static PHP_METHOD(Math, reduceMax) 113 | { 114 | php_interop_polite_math_matrix_linear_buffer_t* bufferA; 115 | php_interop_polite_math_matrix_linear_buffer_t* bufferB; 116 | zend_long m; 117 | zend_long n; 118 | zend_long k; 119 | zval* a=NULL; 120 | zend_long offsetA; 121 | zval* b=NULL; 122 | zend_long offsetB; 123 | 124 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 7, 7) 125 | Z_PARAM_LONG(m) 126 | Z_PARAM_LONG(n) 127 | Z_PARAM_LONG(k) 128 | Z_PARAM_OBJECT(a) // Interop\Polite\Math\Matrix\LinearBuffer 129 | Z_PARAM_LONG(offsetA) 130 | Z_PARAM_OBJECT(b) // Interop\Polite\Math\Matrix\LinearBuffer 131 | Z_PARAM_LONG(offsetB) 132 | ZEND_PARSE_PARAMETERS_END(); 133 | 134 | if(php_rindow_openblas_assert_shape_parameter( 135 | "m", m)) { 136 | return; 137 | } 138 | if(php_rindow_openblas_assert_shape_parameter( 139 | "n", n)) { 140 | return; 141 | } 142 | if(php_rindow_openblas_assert_shape_parameter( 143 | "k", k)) { 144 | return; 145 | } 146 | // Check Buffer A 147 | bufferA = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(a); 148 | if(php_rindow_openblas_assert_buffer_type(bufferA,"a")) { 149 | return; 150 | } 151 | if(offsetA<0) { 152 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument offsetA must be greater than or equal 0.", 0); 153 | return; 154 | } 155 | if(offsetA+m*n*k>bufferA->size) { 156 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix specification too large for bufferA.", 0); 157 | return; 158 | } 159 | 160 | // Check Buffer B 161 | bufferB = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(b); 162 | if(php_rindow_openblas_assert_buffer_type(bufferB,"b")) { 163 | return; 164 | } 165 | if(offsetB<0) { 166 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument offsetB must be greater than or equal 0.", 0); 167 | return; 168 | } 169 | if(offsetB+m*k>bufferB->size) { 170 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix specification too large for bufferB.", 0); 171 | return; 172 | } 173 | 174 | // Check Buffer A and B 175 | if(bufferA->dtype!=bufferB->dtype) { 176 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch data type for A and B", 0); 177 | return; 178 | } 179 | 180 | switch (bufferA->dtype) { 181 | case php_interop_polite_math_matrix_dtype_float32: { 182 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataA,bufferA,offsetA) 183 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataB,bufferB,offsetB) 184 | rindow_matlib_s_reducemax((index_t)m,(index_t)n,(index_t)k,pDataA,pDataB); 185 | break; 186 | } 187 | case php_interop_polite_math_matrix_dtype_float64: { 188 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataA,bufferA,offsetA) 189 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataB,bufferB,offsetB) 190 | rindow_matlib_d_reducemax((index_t)m,(index_t)n,(index_t)k,pDataA,pDataB); 191 | break; 192 | } 193 | default: { 194 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 195 | return; 196 | } 197 | } 198 | } 199 | /* }}} */ 200 | 201 | /* 202 | X(m) := argmax( A(m,n) ) 203 | 204 | Method Rindow\OpenBLAS\Math:: 205 | public function reduceArgMax( 206 | int $m, 207 | int $n, 208 | int $k, 209 | Buffer $A, int $offsetA, 210 | Buffer $B, int $offsetB ) : void 211 | {{{ */ 212 | static PHP_METHOD(Math, reduceArgMax) 213 | { 214 | php_interop_polite_math_matrix_linear_buffer_t* bufferA; 215 | php_interop_polite_math_matrix_linear_buffer_t* bufferB; 216 | zend_long m; 217 | zend_long n; 218 | zend_long k; 219 | zval* a=NULL; 220 | zend_long offsetA; 221 | zval* b=NULL; 222 | zend_long offsetB; 223 | 224 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 7, 7) 225 | Z_PARAM_LONG(m) 226 | Z_PARAM_LONG(n) 227 | Z_PARAM_LONG(k) 228 | Z_PARAM_OBJECT(a) // Interop\Polite\Math\Matrix\LinearBuffer 229 | Z_PARAM_LONG(offsetA) 230 | Z_PARAM_OBJECT(b) // Interop\Polite\Math\Matrix\LinearBuffer 231 | Z_PARAM_LONG(offsetB) 232 | ZEND_PARSE_PARAMETERS_END(); 233 | 234 | if(php_rindow_openblas_assert_shape_parameter( 235 | "m", m)) { 236 | return; 237 | } 238 | if(php_rindow_openblas_assert_shape_parameter( 239 | "n", n)) { 240 | return; 241 | } 242 | if(php_rindow_openblas_assert_shape_parameter( 243 | "k", k)) { 244 | return; 245 | } 246 | // Check Buffer A 247 | bufferA = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(a); 248 | if(php_rindow_openblas_assert_buffer_type(bufferA,"a")) { 249 | return; 250 | } 251 | if(offsetA<0) { 252 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument offsetA must be greater than or equal 0.", 0); 253 | return; 254 | } 255 | if(offsetA+m*n*k>bufferA->size) { 256 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix specification too large for bufferA.", 0); 257 | return; 258 | } 259 | 260 | // Check Buffer B 261 | bufferB = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(b); 262 | if(php_rindow_openblas_assert_buffer_type(bufferB,"b")) { 263 | return; 264 | } 265 | if(offsetB<0) { 266 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument offsetB must be greater than or equal 0.", 0); 267 | return; 268 | } 269 | if(offsetB+m*k>bufferB->size) { 270 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix specification too large for bufferB.", 0); 271 | return; 272 | } 273 | 274 | switch (bufferA->dtype) { 275 | case php_interop_polite_math_matrix_dtype_float32: { 276 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataA,bufferA,offsetA) 277 | void *pDataB = rindow_matlib_common_get_address((dtype_t)bufferB->dtype, bufferB->data,(index_t)offsetB); 278 | rindow_matlib_s_reduceargmax((index_t)m,(index_t)n,(index_t)k,pDataA,(dtype_t)bufferB->dtype,pDataB); 279 | break; 280 | } 281 | case php_interop_polite_math_matrix_dtype_float64: { 282 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataA,bufferA,offsetA) 283 | void *pDataB = rindow_matlib_common_get_address((dtype_t)bufferB->dtype, bufferB->data,(index_t)offsetB); 284 | rindow_matlib_d_reduceargmax((index_t)m,(index_t)n,(index_t)k,pDataA,(dtype_t)bufferB->dtype,pDataB); 285 | break; 286 | } 287 | default: { 288 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 289 | return; 290 | } 291 | } 292 | } 293 | /* }}} */ 294 | -------------------------------------------------------------------------------- /src/Rindow/OpenBLAS/Lapack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #if _MSC_VER 7 | #include 8 | #define lapack_complex_float _Fcomplex 9 | #define lapack_complex_double _Dcomplex 10 | #endif 11 | #include 12 | #include 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include "config.h" 16 | #endif 17 | 18 | #include "php_rindow_openblas.h" 19 | 20 | #ifndef MAX 21 | #define MAX(a,b) (((a) > (b)) ? (a) : (b)) 22 | #endif 23 | #ifndef MIN 24 | #define MIN(a,b) (((a) < (b)) ? (a) : (b)) 25 | #endif 26 | 27 | static zend_object_handlers rindow_openblas_lapack_object_handlers; 28 | 29 | // destractor 30 | static void php_rindow_openblas_lapack_free_object(zend_object* object) 31 | { 32 | zend_object_std_dtor(object); 33 | } 34 | 35 | // constructor 36 | static zend_object* php_rindow_openblas_lapack_create_object(zend_class_entry* class_type) /* {{{ */ 37 | { 38 | zend_object* intern = NULL; 39 | 40 | intern = (zend_object*)ecalloc(1, sizeof(zend_object) + zend_object_properties_size(class_type)); 41 | 42 | zend_object_std_init(intern, class_type); 43 | object_properties_init(intern, class_type); 44 | 45 | intern->handlers = &rindow_openblas_lapack_object_handlers; 46 | 47 | return intern; 48 | } /* }}} */ 49 | 50 | 51 | /* Method Rindow\OpenBLAS\Lapack:: 52 | public function gesvd( 53 | int $matrix_layout, 54 | string $jobu, 55 | string $jobvt, 56 | int $m, 57 | int $n, 58 | Buffer $A, int $offsetA, int $ldA, 59 | Buffer $S, int $offsetS, 60 | Buffer $U, int $offsetU, int $ldU, 61 | Buffer $VT, int $offsetVT, int $ldVT, 62 | Buffer $SuperB, int $offsetSuperB 63 | ) : void 64 | {{{ */ 65 | static PHP_METHOD(Lapack, gesvd) 66 | { 67 | /* 68 | lapack_int LAPACKE_dgesvd( int matrix_layout, char jobu, char jobvt, 69 | lapack_int m, lapack_int n, double* a, 70 | lapack_int lda, double* s, double* u, lapack_int ldu, 71 | double* vt, lapack_int ldvt, double* superb ); 72 | */ 73 | php_interop_polite_math_matrix_linear_buffer_t* bufferA; 74 | php_interop_polite_math_matrix_linear_buffer_t* bufferS; 75 | php_interop_polite_math_matrix_linear_buffer_t* bufferU; 76 | php_interop_polite_math_matrix_linear_buffer_t* bufferVT; 77 | php_interop_polite_math_matrix_linear_buffer_t* bufferSuperB; 78 | zend_long matrix_layout; 79 | zend_long jobu; 80 | zend_long jobvt; 81 | zend_long m; 82 | zend_long n; 83 | zval* objA=NULL; 84 | zend_long offsetA; 85 | zend_long ldA; 86 | zval* objS=NULL; 87 | zend_long offsetS; 88 | zval* objU=NULL; 89 | zend_long offsetU; 90 | zend_long ldU; 91 | zval* objVT=NULL; 92 | zend_long offsetVT; 93 | zend_long ldVT; 94 | zval* objSuperB=NULL; 95 | zend_long offsetSuperB; 96 | int info; 97 | 98 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 18, 18) 99 | Z_PARAM_LONG(matrix_layout) 100 | Z_PARAM_LONG(jobu) 101 | Z_PARAM_LONG(jobvt) 102 | Z_PARAM_LONG(m) 103 | Z_PARAM_LONG(n) 104 | 105 | Z_PARAM_OBJECT(objA) // Interop\Polite\Math\Matrix\LinearBuffer 106 | Z_PARAM_LONG(offsetA) 107 | Z_PARAM_LONG(ldA) 108 | Z_PARAM_OBJECT(objS) // Interop\Polite\Math\Matrix\LinearBuffer 109 | Z_PARAM_LONG(offsetS) 110 | 111 | Z_PARAM_OBJECT(objU) // Interop\Polite\Math\Matrix\LinearBuffer 112 | Z_PARAM_LONG(offsetU) 113 | Z_PARAM_LONG(ldU) 114 | Z_PARAM_OBJECT(objVT) // Interop\Polite\Math\Matrix\LinearBuffer 115 | Z_PARAM_LONG(offsetVT) 116 | 117 | Z_PARAM_LONG(ldVT) 118 | Z_PARAM_OBJECT(objSuperB) // Interop\Polite\Math\Matrix\LinearBuffer 119 | Z_PARAM_LONG(offsetSuperB) 120 | ZEND_PARSE_PARAMETERS_END(); 121 | 122 | if(php_rindow_openblas_assert_shape_parameter( 123 | "m", m)) { 124 | return; 125 | } 126 | if(php_rindow_openblas_assert_shape_parameter( 127 | "n", n)) { 128 | return; 129 | } 130 | if( offsetS < 0 ) { 131 | zend_throw_exception(spl_ce_InvalidArgumentException, "offsetS must be greater than zero or equal", 0); 132 | return; 133 | } 134 | if( offsetU < 0 ) { 135 | zend_throw_exception(spl_ce_InvalidArgumentException, "offsetU must be greater than zero or equal", 0); 136 | return; 137 | } 138 | if( ldU <= 0 ) { 139 | zend_throw_exception(spl_ce_InvalidArgumentException, "ldU must be greater than zero", 0); 140 | return; 141 | } 142 | if( offsetVT < 0 ) { 143 | zend_throw_exception(spl_ce_InvalidArgumentException, "offsetVT must be greater than zero or equal", 0); 144 | return; 145 | } 146 | if( ldVT <= 0 ) { 147 | zend_throw_exception(spl_ce_InvalidArgumentException, "ldVT must be greater than zero", 0); 148 | return; 149 | } 150 | if( offsetSuperB < 0 ) { 151 | zend_throw_exception(spl_ce_InvalidArgumentException, "offsetVT must be greater than zero or equal", 0); 152 | return; 153 | } 154 | // Check Buffer A 155 | bufferA = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(objA); 156 | if(php_rindow_openblas_assert_buffer_type(bufferA,"a")) { 157 | return; 158 | } 159 | if(php_rindow_openblas_assert_matrix_buffer_spec( 160 | "A", bufferA,m,n,offsetA,ldA)) { 161 | return; 162 | } 163 | 164 | // Check Buffer S 165 | bufferS = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(objS); 166 | if(php_rindow_openblas_assert_buffer_type(bufferS,"s")) { 167 | return; 168 | } 169 | if( offsetS+MIN(m,n) > bufferS->size) { 170 | zend_throw_exception(spl_ce_InvalidArgumentException, "BufferS size is too small", 0); 171 | return; 172 | } 173 | 174 | // Check Buffer U 175 | bufferU = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(objU); 176 | if(php_rindow_openblas_assert_buffer_type(bufferU,"u")) { 177 | return; 178 | } 179 | if( offsetU+m*ldU > bufferU->size) { 180 | zend_throw_exception(spl_ce_InvalidArgumentException, "BufferU size is too small", 0); 181 | return; 182 | } 183 | 184 | // Check Buffer VT 185 | bufferVT = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(objVT); 186 | if(php_rindow_openblas_assert_buffer_type(bufferVT,"vt")) { 187 | return; 188 | } 189 | if( offsetVT+ldVT*n > bufferVT->size) { 190 | zend_throw_exception(spl_ce_InvalidArgumentException, "BufferVT size is too small", 0); 191 | return; 192 | } 193 | 194 | // Check Buffer SuperB 195 | bufferSuperB = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(objSuperB); 196 | if(php_rindow_openblas_assert_buffer_type(bufferSuperB,"b")) { 197 | return; 198 | } 199 | if( offsetSuperB+MIN(m,n)-1 > bufferSuperB->size) { 200 | zend_throw_exception(spl_ce_InvalidArgumentException, "bufferSuperB size is too small", 0); 201 | return; 202 | } 203 | 204 | // Check Buffer A and B and C 205 | if(bufferA->dtype!=bufferS->dtype || 206 | bufferA->dtype!=bufferU->dtype || 207 | bufferA->dtype!=bufferVT->dtype || 208 | bufferA->dtype!=bufferSuperB->dtype 209 | ) { 210 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch data type", 0); 211 | return; 212 | } 213 | 214 | switch (bufferA->dtype) { 215 | case php_interop_polite_math_matrix_dtype_float32: 216 | info = LAPACKE_sgesvd( 217 | (int)matrix_layout, 218 | (char)jobu, 219 | (char)jobvt, 220 | (lapack_int)m,(lapack_int)n, 221 | &(((float *)bufferA->data)[offsetA]), (lapack_int)ldA, 222 | &(((float *)bufferS->data)[offsetS]), 223 | &(((float *)bufferU->data)[offsetU]), (lapack_int)ldU, 224 | &(((float *)bufferVT->data)[offsetVT]), (lapack_int)ldVT, 225 | &(((float *)bufferSuperB->data)[offsetSuperB]) 226 | ); 227 | break; 228 | case php_interop_polite_math_matrix_dtype_float64: 229 | info = LAPACKE_dgesvd( 230 | (int)matrix_layout, 231 | (char)jobu, 232 | (char)jobvt, 233 | (lapack_int)m,(lapack_int)n, 234 | &(((double *)bufferA->data)[offsetA]), (lapack_int)ldA, 235 | &(((double *)bufferS->data)[offsetS]), 236 | &(((double *)bufferU->data)[offsetU]), (lapack_int)ldU, 237 | &(((double *)bufferVT->data)[offsetVT]), (lapack_int)ldVT, 238 | &(((double *)bufferSuperB->data)[offsetSuperB]) 239 | ); 240 | break; 241 | default: 242 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 243 | return; 244 | } 245 | if( info == LAPACK_WORK_MEMORY_ERROR ) { 246 | zend_throw_exception(spl_ce_RuntimeException, "Not enough memory to allocate work array.", info); 247 | return; 248 | } else if( info == LAPACK_TRANSPOSE_MEMORY_ERROR ) { 249 | zend_throw_exception(spl_ce_RuntimeException, "Not enough memory to transpose matrix.", info); 250 | return; 251 | } else if( info < 0 ) { 252 | zend_throw_exception(spl_ce_RuntimeException, "Wrong parameter.", info); 253 | return; 254 | } 255 | } 256 | /* }}} */ 257 | 258 | 259 | ZEND_BEGIN_ARG_INFO_EX(ai_Lapack_gesvd, 0, 0, 18) 260 | ZEND_ARG_INFO(0, matrix_layout) 261 | ZEND_ARG_INFO(0, jobu) 262 | ZEND_ARG_INFO(0, jobvt) 263 | ZEND_ARG_INFO(0, m) 264 | ZEND_ARG_INFO(0, n) 265 | 266 | ZEND_ARG_OBJ_INFO(0, objA, Interop\\Polite\\Math\\Matrix\\LinearBuffer, 0) 267 | ZEND_ARG_INFO(0, offsetA) 268 | ZEND_ARG_INFO(0, ldA) 269 | ZEND_ARG_OBJ_INFO(0, objS, Interop\\Polite\\Math\\Matrix\\LinearBuffer, 0) 270 | ZEND_ARG_INFO(0, offsetS) 271 | 272 | ZEND_ARG_OBJ_INFO(0, objU, Interop\\Polite\\Math\\Matrix\\LinearBuffer, 0) 273 | ZEND_ARG_INFO(0, offsetU) 274 | ZEND_ARG_INFO(0, ldU) 275 | ZEND_ARG_OBJ_INFO(0, objVT, Interop\\Polite\\Math\\Matrix\\LinearBuffer, 0) 276 | ZEND_ARG_INFO(0, offsetVT) 277 | 278 | ZEND_ARG_INFO(0, ldVT) 279 | ZEND_ARG_OBJ_INFO(0, objSuperB, Interop\\Polite\\Math\\Matrix\\LinearBuffer, 0) 280 | ZEND_ARG_INFO(0, offsetSuperB) 281 | ZEND_END_ARG_INFO() 282 | 283 | ZEND_BEGIN_ARG_INFO_EX(ai_Lapack_void, 0, 0, 0) 284 | ZEND_END_ARG_INFO() 285 | 286 | /* {{{ Rindow\OpenBLAS\Lapack function entries */ 287 | static zend_function_entry php_rindow_openblas_lapack_me[] = { 288 | /* clang-format off */ 289 | PHP_ME(Lapack, gesvd, ai_Lapack_gesvd, ZEND_ACC_PUBLIC) 290 | PHP_FE_END 291 | /* clang-format on */ 292 | }; 293 | /* }}} */ 294 | 295 | /* Class Rindow\OpenBLAS\Lapack {{{ */ 296 | static zend_class_entry* rindow_openblas_lapack_ce; 297 | 298 | void php_rindow_openblas_lapack_init_ce(INIT_FUNC_ARGS) 299 | { 300 | zend_class_entry ce; 301 | 302 | INIT_NS_CLASS_ENTRY(ce, "Rindow\\OpenBLAS", "Lapack", php_rindow_openblas_lapack_me); 303 | rindow_openblas_lapack_ce = zend_register_internal_class(&ce); 304 | rindow_openblas_lapack_ce->create_object = php_rindow_openblas_lapack_create_object; 305 | 306 | memcpy(&rindow_openblas_lapack_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 307 | rindow_openblas_lapack_object_handlers.offset = 0; 308 | rindow_openblas_lapack_object_handlers.free_obj = php_rindow_openblas_lapack_free_object; 309 | rindow_openblas_lapack_object_handlers.clone_obj = NULL; 310 | 311 | //zend_class_implements(rindow_openblas_lapack_ce, 2, spl_ce_ArrayAccess, spl_ce_Countable); 312 | } 313 | /* }}} */ 314 | -------------------------------------------------------------------------------- /phpunit/BufferTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('0.1.7',phpversion('rindow_openblas')); 20 | //} 21 | 22 | public function testNormal() 23 | { 24 | $buf = new Buffer(3,NDArray::float32); 25 | $buf[0] = 0.5; 26 | $buf[1] = 1.5; 27 | $buf[2] = 2.5; 28 | $this->assertEquals(3,count($buf)); 29 | $this->assertEquals(NDArray::float32,$buf->dtype()); 30 | $this->assertTrue(is_float($buf[0])); 31 | $this->assertEquals(0.5,$buf[0]); 32 | $this->assertEquals(1.5,$buf[1]); 33 | $this->assertEquals(2.5,$buf[2]); 34 | } 35 | 36 | public function testDtypesAndOffsetOfDtypes() 37 | { 38 | $buf = new Buffer(3,NDArray::bool); 39 | $buf[2] = true; 40 | $this->assertEquals(NDArray::bool,$buf->dtype()); 41 | $this->assertTrue(is_bool($buf[0])); 42 | $this->assertEquals(true,$buf[2]); 43 | 44 | $buf = new Buffer(3,NDArray::int8); 45 | $buf[2] = -1; 46 | $this->assertEquals(NDArray::int8,$buf->dtype()); 47 | $this->assertTrue(is_int($buf[0])); 48 | $this->assertEquals(-1,$buf[2]); 49 | 50 | $buf = new Buffer(3,NDArray::uint8); 51 | $buf[2] = -1; 52 | $this->assertEquals(NDArray::uint8,$buf->dtype()); 53 | $this->assertTrue(is_int($buf[0])); 54 | $this->assertEquals(255,$buf[2]); 55 | 56 | $buf = new Buffer(3,NDArray::int16); 57 | $buf[2] = -1; 58 | $this->assertEquals(NDArray::int16,$buf->dtype()); 59 | $this->assertTrue(is_int($buf[0])); 60 | $this->assertEquals(-1,$buf[2]); 61 | 62 | $buf = new Buffer(3,NDArray::uint16); 63 | $buf[2] = -1; 64 | $this->assertEquals(NDArray::uint16,$buf->dtype()); 65 | $this->assertTrue(is_int($buf[0])); 66 | $this->assertEquals(65535,$buf[2]); 67 | 68 | $buf = new Buffer(3,NDArray::int32); 69 | $buf[2] = -1; 70 | $this->assertEquals(NDArray::int32,$buf->dtype()); 71 | $this->assertTrue(is_int($buf[0])); 72 | $this->assertEquals(-1,$buf[2]); 73 | 74 | $buf = new Buffer(3,NDArray::uint32); 75 | $buf[2] = -1; 76 | $this->assertEquals(NDArray::uint32,$buf->dtype()); 77 | $this->assertTrue(is_int($buf[0])); 78 | $this->assertEquals(4294967295,$buf[2]); 79 | 80 | $buf = new Buffer(3,NDArray::int64); 81 | $buf[2] = -1; 82 | $this->assertEquals(NDArray::int64,$buf->dtype()); 83 | $this->assertTrue(is_int($buf[0])); 84 | $this->assertEquals(-1,$buf[2]); 85 | 86 | $buf = new Buffer(3,NDArray::uint64); 87 | $buf[2] = -1; 88 | $this->assertEquals(NDArray::uint64,$buf->dtype()); 89 | $this->assertTrue(is_int($buf[0])); 90 | $this->assertEquals(-1,$buf[2]); // *** CAUTION **** 91 | 92 | $buf = new Buffer(3,NDArray::float32); 93 | $buf[2] = 0.5; 94 | $this->assertEquals(NDArray::float32,$buf->dtype()); 95 | $this->assertTrue(is_float($buf[0])); 96 | $this->assertEquals(0.5,$buf[2]); 97 | 98 | $buf = new Buffer(3,NDArray::float64); 99 | $buf[2] = 0.5; 100 | $this->assertEquals(NDArray::float64,$buf->dtype()); 101 | $this->assertTrue(is_float($buf[0])); 102 | $this->assertEquals(0.5,$buf[2]); 103 | } 104 | 105 | public function testOffsetExists() 106 | { 107 | $buf = new Buffer(3,NDArray::float32); 108 | $this->assertTrue(isset($buf[0])); 109 | $this->assertTrue(isset($buf[2])); 110 | $this->assertFalse(isset($buf[-1])); 111 | $this->assertFalse(isset($buf[3])); 112 | } 113 | 114 | public function testUnset() 115 | { 116 | $buf = new Buffer(3,NDArray::float32); 117 | $buf[0] = 1; 118 | $this->assertEquals(1,$buf[0]); 119 | unset($buf[0]); // unset means set zero 120 | $this->assertEquals(0,$buf[0]); 121 | } 122 | 123 | public function testDumpAndLoad() 124 | { 125 | $buf = new Buffer(3,NDArray::float32); 126 | $buf[0] = 1; 127 | $buf[1] = 2; 128 | $buf[2] = 3; 129 | 130 | $buf2 = new Buffer(3,NDArray::float32); 131 | $buf2[0] = 0; 132 | $buf2[1] = 0; 133 | $buf2[2] = 0; 134 | 135 | $dump = $buf->dump(); 136 | $buf2->load($dump); 137 | $this->assertEquals(1,$buf2[0]); 138 | $this->assertEquals(2,$buf2[1]); 139 | $this->assertEquals(3,$buf2[2]); 140 | } 141 | 142 | public function testSetOutOfBoundsWithHighOffset() 143 | { 144 | //$buf = new \SplFixedArray(3); 145 | $buf = new Buffer(3,NDArray::float32); 146 | $this->expectException(OutOfRangeException::class); 147 | $this->expectExceptionMessage('Index invalid or out of range'); 148 | $buf[3] = 1; 149 | } 150 | 151 | public function testSetOutOfBoundsWithLowOffset() 152 | { 153 | //$buf = new \SplFixedArray(3); 154 | $buf = new Buffer(3,NDArray::float32); 155 | $this->expectException(OutOfRangeException::class); 156 | $this->expectExceptionMessage('Index invalid or out of range'); 157 | $buf[-1] = 1; 158 | } 159 | 160 | public function testGetOutOfBoundsWithHighOffset() 161 | { 162 | //$buf = new \SplFixedArray(3); 163 | $buf = new Buffer(3,NDArray::float32); 164 | $this->expectException(OutOfRangeException::class); 165 | $this->expectExceptionMessage('Index invalid or out of range'); 166 | $x = $buf[3]; 167 | } 168 | 169 | public function testGetOutOfBoundsWithLowOffset() 170 | { 171 | //$buf = new \SplFixedArray(3); 172 | $buf = new Buffer(3,NDArray::float32); 173 | $this->expectException(OutOfRangeException::class); 174 | $this->expectExceptionMessage('Index invalid or out of range'); 175 | $x = $buf[-1]; 176 | } 177 | 178 | public function testUnsetOutOfBoundsWithHighOffset() 179 | { 180 | //$buf = new \SplFixedArray(3); 181 | $buf = new Buffer(3,NDArray::float32); 182 | unset($buf[3]); 183 | $this->assertTrue(true); 184 | } 185 | 186 | public function testUnsetOutOfBoundsWithLowOffset() 187 | { 188 | //$buf = new \SplFixedArray(3); 189 | $buf = new Buffer(3,NDArray::float32); 190 | unset($buf[-1]); 191 | $this->assertTrue(true); 192 | } 193 | 194 | public function testIsExistsOutOfBoundsWithHighOffset() 195 | { 196 | //$buf = new \SplFixedArray(3); 197 | $buf = new Buffer(3,NDArray::float32); 198 | $this->assertFalse(isset($buf[3])); 199 | } 200 | 201 | public function testIsExistsOutOfBoundsWithLowOffset() 202 | { 203 | //$buf = new \SplFixedArray(3); 204 | $buf = new Buffer(3,NDArray::float32); 205 | $this->assertFalse(isset($buf[-1])); 206 | } 207 | 208 | public function testOffsetSetWithNoOffset() 209 | { 210 | $buf = new Buffer(3,NDArray::float32); 211 | $this->expectException(ArgumentCountError::class); 212 | if(version_compare(PHP_VERSION, '8.0.0')<0) { 213 | $this->expectExceptionMessage('offsetSet() expects exactly 2 parameters, 0 given'); 214 | } else { 215 | $this->expectExceptionMessage('offsetSet() expects exactly 2 arguments, 0 given'); 216 | } 217 | $a = $buf->offsetSet(); 218 | } 219 | 220 | public function testOffsetSetIllegalTypeOffset() 221 | { 222 | $buf = new Buffer(3,NDArray::float32); 223 | $this->expectException(TypeError::class); 224 | if(version_compare(PHP_VERSION, '8.0.0')<0) { 225 | $this->expectExceptionMessage('offsetSet() expects parameter 1 to be int'); 226 | } else { 227 | $this->expectExceptionMessage('offsetSet(): Argument #1 ($offset) must be of type int'); 228 | } 229 | $buf->offsetSet(new \stdClass(),1); 230 | } 231 | 232 | public function testOffsetGetWithNoOffset() 233 | { 234 | $buf = new Buffer(3,NDArray::float32); 235 | $this->expectException(ArgumentCountError::class); 236 | if(version_compare(PHP_VERSION, '8.0.0')<0) { 237 | $this->expectExceptionMessage('offsetGet() expects exactly 1 parameter, 0 given'); 238 | } else { 239 | $this->expectExceptionMessage('offsetGet() expects exactly 1 argument, 0 given'); 240 | } 241 | $a = $buf->offsetGet(); 242 | } 243 | 244 | public function testOffsetGetIllegalType() 245 | { 246 | $buf = new Buffer(3,NDArray::float32); 247 | $this->expectException(TypeError::class); 248 | if(version_compare(PHP_VERSION, '8.0.0')<0) { 249 | $this->expectExceptionMessage('offsetGet() expects parameter 1 to be int'); 250 | } else { 251 | $this->expectExceptionMessage('offsetGet(): Argument #1 ($offset) must be of type int'); 252 | } 253 | $a = $buf->offsetGet(new \stdClass()); 254 | } 255 | 256 | public function testOffsetUnsetWithNoOffset() 257 | { 258 | $buf = new Buffer(3,NDArray::float32); 259 | $this->expectException(ArgumentCountError::class); 260 | if(version_compare(PHP_VERSION, '8.0.0')<0) { 261 | $this->expectExceptionMessage('offsetUnset() expects exactly 1 parameter, 0 given'); 262 | } else { 263 | $this->expectExceptionMessage('offsetUnset() expects exactly 1 argument, 0 given'); 264 | } 265 | $buf->offsetUnset(); 266 | } 267 | 268 | public function testOffsetUnsetIllegalType() 269 | { 270 | $buf = new Buffer(3,NDArray::float32); 271 | $this->expectException(TypeError::class); 272 | if(version_compare(PHP_VERSION, '8.0.0')<0) { 273 | $this->expectExceptionMessage('offsetUnset() expects parameter 1 to be int'); 274 | } else { 275 | $this->expectExceptionMessage('offsetUnset(): Argument #1 ($offset) must be of type int'); 276 | } 277 | $buf->offsetUnset(new \stdClass()); 278 | } 279 | 280 | public function testLoadWithNoOffset() 281 | { 282 | $buf = new Buffer(3,NDArray::float32); 283 | $this->expectException(ArgumentCountError::class); 284 | if(version_compare(PHP_VERSION, '8.0.0')<0) { 285 | $this->expectExceptionMessage('load() expects exactly 1 parameter, 0 given'); 286 | } else { 287 | $this->expectExceptionMessage('load() expects exactly 1 argument, 0 given'); 288 | } 289 | $buf->load(); 290 | } 291 | 292 | public function testLoadIllegalType() 293 | { 294 | $buf = new Buffer(3,NDArray::float32); 295 | $this->expectException(TypeError::class); 296 | if(version_compare(PHP_VERSION, '8.0.0')<0) { 297 | $this->expectExceptionMessage('load() expects parameter 1 to be string'); 298 | } else { 299 | $this->expectExceptionMessage('load(): Argument #1 must be of type string'); 300 | } 301 | $buf->load(new \stdClass()); 302 | } 303 | 304 | public function testConstractWithNoArgument() 305 | { 306 | $this->expectException(ArgumentCountError::class); 307 | if(version_compare(PHP_VERSION, '8.0.0')<0) { 308 | $this->expectExceptionMessage('__construct() expects exactly 2 parameters, 0 given'); 309 | } else { 310 | $this->expectExceptionMessage('__construct() expects exactly 2 arguments, 0 given'); 311 | } 312 | $buf = new Buffer(); 313 | } 314 | 315 | public function testConstractIllegalType() 316 | { 317 | $this->expectException(TypeError::class); 318 | if(version_compare(PHP_VERSION, '8.0.0')<0) { 319 | $this->expectExceptionMessage('__construct() expects parameter 1 to be int'); 320 | } else { 321 | $this->expectExceptionMessage('__construct(): Argument #1 ($size) must be of type int'); 322 | } 323 | $buf = new Buffer(new \stdClass(),NDArray::float32); 324 | } 325 | } 326 | -------------------------------------------------------------------------------- /src/Rindow/OpenBLAS/Math_im2col1d.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | static inline int im2col1d_copyCell( 4 | zend_bool reverse, 5 | php_interop_polite_math_matrix_linear_buffer_t *images, 6 | zend_long images_pos, 7 | zend_long im_w, 8 | zend_long channels, 9 | zend_long channel_step, 10 | zend_long filter_w_step, 11 | zend_long vim_x, 12 | zend_long vfilter_w, 13 | zend_long dilation_w, 14 | php_interop_polite_math_matrix_linear_buffer_t *out, 15 | zend_long out_pos, 16 | zend_long out_filter_step, 17 | zend_long out_channel_step 18 | ) 19 | { 20 | zend_long vfilter_x; 21 | zend_long filter_w_pos; 22 | zend_long out_filter_pos; 23 | zend_long input_x; 24 | zend_long channel_pos; 25 | zend_long out_channel_pos; 26 | zend_long c; 27 | 28 | filter_w_pos = images_pos; 29 | out_filter_pos = out_pos; 30 | for(vfilter_x=0; vfilter_x=im_w) { 36 | if(out_channel_pos<0 ||out_channel_pos>=out->size) { 37 | zend_throw_exception(spl_ce_RuntimeException, "cols data out of range", 0); 38 | return -1; 39 | } 40 | if(!reverse) { 41 | if(images->dtype== php_interop_polite_math_matrix_dtype_float32) { 42 | ((float*)(out->data))[out_channel_pos] 43 | = 0; 44 | } else { 45 | ((double*)(out->data))[out_channel_pos] 46 | = 0; 47 | } 48 | } 49 | } else { 50 | if(channel_pos<0 ||channel_pos>=images->size) { 51 | zend_throw_exception(spl_ce_RuntimeException, "images data out of range", 0); 52 | return -1; 53 | } 54 | if(out_channel_pos<0 ||out_channel_pos>=out->size) { 55 | zend_throw_exception(spl_ce_RuntimeException, "cols data out of range", 0); 56 | return -1; 57 | } 58 | if(!reverse) { 59 | if(images->dtype== php_interop_polite_math_matrix_dtype_float32) { 60 | ((float*)(out->data))[out_channel_pos] 61 | = ((float*)(images->data))[channel_pos]; 62 | } else { 63 | ((double*)(out->data))[out_channel_pos] 64 | = ((double*)(images->data))[channel_pos]; 65 | } 66 | } else { 67 | // Sum for Back propagation 68 | if(images->dtype== php_interop_polite_math_matrix_dtype_float32) { 69 | ((float*)(images->data))[channel_pos] 70 | += ((float*)(out->data))[out_channel_pos]; 71 | } else { 72 | ((double*)(images->data))[channel_pos] 73 | += ((double*)(out->data))[out_channel_pos]; 74 | } 75 | } 76 | } 77 | out_channel_pos += out_channel_step; 78 | channel_pos += channel_step; 79 | } 80 | out_filter_pos += out_filter_step; 81 | filter_w_pos += filter_w_step; 82 | } 83 | return 0; 84 | } 85 | 86 | 87 | static inline int im2col1d_execute( 88 | zend_bool reverse, 89 | php_interop_polite_math_matrix_linear_buffer_t* images, 90 | zend_long images_offset, 91 | zend_long images_size, 92 | zend_long batches, 93 | 94 | zend_long im_w, 95 | zend_long channels, 96 | zend_long filter_w, 97 | zend_long stride_w, 98 | zend_bool padding, 99 | 100 | zend_bool channels_first, 101 | zend_long dilation_w, 102 | zend_bool cols_channels_first, 103 | php_interop_polite_math_matrix_linear_buffer_t* cols, 104 | zend_long cols_offset, 105 | 106 | zend_long cols_size 107 | ) 108 | { 109 | zend_long out_w; 110 | zend_long stride_w_step; 111 | zend_long batch_step; 112 | zend_long channel_step; 113 | zend_long filter_w_step; 114 | zend_long out_filter_step; 115 | zend_long out_channel_step; 116 | zend_long out_cell_step; 117 | zend_long out_pos; 118 | zend_long batch_pos; 119 | zend_long padding_w; 120 | zend_long im_w_step; 121 | 122 | zend_long batch; 123 | zend_long stride_w_pos; 124 | zend_long vim_x; 125 | zend_long vim_w; 126 | zend_long vfilter_w; 127 | 128 | if((batches*im_w*channels) 129 | !=images_size) { 130 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch images buffer size and images shape", 0); 131 | return -1; 132 | } 133 | out_w = ((im_w-(filter_w-1)*dilation_w-1)/stride_w)+1; 134 | if(out_w<=0) { 135 | zend_throw_exception(spl_ce_InvalidArgumentException, "Invalid shape or parameters.", 0); 136 | return -1; 137 | } 138 | if(padding) { 139 | if((batches* 140 | im_w*filter_w* 141 | channels)!=cols_size) { 142 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch cols buffer size and images shape", 0); 143 | return -1; 144 | } 145 | padding_w = ((im_w-1)*stride_w-im_w+(filter_w-1)*dilation_w+1)/2; 146 | out_w = im_w; 147 | } else { 148 | if((batches* 149 | out_w*filter_w* 150 | channels)!=cols_size) { 151 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch cols buffer size and images shape", 0); 152 | return -1; 153 | } 154 | padding_w = 0; 155 | } 156 | if(channels_first) { 157 | im_w_step = 1; 158 | channel_step = im_w; 159 | batch_step = im_w*channels; 160 | } else { 161 | channel_step = 1; 162 | im_w_step = channels; 163 | batch_step = channels*im_w; 164 | } 165 | stride_w_step = im_w_step*stride_w; 166 | filter_w_step = im_w_step*dilation_w; 167 | 168 | if(cols_channels_first) { 169 | out_filter_step = 1; 170 | out_channel_step = filter_w; 171 | } else { 172 | out_filter_step = channels; 173 | out_channel_step = 1; 174 | } 175 | out_cell_step = filter_w*channels; 176 | 177 | batch_pos = images_offset-im_w_step*padding_w; 178 | out_pos = cols_offset; 179 | 180 | vim_w = out_w*stride_w; 181 | vfilter_w = filter_w*dilation_w; 182 | 183 | for(batch=0; batchdtype!=php_interop_polite_math_matrix_dtype_float32 && 304 | images->dtype!=php_interop_polite_math_matrix_dtype_float64) { 305 | zend_throw_exception(spl_ce_InvalidArgumentException, 306 | "Unsupported data type", 0); 307 | return; 308 | } 309 | // Check dtype and Buffer Y 310 | if(images->dtype!=cols->dtype) { 311 | zend_throw_exception(spl_ce_InvalidArgumentException, 312 | "Unmatch data type of images and cols", 0); 313 | return; 314 | } 315 | if(images->sizedtype, images->data,(index_t)images_offset); 322 | void *pDataCols = rindow_matlib_common_get_address((dtype_t)cols->dtype, cols->data,(index_t)cols_offset); 323 | 324 | int32_t rc = rindow_matlib_im2col1d( 325 | (dtype_t)images->dtype,reverse, 326 | pDataImages, 327 | (index_t)images_size, 328 | (index_t)batches, 329 | (index_t)im_w, 330 | (index_t)channels, 331 | (index_t)filter_w, 332 | (index_t)stride_w, 333 | padding, 334 | channels_first, 335 | (index_t)dilation_w, 336 | cols_channels_first, 337 | pDataCols, 338 | (index_t)cols_size 339 | ); 340 | switch(rc) { 341 | case 0: { 342 | break; 343 | } 344 | case RINDOW_MATLIB_E_UNSUPPORTED_DATA_TYPE: { 345 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 346 | return; 347 | } 348 | case RINDOW_MATLIB_E_INVALID_SHAPE_OR_PARAM: { 349 | zend_throw_exception(spl_ce_InvalidArgumentException, "Invalid shape or parameters.", 0); 350 | return; 351 | } 352 | case RINDOW_MATLIB_E_UNMATCH_COLS_BUFFER_SIZE: { 353 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch cols buffer size and images shape", 0); 354 | return; 355 | } 356 | case RINDOW_MATLIB_E_UNMATCH_IMAGE_BUFFER_SIZE: { 357 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch images buffer size and images shape", 0); 358 | return; 359 | } 360 | case RINDOW_MATLIB_E_IMAGES_OUT_OF_RANGE: { 361 | zend_throw_exception(spl_ce_RuntimeException, "Images data out of range", 0); 362 | return; 363 | } 364 | case RINDOW_MATLIB_E_COLS_OUT_OF_RANGE: { 365 | zend_throw_exception(spl_ce_RuntimeException, "Cols data out of range", 0); 366 | return; 367 | } 368 | default: { 369 | zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Unkown Error (%d)", rc); 370 | return; 371 | } 372 | } 373 | /* 374 | im2col1d_execute( 375 | reverse, 376 | images, 377 | images_offset, 378 | images_size, 379 | batches, 380 | 381 | im_w, 382 | channels, 383 | filter_w, 384 | stride_w, 385 | padding, 386 | 387 | channels_first, 388 | dilation_w, 389 | cols_channels_first, 390 | cols, 391 | cols_offset, 392 | 393 | cols_size 394 | ); 395 | */ 396 | return; 397 | } 398 | /* }}} */ 399 | -------------------------------------------------------------------------------- /src/Rindow/OpenBLAS/Math_im2col2d.c: -------------------------------------------------------------------------------- 1 | /* 2 | static inline int im2col2d_copyCell( 3 | zend_bool reverse, 4 | php_interop_polite_math_matrix_linear_buffer_t *images, 5 | zend_long images_pos, 6 | zend_long im_h, 7 | zend_long im_w, 8 | zend_long channels, 9 | zend_long channel_step, 10 | zend_long filter_h_step, 11 | zend_long filter_w_step, 12 | zend_long vim_y, 13 | zend_long vim_x, 14 | zend_long vfilter_h, 15 | zend_long vfilter_w, 16 | zend_long dilation_h, 17 | zend_long dilation_w, 18 | php_interop_polite_math_matrix_linear_buffer_t *out, 19 | zend_long out_pos, 20 | zend_long out_filter_step, 21 | zend_long out_channel_step 22 | ) 23 | { 24 | zend_long vfilter_y; 25 | zend_long vfilter_x; 26 | zend_long filter_h_pos; 27 | zend_long filter_w_pos; 28 | zend_long out_filter_pos; 29 | zend_long input_y; 30 | zend_long input_x; 31 | zend_long channel_pos; 32 | zend_long out_channel_pos; 33 | zend_long c; 34 | 35 | filter_h_pos = images_pos; 36 | out_filter_pos = out_pos; 37 | for(vfilter_y=0; vfilter_y=im_h || 46 | input_x<0 || input_x>=im_w) { 47 | if(out_channel_pos<0 ||out_channel_pos>=out->size) { 48 | zend_throw_exception(spl_ce_RuntimeException, "cols data out of range", 0); 49 | return -1; 50 | } 51 | if(!reverse) { 52 | if(images->dtype == php_interop_polite_math_matrix_dtype_float32) { 53 | ((float*)(out->data))[out_channel_pos] 54 | = 0; 55 | } else { 56 | ((double*)(out->data))[out_channel_pos] 57 | = 0; 58 | } 59 | } 60 | } else { 61 | if(channel_pos<0 ||channel_pos>=images->size) { 62 | zend_throw_exception(spl_ce_RuntimeException, "images data out of range", 0); 63 | return -1; 64 | } 65 | if(out_channel_pos<0 ||out_channel_pos>=out->size) { 66 | zend_throw_exception(spl_ce_RuntimeException, "cols data out of range", 0); 67 | return -1; 68 | } 69 | if(!reverse) { 70 | if(images->dtype== php_interop_polite_math_matrix_dtype_float32) { 71 | ((float*)(out->data))[out_channel_pos] 72 | = ((float*)(images->data))[channel_pos]; 73 | } else { 74 | ((double*)(out->data))[out_channel_pos] 75 | = ((double*)(images->data))[channel_pos]; 76 | } 77 | } else { 78 | // Sum for Back propagation 79 | if(images->dtype== php_interop_polite_math_matrix_dtype_float32) { 80 | ((float*)(images->data))[channel_pos] 81 | += ((float*)(out->data))[out_channel_pos]; 82 | } else { 83 | ((double*)(images->data))[channel_pos] 84 | += ((double*)(out->data))[out_channel_pos]; 85 | } 86 | } 87 | } 88 | out_channel_pos += out_channel_step; 89 | channel_pos += channel_step; 90 | } 91 | out_filter_pos += out_filter_step; 92 | filter_w_pos += filter_w_step; 93 | } 94 | filter_h_pos += filter_h_step; 95 | } 96 | return 0; 97 | } 98 | 99 | 100 | static inline int im2col2d_execute( 101 | zend_bool reverse, 102 | php_interop_polite_math_matrix_linear_buffer_t* images, 103 | zend_long images_offset, 104 | zend_long images_size, 105 | zend_long batches, 106 | 107 | zend_long im_h, 108 | zend_long im_w, 109 | zend_long channels, 110 | zend_long filter_h, 111 | zend_long filter_w, 112 | 113 | zend_long stride_h, 114 | zend_long stride_w, 115 | zend_bool padding, 116 | zend_bool channels_first, 117 | zend_long dilation_h, 118 | 119 | zend_long dilation_w, 120 | zend_bool cols_channels_first, 121 | php_interop_polite_math_matrix_linear_buffer_t* cols, 122 | zend_long cols_offset, 123 | zend_long cols_size 124 | ) 125 | { 126 | zend_long out_h; 127 | zend_long out_w; 128 | zend_long stride_h_step; 129 | zend_long stride_w_step; 130 | zend_long batch_step; 131 | zend_long channel_step; 132 | zend_long filter_h_step; 133 | zend_long filter_w_step; 134 | zend_long out_filter_step; 135 | zend_long out_channel_step; 136 | zend_long out_cell_step; 137 | zend_long out_pos; 138 | zend_long batch_pos; 139 | zend_long padding_h; 140 | zend_long padding_w; 141 | zend_long im_w_step; 142 | zend_long im_h_step; 143 | 144 | zend_long batch; 145 | zend_long stride_h_pos; 146 | zend_long stride_w_pos; 147 | zend_long vim_y; 148 | zend_long vim_x; 149 | zend_long vim_h; 150 | zend_long vim_w; 151 | zend_long vfilter_h; 152 | zend_long vfilter_w; 153 | 154 | if((batches*im_h*im_w*channels) 155 | !=images_size) { 156 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch images buffer size and images shape", 0); 157 | return -1; 158 | } 159 | out_h = ((im_h-(filter_h-1)*dilation_h-1)/stride_h)+1; 160 | out_w = ((im_w-(filter_w-1)*dilation_w-1)/stride_w)+1; 161 | if(out_h<=0 || out_w<=0) { 162 | zend_throw_exception(spl_ce_InvalidArgumentException, "Invalid shape or parameters.", 0); 163 | return -1; 164 | } 165 | if(padding) { 166 | if((batches* 167 | im_h*filter_h* 168 | im_w*filter_w* 169 | channels)!=cols_size) { 170 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch cols buffer size and images shape", 0); 171 | return -1; 172 | } 173 | padding_h = ((im_h-1)*stride_h-im_h+(filter_h-1)*dilation_h+1)/2; 174 | padding_w = ((im_w-1)*stride_w-im_w+(filter_w-1)*dilation_w+1)/2; 175 | out_h = im_h; 176 | out_w = im_w; 177 | } else { 178 | if((batches* 179 | out_h*filter_h* 180 | out_w*filter_w* 181 | channels)!=cols_size) { 182 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch cols buffer size and images shape", 0); 183 | return -1; 184 | } 185 | padding_h = 0; 186 | padding_w = 0; 187 | } 188 | if(channels_first) { 189 | im_w_step = 1; 190 | im_h_step = im_w; 191 | channel_step = im_w*im_h; 192 | batch_step = im_w*im_h*channels; 193 | } else { 194 | channel_step = 1; 195 | im_w_step = channels; 196 | im_h_step = channels*im_w; 197 | batch_step = channels*im_w*im_h; 198 | } 199 | stride_w_step = im_w_step*stride_w; 200 | stride_h_step = im_h_step*stride_h; 201 | filter_w_step = im_w_step*dilation_w; 202 | filter_h_step = im_h_step*dilation_h; 203 | 204 | if(cols_channels_first) { 205 | out_filter_step = 1; 206 | out_channel_step = filter_h*filter_w; 207 | } else { 208 | out_filter_step = channels; 209 | out_channel_step = 1; 210 | } 211 | out_cell_step = filter_h*filter_w*channels; 212 | 213 | batch_pos = images_offset-im_h_step*padding_h-im_w_step*padding_w; 214 | out_pos = cols_offset; 215 | 216 | vim_h = out_h*stride_h; 217 | vim_w = out_w*stride_w; 218 | vfilter_h = filter_h*dilation_h; 219 | vfilter_w = filter_w*dilation_w; 220 | 221 | for(batch=0; batchdtype!=php_interop_polite_math_matrix_dtype_float32 && 363 | images->dtype!=php_interop_polite_math_matrix_dtype_float64) { 364 | zend_throw_exception(spl_ce_InvalidArgumentException, 365 | "Unsupported data type", 0); 366 | return; 367 | } 368 | // Check dtype and Buffer Y 369 | if(images->dtype!=cols->dtype) { 370 | zend_throw_exception(spl_ce_InvalidArgumentException, 371 | "Unmatch data type of images and cols", 0); 372 | return; 373 | } 374 | if(images->sizedtype, images->data,(index_t)images_offset); 381 | void *pDataCols = rindow_matlib_common_get_address((dtype_t)cols->dtype, cols->data,(index_t)cols_offset); 382 | 383 | int32_t rc = rindow_matlib_im2col2d( 384 | (dtype_t)images->dtype, 385 | reverse, 386 | pDataImages, 387 | (index_t)images_size, 388 | (index_t)batches, 389 | 390 | (index_t)im_h, 391 | (index_t)im_w, 392 | (index_t)channels, 393 | (index_t)filter_h, 394 | (index_t)filter_w, 395 | 396 | (index_t)stride_h, 397 | (index_t)stride_w, 398 | padding, 399 | channels_first, 400 | (index_t)dilation_h, 401 | 402 | (index_t)dilation_w, 403 | cols_channels_first, 404 | pDataCols, 405 | (index_t)cols_size 406 | ); 407 | switch(rc) { 408 | case 0: { 409 | break; 410 | } 411 | case RINDOW_MATLIB_E_UNSUPPORTED_DATA_TYPE: { 412 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 413 | return; 414 | } 415 | case RINDOW_MATLIB_E_INVALID_SHAPE_OR_PARAM: { 416 | zend_throw_exception(spl_ce_InvalidArgumentException, "Invalid shape or parameters.", 0); 417 | return; 418 | } 419 | case RINDOW_MATLIB_E_UNMATCH_COLS_BUFFER_SIZE: { 420 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch cols buffer size and images shape", 0); 421 | return; 422 | } 423 | case RINDOW_MATLIB_E_UNMATCH_IMAGE_BUFFER_SIZE: { 424 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch images buffer size and images shape", 0); 425 | return; 426 | } 427 | case RINDOW_MATLIB_E_IMAGES_OUT_OF_RANGE: { 428 | zend_throw_exception(spl_ce_RuntimeException, "Images data out of range", 0); 429 | return; 430 | } 431 | case RINDOW_MATLIB_E_COLS_OUT_OF_RANGE: { 432 | zend_throw_exception(spl_ce_RuntimeException, "Cols data out of range", 0); 433 | return; 434 | } 435 | default: { 436 | zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Unkown Error (%d)", rc); 437 | return; 438 | } 439 | } 440 | 441 | /* 442 | im2col2d_execute( 443 | reverse, 444 | images, 445 | images_offset, 446 | images_size, 447 | batches, 448 | 449 | im_h, 450 | im_w, 451 | channels, 452 | filter_h, 453 | filter_w, 454 | 455 | stride_h, 456 | stride_w, 457 | padding, 458 | channels_first, 459 | dilation_h, 460 | 461 | dilation_w, 462 | cols_channels_first, 463 | cols, 464 | cols_offset, 465 | cols_size 466 | ); 467 | return; 468 | */ 469 | } 470 | /* }}} */ 471 | -------------------------------------------------------------------------------- /src/Rindow/OpenBLAS/Math_gather.c: -------------------------------------------------------------------------------- 1 | /* 2 | B(n,k) := A(X(n),k) 3 | 4 | Method Rindow\OpenBLAS\Math:: 5 | public function gather( 6 | bool $reverse, 7 | bool $addMode, 8 | int $n, 9 | int $k, 10 | int $numClass, 11 | Buffer $X, int $offsetX, 12 | Buffer $A, int $offsetA, 13 | Buffer $B, int $offsetB 14 | ) : void 15 | {{{ */ 16 | static PHP_METHOD(Math, gather) 17 | { 18 | zend_bool reverse; 19 | zend_bool addMode; 20 | zend_long n; 21 | zend_long k; 22 | zend_long numClass; 23 | zval* x; 24 | zend_long offsetX; 25 | zval* a; 26 | zend_long offsetA; 27 | zval* b; 28 | zend_long offsetB; 29 | php_interop_polite_math_matrix_linear_buffer_t* bufferX; 30 | php_interop_polite_math_matrix_linear_buffer_t* bufferA; 31 | php_interop_polite_math_matrix_linear_buffer_t* bufferB; 32 | 33 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 11, 11) 34 | Z_PARAM_BOOL(reverse) 35 | Z_PARAM_BOOL(addMode) 36 | Z_PARAM_LONG(n) 37 | Z_PARAM_LONG(k) 38 | Z_PARAM_LONG(numClass) 39 | Z_PARAM_OBJECT(x) // Interop\Polite\Math\Matrix\LinearBuffer 40 | Z_PARAM_LONG(offsetX) 41 | Z_PARAM_OBJECT(a) // Interop\Polite\Math\Matrix\LinearBuffer 42 | Z_PARAM_LONG(offsetA) 43 | Z_PARAM_OBJECT(b) // Interop\Polite\Math\Matrix\LinearBuffer 44 | Z_PARAM_LONG(offsetB) 45 | ZEND_PARSE_PARAMETERS_END(); 46 | 47 | if(php_rindow_openblas_assert_shape_parameter( 48 | "n", n)) { 49 | return; 50 | } 51 | if(php_rindow_openblas_assert_shape_parameter( 52 | "k", k)) { 53 | return; 54 | } 55 | if(numClass<=0) { 56 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument numClass must be greater than or equal 0.", 0); 57 | return; 58 | } 59 | 60 | // Check Buffer X 61 | bufferX = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(x); 62 | if(php_rindow_openblas_assert_buffer_type(bufferX,"x")) { 63 | return; 64 | } 65 | if(offsetX<0) { 66 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument offsetX must be greater than or equal 0.", 0); 67 | return; 68 | } 69 | if(offsetX+n > bufferX->size) { 70 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix X specification too large for buffer.", 0); 71 | return; 72 | } 73 | 74 | // Check Buffer A 75 | bufferA = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(a); 76 | if(php_rindow_openblas_assert_buffer_type(bufferA,"a")) { 77 | return; 78 | } 79 | if(offsetA<0) { 80 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument offsetA must be greater than or equal 0.", 0); 81 | return; 82 | } 83 | if(offsetA+numClass*k > bufferA->size) { 84 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix A specification too large for buffer.", 0); 85 | return; 86 | } 87 | 88 | // Check Buffer B 89 | bufferB = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(b); 90 | if(php_rindow_openblas_assert_buffer_type(bufferB,"b")) { 91 | return; 92 | } 93 | if(offsetB<0) { 94 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument offsetB must be greater than or equal 0.", 0); 95 | return; 96 | } 97 | if(offsetB+n*k > bufferB->size) { 98 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix B specification too large for buffer.", 0); 99 | return; 100 | } 101 | 102 | // Check Buffer A and Y 103 | if(bufferA->dtype!=bufferB->dtype) { 104 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch data type for A and B", 0); 105 | return; 106 | } 107 | if(bufferX->dtype==php_interop_polite_math_matrix_dtype_bool) { 108 | zend_throw_exception(spl_ce_InvalidArgumentException, "Data type of BufferX must not be bool", 0); 109 | return; 110 | } 111 | 112 | switch (bufferA->dtype) { 113 | case php_interop_polite_math_matrix_dtype_float32: { 114 | void *pDataX = rindow_matlib_common_get_address((dtype_t)bufferX->dtype, bufferX->data,(index_t)offsetX); 115 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataA,bufferA,offsetA) 116 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataB,bufferB,offsetB) 117 | if(pDataX==NULL) { 118 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type of label number.", 0); 119 | return; 120 | } 121 | int32_t errcode = rindow_matlib_s_gather(reverse,addMode,(index_t)n,(index_t)k,(index_t)numClass,(dtype_t)bufferX->dtype,pDataX,pDataA,pDataB); 122 | if(errcode) { 123 | if(errcode == RINDOW_MATLIB_E_UNSUPPORTED_DATA_TYPE) { 124 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type of label number.", 0); 125 | return; 126 | } else if(errcode == RINDOW_MATLIB_E_PERM_OUT_OF_RANGE) { 127 | zend_throw_exception(spl_ce_RuntimeException, "Label number is out of bounds.", 0); 128 | return; 129 | } else { 130 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Unknown error.(%d)", errcode); 131 | return; 132 | } 133 | } 134 | break; 135 | } 136 | case php_interop_polite_math_matrix_dtype_float64: { 137 | void *pDataX = rindow_matlib_common_get_address((dtype_t)bufferX->dtype, bufferX->data,(index_t)offsetX); 138 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataA,bufferA,offsetA) 139 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataB,bufferB,offsetB) 140 | if(pDataX==NULL) { 141 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type of label number.", 0); 142 | return; 143 | } 144 | int32_t errcode = rindow_matlib_d_gather(reverse,addMode,(index_t)n,(index_t)k,(index_t)numClass,(dtype_t)bufferX->dtype,pDataX,pDataA,pDataB); 145 | if(errcode) { 146 | if(errcode == RINDOW_MATLIB_E_UNSUPPORTED_DATA_TYPE) { 147 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type of label number.", 0); 148 | return; 149 | } else if(errcode == RINDOW_MATLIB_E_PERM_OUT_OF_RANGE) { 150 | zend_throw_exception(spl_ce_RuntimeException, "Label number is out of bounds.", 0); 151 | return; 152 | } else { 153 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Unknown error.: %d", errcode); 154 | return; 155 | } 156 | } 157 | break; 158 | } 159 | default: { 160 | if(!php_rindow_openblas_common_dtype_is_int(bufferA->dtype)&& 161 | !php_rindow_openblas_common_dtype_is_bool(bufferA->dtype)) { 162 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 163 | return; 164 | } 165 | void *pDataX = rindow_matlib_common_get_address((dtype_t)bufferX->dtype, bufferX->data,(index_t)offsetX); 166 | void *pDataA = rindow_matlib_common_get_address((dtype_t)bufferA->dtype, bufferA->data,(index_t)offsetA); 167 | void *pDataB = rindow_matlib_common_get_address((dtype_t)bufferB->dtype, bufferB->data,(index_t)offsetB); 168 | if(pDataX==NULL) { 169 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type of label number.", 0); 170 | return; 171 | } 172 | int32_t errcode = rindow_matlib_i_gather(reverse,addMode,(index_t)n,(index_t)k,(index_t)numClass,(dtype_t)bufferX->dtype,pDataX,(dtype_t)bufferA->dtype,pDataA,pDataB); 173 | if(errcode) { 174 | if(errcode == RINDOW_MATLIB_E_UNSUPPORTED_DATA_TYPE) { 175 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 176 | return; 177 | } else if(errcode == RINDOW_MATLIB_E_PERM_OUT_OF_RANGE) { 178 | zend_throw_exception(spl_ce_RuntimeException, "Label number is out of bounds.", 0); 179 | return; 180 | } else { 181 | zend_throw_exception(spl_ce_RuntimeException, "Unknown error.", 0); 182 | return; 183 | } 184 | } 185 | break; 186 | } 187 | } 188 | 189 | } 190 | 191 | /* 192 | B(m,n) := A(m,X(m,n)) 193 | 194 | public function reduceGather( 195 | bool $reverse, 196 | bool $addMode, 197 | int $m, 198 | int $n, 199 | int $numClass, 200 | Buffer $X, int $offsetX, 201 | Buffer $A, int $offsetA, 202 | Buffer $B, int $offsetB 203 | ) : void 204 | {{{ */ 205 | static PHP_METHOD(Math, reduceGather) 206 | { 207 | zend_bool reverse; 208 | zend_bool addMode; 209 | zend_long m; 210 | zend_long n; 211 | zend_long numClass; 212 | zval* x; 213 | zend_long offsetX; 214 | zval* a; 215 | zend_long offsetA; 216 | zval* b; 217 | zend_long offsetB; 218 | php_interop_polite_math_matrix_linear_buffer_t* bufferX; 219 | php_interop_polite_math_matrix_linear_buffer_t* bufferA; 220 | php_interop_polite_math_matrix_linear_buffer_t* bufferB; 221 | 222 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 11, 11) 223 | Z_PARAM_BOOL(reverse) 224 | Z_PARAM_BOOL(addMode) 225 | Z_PARAM_LONG(m) 226 | Z_PARAM_LONG(n) 227 | Z_PARAM_LONG(numClass) 228 | Z_PARAM_OBJECT(x) // Interop\Polite\Math\Matrix\LinearBuffer 229 | Z_PARAM_LONG(offsetX) 230 | Z_PARAM_OBJECT(a) // Interop\Polite\Math\Matrix\LinearBuffer 231 | Z_PARAM_LONG(offsetA) 232 | Z_PARAM_OBJECT(b) // Interop\Polite\Math\Matrix\LinearBuffer 233 | Z_PARAM_LONG(offsetB) 234 | ZEND_PARSE_PARAMETERS_END(); 235 | 236 | if(php_rindow_openblas_assert_shape_parameter( 237 | "m", m)) { 238 | return; 239 | } 240 | if(php_rindow_openblas_assert_shape_parameter( 241 | "n", n)) { 242 | return; 243 | } 244 | if(numClass<=0) { 245 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument numClass must be greater than or equal 0.", 0); 246 | return; 247 | } 248 | // Check Buffer X 249 | bufferX = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(x); 250 | if(php_rindow_openblas_assert_buffer_type(bufferX,"x")) { 251 | return; 252 | } 253 | if(offsetX<0) { 254 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument offsetX must be greater than or equal 0.", 0); 255 | return; 256 | } 257 | if(offsetX+m*n > bufferX->size) { 258 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix X specification too large for buffer.", 0); 259 | return; 260 | } 261 | 262 | // Check Buffer A 263 | bufferA = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(a); 264 | if(php_rindow_openblas_assert_buffer_type(bufferA,"a")) { 265 | return; 266 | } 267 | if(offsetA<0) { 268 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument offsetA must be greater than or equal 0.", 0); 269 | return; 270 | } 271 | if(offsetA+m*numClass > bufferA->size) { 272 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix A specification too large for buffer.", 0); 273 | return; 274 | } 275 | 276 | // Check Buffer B 277 | bufferB = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(b); 278 | if(php_rindow_openblas_assert_buffer_type(bufferB,"b")) { 279 | return; 280 | } 281 | if(offsetB<0) { 282 | zend_throw_exception(spl_ce_InvalidArgumentException, "Argument offsetB must be greater than or equal 0.", 0); 283 | return; 284 | } 285 | if(offsetB+m*n > bufferB->size) { 286 | zend_throw_exception(spl_ce_InvalidArgumentException, "Matrix B specification too large for buffer.", 0); 287 | return; 288 | } 289 | 290 | // Check Buffer A and Y 291 | if(bufferA->dtype!=bufferB->dtype) { 292 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch data type for A and B", 0); 293 | return; 294 | } 295 | if(bufferX->dtype==php_interop_polite_math_matrix_dtype_bool) { 296 | zend_throw_exception(spl_ce_InvalidArgumentException, "Data type of BufferX must not be bool", 0); 297 | return; 298 | } 299 | 300 | switch (bufferA->dtype) { 301 | case php_interop_polite_math_matrix_dtype_float32: { 302 | void *pDataX = rindow_matlib_common_get_address((dtype_t)bufferX->dtype, bufferX->data,(index_t)offsetX); 303 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataA,bufferA,offsetA) 304 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(float,pDataB,bufferB,offsetB) 305 | if(pDataX==NULL) { 306 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type of label number.", 0); 307 | return; 308 | } 309 | int32_t errcode = rindow_matlib_s_reducegather(reverse,addMode,(index_t)m,(index_t)n,(index_t)numClass,(dtype_t)bufferX->dtype,pDataX,pDataA,pDataB); 310 | if(errcode) { 311 | if(errcode == RINDOW_MATLIB_E_UNSUPPORTED_DATA_TYPE) { 312 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type of label number.", 0); 313 | return; 314 | } else if(errcode == RINDOW_MATLIB_E_PERM_OUT_OF_RANGE) { 315 | zend_throw_exception(spl_ce_RuntimeException, "Label number is out of bounds.", 0); 316 | return; 317 | } else { 318 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Unknown error.(%d)", errcode); 319 | return; 320 | } 321 | } 322 | break; 323 | } 324 | case php_interop_polite_math_matrix_dtype_float64: { 325 | void *pDataX = rindow_matlib_common_get_address((dtype_t)bufferX->dtype, bufferX->data,(index_t)offsetX); 326 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataA,bufferA,offsetA) 327 | PHP_RINDOW_OPENBLAS_MATH_DEFDATA_TEMPLATE(double,pDataB,bufferB,offsetB) 328 | if(pDataX==NULL) { 329 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type of label number.", 0); 330 | return; 331 | } 332 | int32_t errcode = rindow_matlib_d_reducegather(reverse,addMode,(index_t)m,(index_t)n,(index_t)numClass,(dtype_t)bufferX->dtype,pDataX,pDataA,pDataB); 333 | if(errcode) { 334 | if(errcode == RINDOW_MATLIB_E_UNSUPPORTED_DATA_TYPE) { 335 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type of label number.", 0); 336 | return; 337 | } else if(errcode == RINDOW_MATLIB_E_PERM_OUT_OF_RANGE) { 338 | zend_throw_exception(spl_ce_RuntimeException, "Label number is out of bounds.", 0); 339 | return; 340 | } else { 341 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Unknown error.: %d", errcode); 342 | return; 343 | } 344 | } 345 | break; 346 | } 347 | default: { 348 | if(!php_rindow_openblas_common_dtype_is_int(bufferA->dtype)&& 349 | !php_rindow_openblas_common_dtype_is_bool(bufferA->dtype)) { 350 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 351 | return; 352 | } 353 | void *pDataX = rindow_matlib_common_get_address((dtype_t)bufferX->dtype, bufferX->data,(index_t)offsetX); 354 | void *pDataA = rindow_matlib_common_get_address((dtype_t)bufferA->dtype, bufferA->data,(index_t)offsetA); 355 | void *pDataB = rindow_matlib_common_get_address((dtype_t)bufferB->dtype, bufferB->data,(index_t)offsetB); 356 | if(pDataX==NULL) { 357 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type of label number.", 0); 358 | return; 359 | } 360 | int32_t errcode = rindow_matlib_i_reducegather(reverse,addMode,(index_t)m,(index_t)n,(index_t)numClass,(dtype_t)bufferX->dtype,pDataX,(dtype_t)bufferA->dtype,pDataA,pDataB); 361 | if(errcode) { 362 | if(errcode == RINDOW_MATLIB_E_UNSUPPORTED_DATA_TYPE) { 363 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 364 | return; 365 | } else if(errcode == RINDOW_MATLIB_E_PERM_OUT_OF_RANGE) { 366 | zend_throw_exception(spl_ce_RuntimeException, "Label number is out of bounds.", 0); 367 | return; 368 | } else { 369 | zend_throw_exception(spl_ce_RuntimeException, "Unknown error.", 0); 370 | return; 371 | } 372 | } 373 | break; 374 | } 375 | } 376 | } 377 | /* }}} */ 378 | -------------------------------------------------------------------------------- /src/Rindow/OpenBLAS/Buffer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef HAVE_CONFIG_H 10 | #include "config.h" 11 | #endif 12 | 13 | #include "php_rindow_openblas.h" 14 | 15 | 16 | static zend_object_handlers rindow_openblas_buffer_object_handlers; 17 | 18 | // destractor 19 | static void php_rindow_openblas_buffer_free_object(zend_object* object) 20 | { 21 | php_interop_polite_math_matrix_linear_buffer_t* obj = php_interop_polite_math_matrix_linear_buffer_fetch_object(object); 22 | if (obj->data) { 23 | efree(obj->data); 24 | } 25 | zend_object_std_dtor(&obj->std); 26 | } 27 | 28 | // constructor 29 | static zend_object* php_rindow_openblas_buffer_create_object(zend_class_entry* class_type) /* {{{ */ 30 | { 31 | php_interop_polite_math_matrix_linear_buffer_t* intern = NULL; 32 | 33 | intern = (php_interop_polite_math_matrix_linear_buffer_t*)ecalloc(1, sizeof(php_interop_polite_math_matrix_linear_buffer_t) + zend_object_properties_size(class_type)); 34 | intern->signature = PHP_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_SIGNATURE; 35 | 36 | zend_object_std_init(&intern->std, class_type); 37 | object_properties_init(&intern->std, class_type); 38 | 39 | intern->std.handlers = &rindow_openblas_buffer_object_handlers; 40 | 41 | return &intern->std; 42 | } /* }}} */ 43 | 44 | static void php_rindow_openblas_buffer_do_set( 45 | php_interop_polite_math_matrix_linear_buffer_t* intern, 46 | zend_long offset, 47 | zend_long intvalue, 48 | double floatvalue) 49 | { 50 | switch(intern->dtype) { 51 | case php_interop_polite_math_matrix_dtype_bool: 52 | case php_interop_polite_math_matrix_dtype_int8: 53 | case php_interop_polite_math_matrix_dtype_uint8: 54 | { 55 | uint8_t* bufint8=(uint8_t*)intern->data; 56 | bufint8[offset]=(uint8_t)(intvalue & 0xff); 57 | } 58 | break; 59 | case php_interop_polite_math_matrix_dtype_int16: 60 | case php_interop_polite_math_matrix_dtype_uint16: 61 | { 62 | int16_t* bufint16=(int16_t*)intern->data; 63 | bufint16[offset]=(int16_t)(intvalue & 0xffff); 64 | } 65 | break; 66 | case php_interop_polite_math_matrix_dtype_int32: 67 | case php_interop_polite_math_matrix_dtype_uint32: 68 | { 69 | int32_t* bufint32=(int32_t*)intern->data; 70 | bufint32[offset]=(int32_t)(intvalue); 71 | } 72 | break; 73 | case php_interop_polite_math_matrix_dtype_int64: 74 | case php_interop_polite_math_matrix_dtype_uint64: 75 | { 76 | int64_t* bufint64=(int64_t*)intern->data; 77 | bufint64[offset]=(int64_t)(intvalue); 78 | } 79 | break; 80 | case php_interop_polite_math_matrix_dtype_float32: 81 | { 82 | float* buffloat32=(float*)intern->data; 83 | buffloat32[offset]=(float)floatvalue; 84 | } 85 | break; 86 | case php_interop_polite_math_matrix_dtype_float64: 87 | { 88 | double* buffloat64=(double*)intern->data; 89 | buffloat64[offset]=(double)floatvalue; 90 | } 91 | break; 92 | default: 93 | zend_throw_exception(spl_ce_InvalidArgumentException, "invalid dtype", 0); 94 | } 95 | } 96 | 97 | /* Method Rindow\OpenBLAS\Buffer::__construct($size,$dtype) {{{ */ 98 | static PHP_METHOD(Buffer, __construct) 99 | { 100 | php_interop_polite_math_matrix_linear_buffer_t* intern; 101 | zend_long size = 0; 102 | zend_long dtype = 0; 103 | 104 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) 105 | Z_PARAM_LONG(size) 106 | Z_PARAM_LONG(dtype) 107 | ZEND_PARSE_PARAMETERS_END(); 108 | 109 | switch(dtype) { 110 | case php_interop_polite_math_matrix_dtype_bool: 111 | case php_interop_polite_math_matrix_dtype_int8: 112 | case php_interop_polite_math_matrix_dtype_uint8: 113 | case php_interop_polite_math_matrix_dtype_int16: 114 | case php_interop_polite_math_matrix_dtype_uint16: 115 | case php_interop_polite_math_matrix_dtype_int32: 116 | case php_interop_polite_math_matrix_dtype_uint32: 117 | case php_interop_polite_math_matrix_dtype_int64: 118 | case php_interop_polite_math_matrix_dtype_uint64: 119 | case php_interop_polite_math_matrix_dtype_float32: 120 | case php_interop_polite_math_matrix_dtype_float64: 121 | break; 122 | default: 123 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 124 | return; 125 | } 126 | 127 | intern = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(getThis()); 128 | if(size<=0 || dtype<=0) { 129 | intern->size = 0; 130 | intern->dtype = 0; 131 | intern->data = NULL; 132 | zend_throw_exception(spl_ce_InvalidArgumentException, "The size must be at least 1 and The dtype must not be 0.", 0); 133 | return; 134 | } 135 | intern->size = size; 136 | intern->dtype = dtype; 137 | intern->value_size = php_rindow_openblas_common_dtype_to_valuesize(dtype); 138 | if(intern->value_size==0) { 139 | intern->data = NULL; 140 | return; 141 | } 142 | intern->data = ecalloc(size, intern->value_size); 143 | } 144 | /* }}} */ 145 | 146 | /* Method Rindow\OpenBLAS\Buffer::offsetExists($offset) {{{ */ 147 | static PHP_METHOD(Buffer, offsetExists) 148 | { 149 | php_interop_polite_math_matrix_linear_buffer_t* intern; 150 | zend_long offset; 151 | 152 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) 153 | Z_PARAM_LONG(offset) 154 | ZEND_PARSE_PARAMETERS_END(); 155 | 156 | intern = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(getThis()); 157 | if(intern->data==NULL) { 158 | zend_throw_exception(spl_ce_DomainException, "uninitialized array", 0); 159 | return; 160 | } 161 | if(offset<0 || offset>=intern->size) { 162 | RETURN_FALSE; 163 | } 164 | RETURN_TRUE; 165 | } 166 | /* }}} */ 167 | 168 | /* Method Rindow\OpenBLAS\Buffer::offsetGet($offset) {{{ */ 169 | static PHP_METHOD(Buffer, offsetGet) 170 | { 171 | php_interop_polite_math_matrix_linear_buffer_t* intern; 172 | zend_long offset; 173 | zend_long intvalue; 174 | double floatvalue; 175 | zend_bool boolvalue; 176 | 177 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) 178 | Z_PARAM_LONG(offset) 179 | ZEND_PARSE_PARAMETERS_END(); 180 | 181 | intern = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(getThis()); 182 | if(intern->data==NULL) { 183 | zend_throw_exception(spl_ce_DomainException, "uninitialized array", 0); 184 | return; 185 | } 186 | if(offset<0 || offset>=intern->size) { 187 | zend_throw_exception(spl_ce_OutOfRangeException, "Index invalid or out of range", 0); 188 | return; 189 | } 190 | switch(intern->dtype) { 191 | case php_interop_polite_math_matrix_dtype_bool: 192 | { 193 | uint8_t* bufbool=(uint8_t*)intern->data; 194 | boolvalue =(zend_bool)bufbool[offset]; 195 | } 196 | RETURN_BOOL(boolvalue); 197 | case php_interop_polite_math_matrix_dtype_int8: 198 | { 199 | int8_t* bufint8=(int8_t*)intern->data; 200 | intvalue =(zend_long)bufint8[offset]; 201 | } 202 | RETURN_LONG(intvalue); 203 | case php_interop_polite_math_matrix_dtype_uint8: 204 | { 205 | uint8_t* bufuint8=(uint8_t*)intern->data; 206 | intvalue =(zend_long)bufuint8[offset]; 207 | } 208 | RETURN_LONG(intvalue); 209 | case php_interop_polite_math_matrix_dtype_int16: 210 | { 211 | int16_t* bufint16=(int16_t*)intern->data; 212 | intvalue = (zend_long)bufint16[offset]; 213 | } 214 | RETURN_LONG(intvalue); 215 | case php_interop_polite_math_matrix_dtype_uint16: 216 | { 217 | uint16_t* bufuint16=(uint16_t*)intern->data; 218 | intvalue = (zend_long)bufuint16[offset]; 219 | } 220 | RETURN_LONG(intvalue); 221 | case php_interop_polite_math_matrix_dtype_int32: 222 | { 223 | int32_t* bufint32=(int32_t*)intern->data; 224 | intvalue = (zend_long)bufint32[offset]; 225 | } 226 | RETURN_LONG(intvalue); 227 | case php_interop_polite_math_matrix_dtype_uint32: 228 | { 229 | uint32_t* bufuint32=(uint32_t*)intern->data; 230 | intvalue = (zend_long)bufuint32[offset]; 231 | } 232 | RETURN_LONG(intvalue); 233 | case php_interop_polite_math_matrix_dtype_int64: 234 | { 235 | int64_t* bufint64=(int64_t*)intern->data; 236 | intvalue = (zend_long)bufint64[offset]; 237 | } 238 | RETURN_LONG(intvalue); 239 | case php_interop_polite_math_matrix_dtype_uint64: 240 | { 241 | uint64_t* bufuint64=(uint64_t*)intern->data; 242 | intvalue = (zend_long)bufuint64[offset]; 243 | } 244 | RETURN_LONG(intvalue); 245 | case php_interop_polite_math_matrix_dtype_float32: 246 | { 247 | float* buffloat32=(float*)intern->data; 248 | floatvalue = (double)buffloat32[offset]; 249 | } 250 | RETURN_DOUBLE(floatvalue); 251 | case php_interop_polite_math_matrix_dtype_float64: 252 | { 253 | double* buffloat64=(double*)intern->data; 254 | floatvalue = (double)buffloat64[offset]; 255 | } 256 | RETURN_DOUBLE(floatvalue); 257 | default: 258 | zend_throw_exception(spl_ce_InvalidArgumentException, "invalid dtype", 0); 259 | } 260 | } 261 | /* }}} */ 262 | 263 | /* Method Rindow\OpenBLAS\Buffer::offsetSet($offset,$value) {{{ */ 264 | static PHP_METHOD(Buffer, offsetSet) 265 | { 266 | php_interop_polite_math_matrix_linear_buffer_t* intern; 267 | zend_long offset; 268 | zend_long intvalue; 269 | double floatvalue; 270 | zend_bool boolvalue; 271 | 272 | intern = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(getThis()); 273 | if(intern->data==NULL) { 274 | zend_throw_exception(spl_ce_DomainException, "uninitialized array", 0); 275 | return; 276 | } 277 | if(php_rindow_openblas_common_dtype_is_int(intern->dtype)) { 278 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) 279 | Z_PARAM_LONG(offset) 280 | Z_PARAM_LONG(intvalue) 281 | ZEND_PARSE_PARAMETERS_END(); 282 | 283 | } else if(php_rindow_openblas_common_dtype_is_float(intern->dtype)) { 284 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) 285 | Z_PARAM_LONG(offset) 286 | Z_PARAM_DOUBLE(floatvalue) 287 | ZEND_PARSE_PARAMETERS_END(); 288 | 289 | } else if(php_rindow_openblas_common_dtype_is_bool(intern->dtype)) { 290 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) 291 | Z_PARAM_LONG(offset) 292 | Z_PARAM_BOOL(boolvalue) 293 | ZEND_PARSE_PARAMETERS_END(); 294 | 295 | if(boolvalue) { 296 | intvalue = 1; 297 | } else { 298 | intvalue = 0; 299 | } 300 | } else { 301 | zend_throw_exception(spl_ce_InvalidArgumentException, "invalid dtype", 0); 302 | return; 303 | } 304 | 305 | if(offset<0 || offset>=intern->size) { 306 | zend_throw_exception(spl_ce_OutOfRangeException, "Index invalid or out of range", 0); 307 | return; 308 | } 309 | php_rindow_openblas_buffer_do_set(intern,offset,intvalue,floatvalue); 310 | } 311 | 312 | /* }}} */ 313 | 314 | /* Method Rindow\OpenBLAS\Buffer::offsetUnset($offset) {{{ */ 315 | static PHP_METHOD(Buffer, offsetUnset) 316 | { 317 | php_interop_polite_math_matrix_linear_buffer_t* intern; 318 | zend_long offset; 319 | 320 | intern = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(getThis()); 321 | if(intern->data==NULL) { 322 | zend_throw_exception(spl_ce_DomainException, "uninitialized array", 0); 323 | return; 324 | } 325 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) 326 | Z_PARAM_LONG(offset) 327 | ZEND_PARSE_PARAMETERS_END(); 328 | 329 | if(offset<0 || offset>=intern->size) { 330 | return; 331 | } 332 | php_rindow_openblas_buffer_do_set(intern,offset,0,0.0); 333 | } 334 | /* }}} */ 335 | 336 | /* Method Rindow\OpenBLAS\Buffer::count() {{{ */ 337 | static PHP_METHOD(Buffer, count) 338 | { 339 | php_interop_polite_math_matrix_linear_buffer_t* intern; 340 | 341 | intern = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(getThis()); 342 | if(intern->data==NULL) { 343 | zend_throw_exception(spl_ce_DomainException, "uninitialized array", 0); 344 | return; 345 | } 346 | RETURN_LONG(intern->size); 347 | } 348 | /* }}} */ 349 | 350 | /* Method Rindow\OpenBLAS\Buffer::dtype() {{{ */ 351 | static PHP_METHOD(Buffer, dtype) 352 | { 353 | php_interop_polite_math_matrix_linear_buffer_t* intern; 354 | 355 | intern = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(getThis()); 356 | if(intern->data==NULL) { 357 | zend_throw_exception(spl_ce_DomainException, "uninitialized array", 0); 358 | return; 359 | } 360 | RETURN_LONG(intern->dtype); 361 | } 362 | /* }}} */ 363 | 364 | /* Method Rindow\OpenBLAS\Buffer::value_size() {{{ */ 365 | static PHP_METHOD(Buffer, value_size) 366 | { 367 | php_interop_polite_math_matrix_linear_buffer_t* intern; 368 | 369 | intern = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(getThis()); 370 | if(intern->data==NULL) { 371 | zend_throw_exception(spl_ce_DomainException, "uninitialized array", 0); 372 | return; 373 | } 374 | RETURN_LONG(intern->value_size); 375 | } 376 | /* }}} */ 377 | 378 | /* Method Rindow\OpenBLAS\Buffer::dump() : string {{{ */ 379 | static PHP_METHOD(Buffer, dump) 380 | { 381 | php_interop_polite_math_matrix_linear_buffer_t* intern; 382 | size_t len=0; 383 | 384 | intern = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(getThis()); 385 | if(intern->data==NULL) { 386 | zend_throw_exception(spl_ce_DomainException, "uninitialized array", 0); 387 | return; 388 | } 389 | 390 | len = intern->size * php_rindow_openblas_common_dtype_to_valuesize(intern->dtype); 391 | RETURN_STRINGL(intern->data,len); 392 | } 393 | /* }}} */ 394 | 395 | /* Method Rindow\OpenBLAS\Buffer::load(string $data) {{{ */ 396 | static PHP_METHOD(Buffer, load) 397 | { 398 | php_interop_polite_math_matrix_linear_buffer_t* intern; 399 | size_t len=0; 400 | char* str=NULL; 401 | 402 | intern = Z_INTEROP_POLITE_MATH_MATRIX_LINEAR_BUFFER_OBJ_P(getThis()); 403 | if(intern->data==NULL) { 404 | zend_throw_exception(spl_ce_DomainException, "uninitialized array", 0); 405 | return; 406 | } 407 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) 408 | Z_PARAM_STRING(str,len) 409 | ZEND_PARSE_PARAMETERS_END(); 410 | 411 | if(len != intern->size * php_rindow_openblas_common_dtype_to_valuesize(intern->dtype)) { 412 | zend_throw_exception(spl_ce_InvalidArgumentException, "unmatch data size", 0); 413 | return; 414 | } 415 | memcpy(intern->data,str,len); 416 | } 417 | /* }}} */ 418 | 419 | ZEND_BEGIN_ARG_INFO_EX(ai_Buffer___construct, 0, 0, 2) 420 | ZEND_ARG_INFO(0, size) 421 | ZEND_ARG_INFO(0, dtype) 422 | ZEND_END_ARG_INFO() 423 | 424 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_Buffer_offsetExists, 0, 1, _IS_BOOL, 0) 425 | ZEND_ARG_INFO(0, offset) 426 | ZEND_END_ARG_INFO() 427 | 428 | #if PHP_MAJOR_VERSION >= 8 429 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_Buffer_offsetGet, 0, 1, IS_MIXED, 0) 430 | ZEND_ARG_INFO(0, offset) 431 | ZEND_END_ARG_INFO() 432 | #else 433 | ZEND_BEGIN_ARG_INFO_EX(ai_Buffer_offsetGet, 0, 0, 1) 434 | ZEND_ARG_INFO(0, offset) 435 | ZEND_END_ARG_INFO() 436 | #endif 437 | 438 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_Buffer_offsetSet, 0, 2, IS_VOID, 0) 439 | ZEND_ARG_INFO(0, offset) 440 | ZEND_ARG_INFO(0, value) 441 | ZEND_END_ARG_INFO() 442 | 443 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_Buffer_offsetUnset, 0, 1, IS_VOID, 0) 444 | ZEND_ARG_INFO(0, offset) 445 | ZEND_END_ARG_INFO() 446 | 447 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_Buffer_count, 0, 0, IS_LONG, 0) 448 | ZEND_END_ARG_INFO() 449 | 450 | ZEND_BEGIN_ARG_INFO_EX(ai_Buffer_load, 0, 0, 1) 451 | ZEND_ARG_INFO(0, data) 452 | ZEND_END_ARG_INFO() 453 | 454 | ZEND_BEGIN_ARG_INFO_EX(ai_Buffer_void, 0, 0, 0) 455 | ZEND_END_ARG_INFO() 456 | 457 | /* {{{ Rindow\OpenBLAS\Buffer function entries */ 458 | static zend_function_entry php_rindow_openblas_buffer_me[] = { 459 | /* clang-format off */ 460 | PHP_ME(Buffer, __construct, ai_Buffer___construct, ZEND_ACC_PUBLIC) 461 | PHP_ME(Buffer, offsetExists, ai_Buffer_offsetExists, ZEND_ACC_PUBLIC) 462 | PHP_ME(Buffer, offsetGet, ai_Buffer_offsetGet, ZEND_ACC_PUBLIC) 463 | PHP_ME(Buffer, offsetSet, ai_Buffer_offsetSet, ZEND_ACC_PUBLIC) 464 | PHP_ME(Buffer, offsetUnset, ai_Buffer_offsetUnset, ZEND_ACC_PUBLIC) 465 | PHP_ME(Buffer, count, ai_Buffer_count, ZEND_ACC_PUBLIC) 466 | PHP_ME(Buffer, value_size, ai_Buffer_void, ZEND_ACC_PUBLIC) 467 | PHP_ME(Buffer, dtype, ai_Buffer_void, ZEND_ACC_PUBLIC) 468 | PHP_ME(Buffer, dump, ai_Buffer_void, ZEND_ACC_PUBLIC) 469 | PHP_ME(Buffer, load, ai_Buffer_void, ZEND_ACC_PUBLIC) 470 | PHP_FE_END 471 | /* clang-format on */ 472 | }; 473 | /* }}} */ 474 | 475 | /* Class Rindow\OpenBLAS\Buffer {{{ */ 476 | zend_class_entry* php_rindow_openblas_buffer_ce; 477 | 478 | void php_rindow_openblas_buffer_init_ce(INIT_FUNC_ARGS) 479 | { 480 | zend_class_entry ce; 481 | 482 | INIT_NS_CLASS_ENTRY(ce, "Rindow\\OpenBLAS", "Buffer", php_rindow_openblas_buffer_me); 483 | php_rindow_openblas_buffer_ce = zend_register_internal_class(&ce); 484 | php_rindow_openblas_buffer_ce->create_object = php_rindow_openblas_buffer_create_object; 485 | 486 | memcpy(&rindow_openblas_buffer_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 487 | rindow_openblas_buffer_object_handlers.offset = XtOffsetOf(php_interop_polite_math_matrix_linear_buffer_t, std); 488 | rindow_openblas_buffer_object_handlers.free_obj = php_rindow_openblas_buffer_free_object; 489 | rindow_openblas_buffer_object_handlers.clone_obj = NULL; 490 | 491 | zend_class_implements(php_rindow_openblas_buffer_ce, 2, zend_ce_arrayaccess, zend_ce_countable); 492 | } 493 | /* }}} */ 494 | -------------------------------------------------------------------------------- /src/Rindow/OpenBLAS/Math_im2col3d.c: -------------------------------------------------------------------------------- 1 | /* 2 | static inline int im2col3d_copyCell( 3 | zend_bool reverse, 4 | php_interop_polite_math_matrix_linear_buffer_t *images, 5 | zend_long images_pos, 6 | zend_long im_d, 7 | zend_long im_h, 8 | zend_long im_w, 9 | zend_long channels, 10 | zend_long channel_step, 11 | zend_long filter_d_step, 12 | zend_long filter_h_step, 13 | zend_long filter_w_step, 14 | zend_long vim_z, 15 | zend_long vim_y, 16 | zend_long vim_x, 17 | zend_long vfilter_d, 18 | zend_long vfilter_h, 19 | zend_long vfilter_w, 20 | zend_long dilation_d, 21 | zend_long dilation_h, 22 | zend_long dilation_w, 23 | php_interop_polite_math_matrix_linear_buffer_t *out, 24 | zend_long out_pos, 25 | zend_long out_filter_step, 26 | zend_long out_channel_step 27 | ) 28 | { 29 | zend_long vfilter_z; 30 | zend_long vfilter_y; 31 | zend_long vfilter_x; 32 | zend_long filter_d_pos; 33 | zend_long filter_h_pos; 34 | zend_long filter_w_pos; 35 | zend_long out_filter_pos; 36 | zend_long input_z; 37 | zend_long input_y; 38 | zend_long input_x; 39 | zend_long channel_pos; 40 | zend_long out_channel_pos; 41 | zend_long c; 42 | 43 | filter_d_pos = images_pos; 44 | out_filter_pos = out_pos; 45 | for(vfilter_z=0; vfilter_z=im_d || 57 | input_y<0 || input_y>=im_h || 58 | input_x<0 || input_x>=im_w) { 59 | if(out_channel_pos<0 ||out_channel_pos>=out->size) { 60 | zend_throw_exception(spl_ce_RuntimeException, "cols data out of range", 0); 61 | return -1; 62 | } 63 | if(!reverse) { 64 | if(images->dtype== php_interop_polite_math_matrix_dtype_float32) { 65 | ((float*)(out->data))[out_channel_pos] 66 | = 0; 67 | } else { 68 | ((double*)(out->data))[out_channel_pos] 69 | = 0; 70 | } 71 | } 72 | } else { 73 | if(channel_pos<0 ||channel_pos>=images->size) { 74 | zend_throw_exception(spl_ce_RuntimeException, "images data out of range", 0); 75 | return -1; 76 | } 77 | if(out_channel_pos<0 ||out_channel_pos>=out->size) { 78 | zend_throw_exception(spl_ce_RuntimeException, "cols data out of range", 0); 79 | return -1; 80 | } 81 | if(!reverse) { 82 | if(images->dtype== php_interop_polite_math_matrix_dtype_float32) { 83 | ((float*)(out->data))[out_channel_pos] 84 | = ((float*)(images->data))[channel_pos]; 85 | } else { 86 | ((double*)(out->data))[out_channel_pos] 87 | = ((double*)(images->data))[channel_pos]; 88 | } 89 | } else { 90 | // Sum for Back propagation 91 | if(images->dtype== php_interop_polite_math_matrix_dtype_float32) { 92 | ((float*)(images->data))[channel_pos] 93 | += ((float*)(out->data))[out_channel_pos]; 94 | } else { 95 | ((double*)(images->data))[channel_pos] 96 | += ((double*)(out->data))[out_channel_pos]; 97 | } 98 | } 99 | } 100 | out_channel_pos += out_channel_step; 101 | channel_pos += channel_step; 102 | } 103 | out_filter_pos += out_filter_step; 104 | filter_w_pos += filter_w_step; 105 | } 106 | filter_h_pos += filter_h_step; 107 | } 108 | filter_d_pos += filter_d_step; 109 | } 110 | return 0; 111 | } 112 | 113 | static inline int im2col3d_execute( 114 | zend_bool reverse, 115 | php_interop_polite_math_matrix_linear_buffer_t* images, 116 | zend_long images_offset, 117 | zend_long images_size, 118 | zend_long batches, 119 | 120 | zend_long im_d, 121 | zend_long im_h, 122 | zend_long im_w, 123 | zend_long channels, 124 | zend_long filter_d, 125 | 126 | zend_long filter_h, 127 | zend_long filter_w, 128 | zend_long stride_d, 129 | zend_long stride_h, 130 | zend_long stride_w, 131 | 132 | zend_bool padding, 133 | zend_bool channels_first, 134 | zend_long dilation_d, 135 | zend_long dilation_h, 136 | zend_long dilation_w, 137 | 138 | zend_bool cols_channels_first, 139 | php_interop_polite_math_matrix_linear_buffer_t* cols, 140 | zend_long cols_offset, 141 | zend_long cols_size 142 | ) 143 | { 144 | zend_long out_d; 145 | zend_long out_h; 146 | zend_long out_w; 147 | zend_long stride_d_step; 148 | zend_long stride_h_step; 149 | zend_long stride_w_step; 150 | zend_long batch_step; 151 | zend_long channel_step; 152 | zend_long filter_d_step; 153 | zend_long filter_h_step; 154 | zend_long filter_w_step; 155 | zend_long out_filter_step; 156 | zend_long out_channel_step; 157 | zend_long out_cell_step; 158 | zend_long out_pos; 159 | zend_long batch_pos; 160 | zend_long padding_d; 161 | zend_long padding_h; 162 | zend_long padding_w; 163 | zend_long im_d_step; 164 | zend_long im_w_step; 165 | zend_long im_h_step; 166 | 167 | zend_long batch; 168 | zend_long stride_d_pos; 169 | zend_long stride_h_pos; 170 | zend_long stride_w_pos; 171 | zend_long vim_z; 172 | zend_long vim_y; 173 | zend_long vim_x; 174 | zend_long vim_d; 175 | zend_long vim_h; 176 | zend_long vim_w; 177 | zend_long vfilter_d; 178 | zend_long vfilter_h; 179 | zend_long vfilter_w; 180 | 181 | if((batches*im_d*im_h*im_w*channels) 182 | !=images_size) { 183 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch images buffer size and images shape", 0); 184 | return -1; 185 | } 186 | out_d = ((im_d-(filter_d-1)*dilation_d-1)/stride_d)+1; 187 | out_h = ((im_h-(filter_h-1)*dilation_h-1)/stride_h)+1; 188 | out_w = ((im_w-(filter_w-1)*dilation_w-1)/stride_w)+1; 189 | if(out_d<=0 || out_h<=0 || out_w<=0) { 190 | zend_throw_exception(spl_ce_InvalidArgumentException, "Invalid shape or parameters.", 0); 191 | return -1; 192 | } 193 | if(padding) { 194 | if((batches* 195 | im_d*filter_d* 196 | im_h*filter_h* 197 | im_w*filter_w* 198 | channels)!=cols_size) { 199 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch cols buffer size and images shape", 0); 200 | return -1; 201 | } 202 | padding_d = ((im_d-1)*stride_d-im_d+(filter_d-1)*dilation_d+1)/2; 203 | padding_h = ((im_h-1)*stride_h-im_h+(filter_h-1)*dilation_h+1)/2; 204 | padding_w = ((im_w-1)*stride_w-im_w+(filter_w-1)*dilation_w+1)/2; 205 | out_d = im_d; 206 | out_h = im_h; 207 | out_w = im_w; 208 | } else { 209 | if((batches* 210 | out_d*filter_d* 211 | out_h*filter_h* 212 | out_w*filter_w* 213 | channels)!=cols_size) { 214 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch cols buffer size and images shape", 0); 215 | return -1; 216 | } 217 | padding_d = 0; 218 | padding_h = 0; 219 | padding_w = 0; 220 | } 221 | if(channels_first) { 222 | im_w_step = 1; 223 | im_h_step = im_w; 224 | im_d_step = im_w*im_h; 225 | channel_step = im_w*im_h*im_d; 226 | batch_step = im_w*im_h*im_d*channels; 227 | } else { 228 | channel_step = 1; 229 | im_w_step = channels; 230 | im_h_step = channels*im_w; 231 | im_d_step = channels*im_w*im_h; 232 | batch_step = channels*im_w*im_h*im_d; 233 | } 234 | stride_d_step = im_d_step*stride_d; 235 | stride_w_step = im_w_step*stride_w; 236 | stride_h_step = im_h_step*stride_h; 237 | filter_d_step = im_d_step*dilation_d; 238 | filter_w_step = im_w_step*dilation_w; 239 | filter_h_step = im_h_step*dilation_h; 240 | 241 | if(cols_channels_first) { 242 | out_filter_step = 1; 243 | out_channel_step = filter_d*filter_h*filter_w; 244 | } else { 245 | out_filter_step = channels; 246 | out_channel_step = 1; 247 | } 248 | out_cell_step = filter_d*filter_h*filter_w*channels; 249 | 250 | batch_pos = images_offset-im_d_step*padding_d-im_h_step*padding_h-im_w_step*padding_w; 251 | out_pos = cols_offset; 252 | 253 | vim_d = out_d*stride_d; 254 | vim_h = out_h*stride_h; 255 | vim_w = out_w*stride_w; 256 | vfilter_d = filter_d*dilation_d; 257 | vfilter_h = filter_h*dilation_h; 258 | vfilter_w = filter_w*dilation_w; 259 | 260 | for(batch=0; batchdtype!=php_interop_polite_math_matrix_dtype_float32 && 424 | images->dtype!=php_interop_polite_math_matrix_dtype_float64) { 425 | zend_throw_exception(spl_ce_InvalidArgumentException, 426 | "Unsupported data type", 0); 427 | return; 428 | } 429 | // Check dtype and Buffer Y 430 | if(images->dtype!=cols->dtype) { 431 | zend_throw_exception(spl_ce_InvalidArgumentException, 432 | "Unmatch data type of images and cols", 0); 433 | return; 434 | } 435 | if(images->sizedtype, images->data,(index_t)images_offset); 442 | void *pDataCols = rindow_matlib_common_get_address((dtype_t)cols->dtype, cols->data,(index_t)cols_offset); 443 | 444 | int32_t rc = rindow_matlib_im2col3d( 445 | (dtype_t)images->dtype, 446 | reverse, 447 | pDataImages, 448 | (index_t)images_size, 449 | (index_t)batches, 450 | 451 | (index_t)im_d, 452 | (index_t)im_h, 453 | (index_t)im_w, 454 | (index_t)channels, 455 | (index_t)filter_d, 456 | 457 | (index_t)filter_h, 458 | (index_t)filter_w, 459 | (index_t)stride_d, 460 | (index_t)stride_h, 461 | (index_t)stride_w, 462 | 463 | padding, 464 | channels_first, 465 | (index_t)dilation_d, 466 | (index_t)dilation_h, 467 | (index_t)dilation_w, 468 | 469 | cols_channels_first, 470 | pDataCols, 471 | (index_t)cols_size 472 | ); 473 | switch(rc) { 474 | case 0: { 475 | break; 476 | } 477 | case RINDOW_MATLIB_E_UNSUPPORTED_DATA_TYPE: { 478 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unsupported data type.", 0); 479 | return; 480 | } 481 | case RINDOW_MATLIB_E_INVALID_SHAPE_OR_PARAM: { 482 | zend_throw_exception(spl_ce_InvalidArgumentException, "Invalid shape or parameters.", 0); 483 | return; 484 | } 485 | case RINDOW_MATLIB_E_UNMATCH_COLS_BUFFER_SIZE: { 486 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch cols buffer size and images shape", 0); 487 | return; 488 | } 489 | case RINDOW_MATLIB_E_UNMATCH_IMAGE_BUFFER_SIZE: { 490 | zend_throw_exception(spl_ce_InvalidArgumentException, "Unmatch images buffer size and images shape", 0); 491 | return; 492 | } 493 | case RINDOW_MATLIB_E_IMAGES_OUT_OF_RANGE: { 494 | zend_throw_exception(spl_ce_RuntimeException, "Images data out of range", 0); 495 | return; 496 | } 497 | case RINDOW_MATLIB_E_COLS_OUT_OF_RANGE: { 498 | zend_throw_exception(spl_ce_RuntimeException, "Cols data out of range", 0); 499 | return; 500 | } 501 | default: { 502 | zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Unkown Error (%d)", rc); 503 | return; 504 | } 505 | } 506 | 507 | /* 508 | im2col3d_execute( 509 | reverse, 510 | images, 511 | images_offset, 512 | images_size, 513 | batches, 514 | 515 | im_d, 516 | im_h, 517 | im_w, 518 | channels, 519 | filter_d, 520 | 521 | filter_h, 522 | filter_w, 523 | stride_d, 524 | stride_h, 525 | stride_w, 526 | 527 | padding, 528 | channels_first, 529 | dilation_d, 530 | dilation_h, 531 | dilation_w, 532 | 533 | cols_channels_first, 534 | cols, 535 | cols_offset, 536 | cols_size 537 | ); 538 | return; 539 | */ 540 | } 541 | /* }}} */ 542 | --------------------------------------------------------------------------------