Skip to content

Commit 43d1083

Browse files
committed
ENH/STY/MAINT/DOC: See full list below.
This commit contains updates in: - functional_basic_example - functional_basic_example_solver - default_functionals - functional - default_functional_test - functional_test functional_basic_example: - minor updates in comments. functional_basic_example_solver: - minor updates in comments. - add example with forward-backward pd solver. - update error in operator norm when chambolle-pock. default_functionals: - doc updates in many of the classes and methods. - inner class L1ConjuagteFunctional -> real class IndicatorLinftyUnitBall. - inner class L2ConjugateFunctional -> real class IndicatorL2UnitBall. - remove class L2SquareConjugateFunctional, since this is just a scalar multiplied with the L2Square functional. - renamed ConstantFunctionalConvexConjuaget to ConjugateToConstantFunctional. - add property to ConjugateToConstantFunctional that returns the constant. functional: - doc updates in some places. - remove storing scalars and functionals when classes inherites from OperatorComp, OperatorLeftScalarMult, etc. since these are stored in parent classes. - remove inner class LeftScalarMultGradient. Not needed, as the same can be achieved in a simpler way. - removed inner class RightScalarMultGradient. Not needed, as the same can be achieved in a simpler way. - input checks on TranslatedFunctional. - add properties to access things as scaling and translation in TranslatedFunctional, ConvexConjugateFuncScaling, etc. default_functionals_test: - add a TODO. functional_test: - style update.
1 parent 72ed1b4 commit 43d1083

File tree

6 files changed

+444
-420
lines changed

6 files changed

+444
-420
lines changed

examples/solvers/functional_basic_example.py

+9-13
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# You should have received a copy of the GNU General Public License
1616
# along with ODL. If not, see <http://www.gnu.org/licenses/>.
1717

18-
"""Basic examples on how to write a fucntional.
18+
"""Basic example on how to write a functional.
1919
2020
When defining a new functional, there are a few standard methods and properties
2121
that can be implemeted. These are:
@@ -32,8 +32,8 @@
3232
operator ``x --> <x, grad_f(y)>``. Note that this has a default
3333
implemetation that uses the gradient in order to achieve this.
3434
35-
Below follows an example of implementing the functional ``||x||_2^2 + <x,y>,
36-
for some parameter y.``
35+
Below follows an example of implementing the functional ``||x||_2^2 + <x,y>``,
36+
for some parameter ``y.``
3737
"""
3838

3939
# Imports for common Python 2/3 codebase
@@ -64,7 +64,7 @@ def __init__(self, domain, y):
6464
self._y = y
6565

6666
# Now we define a propert which returns y, so that the user can see which
67-
# translation is used in a particular instance of the class.
67+
# value is used in a particular instance of the class.
6868
@property
6969
def y(self):
7070
return self._y
@@ -80,24 +80,20 @@ def gradient(self):
8080
# defined anywhere and just returned here, but in this example we will
8181
# also define it here.
8282

83-
# In order for the initialization of the operator to know which
84-
# functional it comes from.
85-
this_functional = self
86-
8783
class MyGradientOperator(odl.Operator):
8884

8985
# Define an __init__ method for this operator
9086
def __init__(self, functional):
91-
super().__init__(domain=this_functional.domain,
92-
range=this_functional.domain)
87+
super().__init__(domain=functional.domain,
88+
range=functional.domain)
9389

9490
self._functional = functional
9591

9692
# Define a _call method for this operator
9793
def _call(self, x):
9894
return 2.0 * x + self._functional.y
9995

100-
return MyGradientOperator(functional=this_functional)
96+
return MyGradientOperator(functional=self)
10197

10298
# Next we define the convex conjugate functional
10399
@property
@@ -108,7 +104,7 @@ def conjugate_functional(self):
108104

109105
# Here is the conjugate functional
110106
class MyFunctionalConjugate(odl.solvers.Functional):
111-
"""Hand calculations give that this funtional has the analytic expression
107+
"""Calculations give that this funtional has the analytic expression
112108
f^*(x) = ||x||^2/2 - ||x-y||^2/4 + ||y||^2/2 - <x,y>.
113109
"""
114110
def __init__(self, domain, y):
@@ -164,7 +160,7 @@ def _call(self, x):
164160
my_deriv = my_func.derivative(x)
165161

166162
if my_deriv(p) == my_gradient(x).inner(p):
167-
print('The default implementation of the gradient works as intended.')
163+
print('The default implementation of the derivative works as intended.')
168164
else:
169165
print('There is a bug in the implementation of the derivative')
170166

