2828/* 1D full convolution: y = conv(a, child), where a is a length-m kernel
2929 * held by param_source and child is a length-n vector. Output length is
3030 * m + n - 1. In matrix form, y = T(a) @ child, where T(a) is the
31- * (m+n-1) x n Toeplitz matrix with T(a)[k, j] = a[k-j] when 0 <= k-j < m.
32- *
33- * Forward and Hessian backprop (w' = T(a)^T w) are direct loops, avoiding
34- * CSR traversal and AT materialization. Jacobian values go through the
35- * existing block-left-mult path so composite children work correctly.
36- *
37- * When param_source is updatable, forward() refreshes T(a)'s CSR values
38- * from the new kernel before running the convolution. The sparsity of
39- * T(a) is kernel-independent (staircase), so only values are rewritten. */
31+ * (m+n-1) x n Toeplitz/convolution matrix with T(a)[k, j] = a[k-j] when
32+ * 0 <= k-j < m. */
4033
4134static void forward (expr * node , const double * u )
4235{
@@ -118,17 +111,14 @@ static void eval_wsum_hess(expr *node, const double *w)
118111{
119112 expr * child = node -> left ;
120113 convolve_expr * cnode = (convolve_expr * ) node ;
121- int m = cnode -> m ;
122- int n = cnode -> n ;
123114 const double * a = cnode -> param_source -> value ;
124115 double * w_prime = node -> work -> dwork ;
125116
126- /* w' = T(a)^T w. T(a)^T[j, k] = a[k-j] for j <= k < j+m, so
127- w'[j] = sum_{i=0..m-1} a[i] * w[i + j]. */
128- for (int j = 0 ; j < n ; j ++ )
117+ /* w' = conv_matrix.T w, so w'[j] = sum_{i=0..m-1} a[i] * w[i + j]. */
118+ for (int j = 0 ; j < cnode -> n ; j ++ )
129119 {
130120 double sum = 0.0 ;
131- for (int i = 0 ; i < m ; i ++ )
121+ for (int i = 0 ; i < cnode -> m ; i ++ )
132122 {
133123 sum += a [i ] * w [i + j ];
134124 }
@@ -160,18 +150,18 @@ expr *new_convolve(expr *param_node, expr *child)
160150 is shape-agnostic (flat buffers of size m + n - 1). Output shape
161151 matches the input orientation. */
162152 int m = param_node -> size ;
163- int n , out_d1 , out_d2 ;
153+ int n , d1 , d2 ;
164154 if (child -> d2 == 1 )
165155 {
166156 n = child -> d1 ;
167- out_d1 = m + n - 1 ;
168- out_d2 = 1 ;
157+ d1 = m + n - 1 ;
158+ d2 = 1 ;
169159 }
170160 else if (child -> d1 == 1 )
171161 {
172162 n = child -> d2 ;
173- out_d1 = 1 ;
174- out_d2 = m + n - 1 ;
163+ d1 = 1 ;
164+ d2 = m + n - 1 ;
175165 }
176166 else
177167 {
@@ -180,15 +170,9 @@ expr *new_convolve(expr *param_node, expr *child)
180170 exit (1 );
181171 }
182172
183- if (m < 1 || n < 1 )
184- {
185- fprintf (stderr , "Error in new_convolve: m and n must be >= 1\n" );
186- exit (1 );
187- }
188-
189173 convolve_expr * cnode = (convolve_expr * ) SP_CALLOC (1 , sizeof (convolve_expr ));
190174 expr * node = & cnode -> base ;
191- init_expr (node , out_d1 , out_d2 , child -> n_vars , forward , jacobian_init_impl ,
175+ init_expr (node , d1 , d2 , child -> n_vars , forward , jacobian_init_impl ,
192176 eval_jacobian , is_affine , wsum_hess_init_impl , eval_wsum_hess ,
193177 free_type_data );
194178 node -> left = child ;
0 commit comments