def test_smoothL21Norm(self):

        ig = ImageGeometry(4, 5)
        bg = BlockGeometry(ig, ig)

        epsilon = 0.5

        f1 = SmoothMixedL21Norm(epsilon)
        x = bg.allocate('random', seed=10)

        print("Check call for smooth MixedL21Norm")

        # check call
        res1 = f1(x)
        res2 = (x.pnorm(2)**2 + epsilon**2).sqrt().sum()

        # alternative
        tmp1 = x.copy()
        tmp1.containers += (epsilon, )
        res3 = tmp1.pnorm(2).sum()

        numpy.testing.assert_almost_equal(res1, res2, decimal=5)
        numpy.testing.assert_almost_equal(res1, res3, decimal=5)

        print("Check gradient for smooth MixedL21Norm ... OK ")

        res1 = f1.gradient(x)
        res2 = x.divide((x.pnorm(2)**2 + epsilon**2).sqrt())
        numpy.testing.assert_array_almost_equal(
            res1.get_item(0).as_array(),
            res2.get_item(0).as_array())

        numpy.testing.assert_array_almost_equal(
            res1.get_item(1).as_array(),
            res2.get_item(1).as_array())

        # check with MixedL21Norm, when epsilon close to 0

        print("Check as epsilon goes to 0 ... OK")

        f1 = SmoothMixedL21Norm(1e-12)
        f2 = MixedL21Norm()

        res1 = f1(x)
        res2 = f2(x)
        numpy.testing.assert_almost_equal(f1(x), f2(x))
    def test_ProjectionMap(self):

        # Check if direct is correct
        ig1 = ImageGeometry(3, 4)
        ig2 = ImageGeometry(5, 6)
        ig3 = ImageGeometry(5, 6, 4)

        # Create BlockGeometry
        bg = BlockGeometry(ig1, ig2, ig3)
        x = bg.allocate(10)

        # Extract containers
        x0, x1, x2 = x[0], x[1], x[2]

        for i in range(3):

            proj_map = ProjectionMap(bg, i)

            # res1 is in ImageData from the X_{i} "ImageGeometry"
            res1 = proj_map.direct(x)

            # res2 is in ImageData from the X_{i} "ImageGeometry" using out
            res2 = bg.geometries[i].allocate(0)
            proj_map.direct(x, out=res2)

            # Check with and without out
            numpy.testing.assert_array_almost_equal(res1.as_array(),
                                                    res2.as_array())

            # Depending on which index is used, check if x0, x1, x2 are the same with res2
            if i == 0:
                numpy.testing.assert_array_almost_equal(
                    x0.as_array(), res2.as_array())
            elif i == 1:
                numpy.testing.assert_array_almost_equal(
                    x1.as_array(), res2.as_array())
            elif i == 2:
                numpy.testing.assert_array_almost_equal(
                    x2.as_array(), res2.as_array())
            else:
                pass

        # Check if adjoint is correct

        bg = BlockGeometry(ig1, ig2, ig3, ig1, ig2, ig3)
        x = ig1.allocate(20)

        index = 3
        proj_map = ProjectionMap(bg, index)

        res1 = bg.allocate(0)
        proj_map.adjoint(x, out=res1)

        # check if all indices return arrays filled with 0, except the input index

        for i in range(len(bg.geometries)):

            if i != index:
                numpy.testing.assert_array_almost_equal(
                    res1[i].as_array(), bg.geometries[i].allocate().as_array())

        # Check error messages
        # Check if index is correct wrt length of Cartesian Product
        try:
            ig = ImageGeometry(3, 4)
            bg = BlockGeometry(ig, ig)
            index = 3
            proj_map = ProjectionMap(bg, index)
        except ValueError as err:
            print(err)

        # Check error if an ImageGeometry is passed
        try:
            proj_map = ProjectionMap(ig, index)
        except ValueError as err:
            print(err)
