diff options
-rw-r--r-- | Wrappers/Python/ccpi/framework.py | 96 | ||||
-rwxr-xr-x | Wrappers/Python/ccpi/optimisation/funcs.py | 30 | ||||
-rwxr-xr-x | Wrappers/Python/ccpi/optimisation/ops.py | 6 | ||||
-rw-r--r-- | Wrappers/Python/conda-recipe/meta.yaml | 5 | ||||
-rwxr-xr-x | Wrappers/Python/conda-recipe/run_test.py | 1012 | ||||
-rw-r--r-- | Wrappers/Python/wip/demo_compare_cvx.py | 62 |
6 files changed, 673 insertions, 538 deletions
diff --git a/Wrappers/Python/ccpi/framework.py b/Wrappers/Python/ccpi/framework.py index 7249d64..4d74d2b 100644 --- a/Wrappers/Python/ccpi/framework.py +++ b/Wrappers/Python/ccpi/framework.py @@ -627,8 +627,8 @@ class DataContainer(object): .format(len(self.shape),len(new_order))) - def copy(self): - '''alias of clone''' + def copy(self): + '''alias of clone''' return self.clone() ## binary operations @@ -647,49 +647,51 @@ class DataContainer(object): elif issubclass(type(out), DataContainer) and issubclass(type(x2), DataContainer): if self.check_dimensions(out) and self.check_dimensions(x2): - pwop(self.as_array(), x2.as_array(), *args, out=out.as_array(), **kwargs ) - return type(self)(out.as_array(), - deep_copy=False, - dimension_labels=self.dimension_labels, - geometry=self.geometry) + pwop(self.as_array(), x2.as_array(), out=out.as_array(), *args, **kwargs ) + #return type(self)(out.as_array(), + # deep_copy=False, + # dimension_labels=self.dimension_labels, + # geometry=self.geometry) + return out else: raise ValueError(message(type(self),"Wrong size for data memory: ", out.shape,self.shape)) elif issubclass(type(out), DataContainer) and isinstance(x2, (int,float,complex)): if self.check_dimensions(out): - pwop(self.as_array(), x2, *args, out=out.as_array(), **kwargs ) - return type(self)(out.as_array(), - deep_copy=False, - dimension_labels=self.dimension_labels, - geometry=self.geometry) + pwop(self.as_array(), x2, out=out.as_array(), *args, **kwargs ) + #return type(self)(out.as_array(), + # deep_copy=False, + # dimension_labels=self.dimension_labels, + # geometry=self.geometry) + return out else: raise ValueError(message(type(self),"Wrong size for data memory: ", out.shape,self.shape)) elif issubclass(type(out), numpy.ndarray): if self.array.shape == out.shape and self.array.dtype == out.dtype: - pwop(self.as_array(), x2 , *args, out=out, **kwargs) - return type(self)(out, - deep_copy=False, - dimension_labels=self.dimension_labels, - geometry=self.geometry) + pwop(self.as_array(), x2 , out=out, *args, **kwargs) + #return type(self)(out, + # deep_copy=False, + # dimension_labels=self.dimension_labels, + # geometry=self.geometry) else: raise ValueError (message(type(self), "incompatible class:" , pwop.__name__, type(out))) def add(self, other , out=None, *args, **kwargs): - return self.pixel_wise_binary(numpy.add, other, *args, out=out, **kwargs) + return self.pixel_wise_binary(numpy.add, other, out=out, *args, **kwargs) def subtract(self, other, out=None , *args, **kwargs): - return self.pixel_wise_binary(numpy.subtract, other, *args, out=out, **kwargs) + return self.pixel_wise_binary(numpy.subtract, other, out=out, *args, **kwargs) def multiply(self, other , out=None, *args, **kwargs): - return self.pixel_wise_binary(numpy.multiply, other, *args, out=out, **kwargs) + return self.pixel_wise_binary(numpy.multiply, other, out=out, *args, **kwargs) def divide(self, other , out=None ,*args, **kwargs): - return self.pixel_wise_binary(numpy.divide, other, *args, out=out, **kwargs) + return self.pixel_wise_binary(numpy.divide, other, out=out, *args, **kwargs) def power(self, other , out=None, *args, **kwargs): - return self.pixel_wise_binary(numpy.power, other, *args, out=out, **kwargs) + return self.pixel_wise_binary(numpy.power, other, out=out, *args, **kwargs) - def maximum(self,x2, out=None): - return self.pixel_wise_binary(numpy.maximum, x2=x2, out=out) + def maximum(self,x2, out=None, *args, **kwargs): + return self.pixel_wise_binary(numpy.maximum, x2=x2, out=out, *args, **kwargs) ## unary operations @@ -702,36 +704,36 @@ class DataContainer(object): geometry=self.geometry) elif issubclass(type(out), DataContainer): if self.check_dimensions(out): - pwop(self.as_array(), *args, out=out.as_array(), **kwargs ) - return type(self)(out.as_array(), - deep_copy=False, - dimension_labels=self.dimension_labels, - geometry=self.geometry) + pwop(self.as_array(), out=out.as_array(), *args, **kwargs ) + #return type(self)(out.as_array(), + # deep_copy=False, + # dimension_labels=self.dimension_labels, + # geometry=self.geometry) else: raise ValueError(message(type(self),"Wrong size for data memory: ", out.shape,self.shape)) elif issubclass(type(out), numpy.ndarray): if self.array.shape == out.shape and self.array.dtype == out.dtype: - pwop(self.as_array(), *args, out=out, **kwargs) - return type(self)(out, - deep_copy=False, - dimension_labels=self.dimension_labels, - geometry=self.geometry) + pwop(self.as_array(), out=out, *args, **kwargs) + #return type(self)(out, + # deep_copy=False, + # dimension_labels=self.dimension_labels, + # geometry=self.geometry) else: raise ValueError (message(type(self), "incompatible class:" , pwop.__name__, type(out))) - def abs(self, out=None): - return self.pixel_wise_unary(numpy.abs, out=out) + def abs(self, out=None, *args, **kwargs): + return self.pixel_wise_unary(numpy.abs, out=out, *args, **kwargs) - def sign(self, out=None): + def sign(self, out=None, *args, **kwargs): #out = numpy.sign(self.as_array() ) #return type(self)(out, # deep_copy=False, # dimension_labels=self.dimension_labels, # geometry=self.geometry) - return self.pixel_wise_unary(numpy.sign , out=out) + return self.pixel_wise_unary(numpy.sign , out=out, *args, **kwargs) - def sqrt(self, out=None): - return self.pixel_wise_unary(numpy.sqrt, out=out) + def sqrt(self, out=None, *args, **kwargs): + return self.pixel_wise_unary(numpy.sqrt, out=out, *args, **kwargs) #def __abs__(self): # operation = FM.OPERATION.ABS @@ -739,9 +741,9 @@ class DataContainer(object): # __abs__ ## reductions - def sum(self): - return self.as_array().sum() - + def sum(self, out=None, *args, **kwargs): + return self.as_array().sum(*args, **kwargs) + #return self.pixel_wise_unary(numpy.sum, out=out, *args, **kwargs) class ImageData(DataContainer): '''DataContainer for holding 2D or 3D DataContainer''' @@ -805,7 +807,7 @@ class ImageData(DataContainer): raise ValueError('Please pass either a DataContainer, ' +\ 'a numpy array or a geometry') else: - if type(array) == DataContainer: + if issubclass(type(array) , DataContainer): # if the array is a DataContainer get the info from there if not ( array.number_of_dimensions == 2 or \ array.number_of_dimensions == 3 or \ @@ -817,7 +819,7 @@ class ImageData(DataContainer): # array.dimension_labels, **kwargs) super(ImageData, self).__init__(array.as_array(), deep_copy, array.dimension_labels, **kwargs) - elif type(array) == numpy.ndarray: + elif issubclass(type(array) , numpy.ndarray): if not ( array.ndim == 2 or array.ndim == 3 or array.ndim == 4 ): raise ValueError( 'Number of dimensions are not 2 or 3 or 4 : {0}'\ @@ -914,7 +916,7 @@ class AcquisitionData(DataContainer): dimension_labels, **kwargs) else: - if type(array) == DataContainer: + if issubclass(type(array) ,DataContainer): # if the array is a DataContainer get the info from there if not ( array.number_of_dimensions == 2 or \ array.number_of_dimensions == 3 or \ @@ -926,7 +928,7 @@ class AcquisitionData(DataContainer): # array.dimension_labels, **kwargs) super(AcquisitionData, self).__init__(array.as_array(), deep_copy, array.dimension_labels, **kwargs) - elif type(array) == numpy.ndarray: + elif issubclass(type(array) ,numpy.ndarray): if not ( array.ndim == 2 or array.ndim == 3 or array.ndim == 4 ): raise ValueError( 'Number of dimensions are not 2 or 3 or 4 : {0}'\ diff --git a/Wrappers/Python/ccpi/optimisation/funcs.py b/Wrappers/Python/ccpi/optimisation/funcs.py index 0ed77ae..db00e9f 100755 --- a/Wrappers/Python/ccpi/optimisation/funcs.py +++ b/Wrappers/Python/ccpi/optimisation/funcs.py @@ -45,6 +45,7 @@ class Function(object): def gradient(self, x, out=None): raise NotImplementedError def proximal(self, x, tau, out=None): raise NotImplementedError + class Norm2(Function): def __init__(self, @@ -108,7 +109,6 @@ class Norm2(Function): else: raise ValueError ('Wrong size: x{0} out{1}'.format(x.shape,out.shape) ) - class TV2D(Norm2): @@ -193,20 +193,21 @@ class ZeroFun(Function): def prox(self,x,tau): return x.copy() - def proximal(self, x, tau, out=None): if out is None: - return self.prox(x,tau) + return self.prox(x, tau) else: if isSizeCorrect(out, x): - # check dimensionality - if issubclass(type(out), DataContainer): - out.fill(x) - - elif issubclass(type(out) , numpy.ndarray): - out[:] = x - else: - raise ValueError ('Wrong size: x{0} out{1}'.format(x.shape,out.shape) ) + # check dimensionality + if issubclass(type(out), DataContainer): + out.fill(x) + + elif issubclass(type(out) , numpy.ndarray): + out[:] = x + else: + raise ValueError ('Wrong size: x{0} out{1}' + .format(x.shape,out.shape) ) + # A more interesting example, least squares plus 1-norm minimization. # Define class to represent 1-norm including prox function class Norm1(Function): @@ -229,11 +230,12 @@ class Norm1(Function): def prox(self,x,tau): return (x.abs() - tau*self.gamma).maximum(0) * x.sign() + def proximal(self, x, tau, out=None): if out is None: - return self.prox(x,tau) + return self.prox(x, tau) else: - if isSizeCorrect(out, x): + if isSizeCorrect(x,out): # check dimensionality if issubclass(type(out), DataContainer): v = (x.abs() - tau*self.gamma).maximum(0) @@ -248,7 +250,6 @@ class Norm1(Function): else: raise ValueError ('Wrong size: x{0} out{1}'.format(x.shape,out.shape) ) - # Box constraints indicator function. Calling returns 0 if argument is within # the box. The prox operator is projection onto the box. Only implements one # scalar lower and one upper as constraint on all elements. Should generalise @@ -290,4 +291,3 @@ class IndicatorBox(Function): x.sign(out=self.sign_x) out.__imul__( self.sign_x ) - diff --git a/Wrappers/Python/ccpi/optimisation/ops.py b/Wrappers/Python/ccpi/optimisation/ops.py index c6775a8..96f85d8 100755 --- a/Wrappers/Python/ccpi/optimisation/ops.py +++ b/Wrappers/Python/ccpi/optimisation/ops.py @@ -47,6 +47,7 @@ class Operator(object): class Identity(Operator): def __init__(self): self.s1 = 1.0 + self.L = 1 super(Identity, self).__init__() def direct(self,x,out=None): @@ -110,18 +111,19 @@ class FiniteDiff2D(Operator): def direct(self,x, out=None): '''Forward differences with Neumann BC.''' # FIXME this seems to be working only with numpy arrays + d1 = numpy.zeros_like(x.as_array()) d1[:,:-1] = x.as_array()[:,1:] - x.as_array()[:,:-1] d2 = numpy.zeros_like(x.as_array()) d2[:-1,:] = x.as_array()[1:,:] - x.as_array()[:-1,:] d = numpy.stack((d1,d2),0) - + #x.geometry.voxel_num_z = 2 return type(x)(d,False,geometry=x.geometry) def adjoint(self,x, out=None): '''Backward differences, Neumann BC.''' Nrows = x.get_dimension_size('horizontal_x') - Ncols = x.get_dimension_size('horizontal_x') + Ncols = x.get_dimension_size('horizontal_y') Nchannels = 1 if len(x.shape) == 4: Nchannels = x.get_dimension_size('channel') diff --git a/Wrappers/Python/conda-recipe/meta.yaml b/Wrappers/Python/conda-recipe/meta.yaml index 4b19a68..327cdcb 100644 --- a/Wrappers/Python/conda-recipe/meta.yaml +++ b/Wrappers/Python/conda-recipe/meta.yaml @@ -1,6 +1,6 @@ package: name: ccpi-framework - version: 0.11.0 + version: 0.11.1 build: @@ -12,7 +12,6 @@ build: requirements: build: - python - - numpy - setuptools run: @@ -23,7 +22,7 @@ requirements: run: - python - numpy - - cvxpy + - cvxpy # [not win] - scipy - matplotlib diff --git a/Wrappers/Python/conda-recipe/run_test.py b/Wrappers/Python/conda-recipe/run_test.py index c1dc59b..d6bc340 100755 --- a/Wrappers/Python/conda-recipe/run_test.py +++ b/Wrappers/Python/conda-recipe/run_test.py @@ -14,12 +14,17 @@ from ccpi.optimisation.funcs import Norm2sq from ccpi.optimisation.funcs import ZeroFun
from ccpi.optimisation.funcs import Norm1
from ccpi.optimisation.funcs import TV2D
+from ccpi.optimisation.funcs import Norm2
from ccpi.optimisation.ops import LinearOperatorMatrix
from ccpi.optimisation.ops import TomoIdentity
from ccpi.optimisation.ops import Identity
-from cvxpy import *
+try:
+ from cvxpy import *
+ cvx_not_installable = False
+except ImportError:
+ cvx_not_installable = True
def aid(x):
@@ -27,76 +32,99 @@ def aid(x): # block address of an array.
return x.__array_interface__['data'][0]
-def dt (steps):
+
+def dt(steps):
return steps[-1] - steps[-2]
+
class TestDataContainer(unittest.TestCase):
-
+ def create_simple_ImageData(self):
+ N = 64
+ ig = ImageGeometry(voxel_num_x=N, voxel_num_y=N)
+ Phantom = ImageData(geometry=ig)
+
+ x = Phantom.as_array()
+
+ x[int(round(N/4)):int(round(3*N/4)),
+ int(round(N/4)):int(round(3*N/4))] = 0.5
+ x[int(round(N/8)):int(round(7*N/8)),
+ int(round(3*N/8)):int(round(5*N/8))] = 1
+
+ return (ig, Phantom)
+
+ def create_DataContainer(self, X,Y,Z, value=1):
+ steps = [timer()]
+ a = value * numpy.ones((X, Y, Z), dtype='float32')
+ steps.append(timer())
+ t0 = dt(steps)
+ #print("a refcount " , sys.getrefcount(a))
+ ds = DataContainer(a, False, ['X', 'Y', 'Z'])
+ return ds
+
def test_creation_nocopy(self):
- shape = (2,3,4,5)
+ shape = (2, 3, 4, 5)
size = shape[0]
for i in range(1, len(shape)):
size = size * shape[i]
#print("a refcount " , sys.getrefcount(a))
- a = numpy.asarray([i for i in range( size )])
+ a = numpy.asarray([i for i in range(size)])
#print("a refcount " , sys.getrefcount(a))
a = numpy.reshape(a, shape)
#print("a refcount " , sys.getrefcount(a))
- ds = DataContainer(a, False, ['X', 'Y','Z' ,'W'])
+ ds = DataContainer(a, False, ['X', 'Y', 'Z', 'W'])
#print("a refcount " , sys.getrefcount(a))
- self.assertEqual(sys.getrefcount(a),3)
- self.assertEqual(ds.dimension_labels , {0: 'X', 1: 'Y', 2: 'Z', 3: 'W'})
-
+ self.assertEqual(sys.getrefcount(a), 3)
+ self.assertEqual(ds.dimension_labels, {0: 'X', 1: 'Y', 2: 'Z', 3: 'W'})
+
def testGb_creation_nocopy(self):
- X,Y,Z = 512,512,512
- X,Y,Z = 256,512,512
+ X, Y, Z = 512, 512, 512
+ X, Y, Z = 256, 512, 512
steps = [timer()]
- a = numpy.ones((X,Y,Z), dtype='float32')
+ a = numpy.ones((X, Y, Z), dtype='float32')
steps.append(timer())
t0 = dt(steps)
print("test clone")
#print("a refcount " , sys.getrefcount(a))
- ds = DataContainer(a, False, ['X', 'Y','Z'])
+ ds = DataContainer(a, False, ['X', 'Y', 'Z'])
#print("a refcount " , sys.getrefcount(a))
- self.assertEqual(sys.getrefcount(a),3)
+ self.assertEqual(sys.getrefcount(a), 3)
ds1 = ds.copy()
self.assertNotEqual(aid(ds.as_array()), aid(ds1.as_array()))
ds1 = ds.clone()
self.assertNotEqual(aid(ds.as_array()), aid(ds1.as_array()))
-
-
+
def testInlineAlgebra(self):
- print ("Test Inline Algebra")
- X,Y,Z = 1024,512,512
- X,Y,Z = 256,512,512
+ print("Test Inline Algebra")
+ X, Y, Z = 1024, 512, 512
+ X, Y, Z = 256, 512, 512
steps = [timer()]
- a = numpy.ones((X,Y,Z), dtype='float32')
+ a = numpy.ones((X, Y, Z), dtype='float32')
steps.append(timer())
t0 = dt(steps)
print(t0)
#print("a refcount " , sys.getrefcount(a))
- ds = DataContainer(a, False, ['X', 'Y','Z'])
+ ds = DataContainer(a, False, ['X', 'Y', 'Z'])
#ds.__iadd__( 2 )
ds += 2
steps.append(timer())
print(dt(steps))
- self.assertEqual(ds.as_array()[0][0][0],3.)
- #ds.__isub__( 2 )
+ self.assertEqual(ds.as_array()[0][0][0], 3.)
+ #ds.__isub__( 2 )
ds -= 2
steps.append(timer())
print(dt(steps))
- self.assertEqual(ds.as_array()[0][0][0],1.)
+ self.assertEqual(ds.as_array()[0][0][0], 1.)
#ds.__imul__( 2 )
ds *= 2
steps.append(timer())
print(dt(steps))
- self.assertEqual(ds.as_array()[0][0][0],2.)
+ self.assertEqual(ds.as_array()[0][0][0], 2.)
#ds.__idiv__( 2 )
ds /= 2
steps.append(timer())
print(dt(steps))
- self.assertEqual(ds.as_array()[0][0][0],1.)
-
+ self.assertEqual(ds.as_array()[0][0][0], 1.)
+
ds1 = ds.copy()
#ds1.__iadd__( 1 )
ds1 += 1
@@ -104,367 +132,371 @@ class TestDataContainer(unittest.TestCase): ds += ds1
steps.append(timer())
print(dt(steps))
- self.assertEqual(ds.as_array()[0][0][0],3.)
+ self.assertEqual(ds.as_array()[0][0][0], 3.)
#ds.__isub__( ds1 )
ds -= ds1
steps.append(timer())
print(dt(steps))
- self.assertEqual(ds.as_array()[0][0][0],1.)
+ self.assertEqual(ds.as_array()[0][0][0], 1.)
#ds.__imul__( ds1 )
ds *= ds1
steps.append(timer())
print(dt(steps))
- self.assertEqual(ds.as_array()[0][0][0],2.)
+ self.assertEqual(ds.as_array()[0][0][0], 2.)
#ds.__idiv__( ds1 )
ds /= ds1
steps.append(timer())
print(dt(steps))
- self.assertEqual(ds.as_array()[0][0][0],1.)
-
-
+ self.assertEqual(ds.as_array()[0][0][0], 1.)
+
def test_unary_operations(self):
- print ("Test unary operations")
- X,Y,Z = 1024,512,512
- X,Y,Z = 256,512,512
+ print("Test unary operations")
+ X, Y, Z = 1024, 512, 512
+ X, Y, Z = 256, 512, 512
steps = [timer()]
- a = -numpy.ones((X,Y,Z), dtype='float32')
+ a = -numpy.ones((X, Y, Z), dtype='float32')
steps.append(timer())
t0 = dt(steps)
print(t0)
#print("a refcount " , sys.getrefcount(a))
- ds = DataContainer(a, False, ['X', 'Y','Z'])
-
+ ds = DataContainer(a, False, ['X', 'Y', 'Z'])
+
ds.sign(out=ds)
steps.append(timer())
print(dt(steps))
- self.assertEqual(ds.as_array()[0][0][0],-1.)
-
+ self.assertEqual(ds.as_array()[0][0][0], -1.)
+
ds.abs(out=ds)
steps.append(timer())
print(dt(steps))
- self.assertEqual(ds.as_array()[0][0][0],1.)
-
- ds.__imul__( 2 )
+ self.assertEqual(ds.as_array()[0][0][0], 1.)
+
+ ds.__imul__(2)
ds.sqrt(out=ds)
steps.append(timer())
print(dt(steps))
- self.assertEqual(ds.as_array()[0][0][0],numpy.sqrt(2., dtype='float32'))
-
-
-
+ self.assertEqual(ds.as_array()[0][0][0],
+ numpy.sqrt(2., dtype='float32'))
+
def test_binary_operations(self):
self.binary_add()
self.binary_subtract()
self.binary_multiply()
self.binary_divide()
-
+
def binary_add(self):
- print ("Test binary add")
- X,Y,Z = 512,512,512
- X,Y,Z = 256,512,512
+ print("Test binary add")
+ X, Y, Z = 512, 512, 512
+ X, Y, Z = 256, 512, 512
steps = [timer()]
- a = numpy.ones((X,Y,Z), dtype='float32')
+ a = numpy.ones((X, Y, Z), dtype='float32')
steps.append(timer())
t0 = dt(steps)
-
+
#print("a refcount " , sys.getrefcount(a))
- ds = DataContainer(a, False, ['X', 'Y','Z'])
+ ds = DataContainer(a, False, ['X', 'Y', 'Z'])
ds1 = ds.copy()
-
+
steps.append(timer())
ds.add(ds1, out=ds)
steps.append(timer())
t1 = dt(steps)
- print("ds.add(ds1, out=ds)",dt(steps))
+ print("ds.add(ds1, out=ds)", dt(steps))
steps.append(timer())
ds2 = ds.add(ds1)
steps.append(timer())
t2 = dt(steps)
- print("ds2 = ds.add(ds1)",dt(steps))
-
- self.assertLess(t1,t2)
- self.assertEqual(ds.as_array()[0][0][0] , 2.)
-
+ print("ds2 = ds.add(ds1)", dt(steps))
+
+ self.assertLess(t1, t2)
+ self.assertEqual(ds.as_array()[0][0][0], 2.)
+
ds0 = ds
- ds0.add(2,out=ds0)
+ ds0.add(2, out=ds0)
steps.append(timer())
- print ("ds0.add(2,out=ds0)", dt(steps), 3 , ds0.as_array()[0][0][0])
+ print("ds0.add(2,out=ds0)", dt(steps), 3, ds0.as_array()[0][0][0])
self.assertEqual(4., ds0.as_array()[0][0][0])
-
- dt1 = dt(steps)
+
+ dt1 = dt(steps)
ds3 = ds0.add(2)
steps.append(timer())
- print ("ds3 = ds0.add(2)", dt(steps), 5 , ds3.as_array()[0][0][0])
+ print("ds3 = ds0.add(2)", dt(steps), 5, ds3.as_array()[0][0][0])
dt2 = dt(steps)
- self.assertLess(dt1,dt2)
-
+ self.assertLess(dt1, dt2)
+
def binary_subtract(self):
- print ("Test binary subtract")
- X,Y,Z = 512,512,512
+ print("Test binary subtract")
+ X, Y, Z = 512, 512, 512
steps = [timer()]
- a = numpy.ones((X,Y,Z), dtype='float32')
+ a = numpy.ones((X, Y, Z), dtype='float32')
steps.append(timer())
t0 = dt(steps)
-
+
#print("a refcount " , sys.getrefcount(a))
- ds = DataContainer(a, False, ['X', 'Y','Z'])
+ ds = DataContainer(a, False, ['X', 'Y', 'Z'])
ds1 = ds.copy()
-
+
steps.append(timer())
ds.subtract(ds1, out=ds)
steps.append(timer())
t1 = dt(steps)
- print("ds.subtract(ds1, out=ds)",dt(steps))
+ print("ds.subtract(ds1, out=ds)", dt(steps))
self.assertEqual(0., ds.as_array()[0][0][0])
-
+
steps.append(timer())
ds2 = ds.subtract(ds1)
self.assertEqual(-1., ds2.as_array()[0][0][0])
-
+
steps.append(timer())
t2 = dt(steps)
- print("ds2 = ds.subtract(ds1)",dt(steps))
-
- self.assertLess(t1,t2)
-
+ print("ds2 = ds.subtract(ds1)", dt(steps))
+
+ self.assertLess(t1, t2)
+
del ds1
ds0 = ds.copy()
steps.append(timer())
- ds0.subtract(2,out=ds0)
+ ds0.subtract(2, out=ds0)
#ds0.__isub__( 2 )
steps.append(timer())
- print ("ds0.subtract(2,out=ds0)", dt(steps), -2. , ds0.as_array()[0][0][0])
+ print("ds0.subtract(2,out=ds0)", dt(
+ steps), -2., ds0.as_array()[0][0][0])
self.assertEqual(-2., ds0.as_array()[0][0][0])
-
- dt1 = dt(steps)
+
+ dt1 = dt(steps)
ds3 = ds0.subtract(2)
steps.append(timer())
- print ("ds3 = ds0.subtract(2)", dt(steps), 0. , ds3.as_array()[0][0][0])
+ print("ds3 = ds0.subtract(2)", dt(steps), 0., ds3.as_array()[0][0][0])
dt2 = dt(steps)
- self.assertLess(dt1,dt2)
+ self.assertLess(dt1, dt2)
self.assertEqual(-2., ds0.as_array()[0][0][0])
self.assertEqual(-4., ds3.as_array()[0][0][0])
-
+
def binary_multiply(self):
- print ("Test binary multiply")
- X,Y,Z = 1024,512,512
- X,Y,Z = 256,512,512
+ print("Test binary multiply")
+ X, Y, Z = 1024, 512, 512
+ X, Y, Z = 256, 512, 512
steps = [timer()]
- a = numpy.ones((X,Y,Z), dtype='float32')
+ a = numpy.ones((X, Y, Z), dtype='float32')
steps.append(timer())
t0 = dt(steps)
-
+
#print("a refcount " , sys.getrefcount(a))
- ds = DataContainer(a, False, ['X', 'Y','Z'])
+ ds = DataContainer(a, False, ['X', 'Y', 'Z'])
ds1 = ds.copy()
-
+
steps.append(timer())
ds.multiply(ds1, out=ds)
steps.append(timer())
t1 = dt(steps)
- print("ds.multiply(ds1, out=ds)",dt(steps))
+ print("ds.multiply(ds1, out=ds)", dt(steps))
steps.append(timer())
ds2 = ds.multiply(ds1)
steps.append(timer())
t2 = dt(steps)
- print("ds2 = ds.multiply(ds1)",dt(steps))
-
- self.assertLess(t1,t2)
-
+ print("ds2 = ds.multiply(ds1)", dt(steps))
+
+ self.assertLess(t1, t2)
+
ds0 = ds
- ds0.multiply(2,out=ds0)
+ ds0.multiply(2, out=ds0)
steps.append(timer())
- print ("ds0.multiply(2,out=ds0)", dt(steps), 2. , ds0.as_array()[0][0][0])
+ print("ds0.multiply(2,out=ds0)", dt(
+ steps), 2., ds0.as_array()[0][0][0])
self.assertEqual(2., ds0.as_array()[0][0][0])
-
- dt1 = dt(steps)
+
+ dt1 = dt(steps)
ds3 = ds0.multiply(2)
steps.append(timer())
- print ("ds3 = ds0.multiply(2)", dt(steps), 4. , ds3.as_array()[0][0][0])
+ print("ds3 = ds0.multiply(2)", dt(steps), 4., ds3.as_array()[0][0][0])
dt2 = dt(steps)
- self.assertLess(dt1,dt2)
+ self.assertLess(dt1, dt2)
self.assertEqual(4., ds3.as_array()[0][0][0])
self.assertEqual(2., ds.as_array()[0][0][0])
-
+
def binary_divide(self):
- print ("Test binary divide")
- X,Y,Z = 1024,512,512
- X,Y,Z = 256,512,512
+ print("Test binary divide")
+ X, Y, Z = 1024, 512, 512
+ X, Y, Z = 256, 512, 512
steps = [timer()]
- a = numpy.ones((X,Y,Z), dtype='float32')
+ a = numpy.ones((X, Y, Z), dtype='float32')
steps.append(timer())
t0 = dt(steps)
-
+
#print("a refcount " , sys.getrefcount(a))
- ds = DataContainer(a, False, ['X', 'Y','Z'])
+ ds = DataContainer(a, False, ['X', 'Y', 'Z'])
ds1 = ds.copy()
-
+
steps.append(timer())
ds.divide(ds1, out=ds)
steps.append(timer())
t1 = dt(steps)
- print("ds.divide(ds1, out=ds)",dt(steps))
+ print("ds.divide(ds1, out=ds)", dt(steps))
steps.append(timer())
ds2 = ds.divide(ds1)
steps.append(timer())
t2 = dt(steps)
- print("ds2 = ds.divide(ds1)",dt(steps))
-
- self.assertLess(t1,t2)
- self.assertEqual(ds.as_array()[0][0][0] , 1.)
-
+ print("ds2 = ds.divide(ds1)", dt(steps))
+
+ self.assertLess(t1, t2)
+ self.assertEqual(ds.as_array()[0][0][0], 1.)
+
ds0 = ds
- ds0.divide(2,out=ds0)
+ ds0.divide(2, out=ds0)
steps.append(timer())
- print ("ds0.divide(2,out=ds0)", dt(steps), 0.5 , ds0.as_array()[0][0][0])
+ print("ds0.divide(2,out=ds0)", dt(steps), 0.5, ds0.as_array()[0][0][0])
self.assertEqual(0.5, ds0.as_array()[0][0][0])
-
- dt1 = dt(steps)
+
+ dt1 = dt(steps)
ds3 = ds0.divide(2)
steps.append(timer())
- print ("ds3 = ds0.divide(2)", dt(steps), 0.25 , ds3.as_array()[0][0][0])
+ print("ds3 = ds0.divide(2)", dt(steps), 0.25, ds3.as_array()[0][0][0])
dt2 = dt(steps)
- self.assertLess(dt1,dt2)
+ self.assertLess(dt1, dt2)
self.assertEqual(.25, ds3.as_array()[0][0][0])
self.assertEqual(.5, ds.as_array()[0][0][0])
-
-
+
def test_creation_copy(self):
- shape = (2,3,4,5)
+ shape = (2, 3, 4, 5)
size = shape[0]
for i in range(1, len(shape)):
size = size * shape[i]
#print("a refcount " , sys.getrefcount(a))
- a = numpy.asarray([i for i in range( size )])
+ a = numpy.asarray([i for i in range(size)])
#print("a refcount " , sys.getrefcount(a))
a = numpy.reshape(a, shape)
#print("a refcount " , sys.getrefcount(a))
- ds = DataContainer(a, True, ['X', 'Y','Z' ,'W'])
+ ds = DataContainer(a, True, ['X', 'Y', 'Z', 'W'])
#print("a refcount " , sys.getrefcount(a))
- self.assertEqual(sys.getrefcount(a),2)
-
+ self.assertEqual(sys.getrefcount(a), 2)
+
def test_subset(self):
- shape = (4,3,2)
+ shape = (4, 3, 2)
a = [i for i in range(2*3*4)]
a = numpy.asarray(a)
a = numpy.reshape(a, shape)
- ds = DataContainer(a, True, ['X', 'Y','Z'])
+ ds = DataContainer(a, True, ['X', 'Y', 'Z'])
sub = ds.subset(['X'])
res = True
try:
numpy.testing.assert_array_equal(sub.as_array(),
- numpy.asarray([0,6,12,18]))
+ numpy.asarray([0, 6, 12, 18]))
except AssertionError as err:
res = False
- print (err)
+ print(err)
self.assertTrue(res)
-
+
sub = ds.subset(['X'], Y=2, Z=0)
res = True
try:
numpy.testing.assert_array_equal(sub.as_array(),
- numpy.asarray([4,10,16,22]))
+ numpy.asarray([4, 10, 16, 22]))
except AssertionError as err:
res = False
- print (err)
+ print(err)
self.assertTrue(res)
-
-
+
sub = ds.subset(['Y'])
try:
numpy.testing.assert_array_equal(
- sub.as_array(), numpy.asarray([0,2,4]))
+ sub.as_array(), numpy.asarray([0, 2, 4]))
res = True
except AssertionError as err:
res = False
- print (err)
+ print(err)
self.assertTrue(res)
-
-
+
sub = ds.subset(['Z'])
try:
numpy.testing.assert_array_equal(
- sub.as_array(), numpy.asarray([0,1]))
+ sub.as_array(), numpy.asarray([0, 1]))
res = True
except AssertionError as err:
res = False
- print (err)
+ print(err)
self.assertTrue(res)
sub = ds.subset(['Z'], X=1, Y=2)
try:
numpy.testing.assert_array_equal(
- sub.as_array(), numpy.asarray([10,11]))
+ sub.as_array(), numpy.asarray([10, 11]))
res = True
except AssertionError as err:
res = False
- print (err)
+ print(err)
self.assertTrue(res)
-
+
print(a)
- sub = ds.subset(['X', 'Y'] , Z=1)
+ sub = ds.subset(['X', 'Y'], Z=1)
res = True
try:
numpy.testing.assert_array_equal(sub.as_array(),
- numpy.asarray([[ 1, 3, 5],
- [ 7, 9, 11],
- [13, 15, 17],
- [19, 21, 23]]))
+ numpy.asarray([[1, 3, 5],
+ [7, 9, 11],
+ [13, 15, 17],
+ [19, 21, 23]]))
except AssertionError as err:
res = False
- print (err)
+ print(err)
self.assertTrue(res)
-
+
def test_ImageData(self):
# create ImageData from geometry
vgeometry = ImageGeometry(voxel_num_x=4, voxel_num_y=3, channels=2)
vol = ImageData(geometry=vgeometry)
- self.assertEqual(vol.shape , (2,3,4))
-
+ self.assertEqual(vol.shape, (2, 3, 4))
+
vol1 = vol + 1
self.assertNumpyArrayEqual(vol1.as_array(), numpy.ones(vol.shape))
-
+
vol1 = vol - 1
self.assertNumpyArrayEqual(vol1.as_array(), -numpy.ones(vol.shape))
-
+
vol1 = 2 * (vol + 1)
self.assertNumpyArrayEqual(vol1.as_array(), 2 * numpy.ones(vol.shape))
-
- vol1 = (vol + 1) / 2
- self.assertNumpyArrayEqual(vol1.as_array(), numpy.ones(vol.shape) / 2 )
-
+
+ vol1 = (vol + 1) / 2
+ self.assertNumpyArrayEqual(vol1.as_array(), numpy.ones(vol.shape) / 2)
+
vol1 = vol + 1
- self.assertEqual(vol1.sum() , 2*3*4)
- vol1 = ( vol + 2 ) ** 2
- self.assertNumpyArrayEqual(vol1.as_array(), numpy.ones(vol.shape) * 4 )
-
-
-
+ self.assertEqual(vol1.sum(), 2*3*4)
+ vol1 = (vol + 2) ** 2
+ self.assertNumpyArrayEqual(vol1.as_array(), numpy.ones(vol.shape) * 4)
+
+ self.assertEqual(vol.number_of_dimensions, 3)
+
def test_AcquisitionData(self):
- sgeometry = AcquisitionGeometry(dimension=2, angles=numpy.linspace(0, 180, num=10),
- geom_type='parallel', pixel_num_v=3,
- pixel_num_h=5 , channels=2)
+ sgeometry = AcquisitionGeometry(dimension=2, angles=numpy.linspace(0, 180, num=10),
+ geom_type='parallel', pixel_num_v=3,
+ pixel_num_h=5, channels=2)
sino = AcquisitionData(geometry=sgeometry)
- self.assertEqual(sino.shape , (2,10,3,5))
-
-
+ self.assertEqual(sino.shape, (2, 10, 3, 5))
+
def assertNumpyArrayEqual(self, first, second):
res = True
try:
numpy.testing.assert_array_equal(first, second)
except AssertionError as err:
res = False
- print (err)
+ print(err)
self.assertTrue(res)
-
def assertNumpyArrayAlmostEqual(self, first, second, decimal=6):
res = True
try:
numpy.testing.assert_array_almost_equal(first, second, decimal)
except AssertionError as err:
res = False
- print (err)
+ print(err)
self.assertTrue(res)
+ def test_DataContainerChaining(self):
+ dc = self.create_DataContainer(256,256,256,1)
+
+ dc.add(9,out=dc)\
+ .subtract(1,out=dc)
+ self.assertEqual(1+9-1,dc.as_array().flatten()[0])
+
+
+
class TestAlgorithms(unittest.TestCase):
def assertNumpyArrayEqual(self, first, second):
@@ -473,311 +505,372 @@ class TestAlgorithms(unittest.TestCase): numpy.testing.assert_array_equal(first, second)
except AssertionError as err:
res = False
- print (err)
+ print(err)
self.assertTrue(res)
-
def assertNumpyArrayAlmostEqual(self, first, second, decimal=6):
res = True
try:
numpy.testing.assert_array_almost_equal(first, second, decimal)
except AssertionError as err:
res = False
- print (err)
+ print(err)
self.assertTrue(res)
- def test_FISTA(self):
- # Problem data.
- m = 30
- n = 20
- np.random.seed(1)
- Amat = np.random.randn(m, n)
- A = LinearOperatorMatrix(Amat)
- bmat = np.random.randn(m)
- bmat.shape = (bmat.shape[0],1)
-
- # A = Identity()
- # Change n to equal to m.
-
- b = DataContainer(bmat)
-
- # Regularization parameter
- lam = 10
- opt = {'memopt':True}
- # Create object instances with the test data A and b.
- f = Norm2sq(A,b,c=0.5, memopt=True)
- g0 = ZeroFun()
-
- # Initial guess
- x_init = DataContainer(np.zeros((n,1)))
-
- f.grad(x_init)
-
- # Run FISTA for least squares plus zero function.
- x_fista0, it0, timing0, criter0 = FISTA(x_init, f, g0 , opt=opt)
-
- # Print solution and final objective/criterion value for comparison
- print("FISTA least squares plus zero function solution and objective value:")
- print(x_fista0.array)
- print(criter0[-1])
-
- # Compare to CVXPY
-
- # Construct the problem.
- x0 = Variable(n)
- objective0 = Minimize(0.5*sum_squares(Amat*x0 - bmat.T[0]) )
- prob0 = Problem(objective0)
-
- # The optimal objective is returned by prob.solve().
- result0 = prob0.solve(verbose=False,solver=SCS,eps=1e-9)
-
- # The optimal solution for x is stored in x.value and optimal objective value
- # is in result as well as in objective.value
- print("CVXPY least squares plus zero function solution and objective value:")
- print(x0.value)
- print(objective0.value)
- self.assertNumpyArrayAlmostEqual(
- numpy.squeeze(x_fista0.array),x0.value,6)
- def test_FISTA_Norm1(self):
-
- opt = {'memopt':True}
- # Problem data.
- m = 30
- n = 20
- np.random.seed(1)
- Amat = np.random.randn(m, n)
- A = LinearOperatorMatrix(Amat)
- bmat = np.random.randn(m)
- bmat.shape = (bmat.shape[0],1)
-
- # A = Identity()
- # Change n to equal to m.
-
- b = DataContainer(bmat)
-
- # Regularization parameter
- lam = 10
- opt = {'memopt':True}
- # Create object instances with the test data A and b.
- f = Norm2sq(A,b,c=0.5, memopt=True)
- g0 = ZeroFun()
-
- # Initial guess
- x_init = DataContainer(np.zeros((n,1)))
-
- # Create 1-norm object instance
- g1 = Norm1(lam)
-
- g1(x_init)
- g1.prox(x_init,0.02)
-
- # Combine with least squares and solve using generic FISTA implementation
- x_fista1, it1, timing1, criter1 = FISTA(x_init, f, g1,opt=opt)
-
- # Print for comparison
- print("FISTA least squares plus 1-norm solution and objective value:")
- print(x_fista1.as_array().squeeze())
- print(criter1[-1])
-
- # Compare to CVXPY
-
- # Construct the problem.
- x1 = Variable(n)
- objective1 = Minimize(0.5*sum_squares(Amat*x1 - bmat.T[0]) + lam*norm(x1,1) )
- prob1 = Problem(objective1)
-
- # The optimal objective is returned by prob.solve().
- result1 = prob1.solve(verbose=False,solver=SCS,eps=1e-9)
-
- # The optimal solution for x is stored in x.value and optimal objective value
- # is in result as well as in objective.value
- print("CVXPY least squares plus 1-norm solution and objective value:")
- print(x1.value)
- print(objective1.value)
-
- self.assertNumpyArrayAlmostEqual(
- numpy.squeeze(x_fista1.array),x1.value,6)
-
- def test_FBPD_Norm1(self):
-
- opt = {'memopt':True}
- # Problem data.
- m = 30
- n = 20
- np.random.seed(1)
- Amat = np.random.randn(m, n)
- A = LinearOperatorMatrix(Amat)
- bmat = np.random.randn(m)
- bmat.shape = (bmat.shape[0],1)
-
- # A = Identity()
- # Change n to equal to m.
-
- b = DataContainer(bmat)
-
- # Regularization parameter
- lam = 10
- opt = {'memopt':True}
- # Create object instances with the test data A and b.
- f = Norm2sq(A,b,c=0.5, memopt=True)
- g0 = ZeroFun()
-
- # Initial guess
- x_init = DataContainer(np.zeros((n,1)))
-
- # Create 1-norm object instance
- g1 = Norm1(lam)
-
-
- # Compare to CVXPY
-
- # Construct the problem.
- x1 = Variable(n)
- objective1 = Minimize(0.5*sum_squares(Amat*x1 - bmat.T[0]) + lam*norm(x1,1) )
- prob1 = Problem(objective1)
-
- # The optimal objective is returned by prob.solve().
- result1 = prob1.solve(verbose=False,solver=SCS,eps=1e-9)
-
- # The optimal solution for x is stored in x.value and optimal objective value
- # is in result as well as in objective.value
- print("CVXPY least squares plus 1-norm solution and objective value:")
- print(x1.value)
- print(objective1.value)
-
- # Now try another algorithm FBPD for same problem:
- x_fbpd1, itfbpd1, timingfbpd1, criterfbpd1 = FBPD(x_init,
- Identity(), None, f, g1)
- print(x_fbpd1)
- print(criterfbpd1[-1])
-
- self.assertNumpyArrayAlmostEqual(
- numpy.squeeze(x_fbpd1.array),x1.value,6)
+
+ def test_FISTA_cvx(self):
+ if not cvx_not_installable:
+ # Problem data.
+ m = 30
+ n = 20
+ np.random.seed(1)
+ Amat = np.random.randn(m, n)
+ A = LinearOperatorMatrix(Amat)
+ bmat = np.random.randn(m)
+ bmat.shape = (bmat.shape[0], 1)
+
+ # A = Identity()
+ # Change n to equal to m.
+
+ b = DataContainer(bmat)
+
+ # Regularization parameter
+ lam = 10
+ opt = {'memopt': True}
+ # Create object instances with the test data A and b.
+ f = Norm2sq(A, b, c=0.5, memopt=True)
+ g0 = ZeroFun()
+
+ # Initial guess
+ x_init = DataContainer(np.zeros((n, 1)))
+
+ f.grad(x_init)
+
+ # Run FISTA for least squares plus zero function.
+ x_fista0, it0, timing0, criter0 = FISTA(x_init, f, g0, opt=opt)
+
+ # Print solution and final objective/criterion value for comparison
+ print("FISTA least squares plus zero function solution and objective value:")
+ print(x_fista0.array)
+ print(criter0[-1])
+
+ # Compare to CVXPY
+
+ # Construct the problem.
+ x0 = Variable(n)
+ objective0 = Minimize(0.5*sum_squares(Amat*x0 - bmat.T[0]))
+ prob0 = Problem(objective0)
+
+ # The optimal objective is returned by prob.solve().
+ result0 = prob0.solve(verbose=False, solver=SCS, eps=1e-9)
+
+ # The optimal solution for x is stored in x.value and optimal objective value
+ # is in result as well as in objective.value
+ print("CVXPY least squares plus zero function solution and objective value:")
+ print(x0.value)
+ print(objective0.value)
+ self.assertNumpyArrayAlmostEqual(
+ numpy.squeeze(x_fista0.array), x0.value, 6)
+ else:
+ self.assertTrue(cvx_not_installable)
+
+ def test_FISTA_Norm1_cvx(self):
+ if not cvx_not_installable:
+ opt = {'memopt': True}
+ # Problem data.
+ m = 30
+ n = 20
+ np.random.seed(1)
+ Amat = np.random.randn(m, n)
+ A = LinearOperatorMatrix(Amat)
+ bmat = np.random.randn(m)
+ bmat.shape = (bmat.shape[0], 1)
+
+ # A = Identity()
+ # Change n to equal to m.
+
+ b = DataContainer(bmat)
+
+ # Regularization parameter
+ lam = 10
+ opt = {'memopt': True}
+ # Create object instances with the test data A and b.
+ f = Norm2sq(A, b, c=0.5, memopt=True)
+ g0 = ZeroFun()
+
+ # Initial guess
+ x_init = DataContainer(np.zeros((n, 1)))
+
+ # Create 1-norm object instance
+ g1 = Norm1(lam)
+
+ g1(x_init)
+ g1.prox(x_init, 0.02)
+
+ # Combine with least squares and solve using generic FISTA implementation
+ x_fista1, it1, timing1, criter1 = FISTA(x_init, f, g1, opt=opt)
+
+ # Print for comparison
+ print("FISTA least squares plus 1-norm solution and objective value:")
+ print(x_fista1.as_array().squeeze())
+ print(criter1[-1])
+
+ # Compare to CVXPY
+
+ # Construct the problem.
+ x1 = Variable(n)
+ objective1 = Minimize(
+ 0.5*sum_squares(Amat*x1 - bmat.T[0]) + lam*norm(x1, 1))
+ prob1 = Problem(objective1)
+
+ # The optimal objective is returned by prob.solve().
+ result1 = prob1.solve(verbose=False, solver=SCS, eps=1e-9)
+
+ # The optimal solution for x is stored in x.value and optimal objective value
+ # is in result as well as in objective.value
+ print("CVXPY least squares plus 1-norm solution and objective value:")
+ print(x1.value)
+ print(objective1.value)
+
+ self.assertNumpyArrayAlmostEqual(
+ numpy.squeeze(x_fista1.array), x1.value, 6)
+ else:
+ self.assertTrue(cvx_not_installable)
+
+ def test_FBPD_Norm1_cvx(self):
+ if not cvx_not_installable:
+ opt = {'memopt': True}
+ # Problem data.
+ m = 30
+ n = 20
+ np.random.seed(1)
+ Amat = np.random.randn(m, n)
+ A = LinearOperatorMatrix(Amat)
+ bmat = np.random.randn(m)
+ bmat.shape = (bmat.shape[0], 1)
+
+ # A = Identity()
+ # Change n to equal to m.
+
+ b = DataContainer(bmat)
+
+ # Regularization parameter
+ lam = 10
+ opt = {'memopt': True}
+ # Create object instances with the test data A and b.
+ f = Norm2sq(A, b, c=0.5, memopt=True)
+ g0 = ZeroFun()
+
+ # Initial guess
+ x_init = DataContainer(np.zeros((n, 1)))
+
+ # Create 1-norm object instance
+ g1 = Norm1(lam)
+
+ # Compare to CVXPY
+
+ # Construct the problem.
+ x1 = Variable(n)
+ objective1 = Minimize(
+ 0.5*sum_squares(Amat*x1 - bmat.T[0]) + lam*norm(x1, 1))
+ prob1 = Problem(objective1)
+
+ # The optimal objective is returned by prob.solve().
+ result1 = prob1.solve(verbose=False, solver=SCS, eps=1e-9)
+
+ # The optimal solution for x is stored in x.value and optimal objective value
+ # is in result as well as in objective.value
+ print("CVXPY least squares plus 1-norm solution and objective value:")
+ print(x1.value)
+ print(objective1.value)
+
+ # Now try another algorithm FBPD for same problem:
+ x_fbpd1, itfbpd1, timingfbpd1, criterfbpd1 = FBPD(x_init,
+ Identity(), None, f, g1)
+ print(x_fbpd1)
+ print(criterfbpd1[-1])
+
+ self.assertNumpyArrayAlmostEqual(
+ numpy.squeeze(x_fbpd1.array), x1.value, 6)
+ else:
+ self.assertTrue(cvx_not_installable)
# Plot criterion curve to see both FISTA and FBPD converge to same value.
# Note that FISTA is very efficient for 1-norm minimization so it beats
- # FBPD in this test by a lot. But FBPD can handle a larger class of problems
+ # FBPD in this test by a lot. But FBPD can handle a larger class of problems
# than FISTA can.
-
-
+
# Now try 1-norm and TV denoising with FBPD, first 1-norm.
-
- # Set up phantom size NxN by creating ImageGeometry, initialising the
+
+ # Set up phantom size NxN by creating ImageGeometry, initialising the
# ImageData object with this geometry and empty array and finally put some
# data into its array, and display as image.
- def test_FISTA_denoise(self):
- opt = {'memopt':True}
+ def test_FISTA_denoise_cvx(self):
+ if not cvx_not_installable:
+ opt = {'memopt': True}
+ N = 64
+ ig = ImageGeometry(voxel_num_x=N, voxel_num_y=N)
+ Phantom = ImageData(geometry=ig)
+
+ x = Phantom.as_array()
+
+ x[int(round(N/4)):int(round(3*N/4)),
+ int(round(N/4)):int(round(3*N/4))] = 0.5
+ x[int(round(N/8)):int(round(7*N/8)),
+ int(round(3*N/8)):int(round(5*N/8))] = 1
+
+ # Identity operator for denoising
+ I = TomoIdentity(ig)
+
+ # Data and add noise
+ y = I.direct(Phantom)
+ y.array = y.array + 0.1*np.random.randn(N, N)
+
+ # Data fidelity term
+ f_denoise = Norm2sq(I, y, c=0.5, memopt=True)
+
+ # 1-norm regulariser
+ lam1_denoise = 1.0
+ g1_denoise = Norm1(lam1_denoise)
+
+ # Initial guess
+ x_init_denoise = ImageData(np.zeros((N, N)))
+
+ # Combine with least squares and solve using generic FISTA implementation
+ x_fista1_denoise, it1_denoise, timing1_denoise, \
+ criter1_denoise = \
+ FISTA(x_init_denoise, f_denoise, g1_denoise, opt=opt)
+
+ print(x_fista1_denoise)
+ print(criter1_denoise[-1])
+
+ # Now denoise LS + 1-norm with FBPD
+ x_fbpd1_denoise, itfbpd1_denoise, timingfbpd1_denoise,\
+ criterfbpd1_denoise = \
+ FBPD(x_init_denoise, I, None, f_denoise, g1_denoise)
+ print(x_fbpd1_denoise)
+ print(criterfbpd1_denoise[-1])
+
+ # Compare to CVXPY
+
+ # Construct the problem.
+ x1_denoise = Variable(N**2, 1)
+ objective1_denoise = Minimize(
+ 0.5*sum_squares(x1_denoise - y.array.flatten()) + lam1_denoise*norm(x1_denoise, 1))
+ prob1_denoise = Problem(objective1_denoise)
+
+ # The optimal objective is returned by prob.solve().
+ result1_denoise = prob1_denoise.solve(
+ verbose=False, solver=SCS, eps=1e-12)
+
+ # The optimal solution for x is stored in x.value and optimal objective value
+ # is in result as well as in objective.value
+ print("CVXPY least squares plus 1-norm solution and objective value:")
+ print(x1_denoise.value)
+ print(objective1_denoise.value)
+ self.assertNumpyArrayAlmostEqual(
+ x_fista1_denoise.array.flatten(), x1_denoise.value, 5)
+
+ self.assertNumpyArrayAlmostEqual(
+ x_fbpd1_denoise.array.flatten(), x1_denoise.value, 5)
+ x1_cvx = x1_denoise.value
+ x1_cvx.shape = (N, N)
+
+ # Now TV with FBPD
+ lam_tv = 0.1
+ gtv = TV2D(lam_tv)
+ gtv(gtv.op.direct(x_init_denoise))
+
+ opt_tv = {'tol': 1e-4, 'iter': 10000}
+
+ x_fbpdtv_denoise, itfbpdtv_denoise, timingfbpdtv_denoise,\
+ criterfbpdtv_denoise = \
+ FBPD(x_init_denoise, gtv.op, None, f_denoise, gtv, opt=opt_tv)
+ print(x_fbpdtv_denoise)
+ print(criterfbpdtv_denoise[-1])
+
+ # Compare to CVXPY
+
+ # Construct the problem.
+ xtv_denoise = Variable((N, N))
+ objectivetv_denoise = Minimize(
+ 0.5*sum_squares(xtv_denoise - y.array) + lam_tv*tv(xtv_denoise))
+ probtv_denoise = Problem(objectivetv_denoise)
+
+ # The optimal objective is returned by prob.solve().
+ resulttv_denoise = probtv_denoise.solve(
+ verbose=False, solver=SCS, eps=1e-12)
+
+ # The optimal solution for x is stored in x.value and optimal objective value
+ # is in result as well as in objective.value
+ print("CVXPY least squares plus 1-norm solution and objective value:")
+ print(xtv_denoise.value)
+ print(objectivetv_denoise.value)
+
+ self.assertNumpyArrayAlmostEqual(
+ x_fbpdtv_denoise.as_array(), xtv_denoise.value, 1)
+
+ else:
+ self.assertTrue(cvx_not_installable)
+
+
+class TestFunction(unittest.TestCase):
+ def assertNumpyArrayEqual(self, first, second):
+ res = True
+ try:
+ numpy.testing.assert_array_equal(first, second)
+ except AssertionError as err:
+ res = False
+ print(err)
+ self.assertTrue(res)
+
+ def create_simple_ImageData(self):
N = 64
- ig = ImageGeometry(voxel_num_x=N,voxel_num_y=N)
+ ig = ImageGeometry(voxel_num_x=N, voxel_num_y=N)
Phantom = ImageData(geometry=ig)
-
+
x = Phantom.as_array()
-
+
x[int(round(N/4)):int(round(3*N/4)),
int(round(N/4)):int(round(3*N/4))] = 0.5
x[int(round(N/8)):int(round(7*N/8)),
int(round(3*N/8)):int(round(5*N/8))] = 1
-
-
- # Identity operator for denoising
- I = TomoIdentity(ig)
-
- # Data and add noise
- y = I.direct(Phantom)
- y.array = y.array + 0.1*np.random.randn(N, N)
-
-
- # Data fidelity term
- f_denoise = Norm2sq(I,y,c=0.5,memopt=True)
-
- # 1-norm regulariser
- lam1_denoise = 1.0
- g1_denoise = Norm1(lam1_denoise)
-
- # Initial guess
- x_init_denoise = ImageData(np.zeros((N,N)))
-
- # Combine with least squares and solve using generic FISTA implementation
- x_fista1_denoise, it1_denoise, timing1_denoise, \
- criter1_denoise = \
- FISTA(x_init_denoise, f_denoise, g1_denoise, opt=opt)
-
- print(x_fista1_denoise)
- print(criter1_denoise[-1])
-
-
- # Now denoise LS + 1-norm with FBPD
- x_fbpd1_denoise, itfbpd1_denoise, timingfbpd1_denoise,\
- criterfbpd1_denoise = \
- FBPD(x_init_denoise, I, None, f_denoise, g1_denoise)
- print(x_fbpd1_denoise)
- print(criterfbpd1_denoise[-1])
-
-
- # Compare to CVXPY
-
- # Construct the problem.
- x1_denoise = Variable(N**2,1)
- objective1_denoise = Minimize(0.5*sum_squares(x1_denoise - y.array.flatten()) + lam1_denoise*norm(x1_denoise,1) )
- prob1_denoise = Problem(objective1_denoise)
-
- # The optimal objective is returned by prob.solve().
- result1_denoise = prob1_denoise.solve(verbose=False,solver=SCS,eps=1e-12)
-
- # The optimal solution for x is stored in x.value and optimal objective value
- # is in result as well as in objective.value
- print("CVXPY least squares plus 1-norm solution and objective value:")
- print(x1_denoise.value)
- print(objective1_denoise.value)
- self.assertNumpyArrayAlmostEqual(
- x_fista1_denoise.array.flatten(),x1_denoise.value,5)
-
- self.assertNumpyArrayAlmostEqual(
- x_fbpd1_denoise.array.flatten(),x1_denoise.value,5)
- x1_cvx = x1_denoise.value
- x1_cvx.shape = (N,N)
-
-
- # Now TV with FBPD
- lam_tv = 0.1
- gtv = TV2D(lam_tv)
- gtv(gtv.op.direct(x_init_denoise))
-
- opt_tv = {'tol': 1e-4, 'iter': 10000}
-
- x_fbpdtv_denoise, itfbpdtv_denoise, timingfbpdtv_denoise,\
- criterfbpdtv_denoise = \
- FBPD(x_init_denoise, gtv.op, None, f_denoise, gtv,opt=opt_tv)
- print(x_fbpdtv_denoise)
- print(criterfbpdtv_denoise[-1])
-
-
-
- # Compare to CVXPY
-
- # Construct the problem.
- xtv_denoise = Variable((N,N))
- objectivetv_denoise = Minimize(0.5*sum_squares(xtv_denoise - y.array) + lam_tv*tv(xtv_denoise) )
- probtv_denoise = Problem(objectivetv_denoise)
-
- # The optimal objective is returned by prob.solve().
- resulttv_denoise = probtv_denoise.solve(verbose=False,solver=SCS,eps=1e-12)
-
- # The optimal solution for x is stored in x.value and optimal objective value
- # is in result as well as in objective.value
- print("CVXPY least squares plus 1-norm solution and objective value:")
- print(xtv_denoise.value)
- print(objectivetv_denoise.value)
-
- self.assertNumpyArrayAlmostEqual(
- x_fbpdtv_denoise.as_array(),xtv_denoise.value,1)
-
+
+ return (ig, Phantom)
+
+ def _test_Norm2(self):
+ print("test Norm2")
+ opt = {'memopt': True}
+ ig, Phantom = self.create_simple_ImageData()
+ x = Phantom.as_array()
+ print(Phantom)
+ print(Phantom.as_array())
+
+ norm2 = Norm2()
+ v1 = norm2(x)
+ v2 = norm2(Phantom)
+ self.assertEqual(v1, v2)
+
+ p1 = norm2.prox(Phantom, 1)
+ print(p1)
+ p2 = norm2.prox(x, 1)
+ self.assertNumpyArrayEqual(p1.as_array(), p2)
+
+ p3 = norm2.proximal(Phantom, 1)
+ p4 = norm2.proximal(x, 1)
+ self.assertNumpyArrayEqual(p3.as_array(), p2)
+ self.assertNumpyArrayEqual(p3.as_array(), p4)
+
+ out = Phantom.copy()
+ p5 = norm2.proximal(Phantom, 1, out=out)
+ self.assertEqual(id(p5), id(out))
+ self.assertNumpyArrayEqual(p5.as_array(), p3.as_array())
# =============================================================================
# def test_upper(self):
# self.assertEqual('foo'.upper(), 'FOO')
-#
+#
# def test_isupper(self):
# self.assertTrue('FOO'.isupper())
# self.assertFalse('Foo'.isupper())
-#
+#
# def test_split(self):
# s = 'hello world'
# self.assertEqual(s.split(), ['hello', 'world'])
@@ -786,5 +879,6 @@ class TestAlgorithms(unittest.TestCase): # s.split(2)
# =============================================================================
+
if __name__ == '__main__':
unittest.main()
diff --git a/Wrappers/Python/wip/demo_compare_cvx.py b/Wrappers/Python/wip/demo_compare_cvx.py index ad79fa5..27b1c97 100644 --- a/Wrappers/Python/wip/demo_compare_cvx.py +++ b/Wrappers/Python/wip/demo_compare_cvx.py @@ -1,10 +1,11 @@ from ccpi.framework import ImageData, ImageGeometry, AcquisitionGeometry, DataContainer from ccpi.optimisation.algs import FISTA, FBPD, CGLS -from ccpi.optimisation.funcs import Norm2sq, ZeroFun, Norm1, TV2D +from ccpi.optimisation.funcs import Norm2sq, ZeroFun, Norm1, TV2D, Norm2 from ccpi.optimisation.ops import LinearOperatorMatrix, TomoIdentity from ccpi.optimisation.ops import Identity +from ccpi.optimisation.ops import FiniteDiff2D # Requires CVXPY, see http://www.cvxpy.org/ # CVXPY can be installed in anaconda using @@ -172,6 +173,8 @@ plt.imshow(y.array) plt.title('Noisy image') plt.show() + +################### # Data fidelity term f_denoise = Norm2sq(I,y,c=0.5,memopt=True) @@ -188,9 +191,9 @@ x_fista1_denoise, it1_denoise, timing1_denoise, criter1_denoise = FISTA(x_init_d print(x_fista1_denoise) print(criter1_denoise[-1]) -plt.imshow(x_fista1_denoise.as_array()) -plt.title('FISTA LS+1') -plt.show() +#plt.imshow(x_fista1_denoise.as_array()) +#plt.title('FISTA LS+1') +#plt.show() # Now denoise LS + 1-norm with FBPD x_fbpd1_denoise, itfbpd1_denoise, timingfbpd1_denoise, \ @@ -198,9 +201,9 @@ x_fbpd1_denoise, itfbpd1_denoise, timingfbpd1_denoise, \ print(x_fbpd1_denoise) print(criterfbpd1_denoise[-1]) -plt.imshow(x_fbpd1_denoise.as_array()) -plt.title('FBPD LS+1') -plt.show() +#plt.imshow(x_fbpd1_denoise.as_array()) +#plt.title('FBPD LS+1') +#plt.show() if use_cvxpy: # Compare to CVXPY @@ -222,25 +225,46 @@ if use_cvxpy: x1_cvx = x1_denoise.value x1_cvx.shape = (N,N) + + +#plt.imshow(x1_cvx) +#plt.title('CVX LS+1') +#plt.show() + +fig = plt.figure() +plt.subplot(1,4,1) +plt.imshow(y.array) +plt.title("LS+1") +plt.subplot(1,4,2) +plt.imshow(x_fista1_denoise.as_array()) +plt.title("fista") +plt.subplot(1,4,3) +plt.imshow(x_fbpd1_denoise.as_array()) +plt.title("fbpd") +plt.subplot(1,4,4) plt.imshow(x1_cvx) -plt.title('CVX LS+1') +plt.title("cvx") plt.show() -# Now TV with FBPD +############################################################## +# Now TV with FBPD and Norm2 lam_tv = 0.1 gtv = TV2D(lam_tv) -gtv(gtv.op.direct(x_init_denoise)) +norm2 = Norm2(lam_tv) +op = FiniteDiff2D() +#gtv(gtv.op.direct(x_init_denoise)) opt_tv = {'tol': 1e-4, 'iter': 10000} x_fbpdtv_denoise, itfbpdtv_denoise, timingfbpdtv_denoise, \ - criterfbpdtv_denoise = FBPD(x_init_denoise, gtv.op, None, f_denoise, gtv,opt=opt_tv) + criterfbpdtv_denoise = FBPD(x_init_denoise, op, None, \ + f_denoise, norm2 ,opt=opt_tv) print(x_fbpdtv_denoise) print(criterfbpdtv_denoise[-1]) plt.imshow(x_fbpdtv_denoise.as_array()) plt.title('FBPD TV') -plt.show() +#plt.show() if use_cvxpy: # Compare to CVXPY @@ -262,7 +286,21 @@ if use_cvxpy: plt.imshow(xtv_denoise.value) plt.title('CVX TV') +#plt.show() + +fig = plt.figure() +plt.subplot(1,3,1) +plt.imshow(y.array) +plt.title("TV2D") +plt.subplot(1,3,2) +plt.imshow(x_fbpdtv_denoise.as_array()) +plt.title("fbpd tv denoise") +plt.subplot(1,3,3) +plt.imshow(xtv_denoise.value) +plt.title("CVX tv") plt.show() + + plt.loglog([0,opt_tv['iter']], [objectivetv_denoise.value,objectivetv_denoise.value], label='CVX TV') plt.loglog(criterfbpdtv_denoise, label='FBPD TV') |