Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NDArray::standard_normal() 'expects at most 3 arguments' bugfix #54

Merged
52 changes: 35 additions & 17 deletions numpower.c
Original file line number Diff line number Diff line change
Expand Up @@ -953,31 +953,51 @@ PHP_METHOD(NDArray, random_binomial) {
RETURN_NDARRAY(rtn, return_value);
}


/**
* NDArray::standard_normal
*
* @param execute_data
* @param return_value
* @param shape
*/
ZEND_BEGIN_ARG_INFO_EX(arginfo_ndarray_standard_normal, 0, 0, 1)
ZEND_ARG_INFO(0, size)
ZEND_BEGIN_ARG_INFO(arginfo_ndarray_standard_normal, 1)
ZEND_ARG_ARRAY_INFO(0, shape, 0)
ZEND_END_ARG_INFO()

PHP_METHOD(NDArray, standard_normal) {
NDArray *rtn = NULL;
int *shape;
zval* size;
ZEND_PARSE_PARAMETERS_START(1, 3)
Z_PARAM_ZVAL(size)
zval* shape;
HashTable *shape_ht;
zend_string *key;
zend_ulong idx;
zval *val;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY(shape)
ZEND_PARSE_PARAMETERS_END();
NDArray *nda = ZVAL_TO_NDARRAY(size);
if (nda == NULL) return;
shape = emalloc(sizeof(int) * NDArray_NUMELEMENTS(nda));
for (int i = 0; i < NDArray_NUMELEMENTS(nda); i++) {
shape[i] = (int) NDArray_DDATA(nda)[i];

shape_ht = Z_ARRVAL_P(shape);

ZEND_HASH_FOREACH_KEY_VAL(shape_ht, idx, key, val) {
if (Z_TYPE_P(val) != IS_LONG) {
zend_throw_error(NULL, "Invalid parameter: Shape elements must be integers.");
return;
}
} ZEND_HASH_FOREACH_END();

NDArray *nda = ZVAL_TO_NDARRAY(shape);

if (nda == NULL) {
return;
}
rtn = NDArray_StandardNormal(shape, NDArray_NUMELEMENTS(nda));

if (NDArray_NUMELEMENTS(nda) == 0) {
NDArray_FREE(nda);
zend_throw_error(NULL, "Invalid parameter: Expected a non-empty array.");
return;
}

rtn = NDArray_StandardNormal(NDArray_ToIntVector(nda), NDArray_NUMELEMENTS(nda));
NDArray_FREE(nda);

RETURN_NDARRAY(rtn, return_value);
}

Expand Down Expand Up @@ -1303,8 +1323,6 @@ PHP_METHOD(NDArray, allclose) {
RETURN_BOOL(rtn);
}



/**
* NDArray::transpose
*
Expand Down
196 changes: 196 additions & 0 deletions tests/random/001-ndarray-standard_normal.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
--TEST--
NDArray::standard_normal
--FILE--
<?php
use NDArray as nd;

new class
{
public function __construct()
{
$this->testCase1();
$this->testCase2();
$this->testCase3();
$this->testCase4();
$this->testCase5();
}

/**
* Successful creation.
*/
private function testCase1(): void
{
echo '--- CASE 1 ---' . PHP_EOL;
$dataset = self::case1DataProvider();
foreach ($dataset as $sk => $shape) {
nd::standard_normal($shape);
echo "successful creation with $sk" . PHP_EOL;
}
echo PHP_EOL;
}

private static function case1DataProvider(): array
{
return [
'1-dim' => [1],
'2-dim' => [2, 3],
'3-dim' => [2, 3, 4],
];
}

/**
* An exception is thrown when parameter has an invalid type.
*/
private function testCase2(): void
{
echo '--- CASE 2 ---' . PHP_EOL;
$dataset = self::case2DataProvider();
foreach ($dataset as $condition => $data) {
try {
nd::standard_normal($data);
} catch (\Throwable $t) {
echo "Error when passed " . $condition. ": " . $t->getMessage() . PHP_EOL;
}
}
echo PHP_EOL;
}

private static function case2DataProvider(): array
{
return [
'shape is integer' => 1,
'shape is double' => 3.5,
'shape is string' => 'test',
'shape is boolean' => true,
'shape is null' => null,
'shape is object' => (object) [],
];
}

/**
* An exception is thrown when passing an array with elements of an invalid type.
*/
private function testCase3(): void
{
echo '--- CASE 3 ---' . PHP_EOL;
$dataset = self::case3DataProvider();
foreach ($dataset as $condition => $data) {
try {
nd::standard_normal([$data]);
} catch (\Throwable $t) {
echo "Error when shape " . $condition . ": " . $t->getMessage() . PHP_EOL;
}
}
echo PHP_EOL;
}

private static function case3DataProvider(): array
{
return [
'value is array' => [],
'value is float' => 3.5,
'value is string' => 'test',
'value is boolean' => true,
'value is null' => null,
'value is object' => (object) [],
];
}

/**
* An exception is thrown when passing an empty array.
*/
private function testCase4(): void
{
echo '--- CASE 4 ---' . PHP_EOL;
try {
nd::standard_normal([]);
} catch (\Throwable $t) {
echo $t->getMessage() . PHP_EOL;
}
echo PHP_EOL;
}

/**
* The resulting array has the correct number of dimensions and
* each dimension contains only integers.
*/
private function testCase5(): void
{
echo '--- CASE 5 ---' . PHP_EOL;
$a = nd::standard_normal([4]);

echo "Shape is: " . count($a->toArray()) . PHP_EOL;

foreach ($a->toArray() as $elk => $el) {
if (is_float($el)) {
echo "element " . $elk + 1 . " is double" . PHP_EOL;
}
}

$a = nd::standard_normal([4, 4]);

foreach ($a->toArray() as $k => $el) {
echo "Shape level of element " . $k + 1 . " is: " . count($el) . PHP_EOL;
}

foreach ($a->toArray() as $elk => $el) {
foreach ($el as $selk => $subEl) {
if (is_float($subEl)) {
echo "sub-element " . $selk . " of element " . $elk + 1 . " is double" . PHP_EOL;
}
}
}
}
};
?>
--EXPECT--
--- CASE 1 ---
successful creation with 1-dim
successful creation with 2-dim
successful creation with 3-dim

