summaryrefslogtreecommitdiffstats
path: root/Wrappers
diff options
context:
space:
mode:
authorepapoutsellis <epapoutsellis@gmail.com>2019-05-23 20:20:00 +0100
committerepapoutsellis <epapoutsellis@gmail.com>2019-05-23 20:20:00 +0100
commita8a53b23990a1cedc77c182f17045b060fa50129 (patch)
treefde82e891d39c041de204638d774b71984769122 /Wrappers
parentc2fe1e798108ac00e209fe403a226ebdc202d701 (diff)
downloadframework-a8a53b23990a1cedc77c182f17045b060fa50129.tar.gz
framework-a8a53b23990a1cedc77c182f17045b060fa50129.tar.bz2
framework-a8a53b23990a1cedc77c182f17045b060fa50129.tar.xz
framework-a8a53b23990a1cedc77c182f17045b060fa50129.zip
delete algs/funcs
Diffstat (limited to 'Wrappers')
-rwxr-xr-xWrappers/Python/ccpi/optimisation/algs.py307
-rwxr-xr-xWrappers/Python/ccpi/optimisation/funcs.py265
2 files changed, 0 insertions, 572 deletions
diff --git a/Wrappers/Python/ccpi/optimisation/algs.py b/Wrappers/Python/ccpi/optimisation/algs.py
deleted file mode 100755
index f5ba85e..0000000
--- a/Wrappers/Python/ccpi/optimisation/algs.py
+++ /dev/null
@@ -1,307 +0,0 @@
-# -*- coding: utf-8 -*-
-# This work is part of the Core Imaging Library developed by
-# Visual Analytics and Imaging System Group of the Science Technology
-# Facilities Council, STFC
-
-# Copyright 2018 Jakob Jorgensen, Daniil Kazantsev and Edoardo Pasca
-
-# 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.
-
-import numpy
-import time
-
-
-
-
-def FISTA(x_init, f=None, g=None, opt=None):
- '''Fast Iterative Shrinkage-Thresholding Algorithm
-
- Beck, A. and Teboulle, M., 2009. A fast iterative shrinkage-thresholding
- algorithm for linear inverse problems.
- SIAM journal on imaging sciences,2(1), pp.183-202.
-
- Parameters:
- x_init: initial guess
- f: data fidelity
- g: regularizer
- h:
- opt: additional algorithm
- '''
- # default inputs
- if f is None: f = ZeroFun()
- if g is None: g = ZeroFun()
-
- # algorithmic parameters
- if opt is None:
- opt = {'tol': 1e-4, 'iter': 1000, 'memopt':False}
-
- max_iter = opt['iter'] if 'iter' in opt.keys() else 1000
- tol = opt['tol'] if 'tol' in opt.keys() else 1e-4
- memopt = opt['memopt'] if 'memopt' in opt.keys() else False
-
-
- # initialization
- if memopt:
- y = x_init.clone()
- x_old = x_init.clone()
- x = x_init.clone()
- u = x_init.clone()
- else:
- x_old = x_init
- y = x_init;
-
- timing = numpy.zeros(max_iter)
- criter = numpy.zeros(max_iter)
-
- invL = 1/f.L
-
- t_old = 1
-
-# c = f(x_init) + g(x_init)
-
- # algorithm loop
- for it in range(0, max_iter):
-
- time0 = time.time()
- if memopt:
- # u = y - invL*f.grad(y)
- # store the result in x_old
- f.gradient(y, out=u)
- u.__imul__( -invL )
- u.__iadd__( y )
- # x = g.prox(u,invL)
- g.proximal(u, invL, out=x)
-
- t = 0.5*(1 + numpy.sqrt(1 + 4*(t_old**2)))
-
- # y = x + (t_old-1)/t*(x-x_old)
- x.subtract(x_old, out=y)
- y.__imul__ ((t_old-1)/t)
- y.__iadd__( x )
-
- x_old.fill(x)
- t_old = t
-
-
- else:
- u = y - invL*f.gradient(y)
-
- x = g.proximal(u,invL)
-
- t = 0.5*(1 + numpy.sqrt(1 + 4*(t_old**2)))
-
- y = x + (t_old-1)/t*(x-x_old)
-
- x_old = x.copy()
- t_old = t
-
- # time and criterion
-# timing[it] = time.time() - time0
-# criter[it] = f(x) + g(x);
-
- # stopping rule
- #if np.linalg.norm(x - x_old) < tol * np.linalg.norm(x_old) and it > 10:
- # break
-
- #print(it, 'out of', 10, 'iterations', end='\r');
-
- #criter = criter[0:it+1];
-# timing = numpy.cumsum(timing[0:it+1]);
-
- return x #, it, timing, criter
-
-def FBPD(x_init, operator=None, constraint=None, data_fidelity=None,\
- regulariser=None, opt=None):
- '''FBPD Algorithm
-
- Parameters:
- x_init: initial guess
- f: constraint
- g: data fidelity
- h: regularizer
- opt: additional algorithm
- '''
- # default inputs
- if constraint is None: constraint = ZeroFun()
- if data_fidelity is None: data_fidelity = ZeroFun()
- if regulariser is None: regulariser = ZeroFun()
-
- # algorithmic parameters
- if opt is None:
- opt = {'tol': 1e-4, 'iter': 1000}
- else:
- try:
- max_iter = opt['iter']
- except KeyError as ke:
- opt[ke] = 1000
- try:
- opt['tol'] = 1000
- except KeyError as ke:
- opt[ke] = 1e-4
- tol = opt['tol']
- max_iter = opt['iter']
- memopt = opt['memopts'] if 'memopts' in opt.keys() else False
-
- # step-sizes
- tau = 2 / (data_fidelity.L + 2)
- sigma = (1/tau - data_fidelity.L/2) / regulariser.L
- inv_sigma = 1/sigma
-
- # initialization
- x = x_init
- y = operator.direct(x);
-
- timing = numpy.zeros(max_iter)
- criter = numpy.zeros(max_iter)
-
-
-
-
- # algorithm loop
- for it in range(0, max_iter):
-
- t = time.time()
-
- # primal forward-backward step
- x_old = x;
- x = x - tau * ( data_fidelity.grad(x) + operator.adjoint(y) );
- x = constraint.prox(x, tau);
-
- # dual forward-backward step
- y = y + sigma * operator.direct(2*x - x_old);
- y = y - sigma * regulariser.prox(inv_sigma*y, inv_sigma);
-
- # time and criterion
- timing[it] = time.time() - t
- criter[it] = constraint(x) + data_fidelity(x) + regulariser(operator.direct(x))
-
- # stopping rule
- #if np.linalg.norm(x - x_old) < tol * np.linalg.norm(x_old) and it > 10:
- # break
-
- criter = criter[0:it+1]
- timing = numpy.cumsum(timing[0:it+1])
-
- return x, it, timing, criter
-
-def CGLS(x_init, operator , data , opt=None):
- '''Conjugate Gradient Least Squares algorithm
-
- Parameters:
- x_init: initial guess
- operator: operator for forward/backward projections
- data: data to operate on
- opt: additional algorithm
- '''
-
- if opt is None:
- opt = {'tol': 1e-4, 'iter': 1000}
- else:
- try:
- max_iter = opt['iter']
- except KeyError as ke:
- opt[ke] = 1000
- try:
- opt['tol'] = 1000
- except KeyError as ke:
- opt[ke] = 1e-4
- tol = opt['tol']
- max_iter = opt['iter']
-
- r = data.copy()
- x = x_init.copy()
-
- d = operator.adjoint(r)
-
- normr2 = (d**2).sum()
-
- timing = numpy.zeros(max_iter)
- criter = numpy.zeros(max_iter)
-
- # algorithm loop
- for it in range(0, max_iter):
-
- t = time.time()
-
- Ad = operator.direct(d)
- alpha = normr2/( (Ad**2).sum() )
- x = x + alpha*d
- r = r - alpha*Ad
- s = operator.adjoint(r)
-
- normr2_new = (s**2).sum()
- beta = normr2_new/normr2
- normr2 = normr2_new
- d = s + beta*d
-
- # time and criterion
- timing[it] = time.time() - t
- criter[it] = (r**2).sum()
-
- return x, it, timing, criter
-
-def SIRT(x_init, operator , data , opt=None, constraint=None):
- '''Simultaneous Iterative Reconstruction Technique
-
- Parameters:
- x_init: initial guess
- operator: operator for forward/backward projections
- data: data to operate on
- opt: additional algorithm
- constraint: func of Indicator type specifying convex constraint.
- '''
-
- if opt is None:
- opt = {'tol': 1e-4, 'iter': 1000}
- else:
- try:
- max_iter = opt['iter']
- except KeyError as ke:
- opt[ke] = 1000
- try:
- opt['tol'] = 1000
- except KeyError as ke:
- opt[ke] = 1e-4
- tol = opt['tol']
- max_iter = opt['iter']
-
- x = x_init.clone()
-
- timing = numpy.zeros(max_iter)
- criter = numpy.zeros(max_iter)
-
- # Relaxation parameter must be strictly between 0 and 2. For now fix at 1.0
- relax_par = 1.0
-
- # Set up scaling matrices D and M.
- M = 1/operator.direct(operator.domain_geometry().allocate(value=1.0))
- D = 1/operator.adjoint(operator.range_geometry().allocate(value=1.0))
-
- # algorithm loop
- for it in range(0, max_iter):
- t = time.time()
- r = data - operator.direct(x)
-
- x = x + relax_par * (D*operator.adjoint(M*r))
-
- if constraint != None:
- x = constraint.prox(x,None)
-
- timing[it] = time.time() - t
- if it > 0:
- criter[it-1] = (r**2).sum()
-
- r = data - operator.direct(x)
- criter[it] = (r**2).sum()
- return x, it, timing, criter
-
diff --git a/Wrappers/Python/ccpi/optimisation/funcs.py b/Wrappers/Python/ccpi/optimisation/funcs.py
deleted file mode 100755
index b2b9791..0000000
--- a/Wrappers/Python/ccpi/optimisation/funcs.py
+++ /dev/null
@@ -1,265 +0,0 @@
-# -*- coding: utf-8 -*-
-# This work is part of the Core Imaging Library developed by
-# Visual Analytics and Imaging System Group of the Science Technology
-# Facilities Council, STFC
-
-# Copyright 2018 Jakob Jorgensen, Daniil Kazantsev and Edoardo Pasca
-
-# 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.
-
-import numpy
-from ccpi.framework import DataContainer
-import warnings
-from ccpi.optimisation.functions import Function
-def isSizeCorrect(data1 ,data2):
- if issubclass(type(data1), DataContainer) and \
- issubclass(type(data2), DataContainer):
- # check dimensionality
- if data1.check_dimensions(data2):
- return True
- elif issubclass(type(data1) , numpy.ndarray) and \
- issubclass(type(data2) , numpy.ndarray):
- return data1.shape == data2.shape
- else:
- raise ValueError("{0}: getting two incompatible types: {1} {2}"\
- .format('Function', type(data1), type(data2)))
- return False
-class Norm2(Function):
-
- def __init__(self,
- gamma=1.0,
- direction=None):
- super(Norm2, self).__init__()
- self.gamma = gamma;
- self.direction = direction;
-
- def __call__(self, x, out=None):
-
- if out is None:
- xx = numpy.sqrt(numpy.sum(numpy.square(x.as_array()), self.direction,
- keepdims=True))
- else:
- if isSizeCorrect(out, x):
- # check dimensionality
- if issubclass(type(out), DataContainer):
- arr = out.as_array()
- numpy.square(x.as_array(), out=arr)
- xx = numpy.sqrt(numpy.sum(arr, self.direction, keepdims=True))
-
- elif issubclass(type(out) , numpy.ndarray):
- numpy.square(x.as_array(), out=out)
- xx = numpy.sqrt(numpy.sum(out, self.direction, keepdims=True))
- else:
- raise ValueError ('Wrong size: x{0} out{1}'.format(x.shape,out.shape) )
-
- p = numpy.sum(self.gamma*xx)
-
- return p
-
- def prox(self, x, tau):
-
- xx = numpy.sqrt(numpy.sum( numpy.square(x.as_array()), self.direction,
- keepdims=True ))
- xx = numpy.maximum(0, 1 - tau*self.gamma / xx)
- p = x.as_array() * xx
-
- return type(x)(p,geometry=x.geometry)
- def proximal(self, x, tau, out=None):
- if out is None:
- return self.prox(x,tau)
- else:
- if isSizeCorrect(out, x):
- # check dimensionality
- if issubclass(type(out), DataContainer):
- numpy.square(x.as_array(), out = out.as_array())
- xx = numpy.sqrt(numpy.sum( out.as_array() , self.direction,
- keepdims=True ))
- xx = numpy.maximum(0, 1 - tau*self.gamma / xx)
- x.multiply(xx, out= out.as_array())
-
-
- elif issubclass(type(out) , numpy.ndarray):
- numpy.square(x.as_array(), out=out)
- xx = numpy.sqrt(numpy.sum(out, self.direction, keepdims=True))
-
- xx = numpy.maximum(0, 1 - tau*self.gamma / xx)
- x.multiply(xx, out= out)
- else:
- raise ValueError ('Wrong size: x{0} out{1}'.format(x.shape,out.shape) )
-
-
-
-
-# Define a class for squared 2-norm
-class Norm2sq(Function):
- '''
- f(x) = c*||A*x-b||_2^2
-
- which has
-
- grad[f](x) = 2*c*A^T*(A*x-b)
-
- and Lipschitz constant
-
- L = 2*c*||A||_2^2 = 2*s1(A)^2
-
- where s1(A) is the largest singular value of A.
-
- '''
-
- def __init__(self,A,b,c=1.0,memopt=False):
- super(Norm2sq, self).__init__()
-
- self.A = A # Should be an operator, default identity
- self.b = b # Default zero DataSet?
- self.c = c # Default 1.
- if memopt:
- try:
- self.range_tmp = A.range_geometry().allocate()
- self.domain_tmp = A.domain_geometry().allocate()
- self.memopt = True
- except NameError as ne:
- warnings.warn(str(ne))
- self.memopt = False
- except NotImplementedError as nie:
- print (nie)
- warnings.warn(str(nie))
- self.memopt = False
- else:
- self.memopt = False
-
- # Compute the Lipschitz parameter from the operator if possible
- # Leave it initialised to None otherwise
- try:
- self.L = 2.0*self.c*(self.A.norm()**2)
- except AttributeError as ae:
- pass
- except NotImplementedError as noe:
- pass
-
- #def grad(self,x):
- # return self.gradient(x, out=None)
-
- def __call__(self,x):
- #return self.c* np.sum(np.square((self.A.direct(x) - self.b).ravel()))
- #if out is None:
- # return self.c*( ( (self.A.direct(x)-self.b)**2).sum() )
- #else:
- y = self.A.direct(x)
- y.__isub__(self.b)
- #y.__imul__(y)
- #return y.sum() * self.c
- try:
- return y.squared_norm() * self.c
- except AttributeError as ae:
- # added for compatibility with SIRF
- return (y.norm()**2) * self.c
-
- def gradient(self, x, out = None):
- if self.memopt:
- #return 2.0*self.c*self.A.adjoint( self.A.direct(x) - self.b )
-
- self.A.direct(x, out=self.range_tmp)
- self.range_tmp -= self.b
- self.A.adjoint(self.range_tmp, out=out)
- #self.direct_placehold.multiply(2.0*self.c, out=out)
- out *= (self.c * 2.0)
- else:
- return (2.0*self.c)*self.A.adjoint( self.A.direct(x) - self.b )
-
-
-
-# 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
-# to vectors to allow different constraints one elements.
-class IndicatorBox(Function):
-
- def __init__(self,lower=-numpy.inf,upper=numpy.inf):
- # Do nothing
- super(IndicatorBox, self).__init__()
- self.lower = lower
- self.upper = upper
-
-
- def __call__(self,x):
-
- if (numpy.all(x.array>=self.lower) and
- numpy.all(x.array <= self.upper) ):
- val = 0
- else:
- val = numpy.inf
- return val
-
- def prox(self,x,tau=None):
- return (x.maximum(self.lower)).minimum(self.upper)
-
- def proximal(self, x, tau, out=None):
- if out is None:
- return self.prox(x, tau)
- else:
- if not x.shape == out.shape:
- raise ValueError('Norm1 Incompatible size:',
- x.shape, out.shape)
- #(x.abs() - tau*self.gamma).maximum(0) * x.sign()
- x.abs(out = out)
- out.__isub__(tau*self.gamma)
- out.maximum(0, out=out)
- if self.sign_x is None or not x.shape == self.sign_x.shape:
- self.sign_x = x.sign()
- else:
- x.sign(out=self.sign_x)
-
- out.__imul__( self.sign_x )
-
-# A more interesting example, least squares plus 1-norm minimization.
-# Define class to represent 1-norm including prox function
-class Norm1(Function):
-
- def __init__(self,gamma):
- super(Norm1, self).__init__()
- self.gamma = gamma
- self.L = 1
- self.sign_x = None
-
- def __call__(self,x,out=None):
- if out is None:
- return self.gamma*(x.abs().sum())
- else:
- if not x.shape == out.shape:
- raise ValueError('Norm1 Incompatible size:',
- x.shape, out.shape)
- x.abs(out=out)
- return out.sum() * self.gamma
-
- 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)
- else:
- if isSizeCorrect(x,out):
- # check dimensionality
- if issubclass(type(out), DataContainer):
- v = (x.abs() - tau*self.gamma).maximum(0)
- x.sign(out=out)
- out *= v
- #out.fill(self.prox(x,tau))
- elif issubclass(type(out) , numpy.ndarray):
- v = (x.abs() - tau*self.gamma).maximum(0)
- out[:] = x.sign()
- out *= v
- #out[:] = self.prox(x,tau)
- else:
- raise ValueError ('Wrong size: x{0} out{1}'.format(x.shape,out.shape) )