Exemplo n.º 3
0
class Gradient_C(LinearOperator):
    '''Finite Difference Operator:
            
            Computes first-order forward/backward differences 
                     on 2D, 3D, 4D ImageData
                     under Neumann/Periodic boundary conditions'''
    def __init__(self, gm_domain, gm_range=None, bnd_cond=NEUMANN, **kwargs):

        self.num_threads = kwargs.get('num_threads', NUM_THREADS)

        self.gm_domain = gm_domain
        self.gm_range = gm_range

        #default is 'Neumann'
        self.bnd_cond = 0

        if bnd_cond == PERIODIC:
            self.bnd_cond = 1

        # Domain Geometry = Range Geometry if not stated
        if self.gm_range is None:
            self.gm_range = BlockGeometry(
                *[gm_domain for _ in range(len(gm_domain.shape))])

        if len(gm_domain.shape) == 4:
            # Voxel size wrt to channel direction == 1.0
            self.fd = cilacc.fdiff4D
        elif len(gm_domain.shape) == 3:
            self.fd = cilacc.fdiff3D
        elif len(gm_domain.shape) == 2:
            self.fd = cilacc.fdiff2D
        else:
            raise ValueError(
                'Number of dimensions not supported, expected 2, 3 or 4, got {}'
                .format(len(gm_domain.shape)))

        self.voxel_size_order = list(self.gm_domain.spacing)
        super(Gradient_C, self).__init__(domain_geometry=self.gm_domain,
                                         range_geometry=self.gm_range)
        print("Initialised GradientOperator with C backend running with ",
              cilacc.openMPtest(self.num_threads), " threads")

    @staticmethod
    def datacontainer_as_c_pointer(x):
        ndx = x.as_array()
        return ndx, ndx.ctypes.data_as(c_float_p)

    @staticmethod
    def ndarray_as_c_pointer(ndx):
        return ndx.ctypes.data_as(c_float_p)

    def direct(self, x, out=None):
        ndx = np.asarray(x.as_array(), dtype=np.float32)
        #ndx , x_p = Gradient_C.datacontainer_as_c_pointer(x)
        x_p = Gradient_C.ndarray_as_c_pointer(ndx)

        return_val = False
        if out is None:
            out = self.gm_range.allocate(None)
            return_val = True
        ndout = [el.as_array() for el in out.containers]

        #pass list of all arguments
        #arg1 = [Gradient_C.datacontainer_as_c_pointer(out.get_item(i))[1] for i in range(self.gm_range.shape[0])]
        arg1 = [
            Gradient_C.ndarray_as_c_pointer(ndout[i])
            for i in range(self.gm_range.shape[0])
        ]
        arg2 = [el for el in x.shape]
        args = arg1 + arg2 + [self.bnd_cond, 1, self.num_threads]
        self.fd(x_p, *args)

        for i in range(len(ndout)):
            out.get_item(i).fill(ndout[i])

        if any(elem != 1.0 for elem in self.voxel_size_order):
            out /= self.voxel_size_order
#        out /= self.voxel_size_order

        if return_val is True:
            return out

    def adjoint(self, x, out=None):

        return_val = False
        if out is None:
            out = self.gm_domain.allocate(None)
            return_val = True
        ndout = out.as_array()

        # ndout, out_p = Gradient_C.datacontainer_as_c_pointer(out)
        out_p = Gradient_C.ndarray_as_c_pointer(ndout)

        if any(elem != 1.0 for elem in self.voxel_size_order):
            tmp = x / self.voxel_size_order
        else:
            tmp = x
        ndx = [el.as_array() for el in tmp.containers]

        #arg1 = [Gradient_C.datacontainer_as_c_pointer(tmp.get_item(i))[1] for i in range(self.gm_range.shape[0])]
        arg1 = [
            Gradient_C.ndarray_as_c_pointer(ndx[i])
            for i in range(self.gm_range.shape[0])
        ]
        arg2 = [el for el in out.shape]
        args = arg1 + arg2 + [self.bnd_cond, 0, self.num_threads]

        self.fd(out_p, *args)
        out.fill(ndout)

        if return_val is True:
            return out
