diff --git a/README.md b/README.md index ad3114f..bb75092 100644 --- a/README.md +++ b/README.md @@ -71,9 +71,28 @@ var_dump($landmarks); ``` +#### chinese whisers + +Provides raw access to dlib's `chinese_whispers` function. +Client need to build and provide edges. Edges are provided +as numeric array. Each element of this array should also be +numeric array with 2 elements of long type. + +Returned value is also numeric array, containing obtained labels. + +```php + +#include +#include + +using namespace dlib; +using namespace std; + +PHP_FUNCTION(dlib_chinese_whispers) +{ + zval *edges_arg; + HashTable *edges_arg_hash; + + std::vector edges; + std::vector labels; + + if(zend_parse_parameters(ZEND_NUM_ARGS(), "a", &edges_arg) == FAILURE){ + zend_throw_exception_ex( + zend_ce_exception, + 0 TSRMLS_CC, + "Unable to parse edges in dlib_chinese_whispers"); + return; + } + + edges_arg_hash = Z_ARRVAL_P(edges_arg); + + try { + HashPosition pos; + zval *edge; + HashTable *edge_hash; + + // Iterate for all given edges, check if they are valid and put them to edges + // + for ( + zend_hash_internal_pointer_reset_ex(edges_arg_hash, &pos); + (edge = zend_hash_get_current_data_ex(edges_arg_hash, &pos)) != nullptr; + zend_hash_move_forward_ex(edges_arg_hash, &pos)) { + // Check that each given edge is actually array + // + if (Z_TYPE_P(edge) != IS_ARRAY) { + zend_throw_exception_ex( + zend_ce_exception, + 0 TSRMLS_CC, + "Each edge provided in array needs to be numeric array of 2 elements"); + return; + } + + edge_hash = Z_ARRVAL_P(edge); + + // Check that there are two elements in this edge + // + if (zend_hash_num_elements(edge_hash) != 2) { + zend_throw_exception_ex( + zend_ce_exception, + 0 TSRMLS_CC, + "Edges need to contain exactly two elements"); + return; + } + + // Check that this is regular array with integer keys + // + if (!zend_hash_index_exists(edge_hash, 0) || + !zend_hash_index_exists(edge_hash, 1)) { + zend_throw_exception_ex( + zend_ce_exception, + 0 TSRMLS_CC, + "Edge should be numeric array with integer keys"); + return; + } + + zval *elem_i = zend_hash_index_find(edge_hash, 0); + zval *elem_j = zend_hash_index_find(edge_hash, 1); + + // Check that both elements in array are longs + if ((Z_TYPE_P(elem_i) != IS_LONG) || (Z_TYPE_P(elem_j) != IS_LONG)) { + zend_throw_exception_ex( + zend_ce_exception, + 0 TSRMLS_CC, + "Both elements in each edge must be of long type"); + return; + } + + // Finally, put extracted elements to edges + edges.push_back(sample_pair(Z_LVAL_P(elem_i), Z_LVAL_P(elem_j))); + } + + chinese_whispers(edges, labels); + + // Preparing and generating response array containing labels + // + array_init(return_value); + for (auto label = labels.begin(); label != labels.end(); label++) { + add_next_index_long(return_value, *label); + } + } catch (exception& e) + { + zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, e.what()); + return; + } +} + diff --git a/src/chinese_whispers.h b/src/chinese_whispers.h new file mode 100644 index 0000000..ec38e62 --- /dev/null +++ b/src/chinese_whispers.h @@ -0,0 +1,13 @@ +// +// Created by branko at kokanovic dot org on 2018/7/19. +// + +#ifndef PHP_DLIB_CHINESE_WHISPERS_H +#define PHP_DLIB_CHINESE_WHISPERS_H + +ZEND_BEGIN_ARG_INFO_EX(dlib_chinese_whispers_arginfo, 0, 0, 1) + ZEND_ARG_INFO(0, edges) +ZEND_END_ARG_INFO() +PHP_FUNCTION(dlib_chinese_whispers); + +#endif //PHP_DLIB_CHINESE_WHISPERS_H diff --git a/tests/chinese_whispers_basic.phpt b/tests/chinese_whispers_basic.phpt new file mode 100644 index 0000000..5f8e58d --- /dev/null +++ b/tests/chinese_whispers_basic.phpt @@ -0,0 +1,27 @@ +--TEST-- +Basic tests for chinese_whispers +--SKIPIF-- + +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + int(0) +} +array(2) { + [0]=> + int(0) + [1]=> + int(1) +} +array(2) { + [0]=> + int(0) + [1]=> + int(0) +} diff --git a/tests/chinese_whispers_edge_associative_array_error.phpt b/tests/chinese_whispers_edge_associative_array_error.phpt new file mode 100644 index 0000000..ac7cd1d --- /dev/null +++ b/tests/chinese_whispers_edge_associative_array_error.phpt @@ -0,0 +1,13 @@ +--TEST-- +Edge given in edges array for chinese_whispers functions is associative array +--SKIPIF-- + +--FILE-- +0, "bar"=>1]]); +} catch (Exception $e) { + var_dump($e->getMessage()); +} +--EXPECT-- +string(46) "Edge should be numeric array with integer keys" diff --git a/tests/chinese_whispers_edge_elements_not_long.phpt b/tests/chinese_whispers_edge_elements_not_long.phpt new file mode 100644 index 0000000..9b06728 --- /dev/null +++ b/tests/chinese_whispers_edge_elements_not_long.phpt @@ -0,0 +1,19 @@ +--TEST-- +Edge elements given in edges array for chinese_whispers functions are not of long type +--SKIPIF-- + +--FILE-- +getMessage()); +} +try { + dlib_chinese_whispers([[0,0], [1, 1.1]]); +} catch (Exception $e) { + var_dump($e->getMessage()); +} +--EXPECT-- +string(47) "Both elements in each edge must be of long type" +string(47) "Both elements in each edge must be of long type" diff --git a/tests/chinese_whispers_edge_not_2_element_error.phpt b/tests/chinese_whispers_edge_not_2_element_error.phpt new file mode 100644 index 0000000..d46de75 --- /dev/null +++ b/tests/chinese_whispers_edge_not_2_element_error.phpt @@ -0,0 +1,20 @@ +--TEST-- +Edge given in edges array for chinese_whispers functions is not having all values to be arrays with 2 elements +--SKIPIF-- + +--FILE-- +getMessage()); +} +try { + dlib_chinese_whispers([[0,0], [1,1,1]]); +} catch (Exception $e) { + var_dump($e->getMessage()); +} +?> +--EXPECT-- +string(42) "Edges need to contain exactly two elements" +string(42) "Edges need to contain exactly two elements" diff --git a/tests/chinese_whispers_edge_not_array_error.phpt b/tests/chinese_whispers_edge_not_array_error.phpt new file mode 100644 index 0000000..01c4a8c --- /dev/null +++ b/tests/chinese_whispers_edge_not_array_error.phpt @@ -0,0 +1,21 @@ +--TEST-- +Edge given in edges array is not array for chinese_whispers functions +--SKIPIF-- + +--FILE-- +getMessage()); +} + +try { + dlib_chinese_whispers([[0,0], 1]); +} catch (Exception $e) { + var_dump($e->getMessage()); +} +?> +--EXPECT-- +string(67) "Each edge provided in array needs to be numeric array of 2 elements" +string(67) "Each edge provided in array needs to be numeric array of 2 elements" diff --git a/tests/chinese_whispers_wrong_arg_type_error.phpt b/tests/chinese_whispers_wrong_arg_type_error.phpt new file mode 100644 index 0000000..15fb21a --- /dev/null +++ b/tests/chinese_whispers_wrong_arg_type_error.phpt @@ -0,0 +1,15 @@ +--TEST-- +Args given to chinese_whispers functions is not correct +--SKIPIF-- + +--FILE-- +getMessage()); +} +?> +--EXPECT-- +Warning: dlib_chinese_whispers() expects parameter 1 to be array, string given in /home/branko/pdlib/tests/chinese_whispers_wrong_arg_type_error.php on line 3 +string(46) "Unable to parse edges in dlib_chinese_whispers"