--- CASE 2 ---
Error when passed shape is integer: NDArray::standard_normal(): Argument #1 ($shape) must be of type array, int given
Error when passed shape is double: NDArray::standard_normal(): Argument #1 ($shape) must be of type array, float given
Error when passed shape is string: NDArray::standard_normal(): Argument #1 ($shape) must be of type array, string given
Error when passed shape is boolean: NDArray::standard_normal(): Argument #1 ($shape) must be of type array, true given
Error when passed shape is null: NDArray::standard_normal(): Argument #1 ($shape) must be of type array, null given
Error when passed shape is object: NDArray::standard_normal(): Argument #1 ($shape) must be of type array, stdClass given

--- CASE 3 ---
Error when shape value is array: Invalid parameter: Shape elements must be integers.
Error when shape value is float: Invalid parameter: Shape elements must be integers.
Error when shape value is string: Invalid parameter: Shape elements must be integers.
Error when shape value is boolean: Invalid parameter: Shape elements must be integers.
Error when shape value is null: Invalid parameter: Shape elements must be integers.
Error when shape value is object: Invalid parameter: Shape elements must be integers.

--- CASE 4 ---
Invalid parameter: Expected a non-empty array.

--- CASE 5 ---
Shape is: 4
element 1 is double
element 2 is double
element 3 is double
element 4 is double
Shape level of element 1 is: 4
Shape level of element 2 is: 4
Shape level of element 3 is: 4
Shape level of element 4 is: 4
sub-element 0 of element 1 is double
sub-element 1 of element 1 is double
sub-element 2 of element 1 is double
sub-element 3 of element 1 is double
sub-element 0 of element 2 is double
sub-element 1 of element 2 is double
sub-element 2 of element 2 is double
sub-element 3 of element 2 is double
sub-element 0 of element 3 is double
sub-element 1 of element 3 is double
sub-element 2 of element 3 is double
sub-element 3 of element 3 is double
sub-element 0 of element 4 is double
sub-element 1 of element 4 is double
sub-element 2 of element 4 is double
sub-element 3 of element 4 is double
Loading