Coverage for gpaw/new/pwfd/lbfgs.py: 13%
102 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-19 00:19 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-19 00:19 +0000
1import numpy as np
2from gpaw.new import zips
5class Vector:
6 def __init__(self, x_unX):
7 self.x_unX = x_unX
9 def copy(self):
10 return Vector([x_nX.copy() for x_nX in self.x_unX])
12 def __iter__(self):
13 yield from self.x_unX
15 def zeros(self):
16 y_unX = []
17 for x_nX in self:
18 y_nX = x_nX.new()
19 y_nX.data[:] = 0.0
20 y_unX.append(y_nX)
21 return Vector(y_unX)
23 def __mul__(self, other):
24 y_unX = self.copy()
25 for y_nX in y_unX:
26 y_nX.data *= other
27 return y_unX
29 def __matmul__(self, other):
30 z = 0.0
31 for x_nX, y_nX in zips(self, other):
32 for x_X, y_X in zips(x_nX, y_nX):
33 z += x_X.integrate(y_X)
34 return 2 * z.real
36 def __sub__(self, other):
37 x_unX = self.copy()
38 for x_nX, y_nX in zips(x_unX, other):
39 x_nX.data -= y_nX.data
40 return x_unX
43class LBFGS:
44 def __init__(self,
45 memory=3):
46 self.memory = memory
47 self.iters = 0
48 self.kp = None
49 self.p = None
50 self.k = None
51 self.s_k = {i: None for i in range(memory)}
52 self.y_k = {i: None for i in range(memory)}
53 self.rho_k = np.zeros(shape=memory)
54 self.kp = {}
55 self.p = 0
56 self.k = 0
57 self.stable = True
59 def update(self,
60 x_k1,
61 g_k1):
62 x_k1 = Vector(x_k1)
63 g_k1 = Vector(g_k1)
64 self.iters += 1
66 if self.k == 0:
67 self.kp[self.k] = self.p
68 self.x_k = x_k1.copy()
69 self.g_k = g_k1
70 self.s_k[self.kp[self.k]] = g_k1.zeros()
71 self.y_k[self.kp[self.k]] = g_k1.zeros()
72 self.k += 1
73 self.p += 1
74 self.kp[self.k] = self.p
75 return (g_k1 * -1.0).x_unX
77 if self.p == self.memory:
78 self.p = 0
79 self.kp[self.k] = self.p
81 s_k = self.s_k
82 x_k = self.x_k
83 y_k = self.y_k
84 g_k = self.g_k
86 x_k1 = x_k1.copy()
88 rho_k = self.rho_k
90 kp = self.kp
91 k = self.k
92 m = self.memory
94 s_k[kp[k]] = x_k1 - x_k
95 y_k[kp[k]] = g_k1 - g_k
96 dot_ys = y_k[kp[k]] @ s_k[kp[k]]
98 if abs(dot_ys) > 1.0e-15:
99 rho_k[kp[k]] = 1.0 / dot_ys
100 else:
101 rho_k[kp[k]] = 1.0e15
103 if dot_ys < 0.0:
104 self.stable = False
106 q = g_k1.copy()
108 alpha = np.zeros(np.minimum(k + 1, m))
109 j = np.maximum(-1, k - m)
111 for i in range(k, j, -1):
112 dot_sq = s_k[kp[i]] @ q
113 alpha[kp[i]] = rho_k[kp[i]] * dot_sq
114 q = q - y_k[kp[i]] * alpha[kp[i]]
116 t = k
117 dot_yy = y_k[kp[t]] @ y_k[kp[t]]
119 if abs(dot_yy) > 1.0e-15:
120 r = q * (1.0 / (rho_k[kp[t]] * dot_yy))
121 else:
122 r = q * 1.0e15
124 for i in range(np.maximum(0, k - m + 1), k + 1):
125 dot_yr = y_k[kp[i]] @ r
126 beta = rho_k[kp[i]] * dot_yr
127 r = r - s_k[kp[i]] * (beta - alpha[kp[i]])
129 # save this step:
130 self.x_k = x_k1.copy()
131 self.g_k = g_k1.copy()
132 self.k += 1
133 self.p += 1
134 self.kp[self.k] = self.p
136 return (r * -1.0).x_unX