33import numpy as np
44from numpy .typing import NDArray
55
6+
67def armijo_line_search (
7- x ,
8- p ,
9- g ,
10- objective : Callable ,
8+ gradient : Callable ,
9+ x : NDArray ,
10+ dx : NDArray ,
1111 step_init : float = 1.0 ,
12- alpha : float = 0.01 ,
13- shrinkage : float = 0.5 ,
14- ):
15- """
16- Performs an Armijo line search to select an appropriate step size along a given search direction.
17- This function iteratively reduces the step size until the decrease in the objective function, along the direction of descent,
18- satisfies the Armijo (sufficient decrease) condition. In each iteration, it checks whether the new point yields a value that is
19- lower than the current value by a margin proportional to the step and directional derivative. If no satisfactory step size is found
20- and the step size becomes exceedingly small (<= 1e-15), a RuntimeError is raised.
21- Parameters:
22- x (array_like): The current point or position in the parameter space.
23- p (array_like): The descent direction along which the line search is performed.
24- g (array_like): The gradient of the objective function evaluated at x.
25- objective (Callable): A callable that computes the objective function value given a point.
26- step_init (float, optional): The initial step size to start the line search. Default is 1.0.
27- alpha (float, optional): The Armijo condition control parameter defining the sufficient decrease criterion. Default is 0.01.
28- shrinkage (float, optional): The factor by which the step is multiplied to reduce the step size in each iteration. Default is 0.5.
29- Returns:
30- float: The step size that satisfies the Armijo sufficient decrease condition.
31- Raises:
32- RuntimeError: If the step size becomes too small (<= 1e-15) without satisfying the Armijo condition,
33- indicating failure in finding a suitable step size.
34- """
35- def sufficiently_improved (new_val , step ):
36- return (new_val - val <= - 1 * alpha * step * np .dot (g , p )) and (
37- not np .isnan (new_val )
38- )
12+ step_const : float = 0.01 ,
13+ step_scale : float = 0.9 ,
14+ step_lb : float = 1e-3 ,
15+ ) -> float :
16+ """Armijo line search.
17+
18+ Parameters
19+ ----------
20+ x
21+ A list a parameters, including x, s, and v, where s is the slackness
22+ variable and v is the dual variable for the constraints.
23+ dx
24+ A list of direction for the parameters.
25+ step_init
26+ Initial step size, by default 1.0.
27+ step_const
28+ Constant for the line search condition, the larger the harder, by
29+ default 0.01.
30+ step_scale
31+ Shrinkage factor for step size, by default 0.9.
32+ step_lb
33+ Lower bound of the step size when the step size is below this bound
34+ the line search will be terminated.
3935
36+ Returns
37+ -------
38+ float
39+ The step size in the given direction.
40+
41+ """
4042 step = step_init
41- new_x = x - step * p
42- val , new_val = objective (x ), objective (new_x )
43- while (not sufficiently_improved (new_val , step )):
44- if step <= 1e-15 :
45- raise RuntimeError (
46- f"Line Search Failed, new_val = { new_val } , prev_val = { val } "
47- )
48- step *= shrinkage
49- new_x = x - step * p
50- new_val = objective (new_x )
51- return step
43+ x_next = x + step * dx
44+ g_next = gradient (x_next )
45+ gnorm_curr = np .max (np .abs (gradient (x )))
46+ gnorm_next = np .max (np .abs (g_next ))
47+
48+ while gnorm_next > (1 - step_const * step ) * gnorm_curr :
49+ if step * step_scale < step_lb :
50+ break
51+ step *= step_scale
52+ x_next = x + step * dx
53+ g_next = gradient (x_next )
54+ gnorm_next = np .max (np .abs (g_next ))
55+
56+ return step
0 commit comments