-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprojectionSVD.py
More file actions
58 lines (54 loc) · 1.89 KB
/
projectionSVD.py
File metadata and controls
58 lines (54 loc) · 1.89 KB
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
import numpy as np
import scipy.linalg as sci
def projectionSVD(A, phi, eps1 = 1e-3, eps2 = 1e-3, eps3 = 1e-3):
"""Construct a projection that includes most of the stuff
being sent to phi."""
normPhi = np.linalg.norm(phi)
if np.abs(normPhi-1) > eps2:
phi = phi/normPhi
U, S, Vh = np.linalg.svd(A)
P = np.outer(phi, phi)
n = len(phi)
tol = 1.-eps1
for k in range(n):
PU = np.matmul(P, U)
sizePU = [np.linalg.norm(PU[:, i]) for i in range(n)]
## The key idea
weightedSize = np.abs([sizePU[i]*S[i] for i in range(n)])
total = np.sum(weightedSize)
if total == 0.:
return np.outer(phi, phi), phi
sortedWeightedSize = np.sort(weightedSize)[::-1]
subtotal = 0.
j = 0
smallest = 0.0
while subtotal/total < tol:
subtotal = subtotal+sortedWeightedSize[j]
smallest = sortedWeightedSize[j]
j+=1
includedVecs = weightedSize >= smallest
vStart = Vh[includedVecs, :]
sizeVStart = np.sum(includedVecs)
newP = np.zeros((n, n))
for i in range(sizeVStart):
newP = newP+np.outer(vStart[i, :], vStart[i, :])
extraPhi = phi-np.matmul(P, phi)
normExtraPhi = np.linalg.norm(extraPhi)
if normExtraPhi > eps2:
extraPhi = extraPhi/normExtraPhi
newP = newP+np.outer(extraPhi, extraPhi)
if np.linalg.norm(newP-P) < eps3:
P = newP
break
else:
P = newP
return P, np.transpose(sci.orth(P))
if __name__ == "__main__":
A = np.array([[2, 0, 0, 0, 0],
[0, 2, 0.5, 0, 0],
[0, -1, 2, 0, 0],
[0, 0, 0, 1, 1],
[0, 0, 0, 0, 1]])
print(A)
P, basis = projectionSVD(A, phi = np.array([0, 0, 1, 0, 0]))
print(basis)