|
1 | 1 | #include <math.h> |
2 | 2 | #include <stdio.h> |
| 3 | +#include <string.h> |
3 | 4 |
|
4 | 5 | #include "atoms/affine.h" |
| 6 | +#include "atoms/elementwise_full_dom.h" |
5 | 7 | #include "atoms/elementwise_restricted_dom.h" |
6 | 8 | #include "expr.h" |
7 | 9 | #include "minunit.h" |
@@ -63,3 +65,89 @@ const char *test_jacobian_convolve_composite(void) |
63 | 65 | free_expr(y); |
64 | 66 | return 0; |
65 | 67 | } |
| 68 | + |
| 69 | +const char *test_jacobian_convolve_csc_consumer(void) |
| 70 | +{ |
| 71 | + /* y = B @ conv([1, 2, 3], exp(x)) with B a sparse CSR: the left matmul |
| 72 | + * (n_blocks = 1) reads conv's Jacobian through its CSC mirror. Checking at |
| 73 | + * two points catches a mirror left stale by the second evaluation. */ |
| 74 | + double kernel[3] = {1.0, 2.0, 3.0}; |
| 75 | + double u1[3] = {0.1, 0.2, 0.3}; |
| 76 | + double u2[3] = {-0.4, 0.5, 1.0}; |
| 77 | + |
| 78 | + CSR_matrix *B = new_CSR_matrix(2, 5, 5); |
| 79 | + int Bp[3] = {0, 3, 5}; |
| 80 | + int Bi[5] = {0, 2, 4, 1, 3}; |
| 81 | + double Bx[5] = {1.0, -2.0, 0.5, 3.0, 1.5}; |
| 82 | + memcpy(B->p, Bp, 3 * sizeof(int)); |
| 83 | + memcpy(B->i, Bi, 5 * sizeof(int)); |
| 84 | + memcpy(B->x, Bx, 5 * sizeof(double)); |
| 85 | + |
| 86 | + expr *kernel_param = new_parameter(3, 1, PARAM_FIXED, 3, kernel); |
| 87 | + expr *x = new_variable(3, 1, 0, 3); |
| 88 | + expr *conv = new_convolve(kernel_param, new_exp(x)); |
| 89 | + expr *y = new_left_matmul(NULL, conv, B); |
| 90 | + |
| 91 | + mu_assert("check_jacobian failed at u1", |
| 92 | + check_jacobian_num(y, u1, NUMERICAL_DIFF_DEFAULT_H)); |
| 93 | + mu_assert("check_jacobian failed at u2", |
| 94 | + check_jacobian_num(y, u2, NUMERICAL_DIFF_DEFAULT_H)); |
| 95 | + |
| 96 | + free_expr(y); |
| 97 | + free_CSR_matrix(B); |
| 98 | + return 0; |
| 99 | +} |
| 100 | + |
| 101 | +const char *test_jacobian_convolve_pd_child(void) |
| 102 | +{ |
| 103 | + /* y = conv([1, 2, 3], exp(D @ x)) with D dense: the child Jacobian is |
| 104 | + * permuted_dense, and so is conv's. */ |
| 105 | + double kernel[3] = {1.0, 2.0, 3.0}; |
| 106 | + double D[12] = {1.0, -0.5, 2.0, 0.5, 1.5, -1.0, 0.3, 0.2, -0.7, -1.2, 0.4, 0.9}; |
| 107 | + double u[3] = {0.1, -0.2, 0.3}; |
| 108 | + |
| 109 | + expr *kernel_param = new_parameter(3, 1, PARAM_FIXED, 3, kernel); |
| 110 | + expr *x = new_variable(3, 1, 0, 3); |
| 111 | + expr *child = new_exp(new_left_matmul_dense(NULL, x, 4, 3, D)); |
| 112 | + expr *y = new_convolve(kernel_param, child); |
| 113 | + |
| 114 | + jacobian_init(y); |
| 115 | + mu_assert("child jacobian must be permuted_dense", |
| 116 | + child->jacobian->kind == MATRIX_PERMUTED_DENSE); |
| 117 | + mu_assert("jacobian must be permuted_dense", |
| 118 | + y->jacobian->kind == MATRIX_PERMUTED_DENSE); |
| 119 | + mu_assert("check_jacobian failed", |
| 120 | + check_jacobian_num(y, u, NUMERICAL_DIFF_DEFAULT_H)); |
| 121 | + |
| 122 | + free_expr(y); |
| 123 | + return 0; |
| 124 | +} |
| 125 | + |
| 126 | +const char *test_jacobian_convolve_spd_child(void) |
| 127 | +{ |
| 128 | + /* y = conv([1, 2, 3], exp(vec(A @ X))) with X a 3x2 matrix variable: the |
| 129 | + * dense left matmul has n_blocks = 2, so the child Jacobian is stacked_pd, |
| 130 | + * and so is conv's. */ |
| 131 | + double kernel[3] = {1.0, 2.0, 3.0}; |
| 132 | + double A[6] = {1.0, -0.5, 2.0, 0.5, 1.5, -1.0}; |
| 133 | + double u1[6] = {0.1, 0.2, 0.3, -0.1, -0.2, -0.3}; |
| 134 | + double u2[6] = {0.4, -0.3, 0.2, 0.1, 0.3, -0.4}; |
| 135 | + |
| 136 | + expr *kernel_param = new_parameter(3, 1, PARAM_FIXED, 6, kernel); |
| 137 | + expr *X = new_variable(3, 2, 0, 6); |
| 138 | + expr *child = |
| 139 | + new_exp(new_reshape(new_left_matmul_dense(NULL, X, 2, 3, A), 4, 1)); |
| 140 | + expr *y = new_convolve(kernel_param, child); |
| 141 | + |
| 142 | + jacobian_init(y); |
| 143 | + mu_assert("child jacobian must be stacked_pd", |
| 144 | + child->jacobian->kind == MATRIX_STACKED_PD); |
| 145 | + mu_assert("jacobian must be stacked_pd", y->jacobian->kind == MATRIX_STACKED_PD); |
| 146 | + mu_assert("check_jacobian failed at u1", |
| 147 | + check_jacobian_num(y, u1, NUMERICAL_DIFF_DEFAULT_H)); |
| 148 | + mu_assert("check_jacobian failed at u2", |
| 149 | + check_jacobian_num(y, u2, NUMERICAL_DIFF_DEFAULT_H)); |
| 150 | + |
| 151 | + free_expr(y); |
| 152 | + return 0; |
| 153 | +} |
0 commit comments