Skip to content

Commit 2fcc71c

Browse files
committed
small edits, most substantial thing removed unnecessary loop
1 parent 89e7033 commit 2fcc71c

6 files changed

Lines changed: 88 additions & 98 deletions

File tree

include/affine.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ expr *new_trace(expr *child);
1818
expr *new_constant(int d1, int d2, int n_vars, const double *values);
1919
expr *new_variable(int d1, int d2, int var_id, int n_vars);
2020

21-
expr *new_index(expr *child, const int *indices, int n_selected);
21+
expr *new_index(expr *child, const int *indices, int n_idxs);
2222

2323
#endif /* AFFINE_H */

include/subexpr.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,13 @@ typedef struct const_vector_mult_expr
109109
double *a; /* length equals node->size */
110110
} const_vector_mult_expr;
111111

112-
/* Index/slicing: y = child[indices] where indices is a list of flattened positions */
112+
/* Index/slicing: y = child[indices] where indices is a list of flat positions */
113113
typedef struct index_expr
114114
{
115115
expr base;
116116
int *indices; /* Flattened indices to select (owned, copied) */
117-
int n_selected; /* Number of selected elements */
118-
bool has_duplicates; /* True if indices contain duplicates (affects Hessian path) */
119-
double *parent_w; /* Scatter buffer for wsum_hess (size = child->size) */
117+
int n_idxs; /* Number of selected elements */
118+
bool has_duplicates; /* True if indices have duplicates (affects Hessian path) */
120119
} index_expr;
121120

122121
#endif /* SUBEXPR_H */

python/atoms/index.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
#include "affine.h"
77
#include "common.h"
88

9-
/* Index/slicing: y = child[indices] where indices is a list of flattened positions */
9+
/* Index/slicing: y = child[indices] where indices is a list of flattened positions
10+
*/
1011
static PyObject *py_make_index(PyObject *self, PyObject *args)
1112
{
1213
PyObject *child_capsule;
@@ -17,26 +18,26 @@ static PyObject *py_make_index(PyObject *self, PyObject *args)
1718
return NULL;
1819
}
1920

20-
expr *child = (expr *)PyCapsule_GetPointer(child_capsule, EXPR_CAPSULE_NAME);
21+
expr *child = (expr *) PyCapsule_GetPointer(child_capsule, EXPR_CAPSULE_NAME);
2122
if (!child)
2223
{
2324
PyErr_SetString(PyExc_ValueError, "invalid child capsule");
2425
return NULL;
2526
}
2627

2728
/* Convert indices array to int32 */
28-
PyArrayObject *indices_array =
29-
(PyArrayObject *)PyArray_FROM_OTF(indices_obj, NPY_INT32, NPY_ARRAY_IN_ARRAY);
29+
PyArrayObject *indices_array = (PyArrayObject *) PyArray_FROM_OTF(
30+
indices_obj, NPY_INT32, NPY_ARRAY_IN_ARRAY);
3031

3132
if (!indices_array)
3233
{
3334
return NULL;
3435
}
3536

36-
int n_selected = (int)PyArray_SIZE(indices_array);
37-
int *indices_data = (int *)PyArray_DATA(indices_array);
37+
int n_idxs = (int) PyArray_SIZE(indices_array);
38+
int *indices_data = (int *) PyArray_DATA(indices_array);
3839

39-
expr *node = new_index(child, indices_data, n_selected);
40+
expr *node = new_index(child, indices_data, n_idxs);
4041

4142
Py_DECREF(indices_array);
4243

src/affine/index.c

Lines changed: 66 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
1-
// SPDX-License-Identifier: Apache-2.0
2-
31
#include "affine.h"
42
#include "subexpr.h"
53
#include <stdlib.h>
64
#include <string.h>
75

8-
/* Index/slicing: y = child[indices] where indices is a list of flattened positions */
6+
/* Index/slicing: y = child[indices] where indices is a list of flat positions */
97

