|
| 1 | +#include <math.h> |
| 2 | +#include <stdio.h> |
| 3 | + |
| 4 | +#include "affine.h" |
| 5 | +#include "elementwise_univariate.h" |
| 6 | +#include "expr.h" |
| 7 | +#include "minunit.h" |
| 8 | +#include "test_helpers.h" |
| 9 | + |
| 10 | +const char *test_jacobian_vstack_vectors(void) |
| 11 | +{ |
| 12 | + /* vstack([log(x), exp(x)]) where x is (3,1) |
| 13 | + * Output (6,1) flat: [log(1), log(2), log(3), exp(1), exp(2), exp(3)] |
| 14 | + * |
| 15 | + * Jacobian is 6x3: |
| 16 | + * row 0: d(log(x0))/dx0 = 1/1 at col 0 |
| 17 | + * row 1: d(log(x1))/dx1 = 1/2 at col 1 |
| 18 | + * row 2: d(log(x2))/dx2 = 1/3 at col 2 |
| 19 | + * row 3: d(exp(x0))/dx0 = e^1 at col 0 |
| 20 | + * row 4: d(exp(x1))/dx1 = e^2 at col 1 |
| 21 | + * row 5: d(exp(x2))/dx2 = e^3 at col 2 |
| 22 | + */ |
| 23 | + double u[3] = {1.0, 2.0, 3.0}; |
| 24 | + expr *x = new_variable(3, 1, 0, 3); |
| 25 | + |
| 26 | + expr *log_x = new_log(x); |
| 27 | + expr *exp_x = new_exp(x); |
| 28 | + |
| 29 | + expr *args[2] = {log_x, exp_x}; |
| 30 | + expr *stack = new_vstack(args, 2, 3); |
| 31 | + |
| 32 | + stack->forward(stack, u); |
| 33 | + stack->jacobian_init(stack); |
| 34 | + stack->eval_jacobian(stack); |
| 35 | + |
| 36 | + double expected_x[6] = {1.0, 0.5, 1.0 / 3.0, exp(1.0), exp(2.0), exp(3.0)}; |
| 37 | + int expected_i[6] = {0, 1, 2, 0, 1, 2}; |
| 38 | + int expected_p[7] = {0, 1, 2, 3, 4, 5, 6}; |
| 39 | + |
| 40 | + mu_assert("vstack jac vectors: vals", |
| 41 | + cmp_double_array(stack->jacobian->x, expected_x, 6)); |
| 42 | + mu_assert("vstack jac vectors: cols", |
| 43 | + cmp_int_array(stack->jacobian->i, expected_i, 6)); |
| 44 | + mu_assert("vstack jac vectors: rows", |
| 45 | + cmp_int_array(stack->jacobian->p, expected_p, 7)); |
| 46 | + |
| 47 | + free_expr(stack); |
| 48 | + return 0; |
| 49 | +} |
| 50 | + |
| 51 | +const char *test_jacobian_vstack_matrix(void) |
| 52 | +{ |
| 53 | + /* vstack([log(x), exp(y)]) where x is (2,3), y is (1,3) |
| 54 | + * x at var_id 0 (6 vars), y at var_id 6 (3 vars), total 9 vars |
| 55 | + * |
| 56 | + * Output (3,3) flat column-wise: |
| 57 | + * [log(x0), log(x1), exp(y0), log(x2), log(x3), exp(y1), |
| 58 | + * log(x4), log(x5), exp(y2)] |
| 59 | + * |
| 60 | + * Jacobian is 9x9 sparse: |
| 61 | + * row 0 (log(x0)): 1/x0 at col 0 |
| 62 | + * row 1 (log(x1)): 1/x1 at col 1 |
| 63 | + * row 2 (exp(y0)): e^y0 at col 6 |
| 64 | + * row 3 (log(x2)): 1/x2 at col 2 |
| 65 | + * row 4 (log(x3)): 1/x3 at col 3 |
| 66 | + * row 5 (exp(y1)): e^y1 at col 7 |
| 67 | + * row 6 (log(x4)): 1/x4 at col 4 |
| 68 | + * row 7 (log(x5)): 1/x5 at col 5 |
| 69 | + * row 8 (exp(y2)): e^y2 at col 8 |
| 70 | + */ |
| 71 | + double u[9] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}; |
| 72 | + expr *x = new_variable(2, 3, 0, 9); |
| 73 | + expr *y = new_variable(1, 3, 6, 9); |
| 74 | + |
| 75 | + expr *log_x = new_log(x); |
| 76 | + expr *exp_y = new_exp(y); |
| 77 | + |
| 78 | + expr *args[2] = {log_x, exp_y}; |
| 79 | + expr *stack = new_vstack(args, 2, 9); |
| 80 | + |
| 81 | + stack->forward(stack, u); |
| 82 | + stack->jacobian_init(stack); |
| 83 | + stack->eval_jacobian(stack); |
| 84 | + |
| 85 | + double expected_x[9] = {1.0, 0.5, exp(7.0), 1.0 / 3.0, 0.25, |
| 86 | + exp(8.0), 0.2, 1.0 / 6.0, exp(9.0)}; |
| 87 | + int expected_i[9] = {0, 1, 6, 2, 3, 7, 4, 5, 8}; |
| 88 | + int expected_p[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; |
| 89 | + |
| 90 | + mu_assert("vstack jac matrix: vals", |
| 91 | + cmp_double_array(stack->jacobian->x, expected_x, 9)); |
| 92 | + mu_assert("vstack jac matrix: cols", |
| 93 | + cmp_int_array(stack->jacobian->i, expected_i, 9)); |
| 94 | + mu_assert("vstack jac matrix: rows", |
| 95 | + cmp_int_array(stack->jacobian->p, expected_p, 10)); |
| 96 | + |
| 97 | + free_expr(stack); |
| 98 | + return 0; |
| 99 | +} |
0 commit comments