Exemplo n.º 4
0
class Gradient_C(LinearOperator):
    '''Finite Difference Operator:
            
            Computes first-order forward/backward differences 
                     on 2D, 3D, 4D ImageData
                     under Neumann/Periodic boundary conditions'''
    def __init__(self, gm_domain, gm_range=None, bnd_cond=NEUMANN, **kwargs):

        self.num_threads = kwargs.get('num_threads', NUM_THREADS)
        self.split = kwargs.get('split', False)
        self.gm_domain = gm_domain
        self.gm_range = gm_range
        self.ndim = self.gm_domain.length

        #default is 'Neumann'
        self.bnd_cond = 0

        if bnd_cond == PERIODIC:
            self.bnd_cond = 1

        # Domain Geometry = Range Geometry if not stated
        if self.gm_range is None:
            if self.split is True and 'channel' in self.gm_domain.dimension_labels:
                self.gm_range = BlockGeometry(
                    gm_domain,
                    BlockGeometry(
                        *[gm_domain for _ in range(len(gm_domain.shape) - 1)]))
            else:
                self.gm_range = BlockGeometry(
                    *[gm_domain for _ in range(len(gm_domain.shape))])
                self.split = False

        if len(gm_domain.shape) == 4:
            # Voxel size wrt to channel direction == 1.0
            self.fd = cilacc.fdiff4D
        elif len(gm_domain.shape) == 3:
            self.fd = cilacc.fdiff3D
        elif len(gm_domain.shape) == 2:
            self.fd = cilacc.fdiff2D
        else:
            raise ValueError(
                'Number of dimensions not supported, expected 2, 3 or 4, got {}'
                .format(len(gm_domain.shape)))

        self.voxel_size_order = list(self.gm_domain.spacing)
        super(Gradient_C, self).__init__(domain_geometry=self.gm_domain,
                                         range_geometry=self.gm_range)
        print("Initialised GradientOperator with C backend running with ",
              cilacc.openMPtest(self.num_threads), " threads")

    @staticmethod
    def datacontainer_as_c_pointer(x):
        ndx = x.as_array()
        return ndx, ndx.ctypes.data_as(c_float_p)

    @staticmethod
    def ndarray_as_c_pointer(ndx):
        return ndx.ctypes.data_as(c_float_p)

    def direct(self, x, out=None):
        ndx = np.asarray(x.as_array(), dtype=np.float32, order='C')
        x_p = Gradient_C.ndarray_as_c_pointer(ndx)

        return_val = False
        if out is None:
            out = self.gm_range.allocate(None)
            return_val = True

        if self.split is False:
            ndout = [el.as_array() for el in out.containers]
        else:
            ind = self.gm_domain.dimension_labels.index('channel')
            ndout = [el.as_array() for el in out.get_item(1).containers]
            ndout.insert(
                ind,
                out.get_item(0).as_array(
                ))  #insert channels dc at correct point for channel data

        #pass list of all arguments
        arg1 = [
            Gradient_C.ndarray_as_c_pointer(ndout[i])
            for i in range(len(ndout))
        ]
        arg2 = [el for el in x.shape]
        args = arg1 + arg2 + [self.bnd_cond, 1, self.num_threads]
        self.fd(x_p, *args)

        for i, el in enumerate(self.voxel_size_order):
            if el != 1:
                ndout[i] /= el

        #fill back out in corerct (non-traivial) order
        if self.split is False:
            for i in range(self.ndim):
                out.get_item(i).fill(ndout[i])
        else:
            ind = self.gm_domain.dimension_labels.index('channel')
            out.get_item(0).fill(ndout[ind])

            j = 0
            for i in range(self.ndim):
                if i != ind:
                    out.get_item(1).get_item(j).fill(ndout[i])
                    j += 1

        if return_val is True:
            return out

    def adjoint(self, x, out=None):

        return_val = False
        if out is None:
            out = self.gm_domain.allocate(None)
            return_val = True

        ndout = np.asarray(out.as_array(), dtype=np.float32, order='C')
        out_p = Gradient_C.ndarray_as_c_pointer(ndout)

        if self.split is False:
            ndx = [el.as_array() for el in x.containers]
        else:
            ind = self.gm_domain.dimension_labels.index('channel')
            ndx = [el.as_array() for el in x.get_item(1).containers]
            ndx.insert(ind, x.get_item(0).as_array())

        for i, el in enumerate(self.voxel_size_order):
            if el != 1:
                ndx[i] /= el

        arg1 = [
            Gradient_C.ndarray_as_c_pointer(ndx[i]) for i in range(self.ndim)
        ]
        arg2 = [el for el in out.shape]
        args = arg1 + arg2 + [self.bnd_cond, 0, self.num_threads]

        self.fd(out_p, *args)
        out.fill(ndout)

        #reset input data
        for i, el in enumerate(self.voxel_size_order):
            if el != 1:
                ndx[i] *= el

        if return_val is True:
            return out