diff options
Diffstat (limited to 'Wrappers')
-rwxr-xr-x | Wrappers/Python/ccpi/framework/BlockDataContainer.py | 97 | ||||
-rwxr-xr-x | Wrappers/Python/ccpi/framework/framework.py | 188 | ||||
-rwxr-xr-x | Wrappers/Python/test/test_BlockDataContainer.py | 6 | ||||
-rw-r--r-- | Wrappers/Python/test/test_functions.py | 10 | ||||
-rwxr-xr-x | Wrappers/Python/wip/pdhg_TV_denoising.py | 57 |
5 files changed, 118 insertions, 240 deletions
diff --git a/Wrappers/Python/ccpi/framework/BlockDataContainer.py b/Wrappers/Python/ccpi/framework/BlockDataContainer.py index 4655e1b..386cd87 100755 --- a/Wrappers/Python/ccpi/framework/BlockDataContainer.py +++ b/Wrappers/Python/ccpi/framework/BlockDataContainer.py @@ -45,6 +45,7 @@ class BlockDataContainer(object): DIVIDE = 'divide' POWER = 'power' __array_priority__ = 1 + __container_priority__ = 2 def __init__(self, *args, **kwargs): '''''' self.containers = args @@ -97,7 +98,6 @@ class BlockDataContainer(object): a = el.is_compatible(other) else: a = el.shape == other.shape -# print ("current element" , el.shape, "other ", other.shape, "same shape" , a) ret = ret and a return ret #return self.get_item(0).shape == other.shape @@ -111,92 +111,45 @@ class BlockDataContainer(object): def __getitem__(self, row): return self.get_item(row) -# def add(self, other, *args, **kwargs): -# if not self.is_compatible(other): -# raise ValueError('Incompatible for add') -# out = kwargs.get('out', None) -# #print ("args" , *args) -# if isinstance(other, Number): -# return type(self)(*[ el.add(other, *args, **kwargs) for el in self.containers], shape=self.shape) -# elif isinstance(other, list) or isinstance(other, numpy.ndarray): -# return type(self)(*[ el.add(ot, *args, **kwargs) for el,ot in zip(self.containers,other)], shape=self.shape) -# elif issubclass(other.__class__, DataContainer): -# # try to do algebra with one DataContainer. Will raise error if not compatible -# return type(self)(*[ el.add(other, *args, **kwargs) for el in self.containers], shape=self.shape) -# -# return type(self)( -# *[ el.add(ot, *args, **kwargs) for el,ot in zip(self.containers,other.containers)], -# shape=self.shape) -# -# def subtract(self, other, *args, **kwargs): -# if not self.is_compatible(other): -# raise ValueError('Incompatible for subtract') -# out = kwargs.get('out', None) -# if isinstance(other, Number): -# return type(self)(*[ el.subtract(other, *args, **kwargs) for el in self.containers], shape=self.shape) -# elif isinstance(other, list) or isinstance(other, numpy.ndarray): -# return type(self)(*[ el.subtract(ot, *args, **kwargs) for el,ot in zip(self.containers,other)], shape=self.shape) -# elif issubclass(other.__class__, DataContainer): -# # try to do algebra with one DataContainer. Will raise error if not compatible -# return type(self)(*[ el.subtract(other, *args, **kwargs) for el in self.containers], shape=self.shape) -# return type(self)(*[ el.subtract(ot, *args, **kwargs) for el,ot in zip(self.containers,other.containers)], -# shape=self.shape) -# -# def multiply(self, other, *args, **kwargs): -# if not self.is_compatible(other): -# raise ValueError('{} Incompatible for multiply'.format(other)) -# out = kwargs.get('out', None) -# if isinstance(other, Number): -# return type(self)(*[ el.multiply(other, *args, **kwargs) for el in self.containers], shape=self.shape) -# elif isinstance(other, list): -# return type(self)(*[ el.multiply(ot, *args, **kwargs) for el,ot in zip(self.containers,other)], shape=self.shape) -# elif isinstance(other, numpy.ndarray): -# return type(self)(*[ el.multiply(ot, *args, **kwargs) for el,ot in zip(self.containers,other)], shape=self.shape) -# elif issubclass(other.__class__, DataContainer): -# # try to do algebra with one DataContainer. Will raise error if not compatible -# return type(self)(*[ el.multiply(other, *args, **kwargs) for el in self.containers], shape=self.shape) -# return type(self)(*[ el.multiply(ot, *args, **kwargs) for el,ot in zip(self.containers,other.containers)], -# shape=self.shape) -# -# def divide_old(self, other, *args, **kwargs): -# if not self.is_compatible(other): -# raise ValueError('Incompatible for divide') -# out = kwargs.get('out', None) -# if isinstance(other, Number): -# return type(self)(*[ el.divide(other, *args, **kwargs) for el in self.containers], shape=self.shape) -# elif isinstance(other, list) or isinstance(other, numpy.ndarray): -# return type(self)(*[ el.divide(ot, *args, **kwargs) for el,ot in zip(self.containers,other)], shape=self.shape) -# elif issubclass(other.__class__, DataContainer): -# # try to do algebra with one DataContainer. Will raise error if not compatible -# if out is not None: -# kw = kwargs.copy() -# for i,el in enumerate(self.containers): -# kw['out'] = out.get_item(i) -# el.divide(other, *args, **kw) -# return -# else: -# return type(self)(*[ el.divide(other, *args, **kwargs) for el in self.containers], shape=self.shape) -# return type(self)(*[ el.divide(ot, *args, **kwargs) for el,ot in zip(self.containers,other.containers)], -# shape=self.shape) def add(self, other, *args, **kwargs): + '''Algebra: add method of BlockDataContainer with number/DataContainer or BlockDataContainer + + :param: other (number, DataContainer or subclasses or BlockDataContainer + :param: out (optional): provides a placehold for the resul. + ''' out = kwargs.get('out', None) if out is not None: self.binary_operations(BlockDataContainer.ADD, other, *args, **kwargs) else: return self.binary_operations(BlockDataContainer.ADD, other, *args, **kwargs) def subtract(self, other, *args, **kwargs): + '''Algebra: subtract method of BlockDataContainer with number/DataContainer or BlockDataContainer + + :param: other (number, DataContainer or subclasses or BlockDataContainer + :param: out (optional): provides a placehold for the resul. + ''' out = kwargs.get('out', None) if out is not None: self.binary_operations(BlockDataContainer.SUBTRACT, other, *args, **kwargs) else: return self.binary_operations(BlockDataContainer.SUBTRACT, other, *args, **kwargs) def multiply(self, other, *args, **kwargs): + '''Algebra: multiply method of BlockDataContainer with number/DataContainer or BlockDataContainer + + :param: other (number, DataContainer or subclasses or BlockDataContainer + :param: out (optional): provides a placehold for the resul. + ''' out = kwargs.get('out', None) if out is not None: self.binary_operations(BlockDataContainer.MULTIPLY, other, *args, **kwargs) else: return self.binary_operations(BlockDataContainer.MULTIPLY, other, *args, **kwargs) def divide(self, other, *args, **kwargs): + '''Algebra: divide method of BlockDataContainer with number/DataContainer or BlockDataContainer + + :param: other (number, DataContainer or subclasses or BlockDataContainer + :param: out (optional): provides a placehold for the resul. + ''' out = kwargs.get('out', None) if out is not None: self.binary_operations(BlockDataContainer.DIVIDE, other, *args, **kwargs) @@ -205,6 +158,14 @@ class BlockDataContainer(object): def binary_operations(self, operation, other, *args, **kwargs): + '''Algebra: generic method of algebric operation with BlockDataContainer with number/DataContainer or BlockDataContainer + + Provides commutativity with DataContainer and subclasses, i.e. this + class's reverse algebric methods take precedence w.r.t. direct algebric + methods of DataContainer and subclasses. + + This method is not to be used directly + ''' if not self.is_compatible(other): raise ValueError('Incompatible for divide') out = kwargs.get('out', None) diff --git a/Wrappers/Python/ccpi/framework/framework.py b/Wrappers/Python/ccpi/framework/framework.py index e03a29c..af4139b 100755 --- a/Wrappers/Python/ccpi/framework/framework.py +++ b/Wrappers/Python/ccpi/framework/framework.py @@ -320,6 +320,7 @@ class DataContainer(object): Data is currently held in a numpy arrays''' + __container_priority__ = 1 def __init__ (self, array, deep_copy=True, dimension_labels=None, **kwargs): '''Holds the data''' @@ -495,119 +496,21 @@ class DataContainer(object): return self.shape == other.shape ## algebra - def __add__(self, other, *args, **kwargs): - out = kwargs.get('out', None) - - if issubclass(type(other), DataContainer): - if self.check_dimensions(other): - out = self.as_array() + other.as_array() - return type(self)(out, - deep_copy=True, - dimension_labels=self.dimension_labels, - geometry=self.geometry) - else: - raise ValueError('Wrong shape: {0} and {1}'.format(self.shape, - other.shape)) - elif isinstance(other, (int, float, complex)): - return type(self)( - self.as_array() + other, - deep_copy=True, - dimension_labels=self.dimension_labels, - geometry=self.geometry) - else: - raise TypeError('Cannot {0} DataContainer with {1}'.format("add" , - type(other))) - # __add__ + def __add__(self, other): + return self.add(other) + def __mul__(self, other): + return self.multiply(other) def __sub__(self, other): - if issubclass(type(other), DataContainer): - if self.check_dimensions(other): - out = self.as_array() - other.as_array() - return type(self)(out, - deep_copy=True, - dimension_labels=self.dimension_labels, - geometry=self.geometry) - else: - raise ValueError('__sub__ Wrong shape: {0} and {1}'.format(self.shape, - other.shape)) - elif isinstance(other, (int, float, complex)): - return type(self)(self.as_array() - other, - deep_copy=True, - dimension_labels=self.dimension_labels, - geometry=self.geometry) - else: - raise TypeError('Cannot {0} DataContainer with {1}'.format("subtract" , - type(other))) - # __sub__ - def __truediv__(self,other): - return self.__div__(other) - + return self.subtract(other) def __div__(self, other): - if issubclass(type(other), DataContainer): - if self.check_dimensions(other): - out = self.as_array() / other.as_array() - return type(self)(out, - deep_copy=True, - dimension_labels=self.dimension_labels, - geometry=self.geometry) - else: - raise ValueError('__div__ Wrong shape: {0} and {1}'.format(self.shape, - other.shape)) - elif isinstance(other, (int, float, complex)): - return type(self)(self.as_array() / other, - deep_copy=True, - dimension_labels=self.dimension_labels, - geometry=self.geometry) - else: - raise TypeError('Cannot {0} DataContainer with {1}'.format("divide" , - type(other))) - # __div__ - + return self.divide(other) + def __truediv__(self, other): + return self.divide(other) def __pow__(self, other): - if issubclass(type(other), DataContainer): - if self.check_dimensions(other): - out = self.as_array() ** other.as_array() - return type(self)(out, - deep_copy=True, - dimension_labels=self.dimension_labels, - geometry=self.geometry) - else: - raise ValueError('__pow__ Wrong shape: {0} and {1}'.format(self.shape, - other.shape)) - elif isinstance(other, (int, float, complex)): - return type(self)(self.as_array() ** other, - deep_copy=True, - dimension_labels=self.dimension_labels, - geometry=self.geometry) - else: - raise TypeError('pow: Cannot {0} DataContainer with {1}'.format("power" , - type(other))) - # __pow__ + return self.power(other) + - def __mul__(self, other): - if issubclass(type(other), DataContainer): - if self.check_dimensions(other): - out = self.as_array() * other.as_array() - return type(self)(out, - deep_copy=True, - dimension_labels=self.dimension_labels, - geometry=self.geometry) - else: - raise ValueError('*:Wrong shape: {0} and {1}'.format(self.shape, - other.shape)) - elif isinstance(other, (int, float, complex,\ - numpy.int, numpy.int8, numpy.int16, numpy.int32, numpy.int64,\ - numpy.float, numpy.float16, numpy.float32, numpy.float64, \ - numpy.complex)): - return type(self)(self.as_array() * other, - deep_copy=True, - dimension_labels=self.dimension_labels, - geometry=self.geometry) - - else: - raise TypeError('Cannot {0} DataContainer with {1}'.format("multiply" , - type(other))) - # __mul__ # reverse operand def __radd__(self, other): @@ -648,54 +551,27 @@ class DataContainer(object): # (+=, -=, *=, /= , //=, # must return self - - def __iadd__(self, other): - if isinstance(other, (int, float)) : - numpy.add(self.array, other, out=self.array) - elif issubclass(type(other), DataContainer): - if self.check_dimensions(other): - numpy.add(self.array, other.array, out=self.array) - else: - raise ValueError('Dimensions do not match') - return self - # __iadd__ + kw = {'out':self} + return self.add(other, **kw) def __imul__(self, other): - if isinstance(other, (int, float)) : - arr = self.as_array() - numpy.multiply(arr, other, out=arr) - elif issubclass(type(other), DataContainer): - if self.check_dimensions(other): - numpy.multiply(self.array, other.array, out=self.array) - else: - raise ValueError('Dimensions do not match') - return self - # __imul__ + kw = {'out':self} + return self.multiply(other, **kw) def __isub__(self, other): - if isinstance(other, (int, float)) : - numpy.subtract(self.array, other, out=self.array) - elif issubclass(type(other), DataContainer): - if self.check_dimensions(other): - numpy.subtract(self.array, other.array, out=self.array) - else: - raise ValueError('Dimensions do not match') - return self - # __isub__ + kw = {'out':self} + return self.subtract(other, **kw) def __idiv__(self, other): - return self.__itruediv__(other) + kw = {'out':self} + return self.divide(other, **kw) + def __itruediv__(self, other): - if isinstance(other, (int, float)) : - numpy.divide(self.array, other, out=self.array) - elif issubclass(type(other), DataContainer): - if self.check_dimensions(other): - numpy.divide(self.array, other.array, out=self.array) - else: - raise ValueError('Dimensions do not match') - return self - # __idiv__ + kw = {'out':self} + return self.divide(other, **kw) + + def __str__ (self, representation=False): repres = "" @@ -802,15 +678,27 @@ class DataContainer(object): raise ValueError (message(type(self), "incompatible class:" , pwop.__name__, type(out))) def add(self, other, *args, **kwargs): + if hasattr(other, '__container_priority__') and \ + self.__class__.__container_priority__ < other.__class__.__container_priority__: + return other.add(self, *args, **kwargs) return self.pixel_wise_binary(numpy.add, other, *args, **kwargs) def subtract(self, other, *args, **kwargs): + if hasattr(other, '__container_priority__') and \ + self.__class__.__container_priority__ < other.__class__.__container_priority__: + return other.subtract(self, *args, **kwargs) return self.pixel_wise_binary(numpy.subtract, other, *args, **kwargs) def multiply(self, other, *args, **kwargs): + if hasattr(other, '__container_priority__') and \ + self.__class__.__container_priority__ < other.__class__.__container_priority__: + return other.multiply(self, *args, **kwargs) return self.pixel_wise_binary(numpy.multiply, other, *args, **kwargs) def divide(self, other, *args, **kwargs): + if hasattr(other, '__container_priority__') and \ + self.__class__.__container_priority__ < other.__class__.__container_priority__: + return other.divide(self, *args, **kwargs) return self.pixel_wise_binary(numpy.divide, other, *args, **kwargs) def power(self, other, *args, **kwargs): @@ -883,7 +771,7 @@ class DataContainer(object): class ImageData(DataContainer): '''DataContainer for holding 2D or 3D DataContainer''' - + __container_priority__ = 1 def __init__(self, array = None, deep_copy=False, @@ -1006,7 +894,7 @@ class ImageData(DataContainer): class AcquisitionData(DataContainer): '''DataContainer for holding 2D or 3D sinogram''' - + __container_priority__ = 1 def __init__(self, array = None, deep_copy=True, diff --git a/Wrappers/Python/test/test_BlockDataContainer.py b/Wrappers/Python/test/test_BlockDataContainer.py index 0dd0657..a20f289 100755 --- a/Wrappers/Python/test/test_BlockDataContainer.py +++ b/Wrappers/Python/test/test_BlockDataContainer.py @@ -369,6 +369,12 @@ class TestBlockDataContainer(unittest.TestCase): c5 = nbdc.get_item(0).power(2).sum()
c5a = nbdc.power(2).sum()
print ("sum", c5a, c5)
+
+ cp0 = BlockDataContainer(data0,data2)
+ a = cp0 * data2
+ b = data2 * cp0
+ self.assertBlockDataContainerEqual(a,b)
+
print ("test_Nested_BlockDataContainer OK")
def stest_NestedBlockDataContainer2(self):
diff --git a/Wrappers/Python/test/test_functions.py b/Wrappers/Python/test/test_functions.py index bc1f034..22721fa 100644 --- a/Wrappers/Python/test/test_functions.py +++ b/Wrappers/Python/test/test_functions.py @@ -323,13 +323,15 @@ class TestFunction(unittest.TestCase): # Define no scale and scaled f_no_scaled = MixedL21Norm() - #f_scaled = 0.5 * MixedL21Norm() + f_scaled = 1 * MixedL21Norm() # call - # a1 = f_no_scaled(U) - # a2 = f_scaled(U) - # self.assertBlockDataContainerEqual(a1,a2) + a1 = f_no_scaled(U) + a2 = f_scaled(U) + self.assertAlmostEqual(a1,a2) + + tmp = [ el**2 for el in U.containers ] self.assertBlockDataContainerEqual(BlockDataContainer(*tmp), U.power(2)) diff --git a/Wrappers/Python/wip/pdhg_TV_denoising.py b/Wrappers/Python/wip/pdhg_TV_denoising.py index 2072ea3..73fd57a 100755 --- a/Wrappers/Python/wip/pdhg_TV_denoising.py +++ b/Wrappers/Python/wip/pdhg_TV_denoising.py @@ -91,36 +91,57 @@ tau = 1/(sigma*normK**2) opt = {'niter':2000} opt1 = {'niter':2000, 'memopt': True} -t1 = timer() -res, time, primal, dual, pdgap = PDHG_old(f, g, operator, tau = tau, sigma = sigma, opt = opt) -print(timer()-t1) +#t1 = timer() +#res, time, primal, dual, pdgap = PDHG_old(f, g, operator, tau = tau, sigma = sigma, opt = opt) +#print(timer()-t1) +# +#print("with memopt \n") +# +#t2 = timer() +#res1, time1, primal1, dual1, pdgap1 = PDHG_old(f, g, operator, tau = tau, sigma = sigma, opt = opt1) +#print(timer()-t2) + +pdhg = PDHG(f=f,g=g,operator=operator, tau=tau, sigma=sigma) +pdhg.max_iteration = 2000 +pdhg.update_objective_interval = 100 + + +pdhgo = PDHG(f=f,g=g,operator=operator, tau=tau, sigma=sigma, memopt=True) +pdhgo.max_iteration = 2000 +pdhgo.update_objective_interval = 100 -print("with memopt \n") +steps = [timer()] +pdhgo.run(2000) +steps.append(timer()) +t1 = dt(steps) + +pdhg.run(2000) +steps.append(timer()) +t2 = dt(steps) + +print ("Time difference {}s {}s {}s Speedup {:.2f}".format(t1,t2,t2-t1, t2/t1)) +res = pdhg.get_output() +res1 = pdhgo.get_output() + +diff = (res-res1) +print ("diff norm {} max {}".format(diff.norm(), diff.abs().as_array().max())) +print ("Sum ( abs(diff) ) {}".format(diff.abs().sum())) -t2 = timer() -res1, time1, primal1, dual1, pdgap1 = PDHG_old(f, g, operator, tau = tau, sigma = sigma, opt = opt1) -print(timer()-t2) plt.figure(figsize=(5,5)) +plt.subplot(1,3,1) plt.imshow(res.as_array()) plt.colorbar() -plt.show() +#plt.show() -plt.figure(figsize=(5,5)) +#plt.figure(figsize=(5,5)) +plt.subplot(1,3,2) plt.imshow(res1.as_array()) plt.colorbar() -plt.show() +#plt.show() -diff = np.abs(res1.as_array()-res.as_array()) -plt.figure(figsize=(5,5)) -plt.imshow(diff) -plt.colorbar() -plt.show() -diff = (res-res1) -print ("diff norm {} max {}".format(diff.norm(), diff.abs().as_array().max())) -print ("Sum ( abs(diff) ) {}".format(diff.abs().sum())) #======= ## opt = {'niter':2000, 'memopt': True} # |