def __init__(self, D, S, opt=None, dimK=None, dimN=2): """ This class supports an arbitrary number of spatial dimensions, `dimN`, with a default of 2. The input dictionary `D` is either `dimN` + 1 dimensional, in which case each spatial component (image in the default case) is assumed to consist of a single channel, or `dimN` + 2 dimensional, in which case the final dimension is assumed to contain the channels (e.g. colour channels in the case of images). The input signal set `S` is either `dimN` dimensional (no channels, only one signal), `dimN` + 1 dimensional (either multiple channels or multiple signals), or `dimN` + 2 dimensional (multiple channels and multiple signals). Determination of problem dimensions is handled by :class:`.cnvrep.CSC_ConvRepIndexing`. Parameters ---------- D : array_like Dictionary array S : array_like Signal array opt : :class:`GenericConvBPDN.Options` object Algorithm options dimK : 0, 1, or None, optional (default None) Number of dimensions in input signal corresponding to multiple independent signals dimN : int, optional (default 2) Number of spatial/temporal dimensions """ # Set default options if none specified if opt is None: opt = ComplexGenericConvBPDN.Options() # Infer problem dimensions and set relevant attributes of self if not hasattr(self, 'cri'): self.cri = cr.CSC_ConvRepIndexing(D, S, dimK=dimK, dimN=dimN) # Call parent class __init__ super(ComplexGenericConvBPDN, self).__init__(self.cri.shpX, S.dtype, opt) # Reshape D and S to standard layout self.D = np.asarray(D.reshape(self.cri.shpD), dtype=self.dtype) self.S = np.asarray(S.reshape(self.cri.shpS), dtype=self.dtype) # Compute signal in complex DFT domain self.Sf = fftn(self.S, None, self.cri.axisN) # Initialise byte-aligned arrays for pyfftw self.YU = empty_aligned(self.Y.shape, dtype=self.dtype) self.Xf = empty_aligned(self.Y.shape, dtype=self.dtype) self.setdict()
def __init__(self, D, S, lmbda, W=None, opt=None, dimK=None, dimN=2): """ | Parameters ---------- D : array_like Dictionary matrix S : array_like Signal vector or matrix lmbda : float Regularisation parameter W : array_like Mask array. The array shape must be such that the array is compatible for multiplication with input array S (see :func:`.cnvrep.mskWshape` for more details). opt : :class:`ConvBPDNMask.Options` object Algorithm options dimK : 0, 1, or None, optional (default None) Number of dimensions in input signal corresponding to multiple independent signals dimN : int, optional (default 2) Number of spatial dimensions """ super(ConvBPDNMask, self).__init__(D, S, lmbda, opt, dimK=dimK, dimN=dimN) if W is None: W = np.array([1.0], dtype=self.dtype) self.W = np.asarray(W.reshape(mskWshape(W, self.cri)), dtype=self.dtype) # Create byte aligned arrays for FFT calls self.WRy = empty_aligned(self.S.shape, dtype=self.dtype) self.Ryf = rfftn_empty_aligned(self.S.shape, self.cri.axisN, self.dtype)
def __init__(self, D, S, lmbda=None, opt=None, dimK=None, dimN=2): """ This class supports an arbitrary number of spatial dimensions, `dimN`, with a default of 2. The input dictionary `D` is either `dimN` + 1 dimensional, in which case each spatial component (image in the default case) is assumed to consist of a single channel, or `dimN` + 2 dimensional, in which case the final dimension is assumed to contain the channels (e.g. colour channels in the case of images). The input signal set `S` is either `dimN` dimensional (no channels, only one signal), `dimN` + 1 dimensional (either multiple channels or multiple signals), or `dimN` + 2 dimensional (multiple channels and multiple signals). Determination of problem dimensions is handled by :class:`.cnvrep.CSC_ConvRepIndexing`. | **Call graph** .. image:: ../_static/jonga/fista_cbpdn_init.svg :width: 20% :target: ../_static/jonga/fista_cbpdn_init.svg | Parameters ---------- D : array_like Dictionary array S : array_like Signal array lmbda : float Regularisation parameter opt : :class:`ConvBPDN.Options` object Algorithm options dimK : 0, 1, or None, optional (default None) Number of dimensions in input signal corresponding to multiple independent signals dimN : int, optional (default 2) Number of spatial/temporal dimensions """ # Set default options if none specified if opt is None: opt = ConvBPDN.Options() # Infer problem dimensions and set relevant attributes of self if not hasattr(self, 'cri'): self.cri = CSC_ConvRepIndexing(D, S, dimK=dimK, dimN=dimN) # Set dtype attribute based on S.dtype and opt['DataType'] self.set_dtype(opt, S.dtype) # Set default lambda value if not specified if lmbda is None: cri = CSC_ConvRepIndexing(D, S, dimK=dimK, dimN=dimN) Df = rfftn(D.reshape(cri.shpD), cri.Nv, axes=cri.axisN) Sf = rfftn(S.reshape(cri.shpS), axes=cri.axisN) b = np.conj(Df) * Sf lmbda = 0.1 * abs(b).max() # Set l1 term scaling and weight array self.lmbda = self.dtype.type(lmbda) self.wl1 = np.asarray(opt['L1Weight'], dtype=self.dtype) # Call parent class __init__ self.Xf = None xshape = self.cri.shpX super(ConvBPDN, self).__init__(xshape, S.dtype, opt) # Reshape D and S to standard layout self.D = np.asarray(D.reshape(self.cri.shpD), dtype=self.dtype) self.S = np.asarray(S.reshape(self.cri.shpS), dtype=self.dtype) # Compute signal in DFT domain self.Sf = rfftn(self.S, None, self.cri.axisN) # Create byte aligned arrays for FFT calls self.Y = self.X.copy() self.X = empty_aligned(self.Y.shape, dtype=self.dtype) self.X[:] = self.Y # Initialise auxiliary variable Vf: Create byte aligned arrays # for FFT calls self.Vf = rfftn_empty_aligned(self.X.shape, self.cri.axisN, self.dtype) self.Xf = rfftn(self.X, None, self.cri.axisN) self.Yf = self.Xf.copy() self.store_prev() self.Yfprv = self.Yf.copy() + 1e5 self.setdict() # Initialization needed for back tracking (if selected) self.postinitialization_backtracking_DFT()
def __init__(self, Z, S, dsz, opt=None, dimK=1, dimN=2): """ This class supports an arbitrary number of spatial dimensions, `dimN`, with a default of 2. The input coefficient map array `Z` (usually labelled X, but renamed here to avoid confusion with the X and Y variables in the ADMM base class) is expected to be in standard form as computed by the ConvBPDN class. The input signal set `S` is either `dimN` dimensional (no channels, only one signal), `dimN` +1 dimensional (either multiple channels or multiple signals), or `dimN` +2 dimensional (multiple channels and multiple signals). Parameter `dimK`, with a default value of 1, indicates the number of multiple-signal dimensions in `S`: :: Default dimK = 1, i.e. assume input S is of form S(N0, N1, C, K) or S(N0, N1, K) If dimK = 0 then input S is of form S(N0, N1, C, K) or S(N0, N1, C) The internal data layout for S, D (X here), and X (Z here) is: :: dim<0> - dim<Nds-1> : Spatial dimensions, product of N0,N1,... is N dim<Nds> : C number of channels in S and D dim<Nds+1> : K number of signals in S dim<Nds+2> : M number of filters in D sptl. chn sig flt S(N0, N1, C, K, 1) D(N0, N1, C, 1, M) (X here) X(N0, N1, 1, K, M) (Z here) The `dsz` parameter indicates the desired filter supports in the output dictionary, since this cannot be inferred from the input variables. The format is the same as the `dsz` parameter of :func:`.cnvrep.bcrop`. Parameters ---------- Z : array_like Coefficient map array S : array_like Signal array dsz : tuple Filter support size(s) opt : ccmod.Options object Algorithm options dimK : int, optional (default 1) Number of dimensions for multiple signals in input S dimN : int, optional (default 2) Number of spatial dimensions """ # Set default options if none specified if opt is None: opt = ComConvCnstrMODBase.Options() # Infer problem dimensions and set relevant attributes of self self.cri = cr.CDU_ConvRepIndexing(dsz, S, dimK=dimK, dimN=dimN) # Call parent class __init__ super(ComConvCnstrMODBase, self).__init__(self.cri.shpD, S.dtype, opt) # Set penalty parameter self.set_attr('rho', opt['rho'], dval=self.cri.K, dtype=self.dtype) # Reshape S to standard layout (Z, i.e. X in cbpdn, is assumed # to be taken from cbpdn, and therefore already in standard # form). If the dictionary has a single channel but the input # (and therefore also the coefficient map array) has multiple # channels, the channel index and multiple image index have # the same behaviour in the dictionary update equation: the # simplest way to handle this is to just reshape so that the # channels also appear on the multiple image index. if self.cri.Cd == 1 and self.cri.C > 1: self.S = S.reshape(self.cri.Nv + (1, ) + (self.cri.C * self.cri.K, ) + (1, )) else: self.S = S.reshape(self.cri.shpS) self.S = np.asarray(self.S, dtype=self.dtype) # Compute signal S in DFT domain self.Sf = fftn(self.S, None, self.cri.axisN) # Create constraint set projection function self.Pcn = cr.getPcn(dsz, self.cri.Nv, self.cri.dimN, self.cri.dimCd, zm=opt['ZeroMean']) # Create byte aligned arrays for FFT calls self.YU = empty_aligned(self.Y.shape, dtype=self.dtype) self.Xf = empty_aligned(self.Y.shape, dtype=self.dtype) if Z is not None: self.setcoef(Z)
def __init__(self, Z, S, dsz, opt=None, dimK=1, dimN=2): """ | **Call graph** .. image:: ../_static/jonga/ccmodcnsns_init.svg :width: 20% :target: ../_static/jonga/ccmodcnsns_init.svg """ # Set default options if none specified if opt is None: opt = ComConvCnstrMOD_Consensus.Options() # Infer problem dimensions and set relevant attributes of self self.cri = cr.CDU_ConvRepIndexing(dsz, S, dimK=dimK, dimN=dimN) # Handle possible reshape of channel axis onto multiple image axis # (see comment below) Nb = self.cri.K if self.cri.C == self.cri.Cd else \ self.cri.C * self.cri.K admm.ADMMConsensus.__init__(self, Nb, self.cri.shpD, S.dtype, opt) # Set penalty parameter self.set_attr('rho', opt['rho'], dval=self.cri.K, dtype=self.dtype) # Reshape S to standard layout (Z, i.e. X in cbpdn, is assumed # to be taken from cbpdn, and therefore already in standard # form). If the dictionary has a single channel but the input # (and therefore also the coefficient map array) has multiple # channels, the channel index and multiple image index have # the same behaviour in the dictionary update equation: the # simplest way to handle this is to just reshape so that the # channels also appear on the multiple image index. if self.cri.Cd == 1 and self.cri.C > 1: self.S = S.reshape(self.cri.Nv + (1, ) + (self.cri.C * self.cri.K, ) + (1, )) else: self.S = S.reshape(self.cri.shpS) self.S = np.asarray(self.S, dtype=self.dtype) # Compute signal S in DFT domain self.Sf = fftn(self.S, None, self.cri.axisN) # Create constraint set projection function self.Pcn = cr.getPcn(dsz, self.cri.Nv, self.cri.dimN, self.cri.dimCd, zm=opt['ZeroMean']) if Z is not None: self.setcoef(Z) self.X = empty_aligned(self.xshape, dtype=self.dtype) # See comment on corresponding test in xstep method if self.cri.Cd > 1: self.YU = empty_aligned(self.yshape, dtype=self.dtype) else: self.YU = empty_aligned(self.xshape, dtype=self.dtype) self.Xf = empty_aligned(self.xshape, dtype=self.dtype)
def __init__(self, Z, S, W, dsz, opt=None, dimK=None, dimN=2): """ | **Call graph** .. image:: ../_static/jonga/ccmodmdfista_init.svg :width: 20% :target: ../_static/jonga/ccmodmdfista_init.svg | Parameters ---------- Z : array_like Coefficient map array S : array_like Signal array W : array_like Mask array. The array shape must be such that the array is compatible for multiplication with the *internal* shape of input array S (see :class:`.cnvrep.CDU_ConvRepIndexing` for a discussion of the distinction between *external* and *internal* data layouts). dsz : tuple Filter support size(s) opt : :class:`ConvCnstrMODMask.Options` object Algorithm options dimK : 0, 1, or None, optional (default None) Number of dimensions in input signal corresponding to multiple independent signals dimN : int, optional (default 2) Number of spatial dimensions """ # Set default options if none specified if opt is None: opt = ConvCnstrMODMask.Options() # Infer problem dimensions and set relevant attributes of self self.cri = CDU_ConvRepIndexing(dsz, S, dimK=dimK, dimN=dimN) # Append singleton dimensions to W if necessary if hasattr(W, 'ndim'): W = atleast_nd(self.cri.dimN + 3, W) # Reshape W if necessary (see discussion of reshape of S in # ccmod base class) if self.cri.Cd == 1 and self.cri.C > 1 and hasattr(W, 'ndim'): # In most cases broadcasting rules make it possible for W # to have a singleton dimension corresponding to a # non-singleton dimension in S. However, when S is # reshaped to interleave axisC and axisK on the same axis, # broadcasting is no longer sufficient unless axisC and # axisK of W are either both singleton or both of the same # size as the corresponding axes of S. If neither of these # cases holds, it is necessary to replicate the axis of W # (axisC or axisK) that does not have the same size as the # corresponding axis of S. shpw = list(W.shape) swck = shpw[self.cri.axisC] * shpw[self.cri.axisK] if swck > 1 and swck < self.cri.C * self.cri.K: if W.shape[self.cri.axisK] == 1 and self.cri.K > 1: shpw[self.cri.axisK] = self.cri.K else: shpw[self.cri.axisC] = self.cri.C W = np.broadcast_to(W, shpw) self.W = W.reshape(W.shape[0:self.cri.dimN] + (1, W.shape[self.cri.axisC] * W.shape[self.cri.axisK], 1)) else: self.W = W super(ConvCnstrMODMask, self).__init__(Z, S, dsz, opt, dimK, dimN) # Create byte aligned arrays for FFT calls self.WRy = empty_aligned(self.S.shape, dtype=self.dtype) self.Ryf = rfftn_empty_aligned(self.S.shape, self.cri.axisN, self.dtype)
def __init__(self, D, B, S, lmbda, mu, W=None, opt=None, dimK=0, dimN=2): """ Parameters ---------- D : array_like Dictionary matrix B : array_like Standard dictionary array S : array_like Signal vector or matrix lmbda : float Regularisation parameter (l1) mu : float Regularisation parameter (gradient) W : array_like Mask array. The array shape must be such that the array is compatible for multiplication with input array S (see :func:`.cnvrep.mskWshape` for more details). opt : :class:`ConvProdDictL1L1Grd.Options` object Algorithm options dimK : 0, 1, optional (default 0) Number of dimensions in input signal corresponding to multiple independent signals dimN : int, optional (default 2) Number of spatial dimensions """ # Set default options if none specified if opt is None: opt = ConvProdDictL1L1Grd.Options() # Keep a record of the B dictionary self.set_dtype(opt, S.dtype) self.B = np.asarray(B, dtype=self.dtype) # S is an N x C matrix, D is an N x N M_D matrix, B is a C x M_B # matrix, and X is an N M x M_B matrix. The base class of this # class expects that X is N M x C (i.e. the same number of columns # as in S), so we pass its initialiser the product S B, which is # a N x M_B matrix, so that it initialises arrays with the correct # number of channels. This is the first of many nasty hacks in # this class! scidx = -2 if dimK == 1 else -1 SB = dot(B.T, S, axis=scidx) super(ConvProdDictL1L1Grd, self).__init__(D, SB, lmbda, mu, W=W, opt=opt, dimK=dimK, dimN=dimN) # Ensure that the dictionary is single channel if self.cri.Cd > 1: raise ValueError('Only single-channel convolutional dictionaries' ' are supported') # We need to correct the shape of S due to the modified S passed to # the base class initialiser shpS = list(self.cri.shpS) shpS[self.cri.axisC] = S.shape[self.cri.axisC] self.cri.shpS = tuple(shpS) self.S = np.asarray(S.reshape(shpS), dtype=self.dtype) # We also need to correct the shapes of a number of other working # arrays because we have to change the mechanism for combining # the Y0 and Y1 blocks into a single array. In the base class # these arrays can just be concatenated on an appropriate axis, # but this is not possible here due to the different array # shapes. The solution is that the composite array is one # dimensional, with the component blocks being extracted via # one dimensional slicing and then reshaped to the appropriate # shapes. self.y0shp = self.cri.shpS self.y1shp = self.cri.shpX self.y0I = int(np.prod(np.array(self.y0shp[self.cri.axisC:]))) self.y1I = int(np.prod(np.array(self.y1shp[self.cri.axisC:]))) self.yshp = self.cri.shpX[0:self.cri.axisC:] + (self.y0I + self.y1I, ) self.Y = np.zeros(self.yshp, dtype=self.dtype) self.U = np.zeros(self.yshp, dtype=self.dtype) self.YU = empty_aligned(self.Y.shape, dtype=self.dtype)
def __init__(self, D, S, lmbda, mu=0.0, opt=None, dimK=None, dimN=2): """ | **Call graph** .. image:: ../_static/jonga/cbpdnrtv_init.svg :width: 20% :target: ../_static/jonga/cbpdnrtv_init.svg | Parameters ---------- D : array_like Dictionary matrix S : array_like Signal vector or matrix lmbda : float Regularisation parameter (l1) mu : float Regularisation parameter (gradient) opt : :class:`ConvBPDNRecTV.Options` object Algorithm options dimK : 0, 1, or None, optional (default None) Number of dimensions in input signal corresponding to multiple independent signals dimN : int, optional (default 2) Number of spatial dimensions """ if opt is None: opt = ConvBPDNRecTV.Options() # Infer problem dimensions and set relevant attributes of self self.cri = cr.CSC_ConvRepIndexing(D, S, dimK=dimK, dimN=dimN) # Call parent class __init__ Nx = np.product(np.array(self.cri.shpX)) yshape = list(self.cri.shpX) yshape[self.cri.axisM] += len(self.cri.axisN) * self.cri.Cd super(ConvBPDNRecTV, self).__init__(Nx, yshape, yshape, S.dtype, opt) # Set l1 term scaling and weight array self.lmbda = self.dtype.type(lmbda) self.Wl1 = np.asarray(opt['L1Weight'], dtype=self.dtype) self.Wl1 = self.Wl1.reshape(cr.l1Wshape(self.Wl1, self.cri)) self.mu = self.dtype.type(mu) if hasattr(opt['TVWeight'], 'ndim') and opt['TVWeight'].ndim > 0: self.Wtv = np.asarray( opt['TVWeight'].reshape((1, ) * (dimN + 2) + opt['TVWeight'].shape), dtype=self.dtype) else: # Wtv is a scalar: no need to change shape self.Wtv = self.dtype.type(opt['TVWeight']) # Set penalty parameter self.set_attr('rho', opt['rho'], dval=(50.0 * self.lmbda + 1.0), dtype=self.dtype) # Set rho_xi attribute self.set_attr('rho_xi', opt['AutoRho', 'RsdlTarget'], dval=1.0, dtype=self.dtype) # Reshape D and S to standard layout self.D = np.asarray(D.reshape(self.cri.shpD), dtype=self.dtype) self.S = np.asarray(S.reshape(self.cri.shpS), dtype=self.dtype) # Compute signal in DFT domain self.Sf = rfftn(self.S, None, self.cri.axisN) self.Gf, GHGf = gradient_filters(self.cri.dimN + 3, self.cri.axisN, self.cri.Nv, dtype=self.dtype) # Initialise byte-aligned arrays for pyfftw self.YU = empty_aligned(self.Y.shape, dtype=self.dtype) self.Xf = rfftn_empty_aligned(self.cri.shpX, self.cri.axisN, self.dtype) self.setdict()
def __init__(self, Z, S, W, dsz, opt=None, dimK=None, dimN=2): """ | **Call graph** .. image:: ../_static/jonga/ccmodmdcnsns_init.svg :width: 20% :target: ../_static/jonga/ccmodmdcnsns_init.svg | Parameters ---------- Z : array_like Coefficient map array S : array_like Signal array W : array_like Mask array. The array shape must be such that the array is compatible for multiplication with input array S (see :func:`.cnvrep.mskWshape` for more details). dsz : tuple Filter support size(s) opt : :class:`.ConvCnstrMOD_Consensus.Options` object Algorithm options dimK : 0, 1, or None, optional (default None) Number of dimensions in input signal corresponding to multiple independent signals dimN : int, optional (default 2) Number of spatial dimensions """ # Set default options if none specified if opt is None: opt = ccmod.ConvCnstrMOD_Consensus.Options() super(ConvCnstrMODMaskDcpl_Consensus, self).__init__(Z, S, dsz, opt=opt, dimK=dimK, dimN=dimN) # Convert W to internal shape if W is None: W = np.array([1.0], dtype=self.dtype) W = np.asarray(W.reshape(cr.mskWshape(W, self.cri)), dtype=S.dtype) # Reshape W if necessary (see discussion of reshape of S in # ccmod.ConvCnstrMOD_Consensus.__init__) if self.cri.Cd == 1 and self.cri.C > 1: # In most cases broadcasting rules make it possible for W # to have a singleton dimension corresponding to a non-singleton # dimension in S. However, when S is reshaped to interleave axisC # and axisK on the same axis, broadcasting is no longer sufficient # unless axisC and axisK of W are either both singleton or both # of the same size as the corresponding axes of S. If neither of # these cases holds, it is necessary to replicate the axis of W # (axisC or axisK) that does not have the same size as the # corresponding axis of S. shpw = list(W.shape) swck = shpw[self.cri.axisC] * shpw[self.cri.axisK] if swck > 1 and swck < self.cri.C * self.cri.K: if W.shape[self.cri.axisK] == 1 and self.cri.K > 1: shpw[self.cri.axisK] = self.cri.K else: shpw[self.cri.axisC] = self.cri.C W = np.broadcast_to(W, shpw) self.W = W.reshape(W.shape[0:self.cri.dimN] + (1, W.shape[self.cri.axisC] * W.shape[self.cri.axisK], 1)) else: self.W = W # Initialise additional variables required for the different # splitting used in combining the consensus solution with mask # decoupling self.Y1 = np.zeros(self.S.shape, dtype=self.dtype) self.U1 = np.zeros(self.S.shape, dtype=self.dtype) self.YU1 = empty_aligned(self.S.shape, dtype=self.dtype)
def __init__(self, Z, S, W, dsz, opt=None, dimK=None, dimN=2): """ Parameters ---------- Z : array_like Coefficient map array S : array_like Signal array W : array_like Mask array. The array shape must be such that the array is compatible for multiplication with the *internal* shape of input array S (see :class:`.cnvrep.CDU_ConvRepIndexing` for a discussion of the distinction between *external* and *internal* data layouts) after reshaping to the shape determined by :func:`.cnvrep.mskWshape`. dsz : tuple Filter support size(s) opt : :class:`ConvCnstrMODMaskDcplBase.Options` object Algorithm options dimK : 0, 1, or None, optional (default None) Number of dimensions in input signal corresponding to multiple independent signals dimN : int, optional (default 2) Number of spatial dimensions """ # Set default options if none specified if opt is None: opt = ConvCnstrMODMaskDcplBase.Options() # Infer problem dimensions and set relevant attributes of self self.cri = cr.CDU_ConvRepIndexing(dsz, S, dimK=dimK, dimN=dimN) # Convert W to internal shape W = np.asarray(W.reshape(cr.mskWshape(W, self.cri)), dtype=S.dtype) # Reshape W if necessary (see discussion of reshape of S below) if self.cri.Cd == 1 and self.cri.C > 1: # In most cases broadcasting rules make it possible for W # to have a singleton dimension corresponding to a non-singleton # dimension in S. However, when S is reshaped to interleave axisC # and axisK on the same axis, broadcasting is no longer sufficient # unless axisC and axisK of W are either both singleton or both # of the same size as the corresponding axes of S. If neither of # these cases holds, it is necessary to replicate the axis of W # (axisC or axisK) that does not have the same size as the # corresponding axis of S. shpw = list(W.shape) swck = shpw[self.cri.axisC] * shpw[self.cri.axisK] if swck > 1 and swck < self.cri.C * self.cri.K: if W.shape[self.cri.axisK] == 1 and self.cri.K > 1: shpw[self.cri.axisK] = self.cri.K else: shpw[self.cri.axisC] = self.cri.C W = np.broadcast_to(W, shpw) self.W = W.reshape(W.shape[0:self.cri.dimN] + (1, W.shape[self.cri.axisC] * W.shape[self.cri.axisK], 1)) else: self.W = W # Call parent class __init__ Nx = self.cri.N * self.cri.Cd * self.cri.M CK = (self.cri.C if self.cri.Cd == 1 else 1) * self.cri.K shpY = list(self.cri.shpX) shpY[self.cri.axisC] = self.cri.Cd shpY[self.cri.axisK] = 1 shpY[self.cri.axisM] += CK super(ConvCnstrMODMaskDcplBase, self).__init__(Nx, shpY, self.cri.axisM, CK, S.dtype, opt) # Reshape S to standard layout (Z, i.e. X in cbpdn, is assumed # to be taken from cbpdn, and therefore already in standard # form). If the dictionary has a single channel but the input # (and therefore also the coefficient map array) has multiple # channels, the channel index and multiple image index have # the same behaviour in the dictionary update equation: the # simplest way to handle this is to just reshape so that the # channels also appear on the multiple image index. if self.cri.Cd == 1 and self.cri.C > 1: self.S = S.reshape(self.cri.Nv + (1, self.cri.C * self.cri.K, 1)) else: self.S = S.reshape(self.cri.shpS) self.S = np.asarray(self.S, dtype=self.dtype) # Create constraint set projection function self.Pcn = cr.getPcn(dsz, self.cri.Nv, self.cri.dimN, self.cri.dimCd, zm=opt['ZeroMean']) # Initialise byte-aligned arrays for pyfftw self.YU = empty_aligned(self.Y.shape, dtype=self.dtype) xfshp = list(self.cri.Nv + (self.cri.Cd, 1, self.cri.M)) self.Xf = rfftn_empty_aligned(xfshp, self.cri.axisN, self.dtype) if Z is not None: self.setcoef(Z)