def tf_unmasked_op(x, idx=0): scaling_norm = tf.dtypes.cast( tf.math.sqrt( tf.dtypes.cast(tf.math.reduce_prod(tf.shape(x)[1:3]), 'float32')), x.dtype) return tf.expand_dims(ifftshift(fft2d(fftshift(x[..., idx], axes=[1, 2])), axes=[1, 2]), axis=-1) / scaling_norm
def operator_and_matrix(self, shape_info, dtype, use_placeholder, ensure_self_adjoint_and_pd=False): shape = shape_info.shape # For this test class, we are creating Hermitian spectrums. # We also want the spectrum to have eigenvalues bounded away from zero. # # pre_spectrum is bounded away from zero. pre_spectrum = linear_operator_test_util.random_uniform( shape=self._shape_to_spectrum_shape(shape), dtype=dtype, minval=1., maxval=2.) pre_spectrum_c = _to_complex(pre_spectrum) # Real{IFFT[pre_spectrum]} # = IFFT[EvenPartOf[pre_spectrum]] # is the IFFT of something that is also bounded away from zero. # Therefore, FFT[pre_h] would be a well-conditioned spectrum. pre_h = fft_ops.ifft2d(pre_spectrum_c) # A spectrum is Hermitian iff it is the DFT of a real convolution kernel. # So we will make spectrum = FFT[h], for real valued h. h = math_ops.real(pre_h) h_c = _to_complex(h) spectrum = fft_ops.fft2d(h_c) lin_op_spectrum = spectrum if use_placeholder: lin_op_spectrum = array_ops.placeholder_with_default(spectrum, shape=None) operator = linalg.LinearOperatorCirculant2D( lin_op_spectrum, is_positive_definite=True if ensure_self_adjoint_and_pd else None, is_self_adjoint=True if ensure_self_adjoint_and_pd else None, input_output_dtype=dtype) self.assertEqual( operator.parameters, { "input_output_dtype": dtype, "is_non_singular": None, "is_positive_definite": ( True if ensure_self_adjoint_and_pd else None), "is_self_adjoint": ( True if ensure_self_adjoint_and_pd else None), "is_square": True, "name": "LinearOperatorCirculant2D", "spectrum": lin_op_spectrum, }) mat = self._spectrum_to_circulant_2d(spectrum, shape, dtype=dtype) return operator, mat
def ortho_fft2d(image): image = _order_for_ft(image) shift_axes = [2, 3] scaling_norm = _compute_scaling_norm(image) shifted_image = fftshift(image, axes=shift_axes) kspace_shifted = fft2d(shifted_image) kspace_unnormed = ifftshift(kspace_shifted, axes=shift_axes) kspace = kspace_unnormed / scaling_norm kspace = _order_after_ft(kspace) return kspace
def operator_and_matrix( self, shape_info, dtype, use_placeholder, ensure_self_adjoint_and_pd=False): shape = shape_info.shape # For this test class, we are creating Hermitian spectrums. # We also want the spectrum to have eigenvalues bounded away from zero. # # pre_spectrum is bounded away from zero. pre_spectrum = linear_operator_test_util.random_uniform( shape=self._shape_to_spectrum_shape(shape), dtype=dtype, minval=1., maxval=2.) pre_spectrum_c = _to_complex(pre_spectrum) # Real{IFFT[pre_spectrum]} # = IFFT[EvenPartOf[pre_spectrum]] # is the IFFT of something that is also bounded away from zero. # Therefore, FFT[pre_h] would be a well-conditioned spectrum. pre_h = fft_ops.ifft2d(pre_spectrum_c) # A spectrum is Hermitian iff it is the DFT of a real convolution kernel. # So we will make spectrum = FFT[h], for real valued h. h = math_ops.real(pre_h) h_c = _to_complex(h) spectrum = fft_ops.fft2d(h_c) lin_op_spectrum = spectrum if use_placeholder: lin_op_spectrum = array_ops.placeholder_with_default(spectrum, shape=None) operator = linalg.LinearOperatorCirculant2D( lin_op_spectrum, is_positive_definite=True if ensure_self_adjoint_and_pd else None, is_self_adjoint=True if ensure_self_adjoint_and_pd else None, input_output_dtype=dtype) mat = self._spectrum_to_circulant_2d(spectrum, shape, dtype=dtype) return operator, mat
def op(self, inputs): if self.multicoil: if self.masked: image, mask, smaps = inputs else: image, smaps = inputs else: if self.masked: image, mask = inputs else: image = inputs image = image[..., 0] scaling_norm = _compute_scaling_norm(image) if self.multicoil: image = tf.expand_dims(image, axis=1) image = image * smaps shifted_image = fftshift(image, axes=self.shift_axes) kspace_shifted = fft2d(shifted_image) kspace_unnormed = ifftshift(kspace_shifted, axes=self.shift_axes) kspace = kspace_unnormed[..., None] / scaling_norm if self.masked: kspace = _mask_tf([kspace, mask]) return kspace
def _spectrum_to_circulant_2d(self, spectrum, shape, dtype): """Creates a block circulant matrix from a spectrum. Intentionally done in an explicit yet inefficient way. This provides a cross check to the main code that uses fancy reshapes. Args: spectrum: Float or complex `Tensor`. shape: Python list. Desired shape of returned matrix. dtype: Type to cast the returned matrix to. Returns: Block circulant (batch) matrix of desired `dtype`. """ spectrum = _to_complex(spectrum) spectrum_shape = self._shape_to_spectrum_shape(shape) domain_dimension = spectrum_shape[-1] if not domain_dimension: return array_ops.zeros(shape, dtype) block_shape = spectrum_shape[-2:] # Explicitly compute the action of spectrum on basis vectors. matrix_rows = [] for n0 in range(block_shape[0]): for n1 in range(block_shape[1]): x = np.zeros(block_shape) # x is a basis vector. x[n0, n1] = 1.0 fft_x = fft_ops.fft2d(math_ops.cast(x, spectrum.dtype)) h_convolve_x = fft_ops.ifft2d(spectrum * fft_x) # We want the flat version of the action of the operator on a basis # vector, not the block version. h_convolve_x = array_ops.reshape(h_convolve_x, shape[:-1]) matrix_rows.append(h_convolve_x) matrix = array_ops.stack(matrix_rows, axis=-1) return math_ops.cast(matrix, dtype)
def _spectrum_to_circulant_2d(self, spectrum, shape, dtype): """Creates a block circulant matrix from a spectrum. Intentionally done in an explicit yet inefficient way. This provides a cross check to the main code that uses fancy reshapes. Args: spectrum: Float or complex `Tensor`. shape: Python list. Desired shape of returned matrix. dtype: Type to cast the returned matrix to. Returns: Block circulant (batch) matrix of desired `dtype`. """ spectrum = _to_complex(spectrum) spectrum_shape = self._shape_to_spectrum_shape(shape) domain_dimension = spectrum_shape[-1] if not domain_dimension: return array_ops.zeros(shape, dtype) block_shape = spectrum_shape[-2:] # Explicitly compute the action of spectrum on basis vectors. matrix_rows = [] for n0 in range(block_shape[0]): for n1 in range(block_shape[1]): x = np.zeros(block_shape) # x is a basis vector. x[n0, n1] = 1.0 fft_x = fft_ops.fft2d(x.astype(np.complex64)) h_convolve_x = fft_ops.ifft2d(spectrum * fft_x) # We want the flat version of the action of the operator on a basis # vector, not the block version. h_convolve_x = array_ops.reshape(h_convolve_x, shape[:-1]) matrix_rows.append(h_convolve_x) matrix = array_ops.stack(matrix_rows, axis=-1) return math_ops.cast(matrix, dtype)