examples/solvers/functional_basic_example_solver.py

+43-13
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@
1515
# You should have received a copy of the GNU General Public License
1616
# along with ODL. If not, see <http://www.gnu.org/licenses/>.
1717

18-
"""Basic examples on how to use the fucntional class together with solvers.
18+
"""Basic example on how to use the functional class together with solvers.
1919
2020
This file shows an example of how to set up and solve an optimization problem
2121
using the default functionals. The problem we will solve is to minimize
2222
1/2 * ||x - g||_2^2 + lam*||x||_1, for some vector g and some constant lam,
2323
subject to that all components in x are greater than or equal to 0. The
2424
theoretical optimal solution to this problem is x = (g - lam)_+, where ( )+
25-
denotes the positive part of (i.e., (z)_+ = z if z >= 0, 0 otherwise).
25+
denotes the positive part of the element, i.e., (z_i)_+ = z_i if z_i >= 0, and
26+
0 otherwise.
2627
"""
2728

2829
import numpy as np
@@ -46,9 +47,37 @@
4647
l2_func = 1.0 / 2.0 * odl.solvers.L2NormSquare(space)
4748
trans_l2_func = l2_func.translate(g)
4849

49-
# The problem will be solved using the Chambolle-Pock algorithm. Here we create
50-
# the necessary proximal factories of the conjugate functionals (see the
51-
# Chambolle-Pock algorithm and examples on this for more information).
50+
# The problem will be solved using the forward-backward primal-dual algorithm.
51+
# In this setting we let f = nonnegativity contraint, g = l1-norm, and h =
52+
# the squared l2-norm. Here we create necessary proximal and gradient operators
53+
# from the functionals.
54+
prox_f = odl.solvers.proximal_nonnegativity(space)
55+
prox_cc_g = lam_l1_func.conjugate_functional.proximal
56+
L = odl.IdentityOperator(space)
57+
grad_h = trans_l2_func.gradient
58+
59+
# Some solver parameters
60+
niter = 50
61+
tau = 0.5
62+
sigma = 0.5
63+
64+
# Starting point, and also updated inplace in the solver
65+
x_fbpd = space.zero()
66+
67+
# Optional: pass callback objects to solver
68+
callback = (odl.solvers.CallbackPrintIteration())
69+
70+
# Run the algorithm
71+
odl.solvers.forward_backward_pd(x=x_fbpd, prox_f=prox_f, prox_cc_g=[prox_cc_g],
72+
L=[L], grad_h=grad_h, tau=tau, sigma=[sigma],
73+
niter=niter, callback=callback)
74+
75+
print(x_fbpd.asarray())
76+
77+
78+
# The problem can also be solved using, e.g., the Chambolle-Pock algorithm.
79+
# Here we create the necessary proximal factories of the conjugate functionals
80+
# (see the Chambolle-Pock algorithm and examples on this for more information).
5281
prox_cc_l2 = trans_l2_func.conjugate_functional.proximal
5382
prox_cc_l1 = lam_l1_func.conjugate_functional.proximal
5483

@@ -62,23 +91,24 @@
6291
# Create the proximal operator for the constraint
6392
proximal_primal = odl.solvers.proximal_nonnegativity(op.domain)
6493

65-
# The operator norm is 1, since only identity operators are used
66-
op_norm = 1
94+
# The operator norm is sqrt(2), since only identity operators are used
95+
op_norm = np.sqrt(2)
6796

6897
# Some solver parameters
69-
niter = 100 # Number of iterations
98+
niter = 50 # Number of iterations
7099
tau = 1.0 / op_norm # Step size for the primal variable
71100
sigma = 1.0 / op_norm # Step size for the dual variable
72101

73102
# Optional: pass callback objects to solver
74103
callback = (odl.solvers.CallbackPrintIteration())
75104

76105
# Starting point, and also updated inplace in the solver
77-
x = op.domain.zero()
106+
x_cp = op.domain.zero()
78107

79108
# Run the algorithm
80-
odl.solvers.chambolle_pock_solver(
81-
op, x, tau=tau, sigma=sigma, proximal_primal=proximal_primal,
82-
proximal_dual=proximal_dual, niter=niter, callback=callback)
109+
odl.solvers.chambolle_pock_solver(op=op, x=x_cp, tau=tau, sigma=sigma,
110+
proximal_primal=proximal_primal,
111+
proximal_dual=proximal_dual, niter=niter,
112+
callback=callback)
83113

84-
print(x.asarray())
114+
print(x_cp.asarray())

0 commit comments

Comments
 (0)