def test_08(self): N = 16 M = 4 Nd = 8 X = np.random.randn(N, N, 1, 1, M) S = np.random.randn(N, N, 1) dt = np.float64 opt = ccmod.ConvCnstrMODOptions( {'Verbose': False, 'MaxMainIter': 20, 'BackTrack': {'Enabled': True}, 'DataType': dt}) c = ccmod.ConvCnstrMOD(X, S, (Nd, Nd, M), opt=opt) c.solve() assert(c.X.dtype == dt) assert(c.Xf.dtype == sl.complex_dtype(dt)) assert(c.Yf.dtype == sl.complex_dtype(dt))
def test_05(self): N = 16 M = 4 Nd = 8 X = np.random.randn(N, N, 1, 1, M) S = np.random.randn(N, N, 1) dt = np.float64 opt = ccmod.ConvCnstrMOD.Options( {'Verbose': False, 'MaxMainIter': 20, 'BackTrack': {'Enabled': True}, 'DataType': dt}) c = ccmod.ConvCnstrMOD(X, S, (Nd, Nd, M), opt=opt) c.solve() assert c.X.dtype == dt assert c.Xf.dtype == sl.complex_dtype(dt) assert c.Yf.dtype == sl.complex_dtype(dt)
def test_06(self): N = 16 Nd = 5 K = 2 M = 4 D = np.random.randn(Nd, Nd, M) s = np.random.randn(N, N, K) dt = np.float32 opt = cbpdn.ConvBPDN.Options({'Verbose': False, 'MaxMainIter': 20, 'BackTrack': {'Enabled': True}, 'DataType': dt}) lmbda = 1e-1 b = cbpdn.ConvBPDN(D, s, lmbda, opt=opt) b.solve() assert b.X.dtype == dt assert b.Xf.dtype == sl.complex_dtype(dt) assert b.Yf.dtype == sl.complex_dtype(dt)
def __init__(self, D, S, lmbda, mu=0.0, opt=None, dimK=None, dimN=2): if opt is None: opt = ConvBPDNRecTV.Options() # Infer problem dimensions and set relevant attributes of self self.cri = cbpdn.ConvRepIndexing(D, S, dimK=dimK, dimN=dimN) # Call parent class __init__ Nx = np.product(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.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 = sl.rfftn(self.S, None, self.cri.axisN) self.Gf, GHGf = sl.GradientFilters(self.cri.dimN+3, self.cri.axisN, self.cri.Nv, dtype=self.dtype) # Initialise byte-aligned arrays for pyfftw self.YU = sl.pyfftw_empty_aligned(self.Y.shape, dtype=self.dtype) xfshp = list(self.cri.shpX) xfshp[dimN-1] = xfshp[dimN-1]//2 + 1 self.Xf = sl.pyfftw_empty_aligned(xfshp, dtype=sl.complex_dtype(self.dtype)) self.setdict()
def test_06(self): N = 16 Nd = 5 K = 2 M = 4 D = np.random.randn(Nd, Nd, M) s = np.random.randn(N, N, K) dt = np.float32 opt = cbpdn.ConvBPDN.Options({ 'Verbose': False, 'MaxMainIter': 20, 'BackTrack': { 'Enabled': True }, 'DataType': dt }) lmbda = 1e-1 b = cbpdn.ConvBPDN(D, s, lmbda, opt=opt) b.solve() assert (b.X.dtype == dt) assert (b.Xf.dtype == sl.complex_dtype(dt)) assert (b.Yf.dtype == sl.complex_dtype(dt))
def __init__(self, D, S, lmbda=None, opt=None, dimK=None, dimN=2): """ Initialise a ConvBPDN object with problem parameters. 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 = cr.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 = cr.CSC_ConvRepIndexing(D, S, dimK=dimK, dimN=dimN) Df = sl.rfftn(D.reshape(cri.shpD), cri.Nv, axes=cri.axisN) Sf = sl.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__ xshape = self.cri.shpX super(ConvBPDN, self).__init__(xshape, S.dtype, opt) if self.opt['BackTrack', 'Enabled']: self.L /= self.lmbda # 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 = sl.rfftn(self.S, None, self.cri.axisN) # Create byte aligned arrays for FFT calls xfshp = list(self.X.shape) xfshp[dimN - 1] = xfshp[dimN - 1] // 2 + 1 self.Xf = sl.pyfftw_empty_aligned(xfshp, dtype=sl.complex_dtype(self.dtype)) # Initialise auxiliary variable Yf self.Yf = sl.pyfftw_empty_aligned(xfshp, dtype=sl.complex_dtype(self.dtype)) self.Ryf = -self.Sf self.Xf = sl.rfftn(self.X, None, self.cri.axisN) self.Yf = self.Xf self.store_prev() self.setdict()
def __init__(self, Z, S, W, dsz, opt=None, dimK=None, dimN=2): """ Initialise a ConvCnstrMODMaskDcplBase object with problem size and options. 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:`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 = sl.pyfftw_empty_aligned(self.Y.shape, dtype=self.dtype) xfshp = list(self.cri.Nv + (self.cri.Cd, 1, self.cri.M)) xfshp[dimN - 1] = xfshp[dimN - 1] // 2 + 1 self.Xf = sl.pyfftw_empty_aligned(xfshp, dtype=sl.complex_dtype(self.dtype)) if Z is not None: self.setcoef(Z)
def __init__(self, Z, S, dsz, opt=None, dimK=1, dimN=2): """Initialise a ConvCnstrMOD_Consensus object with problem parameters. See :meth:`.ConvCnstrMODBase.__init__` for interface details. | **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 = ConvCnstrMOD_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 = sl.rfftn(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 = sl.pyfftw_empty_aligned(self.xshape, dtype=self.dtype) # See comment on corresponding test in xstep method if self.cri.Cd > 1: self.YU = sl.pyfftw_empty_aligned(self.yshape, dtype=self.dtype) else: self.YU = sl.pyfftw_empty_aligned(self.xshape, dtype=self.dtype) xfshp = list(self.xshape) xfshp[dimN - 1] = xfshp[dimN - 1] // 2 + 1 self.Xf = sl.pyfftw_empty_aligned(xfshp, dtype=sl.complex_dtype(self.dtype))
def __init__(self, Z, S, dsz, opt=None, dimK=1, dimN=2): """Initialise a ConvCnstrMODBase object with problem parameters. 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 = ConvCnstrMODBase.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(ConvCnstrMODBase, 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 = sl.rfftn(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 = sl.pyfftw_empty_aligned(self.Y.shape, dtype=self.dtype) xfshp = list(self.Y.shape) xfshp[dimN - 1] = xfshp[dimN - 1] // 2 + 1 self.Xf = sl.pyfftw_empty_aligned(xfshp, dtype=sl.complex_dtype(self.dtype)) if Z is not None: self.setcoef(Z)
def rfftn_empty(shape, axes, dtype, order='C', n=None): ashp = list(shape) raxis = axes[-1] ashp[raxis] = ashp[raxis] // 2 + 1 cdtype = spl.complex_dtype(dtype) return np.zeros(ashp, dtype=cdtype)
def __init__(self, D, S, lmbda, mu=0.0, opt=None, dimK=None, dimN=2): """ Initialise a ConvBPDNRecTV object with problem parameters. | **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(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 = sl.rfftn(self.S, None, self.cri.axisN) self.Gf, GHGf = sl.GradientFilters(self.cri.dimN + 3, self.cri.axisN, self.cri.Nv, dtype=self.dtype) # Initialise byte-aligned arrays for pyfftw self.YU = sl.pyfftw_empty_aligned(self.Y.shape, dtype=self.dtype) xfshp = list(self.cri.shpX) xfshp[dimN - 1] = xfshp[dimN - 1] // 2 + 1 self.Xf = sl.pyfftw_empty_aligned(xfshp, dtype=sl.complex_dtype(self.dtype)) self.setdict()