summaryrefslogtreecommitdiffstats
path: root/Wrappers
diff options
context:
space:
mode:
Diffstat (limited to 'Wrappers')
-rwxr-xr-xWrappers/Python/ccpi/framework/framework.py4
-rwxr-xr-xWrappers/Python/ccpi/optimisation/operators/BlockOperator.py49
-rw-r--r--Wrappers/Python/test/test_BlockOperator.py49
3 files changed, 99 insertions, 3 deletions
diff --git a/Wrappers/Python/ccpi/framework/framework.py b/Wrappers/Python/ccpi/framework/framework.py
index 5bc01e5..bf8273b 100755
--- a/Wrappers/Python/ccpi/framework/framework.py
+++ b/Wrappers/Python/ccpi/framework/framework.py
@@ -150,12 +150,12 @@ class ImageGeometry(object):
if value != 0:
out += value
else:
- if value == ImageData.RANDOM:
+ if value == ImageGeometry.RANDOM:
seed = kwargs.get('seed', None)
if seed is not None:
numpy.random.seed(seed)
out.fill(numpy.random.random_sample(self.shape))
- elif value == ImageData.RANDOM_INT:
+ elif value == ImageGeometry.RANDOM_INT:
seed = kwargs.get('seed', None)
if seed is not None:
numpy.random.seed(seed)
diff --git a/Wrappers/Python/ccpi/optimisation/operators/BlockOperator.py b/Wrappers/Python/ccpi/optimisation/operators/BlockOperator.py
index 4ff38c6..3679136 100755
--- a/Wrappers/Python/ccpi/optimisation/operators/BlockOperator.py
+++ b/Wrappers/Python/ccpi/optimisation/operators/BlockOperator.py
@@ -23,6 +23,9 @@ class BlockOperator(Operator):
Nx1 BlockDataContainer, will yield and Mx1 BlockDataContainer.
Notice: BlockDatacontainer are only allowed to have the shape of N x 1, with
N rows and 1 column.
+
+ Operators in a Block are required to have the same domain column-wise and the
+ same range row-wise.
'''
__array_priority__ = 1
def __init__(self, *args, **kwargs):
@@ -52,6 +55,39 @@ class BlockOperator(Operator):
raise ValueError(
'Dimension and size do not match: expected {} got {}'
.format(n_elements,len(args)))
+ # test if operators are compatible
+ if not self.column_wise_compatible():
+ raise ValueError('Operators in each column must have the same domain')
+ if not self.row_wise_compatible():
+ raise ValueError('Operators in each row must have the same range')
+
+ def column_wise_compatible(self):
+ '''Operators in a Block should have the same domain per column'''
+ rows, cols = self.shape
+ compatible = True
+ for col in range(cols):
+ row_compatible = True
+ for row in range(1,rows):
+ dg0 = self.get_item(row-1,col).domain_geometry()
+ dg1 = self.get_item(row,col).domain_geometry()
+ row_compatible = dg0.__dict__ == dg1.__dict__ and row_compatible
+ compatible = compatible and row_compatible
+ return compatible
+
+ def row_wise_compatible(self):
+ '''Operators in a Block should have the same range per row'''
+ rows, cols = self.shape
+ compatible = True
+ for row in range(rows):
+ column_compatible = True
+ for col in range(1,cols):
+ dg0 = self.get_item(row,col-1).range_geometry()
+ dg1 = self.get_item(row,col).range_geometry()
+ column_compatible = dg0.__dict__ == dg1.__dict__ and column_compatible
+ print ("column_compatible" , column_compatible, dg0.shape, dg1.shape)
+ compatible = compatible and column_compatible
+ return compatible
+
def get_item(self, row, col):
if row > self.shape[0]:
raise ValueError('Requested row {} > max {}'.format(row, self.shape[0]))
@@ -153,5 +189,18 @@ class BlockOperator(Operator):
shape = (self.shape[1], self.shape[0])
return type(self)(*self.operators, shape=shape)
+ def domain_geometry(self):
+ if self.shape[1] == 1:
+ # column BlockOperator
+ return self[0].domain_geometry()
+ else:
+ shape = (self.shape[0], 1)
+ return BlockGeometry(*[el.domain_geometry() for el in self.operators],
+ shape=shape)
+
+ def range_geometry(self):
+ shape = (self.shape[1], 1)
+ return BlockGeometry(*[el.range_geometry() for el in self.operators],
+ shape=shape)
if __name__ == '__main__':
pass
diff --git a/Wrappers/Python/test/test_BlockOperator.py b/Wrappers/Python/test/test_BlockOperator.py
index 951aa0a..c042d04 100644
--- a/Wrappers/Python/test/test_BlockOperator.py
+++ b/Wrappers/Python/test/test_BlockOperator.py
@@ -6,6 +6,13 @@ from ccpi.framework import ImageGeometry, ImageData
import numpy
from ccpi.optimisation.operators import FiniteDiff
+class TestOperator(TomoIdentity):
+ def __init__(self, *args, **kwargs):
+ super(TestOperator, self).__init__(*args, **kwargs)
+ self.range = kwargs.get('range', self.geometry)
+ def range_geometry(self):
+ return self.range
+
class TestBlockOperator(unittest.TestCase):
def test_BlockOperator(self):
@@ -32,7 +39,47 @@ class TestBlockOperator(unittest.TestCase):
zero = numpy.zeros(X.get_item(0).shape)
numpy.testing.assert_array_equal(Y.get_item(0).as_array(),len(x)+zero)
-
+ try:
+ # this should fail as the domain is not compatible
+ ig = [ ImageGeometry(10,20,31) , \
+ ImageGeometry(10,20,30) , \
+ ImageGeometry(10,20,30) ]
+ x = [ g.allocate() for g in ig ]
+ ops = [ TomoIdentity(g) for g in ig ]
+
+ K = BlockOperator(*ops)
+ self.assertTrue(False)
+ except ValueError as ve:
+ print (ve)
+ self.assertTrue(True)
+
+ try:
+ # this should fail as the range is not compatible
+ ig = [ ImageGeometry(10,20,30) , \
+ ImageGeometry(10,20,30) , \
+ ImageGeometry(10,20,30) ]
+ rg0 = [ ImageGeometry(10,20,31) , \
+ ImageGeometry(10,20,31) , \
+ ImageGeometry(10,20,31) ]
+ rg1 = [ ImageGeometry(10,22,31) , \
+ ImageGeometry(10,22,31) , \
+ ImageGeometry(10,20,31) ]
+ x = [ g.allocate() for g in ig ]
+ ops = [ TestOperator(g, range=r) for g,r in zip(ig, rg0) ]
+ ops += [ TestOperator(g, range=r) for g,r in zip(ig, rg1) ]
+ print (len(ops))
+ K = BlockOperator(*ops)
+ print ("K col comp? " , K.column_wise_compatible())
+ print ("K row comp? " , K.row_wise_compatible())
+ for op in ops:
+ print ("range" , op.range_geometry().shape)
+ for op in ops:
+ print ("domain" , op.domain_geometry().shape)
+ self.assertTrue(False)
+ except ValueError as ve:
+ print (ve)
+ self.assertTrue(True)
+
def test_ScaledBlockOperatorSingleScalar(self):
ig = [ ImageGeometry(10,20,30) , \
ImageGeometry(10,20,30) , \