Exemplo n.º 1
0
    def __init__(self, G, S, lmbda, opt=None, dimN=2):
        """
        Initalize the solver object.

        Parameters
        ----------
        G : array_like
          Convolution kernel array
        S:  array_like
          Signal array
        lmbda: float
           Regularization parameter
        opt: :class:`CnsGrdRegDeconvPGM.Options` object
           Algorithm options
        """

        if opt is None:
            opt = CnsGrdRegDeconvPGM.Options()

        self.dimN = dimN
        self.axes = tuple(range(dimN))

        self.set_dtype(opt, S.dtype)
        self.lmbda = self.dtype.type(lmbda)
        self.set_attr('L', opt['L'], dval=1e1, dtype=self.dtype)

        super(CnsGrdRegDeconvPGM, self).__init__(xshape=S.shape,
                                                 Nv=S.shape,
                                                 axisN=tuple(range(dimN)),
                                                 dtype=S.dtype,
                                                 opt=opt)

        self.setS(S)
        self.setG(G)
        self.Df, self.DHDf = gradient_filters(dimN,
                                              self.axes,
                                              S.shape,
                                              dtype=self.dtype)

        self.Wsm = opt['SupportMask']
        self.nrmflg = opt['Normalize']

        self.Y = self.X
        self.X[:] = self.Y
        self.Vf = rfftn_empty_aligned(self.X.shape, self.axes, self.dtype)
        self.Xf = rfftn(self.X, None, self.axes)
        self.Yf = self.Xf
        self.Yprv = self.Y.copy()
        self.Yfprv = self.Yf.copy() + 1e5
Exemplo n.º 2
0
    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)
Exemplo n.º 3
0
    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()
Exemplo n.º 4
0
    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 = 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 = 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 = 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 = rfftn_empty_aligned(self.xshape, self.cri.axisN, self.dtype)
Exemplo n.º 5
0
    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 = 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 = 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 = empty_aligned(self.Y.shape, dtype=self.dtype)
        self.Xf = rfftn_empty_aligned(self.Y.shape, self.cri.axisN, self.dtype)

        if Z is not None:
            self.setcoef(Z)
Exemplo n.º 6
0
    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)
Exemplo n.º 7
0
    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()
Exemplo n.º 8
0
    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)