Skip to content

Commit fdba492

Browse files
authored
Merge pull request #118 from PerformanceEstimation/feature/radius_for_convex_indicator
Feature/radius for convex indicator
2 parents 250d0e9 + 2887acc commit fdba492

4 files changed

Lines changed: 96 additions & 73 deletions

File tree

PEPit/examples/composite_convex_minimization/frank_wolfe.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,25 @@
44
from PEPit.primitive_steps import linear_optimization_step
55

66

7-
def wc_frank_wolfe(L, D, n, wrapper="cvxpy", solver=None, verbose=1):
7+
def wc_frank_wolfe(L, D, R, center, n, wrapper="cvxpy", solver=None, verbose=1):
88
"""
99
Consider the composite convex minimization problem
1010
1111
.. math:: F_\\star \\triangleq \\min_x \\{F(x) \\equiv f_1(x) + f_2(x)\\},
1212
1313
where :math:`f_1` is :math:`L`-smooth and convex
14-
and where :math:`f_2` is a convex indicator function on :math:`\\mathcal{D}` of diameter at most :math:`D`.
14+
and where :math:`f_2` is a convex indicator function on :math:`\\mathcal{D}`
15+
of diameter at most :math:`D` and radius at most :math:`R` around `center`.
1516
1617
This code computes a worst-case guarantee for the **conditional gradient** method, aka **Frank-Wolfe** method.
1718
That is, it computes the smallest possible :math:`\\tau(n, L)` such that the guarantee
1819
19-
.. math :: F(x_n) - F(x_\\star) \\leqslant \\tau(n, L) D^2,
20+
.. math :: F(x_n) - F(x_\\star) \\leqslant \\tau(n, L, D, R),
2021
2122
is valid, where x_n is the output of the **conditional gradient** method,
2223
and where :math:`x_\\star` is a minimizer of :math:`F`.
23-
In short, for given values of :math:`n` and :math:`L`, :math:`\\tau(n, L)` is computed as the worst-case value of
24-
:math:`F(x_n) - F(x_\\star)` when :math:`D \\leqslant 1`.
24+
In short, for given values of :math:`n` and :math:`L`, :math:`\\tau(n, L, D, R)`
25+
is computed as the worst-case value of :math:`F(x_n) - F(x_\\star)`.
2526
2627
**Algorithm**:
2728
@@ -36,7 +37,7 @@ def wc_frank_wolfe(L, D, n, wrapper="cvxpy", solver=None, verbose=1):
3637
3738
**Theoretical guarantee**:
3839
39-
An **upper** guarantee obtained in [2, Theorem 1] is
40+
An **upper** guarantee obtained in [2, Theorem 1] when R = infinity is
4041
4142
.. math :: F(x_n) - F(x_\\star) \\leqslant \\frac{2L D^2}{n+2}.
4243
@@ -54,7 +55,9 @@ def wc_frank_wolfe(L, D, n, wrapper="cvxpy", solver=None, verbose=1):
5455
5556
Args:
5657
L (float): the smoothness parameter.
57-
D (float): diameter of :math:`f_2`.
58+
D (float): diameter of :math:`\\mathcal{D}`.
59+
R (float): radius of :math:`\\mathcal{D}`.
60+
center (Point): center of :math:`\\mathcal{D}`. If None, the radius constraint must be observed to one center.
5861
n (int): number of iterations.
5962
wrapper (str): the name of the wrapper to be used.
6063
solver (str): the name of the solver the wrapper should use.
@@ -70,7 +73,8 @@ def wc_frank_wolfe(L, D, n, wrapper="cvxpy", solver=None, verbose=1):
7073
theoretical_tau (float): theoretical value.
7174
7275
Example:
73-
>>> pepit_tau, theoretical_tau = wc_frank_wolfe(L=1, D=1, n=10, wrapper="cvxpy", solver=None, verbose=1)
76+
>>> pepit_tau, theoretical_tau = wc_frank_wolfe(L=1, D=1, R=float('inf'), center=None, n=10,
77+
>>> wrapper="cvxpy", solver=None, verbose=1)
7478
(PEPit) Setting up the problem: size of the Gram matrix: 26x26
7579
(PEPit) Setting up the problem: performance measure is the minimum of 1 element(s)
7680
(PEPit) Setting up the problem: Adding initial conditions and general constraints ...
@@ -102,9 +106,9 @@ def wc_frank_wolfe(L, D, n, wrapper="cvxpy", solver=None, verbose=1):
102106
# Instantiate PEP
103107
problem = PEP()
104108

105-
# Declare a smooth convex function and a convex indicator of rayon D
109+
# Declare a smooth convex function and a convex indicator of diameter D
106110
func1 = problem.declare_function(function_class=SmoothConvexFunction, L=L)
107-
func2 = problem.declare_function(function_class=ConvexIndicatorFunction, D=D)
111+
func2 = problem.declare_function(function_class=ConvexIndicatorFunction, D=D, R=R, center=center)
108112
# Define the function to optimize as the sum of func1 and func2
109113
func = func1 + func2
110114

@@ -135,7 +139,7 @@ def wc_frank_wolfe(L, D, n, wrapper="cvxpy", solver=None, verbose=1):
135139
pepit_tau = problem.solve(wrapper=wrapper, solver=solver, verbose=pepit_verbose)
136140

137141
# Compute theoretical guarantee (for comparison)
138-
# when theta = 1
142+
# when theta = 1, and R = infinity
139143
theoretical_tau = 2 * L * D ** 2 / (n + 2)
140144

141145
# Print conclusion if required
@@ -149,4 +153,5 @@ def wc_frank_wolfe(L, D, n, wrapper="cvxpy", solver=None, verbose=1):
149153

150154

151155
if __name__ == "__main__":
152-
pepit_tau, theoretical_tau = wc_frank_wolfe(L=1, D=1, n=10, wrapper="cvxpy", solver=None, verbose=1)
156+
pepit_tau, theoretical_tau = wc_frank_wolfe(L=1, D=1, R=float('inf'), center=None, n=10,
157+
wrapper="cvxpy", solver=None, verbose=1)

PEPit/functions/convex_indicator.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import numpy as np
22

3+
from PEPit.point import Point
34
from PEPit.function import Function
45

6+
57
class ConvexIndicatorFunction(Function):
68
"""
79
The :class:`ConvexIndicatorFunction` class overwrites the `add_class_constraints` method of :class:`Function`,
@@ -10,8 +12,9 @@ class ConvexIndicatorFunction(Function):
1012
Attributes:
1113
D (float): upper bound on the diameter of the feasible set, possibly set to np.inf
1214
R (float): upper bound on the radius of the feasible set, possibly set to np.inf
13-
center (Point): Center of the feasible set spanned by the radius constraint, possibly set to None.
14-
Convex indicator functions are characterized by a parameter `D` (or `R`), hence can be instantiated as
15+
center (Point): Center of the feasible set spanned by the radius constraint.
16+
If set to None, there exists such a point but it remains undefined.
17+
Convex indicator functions are characterized by a parameter `D` and/or `R`, hence can be instantiated as
1518
1619
Example:
1720
>>> from PEPit import PEP
@@ -67,8 +70,11 @@ def __init__(self,
6770
self.D = D
6871
# Store the radius R in an attribute
6972
self.R = R
70-
# Store the center in an attribute
71-
self.center = center
73+
# Store the center in an attribute
74+
if center is None and self.R != np.inf:
75+
self.center = Point()
76+
else:
77+
self.center = center
7278

7379
@staticmethod
7480
def set_value_constraint_i(xi, gi, fi):
@@ -104,14 +110,17 @@ def set_diameter_constraint_i_j(self,
104110
# Diameter constraint
105111
constraint = ((xi - xj) ** 2 <= self.D ** 2)
106112

107-
# Radius constraint
108-
if self.R < np.inf:
109-
# No self.center provided centers the ball on the origin
110-
if self.center is None:
111-
constraint = ((xi)**2 <= self.R ** 2)
112-
# Centering the ball on self.center
113-
else:
114-
constraint = ((self.center - xi)**2 <= self.R ** 2)
113+
return constraint
114+
115+
def set_radius_constraint_i(self,
116+
xi, gi, fi,
117+
):
118+
"""
119+
Formulate the constraints bounding the radius of the support of self around self.center.
120+
121+
"""
122+
# Radius constraint
123+
constraint = ((xi - self.center)**2 <= self.R ** 2)
115124

116125
return constraint
117126

@@ -130,9 +139,16 @@ def add_class_constraints(self):
130139
constraint_name="convexity",
131140
set_class_constraint_i_j=self.set_convexity_constraint_i_j,
132141
)
133-
if (self.D != np.inf) or (self.R != np.inf):
142+
143+
if self.D != np.inf:
134144
self.add_constraints_from_two_lists_of_points(list_of_points_1=self.list_of_points,
135145
list_of_points_2=self.list_of_points,
136146
constraint_name="diameter",
137147
set_class_constraint_i_j=self.set_diameter_constraint_i_j,
138148
)
149+
150+
if self.R != np.inf:
151+
self.add_constraints_from_one_list_of_points(list_of_points=self.list_of_points,
152+
constraint_name="radius",
153+
set_class_constraint_i=self.set_radius_constraint_i,
154+
)

docs/source/whatsnew/0.4.0.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ What's new in PEPit 0.4.0
1414
- New examples: (i) Refined block-coordinate descent (refined interpolation techniques--but computationally more expensive) (ii) introduction of quadratic Lojasiewicz inequalities, examples on gradient descent (with different ways to improse Lojasiewicz inequalities, from naive ones to more advanced SDP-representable ones) (iii) optimistic gradient with more advanced SDP-representable monotonocity/Lipschitz characterization, (iv) difference-of-convex algorithm (DCA, also known as the convex-concave procedure), (v) online learning settings (online gradient descent, online Frank-Wolfe, follow the leader, follow the regularized leader).
1515

1616
- Corrected example: SGD's closed-form solution has been updated.
17+
18+
- The support of functions of the class :class:`ConvexIndicatorFunction` can be constrained through a radius in addition to a diameter.

0 commit comments

Comments
 (0)