commit df8ca9971a06d0f5cdb6ac99e96101b692c054d3 Author: Jakub Zelenka Date: Sun Dec 16 18:05:48 2012 +0000 Initial commit with working simple_test.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c32047e --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.libs/ +.svnignore +.deps +*.lo +*.la \ No newline at end of file diff --git a/CREDITS b/CREDITS new file mode 100644 index 0000000..6afe2fa --- /dev/null +++ b/CREDITS @@ -0,0 +1 @@ +fann \ No newline at end of file diff --git a/EXPERIMENTAL b/EXPERIMENTAL new file mode 100644 index 0000000..e69de29 diff --git a/config.m4 b/config.m4 new file mode 100644 index 0000000..aee024f --- /dev/null +++ b/config.m4 @@ -0,0 +1,52 @@ +dnl $Id$ +dnl config.m4 for extension fann + +PHP_ARG_WITH(fann, for fann support, +[ --with-fann Include fann support]) + +if test "$PHP_FANN" != "no"; then + + SEARCH_PATH="/usr/local /usr /local /opt" + SEARCH_FOR="/include/fann.h" + + if test "$PHP_FANN" = "yes"; then + AC_MSG_CHECKING([for libfann headers in default path]) + for i in $SEARCH_PATH ; do + if test -r $i/$SEARCH_FOR; then + FANN_DIR=$i + AC_MSG_RESULT(found in $i) + fi + done + else + AC_MSG_CHECKING([for libfann headers in $PHP_FANN]) + if test -r $PHP_FANN/$SEARCH_FOR; then + FANN_DIR=$PHP_FANN + AC_MSG_RESULT([found]) + fi + fi + + if test -z "$FANN_DIR"; then + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([Cannot find libfann headers]) + fi + + PHP_ADD_INCLUDE($FANN_DIR/include) + + LIBNAME=fann + LIBSYMBOL=fann_create_standard + + PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, + [ + PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $FANN_DIR/$PHP_LIBDIR, FANN_SHARED_LIBADD) + AC_DEFINE(HAVE_FANN,1,[ ]) + ],[ + AC_MSG_ERROR([wrong libfann version or lib not found]) + ],[ + -L$FANN_DIR/$PHP_LIBDIR -lm + ]) + + PHP_SUBST(FANN_SHARED_LIBADD) + + PHP_NEW_EXTENSION(fann, fann.c, $ext_shared) +fi + diff --git a/config.w32 b/config.w32 new file mode 100644 index 0000000..009b727 --- /dev/null +++ b/config.w32 @@ -0,0 +1,12 @@ +// $Id$ +// vim:ft=javascript + +ARG_WITH("fann", "for fann support", "yes"); + +if (PHP_FANN == "yes") { + if (CHECK_LIB("libfann.lib", "fann_create_standard") && + CHECK_HEADER_ADD_INCLUDE("fann.h", "CFLAGS_FANN")) { + + EXTENSION("fann", "fann.c"); + } +} \ No newline at end of file diff --git a/examples/simple_test.php b/examples/simple_test.php new file mode 100644 index 0000000..6391512 --- /dev/null +++ b/examples/simple_test.php @@ -0,0 +1,6 @@ + %f\n", $input[0], $input[1], $calc_out[0]); +fann_destroy($ann); \ No newline at end of file diff --git a/examples/xor_float.net b/examples/xor_float.net new file mode 100644 index 0000000..83b96d0 --- /dev/null +++ b/examples/xor_float.net @@ -0,0 +1,36 @@ +FANN_FLO_2.1 +num_layers=3 +learning_rate=0.700000 +connection_rate=1.000000 +network_type=0 +learning_momentum=0.000000 +training_algorithm=2 +train_error_function=1 +train_stop_function=1 +cascade_output_change_fraction=0.010000 +quickprop_decay=-0.000100 +quickprop_mu=1.750000 +rprop_increase_factor=1.200000 +rprop_decrease_factor=0.500000 +rprop_delta_min=0.000000 +rprop_delta_max=50.000000 +rprop_delta_zero=0.100000 +cascade_output_stagnation_epochs=12 +cascade_candidate_change_fraction=0.010000 +cascade_candidate_stagnation_epochs=12 +cascade_max_out_epochs=150 +cascade_min_out_epochs=50 +cascade_max_cand_epochs=150 +cascade_min_cand_epochs=50 +cascade_num_candidate_groups=2 +bit_fail_limit=9.99999977648258209229e-03 +cascade_candidate_limit=1.00000000000000000000e+03 +cascade_weight_multiplier=4.00000005960464477539e-01 +cascade_activation_functions_count=10 +cascade_activation_functions=3 5 7 8 10 11 14 15 16 17 +cascade_activation_steepnesses_count=4 +cascade_activation_steepnesses=2.50000000000000000000e-01 5.00000000000000000000e-01 7.50000000000000000000e-01 1.00000000000000000000e+00 +layer_sizes=3 4 2 +scale_included=0 +neurons (num_inputs, activation_function, activation_steepness)=(0, 0, 0.00000000000000000000e+00) (0, 0, 0.00000000000000000000e+00) (0, 0, 0.00000000000000000000e+00) (3, 5, 1.00000000000000000000e+00) (3, 5, 1.00000000000000000000e+00) (3, 5, 1.00000000000000000000e+00) (0, 5, 1.00000000000000000000e+00) (4, 5, 1.00000000000000000000e+00) (0, 5, 1.00000000000000000000e+00) +connections (connected_to_neuron, weight)=(0, 2.27071380615234375000e+00) (1, 1.48452591896057128906e+00) (2, 2.38130116462707519531e+00) (0, -2.08913373947143554688e+00) (1, 1.92993474006652832031e+00) (2, -1.92381155490875244141e+00) (0, -1.34361982345581054688e-01) (1, 1.02422714233398437500e+00) (2, 1.95691734552383422852e-01) (3, 3.28824639320373535156e+00) (4, 3.42872691154479980469e+00) (5, -3.84175777435302734375e+00) (6, 1.89344108104705810547e-01) diff --git a/fann.c b/fann.c new file mode 100644 index 0000000..c48a60f --- /dev/null +++ b/fann.c @@ -0,0 +1,281 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "php_fann.h" +#include "floatfann.h" + +/* If you declare any globals in php_fann.h uncomment this: +ZEND_DECLARE_MODULE_GLOBALS(fann) +*/ + +/* True global resources - no need for thread safety here */ +static int le_fannbuf; +#define le_fannbuf_name "FANN Buffer" + +/* {{{ arginfo */ +ZEND_BEGIN_ARG_INFO(arginfo_fann_create_from_file, 0) +ZEND_ARG_INFO(0, configuration_file) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_fann_run, 0) +ZEND_ARG_INFO(0, ann) +ZEND_ARG_INFO(0, info) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_fann_destroy, 0) +ZEND_ARG_INFO(0, ann) +ZEND_END_ARG_INFO() +/* }}} */ + +/* {{{ fann_functions[] */ +const zend_function_entry fann_functions[] = { + PHP_FE(confirm_fann_compiled, NULL) + PHP_FE(fann_create_from_file, arginfo_fann_create_from_file) + PHP_FE(fann_run, arginfo_fann_run) + PHP_FE(fann_destroy, arginfo_fann_destroy) + PHP_FE_END +}; +/* }}} */ + +/* {{{ fann_module_entry */ +zend_module_entry fann_module_entry = { +#if ZEND_MODULE_API_NO >= 20010901 + STANDARD_MODULE_HEADER, +#endif + "fann", + fann_functions, + PHP_MINIT(fann), + PHP_MSHUTDOWN(fann), + NULL, + NULL, + PHP_MINFO(fann), +#if ZEND_MODULE_API_NO >= 20010901 + "0.1", +#endif + STANDARD_MODULE_PROPERTIES +}; +/* }}} */ + +#ifdef COMPILE_DL_FANN +ZEND_GET_MODULE(fann) +#endif + +/* {{{ PHP_INI + */ +/* Remove comments and fill if you need to have entries in php.ini +PHP_INI_BEGIN() + STD_PHP_INI_ENTRY("fann.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_fann_globals, fann_globals) + STD_PHP_INI_ENTRY("fann.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_fann_globals, fann_globals) +PHP_INI_END() +*/ +/* }}} */ + +/* {{{ php_fann_init_globals + */ +/* Uncomment this function if you have INI entries +static void php_fann_init_globals(zend_fann_globals *fann_globals) +{ + fann_globals->global_value = 0; + fann_globals->global_string = NULL; +} +*/ +/* }}} */ + +static void fann_destructor_fannbuf(zend_rsrc_list_entry *rsrc TSRMLS_DC) +{ + struct fann *ann = (struct fann *) rsrc->ptr; + fann_destroy(ann); +} + +#define PHP_FANN_ERROR_CHECK(ann) \ +if (fann_get_errno((struct fann_error *) ann) != 0) { \ + php_error_docref(NULL TSRMLS_CC, E_WARNING, fann_get_errstr((struct fann_error *) ann)); \ + RETURN_FALSE; \ +} + +/* {{{ PHP_MINIT_FUNCTION + */ +PHP_MINIT_FUNCTION(fann) +{ + le_fannbuf = zend_register_list_destructors_ex(fann_destructor_fannbuf, NULL, le_fannbuf_name, module_number); + + /* If you have INI entries, uncomment these lines + REGISTER_INI_ENTRIES(); + */ + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_MSHUTDOWN_FUNCTION + */ +PHP_MSHUTDOWN_FUNCTION(fann) +{ + /* uncomment this line if you have INI entries + UNREGISTER_INI_ENTRIES(); + */ + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_MINFO_FUNCTION + */ +PHP_MINFO_FUNCTION(fann) +{ + php_info_print_table_start(); + php_info_print_table_header(2, "fann support", "enabled"); + php_info_print_table_end(); + + /* Remove comments if you have entries in php.ini + DISPLAY_INI_ENTRIES(); + */ +} +/* }}} */ + + +/* {{{ proto string confirm_fann_compiled(string arg) + Confirms that fann is compiled */ +PHP_FUNCTION(confirm_fann_compiled) +{ + char *arg = NULL; + int arg_len, len; + char *strg; + + fann_type *calc_out; + fann_type input[2]; + + struct fann *ann = fann_create_from_file("/home/jakub/prog/fann/examples/xor_float.net"); + + input[0] = 1; + input[1] = -1; + calc_out = fann_run(ann, input); + + php_printf("xor test (%f,%f) -> %f\n", input[0], input[1], calc_out[0]); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { + return; + } + + len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "fann", arg); + RETURN_STRINGL(strg, len, 0); +} +/* }}} */ + +/* {{{ proto resource fann_create_from_file(string configuration_file) + Initializes neural network from configuration file */ +PHP_FUNCTION(fann_create_from_file) +{ + char *cf_name = NULL; + int cf_name_len; + FILE *cf_file; + struct fann *ann; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &cf_name, &cf_name_len) == FAILURE) { + return; + } + + cf_file = fopen(cf_name, "r"); + if (!cf_file) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "File cannot be opened for reading"); + RETURN_FALSE; + } + fclose(cf_file); + + if (!(ann = fann_create_from_file(cf_name))) { + RETURN_FALSE; + } + + ZEND_REGISTER_RESOURCE(return_value, ann, le_fannbuf); +} +/* }}} */ + + +/* {{{ proto resource fann_run(string configuration_file) + Runs input through the neural network */ +PHP_FUNCTION(fann_run) +{ + zval *z_ann, *array, **elem; + HashPosition pos; + struct fann *ann; + float *input, *calc_out; + int c = 0, num_out = 0; + + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra", &z_ann, &array) == FAILURE) { + return; + } + + ZEND_FETCH_RESOURCE(ann, struct fann *, &z_ann, -1, le_fannbuf_name, le_fannbuf); + + input = (float *) emalloc(sizeof(float) * zend_hash_num_elements(Z_ARRVAL_P(array))); + + for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos); + zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **) &elem, &pos) == SUCCESS; + zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos)) { + convert_to_double(*elem); + input[c++] = Z_DVAL_PP(elem); + } + + calc_out = fann_run(ann, input); + + num_out = fann_get_num_output(ann); + array_init(return_value); + for (c = 0; c < num_out; c++) { + add_next_index_double(return_value, calc_out[c]); + } + + efree(input); + + PHP_FANN_ERROR_CHECK(ann); +} +/* }}} */ + + +/* {{{ proto resource fann_create_from_file(string configuration_file) + Destroys neural network */ +PHP_FUNCTION(fann_destroy) +{ + zval *z_ann; + struct fann *ann; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_ann) == FAILURE) { + return; + } + + ZEND_FETCH_RESOURCE(ann, struct fann *, &z_ann, -1, le_fannbuf_name, le_fannbuf); + + RETURN_BOOL(zend_list_delete(Z_LVAL_P(z_ann)) == SUCCESS); +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/fann.php b/fann.php new file mode 100644 index 0000000..141fe0f --- /dev/null +++ b/fann.php @@ -0,0 +1,21 @@ +"; + +if(!extension_loaded('fann')) { + dl('fann.' . PHP_SHLIB_SUFFIX); +} +$module = 'fann'; +$functions = get_extension_funcs($module); +echo "Functions available in the test extension:$br\n"; +foreach($functions as $func) { + echo $func."$br\n"; +} +echo "$br\n"; +$function = 'confirm_' . $module . '_compiled'; +if (extension_loaded($module)) { + $str = $function($module); +} else { + $str = "Module $module is not compiled into PHP"; +} +echo "$str\n"; +?> diff --git a/php_fann.h b/php_fann.h new file mode 100644 index 0000000..de37f63 --- /dev/null +++ b/php_fann.h @@ -0,0 +1,86 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef PHP_FANN_H +#define PHP_FANN_H + +extern zend_module_entry fann_module_entry; +#define phpext_fann_ptr &fann_module_entry + +#ifdef PHP_WIN32 +# define PHP_FANN_API __declspec(dllexport) +#elif defined(__GNUC__) && __GNUC__ >= 4 +# define PHP_FANN_API __attribute__ ((visibility("default"))) +#else +# define PHP_FANN_API +#endif + +#ifdef ZTS +#include "TSRM.h" +#endif + +PHP_MINIT_FUNCTION(fann); +PHP_MSHUTDOWN_FUNCTION(fann); +PHP_RINIT_FUNCTION(fann); +PHP_RSHUTDOWN_FUNCTION(fann); +PHP_MINFO_FUNCTION(fann); + +PHP_FUNCTION(confirm_fann_compiled); +PHP_FUNCTION(fann_create_from_file); +PHP_FUNCTION(fann_run); +PHP_FUNCTION(fann_destroy); + +/* + Declare any global variables you may need between the BEGIN + and END macros here: + +ZEND_BEGIN_MODULE_GLOBALS(fann) + long global_value; + char *global_string; +ZEND_END_MODULE_GLOBALS(fann) +*/ + +/* In every utility function you add that needs to use variables + in php_fann_globals, call TSRMLS_FETCH(); after declaring other + variables used by that function, or better yet, pass in TSRMLS_CC + after the last function argument and declare your utility function + with TSRMLS_DC after the last declared argument. Always refer to + the globals in your function as FANN_G(variable). You are + encouraged to rename these macros something shorter, see + examples in any other php module directory. +*/ + +#ifdef ZTS +#define FANN_G(v) TSRMG(fann_globals_id, zend_fann_globals *, v) +#else +#define FANN_G(v) (fann_globals.v) +#endif + +#endif /* PHP_FANN_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/tests/001.phpt b/tests/001.phpt new file mode 100644 index 0000000..86ba652 --- /dev/null +++ b/tests/001.phpt @@ -0,0 +1,21 @@ +--TEST-- +Check for fann presence +--SKIPIF-- + +--FILE-- + +--EXPECT-- +fann extension is available