108
/* Check if indices array contains duplicates using a bitmap.
119
* Returns true if duplicates exist, false otherwise. */
12-
static bool check_for_duplicates(const int *indices, int n_selected, int max_idx)
10+
static bool check_for_duplicates(const int *indices, int n_idxs, int max_idx)
1311
{
14-
bool *seen = (bool *)calloc(max_idx, sizeof(bool));
12+
bool *seen = (bool *) calloc(max_idx, sizeof(bool));
1513
bool has_dup = false;
16-
for (int i = 0; i < n_selected && !has_dup; i++)
14+
for (int i = 0; i < n_idxs && !has_dup; i++)
1715
{
1816
if (seen[indices[i]])
1917
{
@@ -27,115 +25,109 @@ static bool check_for_duplicates(const int *indices, int n_selected, int max_idx
2725

2826
static void forward(expr *node, const double *u)
2927
{
30-
expr *child = node->left;
31-
index_expr *idx = (index_expr *)node;
28+
expr *x = node->left;
29+
index_expr *idx = (index_expr *) node;
3230

3331
/* child's forward pass */
34-
child->forward(child, u);
32+
x->forward(x, u);
3533

3634
/* gather selected elements */
37-
for (int i = 0; i < idx->n_selected; i++)
35+
for (int i = 0; i < idx->n_idxs; i++)
3836
{
39-
node->value[i] = child->value[idx->indices[i]];
37+
node->value[i] = x->value[idx->indices[i]];
4038
}
4139
}
4240

4341
static void jacobian_init(expr *node)
4442
{
45-
expr *child = node->left;
46-
index_expr *idx = (index_expr *)node;
47-
48-
child->jacobian_init(child);
49-
CSR_Matrix *J_child = child->jacobian;
50-
51-
/* count nnz */
52-
int nnz = 0;
53-
for (int i = 0; i < idx->n_selected; i++)
54-
{
55-
int row = idx->indices[i];
56-
nnz += J_child->p[row + 1] - J_child->p[row];
57-
}
43+
expr *x = node->left;
44+
index_expr *idx = (index_expr *) node;
45+
x->jacobian_init(x);
5846

59-
node->jacobian = new_csr_matrix(idx->n_selected, node->n_vars, nnz);
60-
CSR_Matrix *J = node->jacobian;
47+
CSR_Matrix *Jx = x->jacobian;
48+
CSR_Matrix *J = new_csr_matrix(node->size, node->n_vars, Jx->nnz);
6149

62-
/* fill p and i arrays in one pass */
50+
/* set sparsity pattern */
6351
J->p[0] = 0;
64-
for (int i = 0; i < idx->n_selected; i++)
52+
for (int i = 0; i < idx->n_idxs; i++)
6553
{
6654
int row = idx->indices[i];
67-
int src = J_child->p[row];
68-
int len = J_child->p[row + 1] - src;
69-
memcpy(J->i + J->p[i], J_child->i + src, len * sizeof(int));
55+
int len = Jx->p[row + 1] - Jx->p[row];
56+
memcpy(J->i + J->p[i], Jx->i + Jx->p[row], len * sizeof(int));
7057
J->p[i + 1] = J->p[i] + len;
7158
}
59+
60+
node->jacobian = J;
7261
}
7362

7463
static void eval_jacobian(expr *node)
7564
{
76-
expr *child = node->left;
77-
index_expr *idx = (index_expr *)node;
78-
79-
child->eval_jacobian(child);
65+
expr *x = node->left;
66+
index_expr *idx = (index_expr *) node;
67+
x->eval_jacobian(x);
8068

8169
CSR_Matrix *J = node->jacobian;
82-
CSR_Matrix *J_child = child->jacobian;
70+
CSR_Matrix *Jx = x->jacobian;
8371

84-
for (int i = 0; i < idx->n_selected; i++)
72+
for (int i = 0; i < idx->n_idxs; i++)
8573
{
8674
int row = idx->indices[i];
8775
int len = J->p[i + 1] - J->p[i];
88-
memcpy(J->x + J->p[i], J_child->x + J_child->p[row], len * sizeof(double));
76+
memcpy(J->x + J->p[i], Jx->x + Jx->p[row], len * sizeof(double));
8977
}
9078
}
9179

9280
static void wsum_hess_init(expr *node)
9381
{
94-
expr *child = node->left;
95-
index_expr *idx = (index_expr *)node;
82+
expr *x = node->left;
9683

9784
/* initialize child's wsum_hess */
98-
child->wsum_hess_init(child);
99-
100-
/* allocate scatter buffer (zeroed) */
101-
idx->parent_w = (double *)calloc(child->size, sizeof(double));
102-
103-
/* wsum_hess inherits from child (affine has no local Hessian) */
104-
/* We need to allocate our own to avoid aliasing issues */
105-
CSR_Matrix *child_hess = child->wsum_hess;
106-
node->wsum_hess = new_csr_matrix(child_hess->m, child_hess->n, child_hess->nnz);
107-
memcpy(node->wsum_hess->p, child_hess->p, (child_hess->m + 1) * sizeof(int));
108-
memcpy(node->wsum_hess->i, child_hess->i, child_hess->nnz * sizeof(int));
85+
x->wsum_hess_init(x);
86+
87+
/* for setting weight vector to evaluate hessian of child */
88+
node->dwork = (double *) calloc(x->size, sizeof(double));
89+
90+
/* in the implementation of eval_wsum_hess we evaluate the
91+
child's hessian with a weight vector that has w[i] = 0
92+
if i is not included in idx->indices. This can lead to
93+
many numerical zeros in child->wsum_hess that are actually
94+
structural zeros, but we do not try to exploit that sparsity
95+
right now. */
96+
CSR_Matrix *H_child = x->wsum_hess;
97+
node->wsum_hess = new_csr_matrix(H_child->m, H_child->n, H_child->nnz);
98+
memcpy(node->wsum_hess->p, H_child->p, (H_child->m + 1) * sizeof(int));
99+
memcpy(node->wsum_hess->i, H_child->i, H_child->nnz * sizeof(int));
109100
}
110101

111102
static void eval_wsum_hess(expr *node, const double *w)
112103
{
113104
expr *child = node->left;
114-
index_expr *idx = (index_expr *)node;
105+
index_expr *idx = (index_expr *) node;
115106

116107
if (idx->has_duplicates)
117108
{
118-
/* slow path: must zero and accumulate for repeated indices */
119-
memset(idx->parent_w, 0, child->size * sizeof(double));
120-
for (int i = 0; i < idx->n_selected; i++)
109+
/* zero and accumulate for repeated indices */
110+
memset(node->dwork, 0, child->size * sizeof(double));
111+
for (int i = 0; i < idx->n_idxs; i++)
121112
{
122-
idx->parent_w[idx->indices[i]] += w[i];
113+
node->dwork[idx->indices[i]] += w[i];
123114
}
124115
}
125116
else
126117
{
127-
/* fast path: direct write (no memset needed, no accumulation) */
128-
for (int i = 0; i < idx->n_selected; i++)
118+
/* direct write (no memset needed, no accumulation) */
119+
for (int i = 0; i < idx->n_idxs; i++)
129120
{
130-
idx->parent_w[idx->indices[i]] = w[i];
121+
node->dwork[idx->indices[i]] = w[i];
131122
}
132123
}
133124

134125
/* delegate to child */
135-
child->eval_wsum_hess(child, idx->parent_w);
126+
child->eval_wsum_hess(child, node->dwork);
136127

137128
/* copy values from child */
138-
memcpy(node->wsum_hess->x, child->wsum_hess->x, child->wsum_hess->nnz * sizeof(double));
129+
memcpy(node->wsum_hess->x, child->wsum_hess->x,
130+
child->wsum_hess->nnz * sizeof(double));
139131
}
140132

141133
static bool is_affine(const expr *node)
@@ -145,44 +137,37 @@ static bool is_affine(const expr *node)
145137

146138
static void free_type_data(expr *node)
147139
{
148-
index_expr *idx = (index_expr *)node;
140+
index_expr *idx = (index_expr *) node;
149141
if (idx->indices)
150142
{
151143
free(idx->indices);
152144
idx->indices = NULL;
153145
}
154-
if (idx->parent_w)
155-
{
156-
free(idx->parent_w);
157-
idx->parent_w = NULL;
158-
}
159146
}
160147

161-
expr *new_index(expr *child, const int *indices, int n_selected)
148+
expr *new_index(expr *child, const int *indices, int n_idxs)
162149
{
163150
/* allocate type-specific struct */
164-
index_expr *idx = (index_expr *)calloc(1, sizeof(index_expr));
151+
index_expr *idx = (index_expr *) calloc(1, sizeof(index_expr));
165152
expr *node = &idx->base;
166153

167-
/* output shape is (n_selected, 1) - flattened */
168-
init_expr(node, n_selected, 1, child->n_vars, forward, jacobian_init,
169-
eval_jacobian, is_affine, free_type_data);
154+
/* output shape is (n_idxs, 1) - flattened */
155+
init_expr(node, n_idxs, 1, child->n_vars, forward, jacobian_init, eval_jacobian,
156+
is_affine, free_type_data);
170157

171-
node->wsum_hess_init = wsum_hess_init;
172-
node->eval_wsum_hess = eval_wsum_hess;
173158
node->left = child;
174159
expr_retain(child);
175160

161+
node->wsum_hess_init = wsum_hess_init;
162+
node->eval_wsum_hess = eval_wsum_hess;
163+
176164
/* copy indices */
177-
idx->indices = (int *)malloc(n_selected * sizeof(int));
178-
memcpy(idx->indices, indices, n_selected * sizeof(int));
179-
idx->n_selected = n_selected;
165+
idx->indices = (int *) malloc(n_idxs * sizeof(int));
166+
memcpy(idx->indices, indices, n_idxs * sizeof(int));
167+
idx->n_idxs = n_idxs;
180168

181169
/* detect duplicates for Hessian optimization */
182-
idx->has_duplicates = check_for_duplicates(indices, n_selected, child->size);
183-
184-
/* parent_w allocated lazily in wsum_hess_init */
185-
idx->parent_w = NULL;
170+
idx->has_duplicates = check_for_duplicates(indices, n_idxs, child->size);
186171

187172
return node;
188173
}

src/other/quad_form.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ static void forward(expr *node, const double *u)
2727

2828
static void jacobian_init(expr *node)
2929
{
30-
CSR_Matrix *Q = ((quad_form_expr *) node)->Q;
3130
assert(node->left->var_id != NOT_A_VARIABLE);
3231
assert(node->left->d2 == 1);
3332
expr *x = node->left;

tests/jacobian_tests/test_index.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,10 @@ const char *test_index_jacobian_of_log(void)
8383
double expected_x[2] = {1.0, 0.25};
8484
int expected_i[2] = {0, 2};
8585

86-
mu_assert("index of log jac vals", cmp_double_array(idx->jacobian->x, expected_x, 2));
87-
mu_assert("index of log jac cols", cmp_int_array(idx->jacobian->i, expected_i, 2));
86+
mu_assert("index of log jac vals",
87+
cmp_double_array(idx->jacobian->x, expected_x, 2));
88+
mu_assert("index of log jac cols",
89+
cmp_int_array(idx->jacobian->i, expected_i, 2));
8890

8991
free_expr(idx);
9092
return 0;
@@ -106,8 +108,12 @@ const char *test_index_jacobian_repeated(void)
106108
int expected_p[3] = {0, 1, 2};
107109
int expected_i[2] = {0, 0}; /* Both reference col 0 */
108110

109-
mu_assert("index repeated jac vals", cmp_double_array(idx->jacobian->x, expected_x, 2));
110-
mu_assert("index repeated jac i", cmp_int_array(idx->jacobian->i, expected_i, 2));
111+
mu_assert("index repeated jac vals",
112+
cmp_double_array(idx->jacobian->x, expected_x, 2));
113+
mu_assert("index repeated row ptr",
114+
cmp_int_array(idx->jacobian->p, expected_p, 4));
115+
mu_assert("index repeated jac i",
116+
cmp_int_array(idx->jacobian->i, expected_i, 2));
111117

112118
free_expr(idx);
113119
return 0;

0 commit comments

Comments
 (0)