#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "kernel/operators.h" /** * 1D convolution between a vector A and B (kernel) with a given stride. * * @param return_value * @param a * @param b * @param stride */ void tensor_convolve_1d(zval * return_value, zval * a, zval * b, zval * stride) { unsigned int i, j; unsigned int jmin, jmax; double sigma; zval c; zend_array * aa = Z_ARR_P(a); zend_array * ab = Z_ARR_P(b); Bucket * ba = aa->arData; Bucket * bb = ab->arData; unsigned int s = zephir_get_intval(stride); unsigned int na = zend_array_count(aa); unsigned int nb = zend_array_count(ab); unsigned int nc = na + nb - 1; double * va = emalloc(na * sizeof(double)); double * vb = emalloc(nb * sizeof(double)); for (i = 0; i < na; ++i) { va[i] = zephir_get_doubleval(&ba[i].val); } for (i = 0; i < nb; ++i) { vb[i] = zephir_get_doubleval(&bb[i].val); } array_init_size(&c, nc / s); for (i = 0; i < nc; i += s) { jmin = i >= nb - 1 ? i - (nb - 1) : 0; jmax = i <= na ? i : na - 1; sigma = 0.0; for (j = jmin; j <= jmax; ++j) { sigma += va[j] * vb[i - j]; } add_next_index_double(&c, sigma); } RETVAL_ARR(Z_ARR(c)); efree(va); efree(vb); } /** * 2D convolution between a matrix A and B (kernel) with a given stride using the "same" method for zero padding. * * @param return_value * @param a * @param b * @param stride */ void tensor_convolve_2d(zval * return_value, zval * a, zval * b, zval * stride) { unsigned int i, j, k, l; int x, y; double sigma; Bucket * row; zval rowC, c; zend_array * aa = Z_ARR_P(a); zend_array * ab = Z_ARR_P(b); Bucket * ba = aa->arData; Bucket * bb = ab->arData; unsigned int s = zephir_get_intval(stride); unsigned int ma = zend_array_count(aa); unsigned int na = zend_array_count(Z_ARR(ba[0].val)); unsigned int mb = zend_array_count(ab); unsigned int nb = zend_array_count(Z_ARR(bb[0].val)); double * va = emalloc(ma * na * sizeof(double)); double * vb = emalloc(mb * nb * sizeof(double)); for (i = 0; i < ma; ++i) { row = Z_ARR(ba[i].val)->arData; for (j = 0; j < na; ++j) { va[i * na + j] = zephir_get_doubleval(&row[j].val); } } for (i = 0; i < mb; ++i) { row = Z_ARR(bb[i].val)->arData; for (j = 0; j < nb; ++j) { vb[i * nb + j] = zephir_get_doubleval(&row[j].val); } } unsigned int p = mb / 2; unsigned int q = nb / 2; array_init_size(&c, ma / s); for (i = 0; i < ma; i += s) { array_init_size(&rowC, na / s); for (j = 0; j < na; j += s) { sigma = 0.0; for (k = 0; k < mb; ++k) { x = i + p - k; if (x < 0 || x >= ma) { continue; } for (l = 0; l < nb; ++l) { y = j + q - l; if (y >= 0 && y < na) { sigma += va[x * na + y] * vb[k * nb + l]; } } } add_next_index_double(&rowC, sigma); } add_next_index_zval(&c, &rowC); } RETVAL_ARR(Z_ARR(c)); efree(va); efree(vb); }