/** * Create an Identity linear operator: I x * @param N number of dimensions * @param dims dimensions of input (domain) */ struct linop_s* linop_identity_create(unsigned int N, const long dims[N]) { PTR_ALLOC(struct identity_data_s, data); SET_TYPEID(identity_data_s, data); data->domain = iovec_create(N, dims, CFL_SIZE); return linop_create(N, dims, N, dims, CAST_UP(PTR_PASS(data)), identity_apply, identity_apply, identity_apply, NULL, identity_free); }
/** * Operator interface for a true matrix: * out = mat * in * in: [x x x x 1 x x K x x] * mat: [x x x x T x x K x x] * out: [x x x x T x x 1 x x] * where the x's are arbitrary dimensions and T and K may be transposed * * use this interface if K == 1 or T == 1 * * @param N number of dimensions * @param out_dims output dimensions after applying the matrix (codomain) * @param in_dims input dimensions to apply the matrix (domain) * @param T_dim dimension corresponding to the rows of A * @param K_dim dimension corresponding to the columns of A * @param matrix matrix data */ struct linop_s* linop_matrix_altcreate(unsigned int N, const long out_dims[N], const long in_dims[N], const unsigned int T_dim, const unsigned int K_dim, const complex float* matrix) { long matrix_dims[N]; md_singleton_dims(N, matrix_dims); matrix_dims[K_dim] = in_dims[K_dim]; matrix_dims[T_dim] = out_dims[T_dim]; unsigned int T = out_dims[T_dim]; unsigned int K = in_dims[K_dim]; PTR_ALLOC(long[N], max_dims); for (unsigned int i = 0; i < N; i++) { if ((in_dims[i] > 1) && (out_dims[i] == 1)) { (*max_dims)[i] = in_dims[i]; } else if ((in_dims[i] == 1) && (out_dims[i] > 1)) { (*max_dims)[i] = out_dims[i]; } else { assert(in_dims[i] == out_dims[i]); (*max_dims)[i] = in_dims[i]; } } complex float* mat = md_alloc_sameplace(N, matrix_dims, CFL_SIZE, matrix); complex float* matc = md_alloc_sameplace(N, matrix_dims, CFL_SIZE, matrix); md_copy(N, matrix_dims, mat, matrix, CFL_SIZE); md_zconj(N, matrix_dims, matc, mat); complex float* gram = NULL; const struct iovec_s* gram_iovec = compute_gram_matrix(N, T_dim, T, K_dim, K, &gram, matrix_dims, matrix); PTR_ALLOC(struct operator_matrix_s, data); SET_TYPEID(operator_matrix_s, data); data->mat_iovec = iovec_create(N, matrix_dims, CFL_SIZE); data->mat_gram_iovec = gram_iovec; data->max_dims = *max_dims; data->mat = mat; data->mat_conj = matc; data->mat_gram = gram; data->K_dim = K_dim; data->T_dim = T_dim; data->K = K; data->T = T; data->domain_iovec = iovec_create(N, in_dims, CFL_SIZE); data->codomain_iovec = iovec_create(N, out_dims, CFL_SIZE); return linop_create(N, out_dims, N, in_dims, CAST_UP(PTR_PASS(data)), linop_matrix_apply, linop_matrix_apply_adjoint, linop_matrix_apply_normal, NULL, linop_matrix_del); }
/** * Compute the Gram matrix, A^H A. * Stores the result in @param gram, which is allocated by the function * Returns: iovec_s corresponding to the gram matrix dimensions * * @param N number of dimensions * @param T_dim dimension corresponding to the rows of A * @param T number of rows of A (codomain) * @param K_dim dimension corresponding to the columns of A * @param K number of columns of A (domain) * @param gram store the result (allocated by this function) * @param matrix_dims dimensions of A * @param matrix matrix data */ const struct iovec_s* compute_gram_matrix(unsigned int N, unsigned int T_dim, unsigned int T, unsigned int K_dim, unsigned int K, complex float** gram, const long matrix_dims[N], const complex float* matrix) { // FIXME this can certainly be simplfied... // Just be careful to consider the case where the data passed to the operator is a subset of a bigger array // B_dims = [T K 1] or [K T 1] // C_dims = [T 1 K] or [1 T K] // A_dims = [1 K K] or [K 1 K] // after: gram_dims = [1 K1 K2] --> [K2 K1 1] or [K1 1 K2] --> [K1 K2 1] long A_dims[N + 1]; long B_dims[N + 1]; long C_dims[N + 1]; long fake_gram_dims[N + 1]; long A_str[N + 1]; long B_str[N + 1]; long C_str[N + 1]; long max_dims[N + 1]; md_singleton_dims(N + 1, A_dims); md_singleton_dims(N + 1, B_dims); md_singleton_dims(N + 1, C_dims); md_singleton_dims(N + 1, fake_gram_dims); md_singleton_dims(N + 1, max_dims); A_dims[K_dim] = K; A_dims[N] = K; B_dims[T_dim] = T; B_dims[K_dim] = K; C_dims[T_dim] = T; C_dims[N] = K; max_dims[T_dim] = T; max_dims[K_dim] = K; max_dims[N] = K; fake_gram_dims[T_dim] = K; fake_gram_dims[K_dim] = K; md_calc_strides(N + 1, A_str, A_dims, CFL_SIZE); md_calc_strides(N + 1, B_str, B_dims, CFL_SIZE); md_calc_strides(N + 1, C_str, C_dims, CFL_SIZE); complex float* tmpA = md_alloc_sameplace(N + 1 , A_dims, CFL_SIZE, matrix); complex float* tmpB = md_alloc_sameplace(N + 1, B_dims, CFL_SIZE, matrix); complex float* tmpC = md_alloc_sameplace(N + 1, C_dims, CFL_SIZE, matrix); md_copy(N, matrix_dims, tmpB, matrix, CFL_SIZE); //md_copy(N, matrix_dims, tmpC, matrix, CFL_SIZE); md_transpose(N + 1, K_dim, N, C_dims, tmpC, B_dims, tmpB, CFL_SIZE); md_clear(N + 1, A_dims, tmpA, CFL_SIZE); md_zfmacc2(N + 1, max_dims, A_str, tmpA, B_str, tmpB, C_str, tmpC); *gram = md_alloc_sameplace(N, fake_gram_dims, CFL_SIZE, matrix); md_transpose(N + 1, T_dim, N, fake_gram_dims, *gram, A_dims, tmpA, CFL_SIZE); const struct iovec_s* s = iovec_create(N, fake_gram_dims, CFL_SIZE); md_free(tmpA); md_free(tmpB); md_free(tmpC); return s; }
/** * Create an Identity linear operator: I x * @param N number of dimensions * @param dims dimensions of input (domain) */ struct linop_s* linop_identity_create(unsigned int N, const long dims[N]) { const struct iovec_s* domain = iovec_create(N, dims, CFL_SIZE); return linop_create(N, dims, N, dims, (void*)domain, identity_apply, identity_apply, identity_apply, NULL, identity_free); }