/* * Implements finite difference operator (order 1 for now) * using circular shift: diff(x) = x - circshift(x) * @param snip Keeps first entry if snip = false; clear first entry if snip = true * * optr = [iptr(1); diff(iptr)] */ static void md_zfinitediff_core2(unsigned int D, const long dims[D], unsigned int flags, bool snip, complex float* tmp, const long ostrs[D], complex float* optr, const long istrs[D], const complex float* iptr) { md_copy2(D, dims, istrs, tmp, istrs, iptr, sizeof(complex float)); long zdims[D]; long center[D]; md_select_dims(D, ~0, zdims, dims); memset(center, 0, D * sizeof(long)); for (unsigned int i=0; i < D; i++) { if (MD_IS_SET(flags, i)) { center[i] = 1; // order md_circ_shift2(D, dims, center, ostrs, optr, istrs, tmp, sizeof(complex float)); zdims[i] = 1; if (!snip) // zero out first dimension before subtracting md_clear2(D, zdims, ostrs, optr, sizeof(complex float)); md_zsub2(D, dims, ostrs, optr, istrs, tmp, ostrs, optr); md_copy2(D, dims, ostrs, tmp, ostrs, optr, sizeof(complex float)); if (snip) // zero out first dimension after subtracting md_clear2(D, zdims, ostrs, optr, sizeof(complex float)); center[i] = 0; zdims[i] = dims[i]; } } }
/* * Adjoint of finite difference operator along specified dimensions. * Equivalent to finite difference in reverse order * * @param snip if false: keeps the original value for the last entry; * if true: implements the adjoint of the difference matrix with all zero first row * * optr = [-diff(iptr); iptr(end)] = flip(fdiff_apply(flip(iptr))) */ static void fdiff_apply_adjoint(const linop_data_t* _data, complex float* optr, const complex float* iptr) { const auto data = CAST_DOWN(fdiff_s, _data); md_copy2(data->D, data->dims, data->str, optr, data->str, iptr, CFL_SIZE); for (unsigned int i=0; i < data->D; i++) { unsigned int single_flag = data->flags & MD_BIT(i); if (single_flag) { complex float* tmp = md_alloc_sameplace(data->D, data->dims, CFL_SIZE, optr); complex float* tmp2 = md_alloc_sameplace(data->D, data->dims, CFL_SIZE, optr); md_flip2(data->D, data->dims, single_flag, data->str, tmp2, data->str, optr, CFL_SIZE); md_zfinitediff_core2(data->D, data->dims, single_flag, false, tmp, data->str, tmp2, data->str, tmp2); md_flip2(data->D, data->dims, single_flag, data->str, optr, data->str, tmp2, CFL_SIZE); md_free(tmp2); md_free(tmp); if (data->snip) { long zdims[data->D]; md_select_dims(data->D, ~0, zdims, data->dims); zdims[i] = 1; md_zsub2(data->D, zdims, data->str, optr, data->str, optr, data->str, iptr); } } } }
/** * * x = (ATA + uI)^-1 b * */ void sum_apply_pinverse(const void* _data, float rho, complex float* dst, const complex float* src) { struct sum_data* data = (struct sum_data*) _data; if (NULL == data->tmp) { #ifdef USE_CUDA data->tmp = (data->use_gpu ? md_alloc_gpu : md_alloc)(DIMS, data->img_dims, CFL_SIZE); #else data->tmp = md_alloc(DIMS, data->img_dims, CFL_SIZE); #endif } // get average md_clear( DIMS, data->img_dims, data->tmp, sizeof( complex float ) ); md_zadd2( DIMS, data->imgd_dims, data->img_strs, data->tmp, data->img_strs, data->tmp , data->imgd_strs, src ); md_zsmul( DIMS, data->img_dims, data->tmp, data->tmp, 1. / data->levels ); // get non-average md_zsub2( DIMS, data->imgd_dims, data->imgd_strs, dst, data->imgd_strs, src, data->img_strs, data->tmp ); // avg = avg / (1 + rho) md_zsmul( DIMS, data->img_dims, data->tmp, data->tmp, 1. / (1. + rho) ); // nonavg = nonavg / rho md_zsmul( DIMS, data->imgd_dims, dst, dst, 1. / rho ); // dst = avg + nonavg md_zadd2( DIMS, data->imgd_dims, data->imgd_strs, dst, data->imgd_strs, dst, data->img_strs, data->tmp ); }
// y = 2*x - circshift(x,center_adj) - circshift(x,center) static void zfinitediff_normal(const linop_data_t* _data, complex float* optr, const complex float* iptr) { const auto data = CAST_DOWN(zfinitediff_data, _data); // Turns out that this is faster, but this requires extra memory. complex float* tmp = md_alloc_sameplace(data->D, data->dims_in, CFL_SIZE, iptr); zfinitediff_apply(_data, tmp, iptr); zfinitediff_adjoint(_data, optr, tmp); md_free(tmp); return; // FIXME: WTF? unsigned long d = data->dim_diff; long nx = data->dims_in[d]; long offset; long dims_sub[data->D]; md_copy_dims(data->D, dims_sub, data->dims_in); // optr and iptr same size regardless if do_circdiff true/false // if (data->do_circdiff) // out = 2*in; // out(..,1:(end-1),..) = out(..,1:(end-1),..) - in(..,2:end,..) // out(..,2:end,..) = out(..,2:end,..) - in(..,1:(end-1),..) // out(..,end,..) = out(..,end,..) - in(..,1,..) // out(..,1,..) = out(..,1,..) - in(..,end,..) // // else // out(..,1,..) = in(..,1,..) // out(..,end,..) = in(..,end,..) // out(..,2:(end-1),..) = 2*in(..,2:(end-1),..) // out(..,1:(end-1),..) = out(..,1:(end-1),..) - in(..,2:end,..) // out(..,2:end,..) = out(..,2:end,..) - in(..,1:(end-1),..) // if (data->do_circdiff) { md_zsmul2(data->D, data->dims_in, data->strides_in, optr, data->strides_in, iptr, 2.); dims_sub[d] = (nx - 1); offset = data->strides_in[d] / CFL_SIZE; // out(..,1:(end-1),..) = out(..,1:(end-1),..) - in(..,2:end,..) md_zsub2(data->D, dims_sub, data->strides_in, optr, data->strides_in, optr, data->strides_in, iptr + offset); // out(..,2:end,..) = out(..,2:end,..) - in(..,1:(end-1),..) md_zsub2(data->D, dims_sub, data->strides_in, optr + offset, data->strides_in, optr + offset, data->strides_in, iptr); dims_sub[d] = 1; offset = (nx - 1) * data->strides_in[d] / CFL_SIZE; // out(..,1,..) = out(..,1,..) - in(..,end,..) md_zsub2(data->D, dims_sub, data->strides_in, optr, data->strides_in, optr, data->strides_in, iptr + offset); // out(..,end,..) = out(..,end,..) - in(..,1,..) md_zsub2(data->D, dims_sub, data->strides_in, optr+offset, data->strides_in, optr+offset, data->strides_in, iptr); } else { dims_sub[d] = 1; offset = (nx - 1) * data->strides_in[d] / CFL_SIZE; // out(..,1,..) = in(..,1,..) md_copy2(data->D, dims_sub, data->strides_in, optr, data->strides_in, iptr, CFL_SIZE); // out(..,end,..) = in(..,end,..) md_copy2(data->D, dims_sub, data->strides_in, optr + offset, data->strides_in, iptr + offset, CFL_SIZE); dims_sub[d] = nx - 2; offset = data->strides_in[d] / CFL_SIZE; // out(..,2:(end-1),..) = 2*in(..,2:(end-1),..) md_zsmul2(data->D, dims_sub, data->strides_in, optr + offset, data->strides_in, iptr + offset, 2.); dims_sub[d] = nx - 1; offset = data->strides_in[d] / CFL_SIZE; // out(..,1:(end-1),..) = out(..,1:(end-1),..) - in(..,2:end,..) md_zsub2(data->D, dims_sub, data->strides_in, optr, data->strides_in, optr, data->strides_in, iptr + offset); // out(..,2:end,..) = out(..,2:end,..) - in(..,1:(end-1),..) md_zsub2(data->D, dims_sub, data->strides_in, optr + offset, data->strides_in, optr + offset, data->strides_in, iptr); } }
static void zfinitediff_adjoint(const linop_data_t* _data, complex float* optr, const complex float* iptr) { const auto data = CAST_DOWN(zfinitediff_data, _data); // if (docircshift) // out(..,2:end,..) = in(..,2:end,..) - in(..,1:(end-1),..) // out(..,1,..) = in(..,1,..) - in(..,end,..) // else // out(..,1,..) = in(..,1,..) // out(..,2:(end-1),..) = in(..,2:end,..) - in(..,1:(end-1),..) // out(..,end,..) = -in(..,end,..); unsigned int d = data->dim_diff; long nx = data->dims_adj[d]; long off_in, off_adj; long dims_sub[data->D]; md_copy_dims(data->D, dims_sub, data->dims_adj); if (data->do_circdiff) { // out(..,2:end,..) = in(..,2:end,..) - in(..,1:(end-1),..) dims_sub[d] = nx - 1; off_adj = data->strides_adj[d] / CFL_SIZE; off_in = data->strides_in[d] / CFL_SIZE; md_zsub2(data->D, dims_sub, data->strides_in, optr + off_in, data->strides_in, iptr + off_adj, data->strides_adj, iptr); // out(..,1,..) = in(..,1,..) - in(..,end,..) dims_sub[d] = 1; off_adj = (nx - 1) * data->strides_adj[d] / CFL_SIZE; off_in = (nx - 1) * data->strides_in[d] / CFL_SIZE; md_zsub2(data->D, dims_sub, data->strides_in, optr, data->strides_adj, iptr, data->strides_adj, iptr + off_adj); } else { // out(..,end,..) = 0 //md_clear2(data->D, data->dims_in, data->strides_in, optr, CFL_SIZE); dims_sub[d] = 1; off_in = nx * data->strides_in[d] / CFL_SIZE; md_clear2(data->D, dims_sub, data->strides_in, optr + off_in, CFL_SIZE); // out(..,1:end-1,:) = in_adj(..,1:end,:) md_copy2(data->D, data->dims_adj, data->strides_in, optr, data->strides_adj, iptr, CFL_SIZE); // out(..,2:end,:) -= in_adj(..,1:end,:) off_in = data->strides_in[d] / CFL_SIZE; md_zsub2(data->D, data->dims_adj, data->strides_in, optr + off_in, data->strides_in, optr + off_in, data->strides_adj, iptr); /* // out(..,1,..) = in_adj(..,1,..) dims_sub[d] = 1; md_copy2(data->D, dims_sub, data->strides_in, optr, data->strides_adj, iptr, CFL_SIZE); // out(..,2:(end-1),..) = in(..,2:end,..) - in(..,1:(end-1),..) dims_sub[d] = nx - 1; off_adj = data->strides_adj[d]/CFL_SIZE; off_in = data->strides_in[d]/CFL_SIZE; md_zsub2(data->D, dims_sub, data->strides_in, optr+off_in, data->strides_adj, iptr+off_adj, data->strides_adj, iptr); // out(..,end,..) = -in(..,end,..); dims_sub[d] = 1; off_adj = (nx - 1) * data->strides_adj[d]/CFL_SIZE; off_in = nx * data->strides_in[d]/CFL_SIZE; // !!!This one operation is really really slow!!! md_zsmul2(data->D, dims_sub, data->strides_in, optr+off_in, data->strides_adj, iptr+off_adj, -1.); */ } }
/** * Originally used md_circshift, but couldn't get it right, so I just * wrote it out for now (also avoids extra memory) */ static void zfinitediff_apply(const linop_data_t* _data, complex float* optr, const complex float* iptr) { // if (docircshift) // out(..,1:(end-1),..) = in(..,1:(end-1),..) - in(..,2:end,..) // out(..,end,..) = in(..,end,..) - in(..,1,..) // else // out = in(..,1:(end-1),..) - in(..,2:end,..) const auto data = CAST_DOWN(zfinitediff_data, _data); unsigned long d = data->dim_diff; long nx = data->dims_in[d]; long dims_sub[data->D]; md_copy_dims(data->D, dims_sub, data->dims_in); long off_in, off_adj; if (data->do_circdiff) { // out(..,1:(end-1),..) = in(..,1:(end-1),..) - in(..,2:end,..) dims_sub[d] = nx - 1; off_in = data->strides_in[d] / CFL_SIZE; //off_adj = data->strides_in[d]/CFL_SIZE; md_zsub2(data->D, dims_sub, data->strides_adj, optr, data->strides_in, iptr, data->strides_in, iptr + off_in); // out(..,end,..) = in(..,end,..) - in(..,1,..) dims_sub[d] = 1; off_in = (nx - 1) * data->strides_in[d] / CFL_SIZE; off_adj = (nx - 1) * data->strides_adj[d] / CFL_SIZE; md_zsub2(data->D, dims_sub, data->strides_adj, optr + off_adj, data->strides_in, iptr + off_in, data->strides_in, iptr); } else { // out(..,1:(end-1),..) = in(..,1:(end-1),..) - in(..,2:end,..) dims_sub[d] = nx - 1; off_in = data->strides_in[d] / CFL_SIZE; md_zsub2(data->D, dims_sub, data->strides_adj, optr, data->strides_in, iptr, data->strides_in, iptr + off_in); } /* long i_shift, i_adj, x_orig, x_new; unsigned int d = data->dim_diff; for (unsigned int i = 0; i < md_calc_size(data->D, data->dims_in); i++) { i_shift = i; i_adj = i; x_orig = (i/data->strs_in[d]) % data->dims_in[d]; x_new = x_orig + 1; // shift by 1 while (x_new >= data->dims_in[d]) x_new -= data->dims_in[d]; i_shift += (x_new - x_orig)*data->strs_in[d]; optr[i_adj] = iptr[i] - iptr[i_shift]; */ }