@@ -54,96 +54,102 @@ def spinwave_calculation(rotations: np.ndarray,
54
54
z_conj = z .conj ()
55
55
eta = rotations [:,:,2 ] # n-by-3 real
56
56
57
- # Create the A, B, and C matrices
58
-
59
57
# Create the matrix sqrt(S_i S_j)/2
60
58
root_mags = np .sqrt (0.5 * magnitudes ) # S_i / sqrt(2)
61
59
spin_coefficients = root_mags .reshape (- 1 , 1 ) * root_mags .reshape (1 , - 1 )
62
60
63
61
energies = []
64
62
methods = []
65
- for q in q_vectors :
66
-
67
- A = np .zeros ((n_sites , n_sites ), dtype = complex )
68
- B = np .zeros ((n_sites , n_sites ), dtype = complex )
69
- C = np .zeros ((n_sites , n_sites ), dtype = complex )
70
63
71
- # Add the terms up to the total spin coefficient
72
- for coupling in couplings :
64
+ # calculate the C matrix for h(q), which is q-independent
65
+ C = np .zeros ((n_sites , n_sites ), dtype = complex )
66
+ for coupling in couplings :
67
+ j = coupling .index2
68
+ for l in range (n_sites ):
69
+ C [j , j ] += spin_coefficients [l ,l ] * eta [j , :].T @ coupling .matrix @ eta [l , :]
73
70
74
- phase_factor = np . exp (( 2j * np . pi ) * np . dot ( q , coupling . inter_site_vector ))
71
+ C *= 2
75
72
76
- i = coupling .index1
77
- j = coupling .index2
73
+ for q in q_vectors :
74
+ eigenvalues , method = spinwave_calculation_single_q (q , C , n_sites , z , z_conj , spin_coefficients , couplings )
75
+ energies .append (eigenvalues ) # These are currently the square energies
76
+ methods .append (method )
78
77
79
- A [i , j ] += z [i , :] @ coupling .matrix @ z_conj [j , :] * phase_factor
80
- B [i , j ] += z [i , :] @ coupling .matrix @ z [j , :] * phase_factor
78
+ return SpinwaveResult (
79
+ q_vectors = q_vectors ,
80
+ raw_energies = energies ,
81
+ method = methods )
81
82
82
83
83
- for l in range (n_sites ):
84
- C [j , j ] += spin_coefficients [l ,l ] * eta [j , :].T @ coupling .matrix @ eta [l , :]
84
+ def spinwave_calculation_single_q (q : float ,
85
+ C : np .ndarray ,
86
+ n_sites : int ,
87
+ z : np .ndarray ,
88
+ z_conj : np .ndarray ,
89
+ spin_coefficients : np .ndarray ,
90
+ couplings : list [Coupling ]):
91
+ """Calculate the energies for the 'Hamiltonian' h(q) for a single q-value."""
92
+ A = np .zeros ((n_sites , n_sites ), dtype = complex )
93
+ B = np .zeros ((n_sites , n_sites ), dtype = complex )
85
94
86
- A *= spin_coefficients
87
- B *= spin_coefficients
88
- C *= 2
89
- #
90
- # print("A", A)
91
- # print("B", B)
92
- # print("C", C)
95
+ # Add the terms up to the total spin coefficient
96
+ for coupling in couplings :
93
97
98
+ phase_factor = np .exp ((2j * np .pi )* np .dot (q , coupling .inter_site_vector ))
94
99
95
- # hamiltonian_matrix = np.block([[A - C, B], [B.conj().T, A.conj().T - C]])
96
- hamiltonian_matrix = np . block ([[ A - C , B ], [ B . conj (). T , A . conj (). T - C ]])
100
+ i = coupling . index1
101
+ j = coupling . index2
97
102
98
- #
99
- # We need to enforce the bosonic commutation properties, we do this
100
- # by finding the 'square root' of the matrix (i.e. finding K such that KK^dagger = H)
101
- # and then negating the second half.
102
- #
103
- # In matrix form we do
104
- #
105
- # M = K^dagger C K
106
- #
107
- # where C is a diagonal matrix of length 2n, with the first n entries being 1, and the
108
- # remaining entries being -1. Note the adjoint is on the other side to the definition in
109
- # of the decomposition
110
- #
111
- # We can also do this via an LDL decomposition, but the method is very slightly different
103
+ A [i , j ] += z [i , :] @ coupling .matrix @ z_conj [j , :] * phase_factor
104
+ B [i , j ] += z [i , :] @ coupling .matrix @ z [j , :] * phase_factor
112
105
113
106
114
- try :
115
- sqrt_hamiltonian = np .linalg .cholesky (hamiltonian_matrix )
107
+ A *= spin_coefficients
108
+ B *= spin_coefficients
109
+ #
110
+ # print("A", A)
111
+ # print("B", B)
112
+ # print("C", C)
116
113
117
- sqrt_hamiltonian_with_commutation = sqrt_hamiltonian .copy ()
118
- sqrt_hamiltonian_with_commutation [:, n_sites :] *= - 1
119
114
120
- to_diagonalise = np .conj (sqrt_hamiltonian_with_commutation ).T @ sqrt_hamiltonian
115
+ # hamiltonian_matrix = np.block([[A - C, B], [B.conj().T, A.conj().T - C]])
116
+ hamiltonian_matrix = np .block ([[A - C , B ], [B .conj ().T , A .conj ().T - C ]])
121
117
122
- methods .append (CalculationMethod .CHOLESKY )
118
+ #
119
+ # We need to enforce the bosonic commutation properties, we do this
120
+ # by finding the 'square root' of the matrix (i.e. finding K such that KK^dagger = H)
121
+ # and then negating the second half.
122
+ #
123
+ # In matrix form we do
124
+ #
125
+ # M = K^dagger C K
126
+ #
127
+ # where C is a diagonal matrix of length 2n, with the first n entries being 1, and the
128
+ # remaining entries being -1. Note the adjoint is on the other side to the definition in
129
+ # of the decomposition
130
+ #
131
+ # We can also do this via an LDL decomposition, but the method is very slightly different
123
132
124
- except np .linalg .LinAlgError : # Catch postive definiteness errors
125
133
134
+ try :
135
+ sqrt_hamiltonian = np .linalg .cholesky (hamiltonian_matrix )
136
+ method = CalculationMethod .CHOLESKY
126
137
127
- # l, d, perm = ldl(hamiltonian_matrix) # To LDL^\dagger (i.e. adjoint on right)
128
- l , d , _ = ldl (hamiltonian_matrix ) # To LDL^\dagger (i.e. adjoint on right)
129
- sqrt_hamiltonian = l @ np .sqrt (d )
138
+ except np .linalg .LinAlgError : # Catch postive definiteness errors
139
+ # l, d, perm = ldl(hamiltonian_matrix) # To LDL^\dagger (i.e. adjoint on right)
140
+ l , d , _ = ldl (hamiltonian_matrix ) # To LDL^\dagger (i.e. adjoint on right)
141
+ sqrt_hamiltonian = l @ np .sqrt (d )
130
142
131
- # TODO: Check for actual diagonal (could potentially contain non-diagonal 2x2 blocks)
143
+ # TODO: Check for actual diagonal (could potentially contain non-diagonal 2x2 blocks)
144
+ method = CalculationMethod .LDL
132
145
133
- sqrt_hamiltonian_with_commutation = sqrt_hamiltonian .copy ()
134
- sqrt_hamiltonian_with_commutation [:, n_sites :] *= - 1
135
146
136
- to_diagonalise = np .conj (sqrt_hamiltonian_with_commutation ).T @ sqrt_hamiltonian
147
+ sqrt_hamiltonian_with_commutation = sqrt_hamiltonian .copy ()
148
+ sqrt_hamiltonian_with_commutation [:, n_sites :] *= - 1
137
149
138
- methods . append ( CalculationMethod . LDL )
150
+ to_diagonalise = np . conj ( sqrt_hamiltonian_with_commutation ). T @ sqrt_hamiltonian
139
151
140
- eig_res = np .linalg .eig (to_diagonalise )
152
+ return np .linalg .eigvals (to_diagonalise ), method
141
153
142
- energies .append (eig_res .eigenvalues ) # These are currently the square energies
143
154
144
- # pylint: enable=C0103
145
155
146
- return SpinwaveResult (
147
- q_vectors = q_vectors ,
148
- raw_energies = energies ,
149
- method = methods )
0 commit comments