├── 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 |
--------------------------------------------------------------------------------