Source code for cil.optimisation.operators.SparseFiniteDifferenceOperator
# Copyright 2019 United Kingdom Research and Innovation
# Copyright 2019 The University of Manchester
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Authors:
# CIL Developers, listed at: https://github.com/TomographicImaging/CIL/blob/master/NOTICE.txt
import scipy.sparse as sp
import numpy as np
from cil.framework import ImageData, ImageGeometry
from cil.optimisation.operators import Operator
[docs]
class SparseFiniteDifferenceOperator(Operator):
'''Create Sparse Matrices for the Finite Difference Operator'''
def __init__(self, domain_geometry, range_geometry=None,
direction=0, bnd_cond = 'Neumann'):
super(SparseFiniteDifferenceOperator, self).__init__(domain_geometry=domain_geometry,
range_geometry=range_geometry)
self.direction = direction
self.bnd_cond = bnd_cond
if self.range_geometry is None:
self.range_geometry = self.domain_geometry
self.get_dims = [i for i in domain_geometry.shape]
if self.direction + 1 > len(self.domain_geometry().shape):
raise ValueError('Gradient directions more than geometry domain')
def matrix(self):
i = self.direction
mat = sp.spdiags(np.vstack([-np.ones((1,self.get_dims[i])),np.ones((1,self.get_dims[i]))]), [0,1], self.get_dims[i], self.get_dims[i], format = 'lil')
if self.bnd_cond == 'Neumann':
mat[-1,:] = 0
elif self.bnd_cond == 'Periodic':
mat[-1,0] = 1
tmpGrad = mat if i == 0 else sp.eye(self.get_dims[0])
for j in range(1, self.domain_geometry().length):
tmpGrad = sp.kron(mat, tmpGrad ) if j == i else sp.kron(sp.eye(self.get_dims[j]), tmpGrad )
return tmpGrad
def T(self):
return self.matrix().T
[docs]
def direct(self, x):
x_asarr = x.as_array()
res = np.reshape( self.matrix() * x_asarr.flatten('F'), self.domain_geometry().shape, 'F')
return type(x)(res)
def adjoint(self, x):
x_asarr = x.as_array()
res = np.reshape( self.matrix().T * x_asarr.flatten('F'), self.domain_geometry().shape, 'F')
return type(x)(res)
def sum_abs_row(self):
res = np.array(np.reshape(abs(self.matrix()).sum(axis=0), self.domain_geometry().shape, 'F'))
#res[res==0]=0
return ImageData(res)
def sum_abs_col(self):
res = np.array(np.reshape(abs(self.matrix()).sum(axis=1), self.domain_geometry().shape, 'F') )
#res[res==0]=0
return ImageData(res)
if __name__ == '__main__':
M, N= 2, 3
ig = ImageGeometry(M, N)
arr = ig.allocate('random_int')
sFD_neum1 = SparseFiniteDifferenceOperator(ig, direction=0, bnd_cond='Neumann')
sFD_neum2 = SparseFiniteDifferenceOperator(ig, direction=1, bnd_cond='Neumann')
DY = sFD_neum1.matrix().toarray()
DX = sFD_neum2.matrix().toarray()
rows = sFD_neum1.sum_abs_row()
cols = sFD_neum1.sum_abs_col()
print(rows.as_array())
print(cols.as_array())