 void lexpr_replace_relu_bounds_specialized(expr_t** expr_array, double* lb_array, double* ub_array, const size_t num_out_neurons_last_layer, const size_t num_out_neurons_current_layer)
 {
     size_t n = blockIdx.x;
-    size_t i = threadIdx.x;
+    size_t i = blockIdx.y*blockDim.x + threadIdx.x;
 
     if(n < num_out_neurons_last_layer)
     {

        {
            // for odd numbers of chunks, need to copy the last chunk over
            memcpy(b + startl, a + startl, (length - startl)*sizeof(size_t));
            memcpy(mirror_1_b + startl, mirror_1_a + startl, (length - startl)*sizeof(double));
            memcpy(mirror_2_b + startl, mirror_2_a + startl, (length - startl)*sizeof(double));
        }
        else
        {
            // for even numbers of chunks, need to mark past-the-end pointer as endu and do a merge
            endu = length;
            merge(a + startl, b + startl, mirror_1_a + startl, mirror_1_b + startl, mirror_2_a + startl, mirror_2_b + startl, startu - startl, endu - startu);
            first = true;
        }

        swap(a, b);
        swap(mirror_1_a, mirror_1_b);
        swap(mirror_2_a, mirror_2_b);

        i = 0;
        startl = 0;


// sorts an array of size_t and mirrors the same permutation to two arrays of double
__device__ __host__
void sort_sparse_expr(size_t* array, double* mirror_array, const size_t length)
{
    size_t* a = array;
    size_t* b = nullptr;
    double* mirror_a = mirror_array;
    double* mirror_b = nullptr;

    bool sorted = true;

