summaryrefslogtreecommitdiffstats
path: root/Wrappers/Python/ccpi/optimisation/functions/FunctionOperatorComposition.py
blob: 24ebbf0018d5f5b59e7cd44b3ee7a6b2d19fa08f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# -*- coding: utf-8 -*-
#  CCP in Tomographic Imaging (CCPi) Core Imaging Library (CIL).

#   Copyright 2017 UKRI-STFC
#   Copyright 2017 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.
from ccpi.optimisation.functions import Function
from ccpi.optimisation.functions import ScaledFunction


class FunctionOperatorComposition(Function):
    
    ''' Function composition with Operator, i.e., f(Ax)
    
        A: operator
        f: function
    
    '''
    
    def __init__(self, function, operator):
        
        super(FunctionOperatorComposition, self).__init__()
        
        self.function = function     
        self.operator = operator
        self.L = function.L * operator.norm()**2 
        
        
    def __call__(self, x):
        
        ''' Evaluate FunctionOperatorComposition at x
        
        returns f(Ax)
        
        '''
    
        return self.function(self.operator.direct(x))  
    
    def gradient(self, x, out=None):
#        
        ''' Gradient takes into account the Operator'''
        if out is None:
            return self.operator.adjoint(self.function.gradient(self.operator.direct(x)))
        else: 
            tmp = self.operator.range_geometry().allocate()
            self.operator.direct(x, out=tmp)
            self.function.gradient(tmp, out=tmp)
            self.operator.adjoint(tmp, out=out)

    

                
if __name__ == '__main__':   

    from ccpi.framework import ImageGeometry, AcquisitionGeometry
    from ccpi.optimisation.operators import Gradient
    from ccpi.optimisation.functions import L2NormSquared
    from ccpi.astra.ops import AstraProjectorSimple
    import numpy as np
        
    M, N= 50, 50
    ig = ImageGeometry(voxel_num_x=M, voxel_num_y = N)
    
    detectors = N
    angles_num = N    
    det_w = 1.0
    
    angles = np.linspace(0, np.pi, angles_num, endpoint=False)
    ag = AcquisitionGeometry('parallel',
                             '2D',
                             angles,
                             detectors,det_w)
    
    
    Aop = AstraProjectorSimple(ig, ag, 'cpu')    

    u = ig.allocate('random_int', seed=15)
    u1 = ig.allocate('random_int', seed=10)
    b = Aop.direct(u1)
    
        
#    G = Gradient(ig)
    alpha = 0.5
    
    f1 =  alpha * L2NormSquared(b=b)    

    f_comp = FunctionOperatorComposition(f1, Aop)
    
    print(f_comp(u))
    
    
    z1 = Aop.direct(u)
    tmp = 0.5 * ((z1 - b)**2).sum()
    
   
    print(tmp)