symfc 1.3.2__tar.gz → 1.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. {symfc-1.3.2/src/symfc.egg-info → symfc-1.3.4}/PKG-INFO +1 -1
  2. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/eig_tools.py +17 -4
  3. symfc-1.3.4/src/symfc/utils/matrix_tools.py +35 -0
  4. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/matrix_tools_O2.py +127 -28
  5. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/matrix_tools_O3.py +126 -28
  6. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/matrix_tools_O4.py +170 -72
  7. symfc-1.3.4/src/symfc/utils/permutation_tools.py +113 -0
  8. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/permutation_tools_O2.py +39 -21
  9. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/permutation_tools_O3.py +41 -24
  10. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/permutation_tools_O4.py +43 -25
  11. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/version.py +1 -1
  12. {symfc-1.3.2 → symfc-1.3.4/src/symfc.egg-info}/PKG-INFO +1 -1
  13. symfc-1.3.2/src/symfc/utils/matrix_tools.py +0 -89
  14. symfc-1.3.2/src/symfc/utils/permutation_tools.py +0 -35
  15. {symfc-1.3.2 → symfc-1.3.4}/LICENSE +0 -0
  16. {symfc-1.3.2 → symfc-1.3.4}/MANIFEST.in +0 -0
  17. {symfc-1.3.2 → symfc-1.3.4}/README.md +0 -0
  18. {symfc-1.3.2 → symfc-1.3.4}/pyproject.toml +0 -0
  19. {symfc-1.3.2 → symfc-1.3.4}/setup.cfg +0 -0
  20. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/__init__.py +0 -0
  21. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/api_symfc.py +0 -0
  22. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/basis_sets/__init__.py +0 -0
  23. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/basis_sets/basis_sets_O1.py +0 -0
  24. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/basis_sets/basis_sets_O2.py +0 -0
  25. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/basis_sets/basis_sets_O3.py +0 -0
  26. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/basis_sets/basis_sets_O4.py +0 -0
  27. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/basis_sets/basis_sets_base.py +0 -0
  28. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/solvers/__init__.py +0 -0
  29. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/solvers/solver_O2.py +0 -0
  30. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/solvers/solver_O2O3.py +0 -0
  31. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/solvers/solver_O2O3O4.py +0 -0
  32. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/solvers/solver_O3.py +0 -0
  33. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/solvers/solver_O3O4.py +0 -0
  34. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/solvers/solver_O4.py +0 -0
  35. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/solvers/solver_base.py +0 -0
  36. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/spg_reps/__init__.py +0 -0
  37. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/spg_reps/spg_reps_O1.py +0 -0
  38. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/spg_reps/spg_reps_O2.py +0 -0
  39. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/spg_reps/spg_reps_O3.py +0 -0
  40. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/spg_reps/spg_reps_O4.py +0 -0
  41. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/spg_reps/spg_reps_base.py +0 -0
  42. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/__init__.py +0 -0
  43. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/cutoff_tools.py +0 -0
  44. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/matrix_tools_O1.py +0 -0
  45. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/rotation_dev/__init__.py +0 -0
  46. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/rotation_dev/run_rotation_tools_O2.py +0 -0
  47. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/rotation_dev/run_rotation_tools_O3.py +0 -0
  48. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/rotation_dev/run_test_O2.py +0 -0
  49. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/rotation_tools_O2.py +0 -0
  50. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/solver_funcs.py +0 -0
  51. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/utils.py +0 -0
  52. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/utils_O1.py +0 -0
  53. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/utils_O2.py +0 -0
  54. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/utils_O3.py +0 -0
  55. {symfc-1.3.2 → symfc-1.3.4}/src/symfc/utils/utils_O4.py +0 -0
  56. {symfc-1.3.2 → symfc-1.3.4}/src/symfc.egg-info/SOURCES.txt +0 -0
  57. {symfc-1.3.2 → symfc-1.3.4}/src/symfc.egg-info/dependency_links.txt +0 -0
  58. {symfc-1.3.2 → symfc-1.3.4}/src/symfc.egg-info/requires.txt +0 -0
  59. {symfc-1.3.2 → symfc-1.3.4}/src/symfc.egg-info/top_level.txt +0 -0
  60. {symfc-1.3.2 → symfc-1.3.4}/tests/NaCl-unitcell.yaml +0 -0
  61. {symfc-1.3.2 → symfc-1.3.4}/tests/basis_sets/test_basis_sets_O2.py +0 -0
  62. {symfc-1.3.2 → symfc-1.3.4}/tests/basis_sets/test_basis_sets_O3.py +0 -0
  63. {symfc-1.3.2 → symfc-1.3.4}/tests/basis_sets/test_basis_sets_O4.py +0 -0
  64. {symfc-1.3.2 → symfc-1.3.4}/tests/basis_sets/test_basis_sets_base.py +0 -0
  65. {symfc-1.3.2 → symfc-1.3.4}/tests/compact_fc_GaN_222.xz +0 -0
  66. {symfc-1.3.2 → symfc-1.3.4}/tests/compact_fc_GaN_442.xz +0 -0
  67. {symfc-1.3.2 → symfc-1.3.4}/tests/compact_fc_NaCl_222.xz +0 -0
  68. {symfc-1.3.2 → symfc-1.3.4}/tests/compact_fc_SiO2_221.xz +0 -0
  69. {symfc-1.3.2 → symfc-1.3.4}/tests/compact_fc_Si_111_fc3_2.xz +0 -0
  70. {symfc-1.3.2 → symfc-1.3.4}/tests/compact_fc_Si_111_fc3_3.xz +0 -0
  71. {symfc-1.3.2 → symfc-1.3.4}/tests/compact_fc_Si_111_fc4_2.xz +0 -0
  72. {symfc-1.3.2 → symfc-1.3.4}/tests/compact_fc_Si_111_fc4_3.xz +0 -0
  73. {symfc-1.3.2 → symfc-1.3.4}/tests/compact_fc_Si_111_fc4_4.xz +0 -0
  74. {symfc-1.3.2 → symfc-1.3.4}/tests/compact_fc_SnO2_223.xz +0 -0
  75. {symfc-1.3.2 → symfc-1.3.4}/tests/conftest.py +0 -0
  76. {symfc-1.3.2 → symfc-1.3.4}/tests/dfset_GaN_222_rd.xz +0 -0
  77. {symfc-1.3.2 → symfc-1.3.4}/tests/dfset_GaN_442_rd.xz +0 -0
  78. {symfc-1.3.2 → symfc-1.3.4}/tests/dfset_NaCl_222_rd.xz +0 -0
  79. {symfc-1.3.2 → symfc-1.3.4}/tests/dfset_SiO2_221_rd.xz +0 -0
  80. {symfc-1.3.2 → symfc-1.3.4}/tests/dfset_Si_111_fc3_rd.xz +0 -0
  81. {symfc-1.3.2 → symfc-1.3.4}/tests/dfset_SnO2_223_rd.xz +0 -0
  82. {symfc-1.3.2 → symfc-1.3.4}/tests/full_fc_NaCl_222.xz +0 -0
  83. {symfc-1.3.2 → symfc-1.3.4}/tests/full_fc_Si_111_fc3_2.xz +0 -0
  84. {symfc-1.3.2 → symfc-1.3.4}/tests/full_fc_Si_111_fc3_3.xz +0 -0
  85. {symfc-1.3.2 → symfc-1.3.4}/tests/full_fc_Si_111_fc4_2.xz +0 -0
  86. {symfc-1.3.2 → symfc-1.3.4}/tests/full_fc_Si_111_fc4_3.xz +0 -0
  87. {symfc-1.3.2 → symfc-1.3.4}/tests/full_fc_Si_111_fc4_4.xz +0 -0
  88. {symfc-1.3.2 → symfc-1.3.4}/tests/full_fc_Si_111_fc4_step_2.xz +0 -0
  89. {symfc-1.3.2 → symfc-1.3.4}/tests/full_fc_Si_111_fc4_step_3.xz +0 -0
  90. {symfc-1.3.2 → symfc-1.3.4}/tests/full_fc_Si_111_fc4_step_4.xz +0 -0
  91. {symfc-1.3.2 → symfc-1.3.4}/tests/full_fc_SnO2_223.xz +0 -0
  92. {symfc-1.3.2 → symfc-1.3.4}/tests/perms_super.dat +0 -0
  93. {symfc-1.3.2 → symfc-1.3.4}/tests/phonopy_to_python.py +0 -0
  94. {symfc-1.3.2 → symfc-1.3.4}/tests/solvers/test_solver_utils.py +0 -0
  95. {symfc-1.3.2 → symfc-1.3.4}/tests/spg_reps/test_spg_reps_O1.py +0 -0
  96. {symfc-1.3.2 → symfc-1.3.4}/tests/spg_reps/test_spg_reps_O2.py +0 -0
  97. {symfc-1.3.2 → symfc-1.3.4}/tests/spg_reps/test_spg_reps_O3.py +0 -0
  98. {symfc-1.3.2 → symfc-1.3.4}/tests/spg_reps/test_spg_reps_O4.py +0 -0
  99. {symfc-1.3.2 → symfc-1.3.4}/tests/spg_reps/test_spg_reps_base.py +0 -0
  100. {symfc-1.3.2 → symfc-1.3.4}/tests/test_api.py +0 -0
  101. {symfc-1.3.2 → symfc-1.3.4}/tests/utils/test_cutoff_tools.py +0 -0
  102. {symfc-1.3.2 → symfc-1.3.4}/tests/utils/test_eig_tools.py +0 -0
  103. {symfc-1.3.2 → symfc-1.3.4}/tests/utils/test_matrix_tools_O2.py +0 -0
  104. {symfc-1.3.2 → symfc-1.3.4}/tests/utils/test_matrix_tools_O3.py +0 -0
  105. {symfc-1.3.2 → symfc-1.3.4}/tests/utils/test_matrix_tools_O4.py +0 -0
  106. {symfc-1.3.2 → symfc-1.3.4}/tests/utils/test_solver_funcs.py +0 -0
  107. {symfc-1.3.2 → symfc-1.3.4}/tests/utils/test_utils.py +0 -0
  108. {symfc-1.3.2 → symfc-1.3.4}/tests/utils/test_utils_O1.py +0 -0
  109. {symfc-1.3.2 → symfc-1.3.4}/tests/utils/test_utils_O2.py +0 -0
  110. {symfc-1.3.2 → symfc-1.3.4}/tests/utils/test_utils_O2_2.py +0 -0
  111. {symfc-1.3.2 → symfc-1.3.4}/tests/utils/test_utils_O3.py +0 -0
  112. {symfc-1.3.2 → symfc-1.3.4}/tests/utils/test_utils_O4.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: symfc
3
- Version: 1.3.2
3
+ Version: 1.3.4
4
4
  Summary: This is the symfc module.
5
5
  Author-email: Atsuto Seko <seko@cms.mtl.kyoto-u.ac.jp>
6
6
  Maintainer-email: Atsushi Togo <atztogo@gmail.com>
@@ -359,10 +359,23 @@ def eigsh_projector_sumrule_large(p: csr_array, verbose: bool = True) -> np.ndar
359
359
  When p = diag(A,B), Av = v, and Bw = w, p[v,0] = [v,0] and p[0,w] = [0,w]
360
360
  are solutions.
361
361
 
362
- This function solves numpy.eigh for all block matrices.
363
- This function is efficient for matrix p composed of nonequivalent
364
- block matrices.
365
-
362
+ This algorithm is optimized to solve an eigenvalue problem for
363
+ projection matrix p with large block submatrices.
364
+ The algorithm for solving each block submatrix is as follows.
365
+ 1. Divide each block submatrix into reasonable sizes of submatrices,
366
+ not projectors.
367
+ 2. Solve eigenvalue problems for these submatrices and eigenvectors
368
+ with eigenvalues of one are extracted. The eigenvectors with
369
+ eigenvalues e < 1 are used for compressing the complementary matrix
370
+ in the next step.
371
+ 3. Calculate the complementary matrix, which corresponds to the complement
372
+ of the vector space spanned by the eigenvectors. The complementary matrix
373
+ is compressed using the eigenvectors with e < 1.
374
+ 4. Solve eigenvalue problem for the complementary matrix and eigenvectors
375
+ with e = 1 are calculated. The eigenvalue problems are efficiently solved
376
+ using the compressed complementary matrix and the eigenvectors are recovered by
377
+ the compression matrix.
378
+ 5. Collect all eigenvectors with e = 1.
366
379
  """
367
380
  group = _find_projector_blocks(p)
368
381
  if verbose:
@@ -0,0 +1,35 @@
1
+ """Matrix utility functions."""
2
+
3
+ import numpy as np
4
+ from scipy.sparse import csr_array
5
+
6
+
7
+ def permutation_dot_lat_trans(
8
+ combinations_ijk: np.ndarray,
9
+ combinations_abc: np.ndarray,
10
+ atomic_decompr_idx: np.ndarray,
11
+ n_perms: int,
12
+ n_perms_group: int,
13
+ n_lp: int,
14
+ order: int,
15
+ natom: int,
16
+ ) -> csr_array:
17
+ """Return C_perm.T @ C_trans for permulation symmetry rules."""
18
+ assert combinations_ijk.shape[0] == combinations_abc.shape[0]
19
+
20
+ sum_abc = 3**order
21
+ sum_ijkabc = natom**order * sum_abc
22
+ n_combinations = combinations_ijk.shape[0] // n_perms
23
+ n_perms_sym = n_perms // n_perms_group
24
+ c_pt = csr_array(
25
+ (
26
+ np.full(n_combinations * n_perms, 1 / np.sqrt(n_perms_sym * n_lp)),
27
+ (
28
+ np.repeat(np.arange(n_combinations * n_perms_group), n_perms_sym),
29
+ atomic_decompr_idx[combinations_ijk] * sum_abc + combinations_abc,
30
+ ),
31
+ ),
32
+ shape=(n_combinations * n_perms_group, sum_ijkabc // n_lp),
33
+ dtype="double",
34
+ )
35
+ return c_pt
@@ -7,7 +7,8 @@ import scipy
7
7
  from scipy.sparse import csr_array
8
8
 
9
9
  from symfc.utils.cutoff_tools import FCCutoff
10
- from symfc.utils.matrix_tools import get_combinations, permutation_dot_lat_trans
10
+ from symfc.utils.matrix_tools import permutation_dot_lat_trans
11
+ from symfc.utils.permutation_tools import get_combinations
11
12
  from symfc.utils.solver_funcs import get_batch_slice
12
13
  from symfc.utils.utils import get_indep_atoms_by_lat_trans
13
14
  from symfc.utils.utils_O2 import _get_atomic_lat_trans_decompr_indices
@@ -103,7 +104,7 @@ def optimize_batch_size_sum_rules_O2(natom: int, n_batch: Optional[int] = None):
103
104
  return batch_size
104
105
 
105
106
 
106
- def compressed_projector_sum_rules_O2_index_atoms(
107
+ def compressed_projector_sum_rules_O2(
107
108
  trans_perms: np.ndarray,
108
109
  n_a_compress_mat: csr_array,
109
110
  atomic_decompr_idx: Optional[np.ndarray] = None,
@@ -111,18 +112,67 @@ def compressed_projector_sum_rules_O2_index_atoms(
111
112
  n_batch: int = 1,
112
113
  use_mkl: bool = False,
113
114
  ) -> csr_array:
114
- """Return projection matrix for sum rule.
115
+ r"""Return projection matrix for translational sum rule.
115
116
 
116
- Calculate a complementary projector for sum rules.
117
- This is compressed by C_trans and n_a_compress_mat without
118
- allocating C_trans.
119
- Memory efficient version using get_atomic_lat_trans_decompr_indices_O3.
117
+ Calculate a compressed projector for translational sum rules
118
+ efficiently using independent atom with respect to lattice translations.
119
+ This compression is achieved using C_trans and n_a_compress_mat,
120
+ without the need to allocate C_trans. The implementation utilizes
121
+ get_atomic_lat_trans_decompr_indices_O3 to ensure efficient memory usage.
120
122
 
121
123
  Return
122
124
  ------
123
- Compressed projector I - P^(c)
124
- P^(c) = n_a_compress_mat.T @ C_trans.T @ C_sum^(c)
125
- @ C_sum^(c).T @ C_trans @ n_a_compress_mat
125
+ Compressed projector I - P^(c).
126
+ I - P^(c)
127
+ = n_a_compress_mat.T @ C_trans.T
128
+ @ [I - C_sum^(c) @ C_sum^(c).T] @ C_trans @ n_a_compress_mat
129
+ = I - [n_a_compress_mat.T @ C_trans.T @ C_sum^(c)]
130
+ @ [C_sum^(c).T @ C_trans @ n_a_compress_mat]
131
+
132
+ Algorithm
133
+ ---------
134
+ 1. C_sum^(c).T = [I, I, I, ...] of size (27N, 27N^2).
135
+ I denotes the unit matrix of size (27N, 27N).
136
+ C_sum^(c).T is composed of N unit matrices.
137
+ In this representation, the translational sum rules are given by
138
+ \sum_i FC2(i, j, a, b) = 0.
139
+
140
+ 2. To divide the computation of a compressed projector into several batches,
141
+ C_sum^(c) and C_trans are permuted from the index order of (i, j, a, b)
142
+ to (a, b, j, i).
143
+ This is represented by C_sum^(c).T @ C_trans = C_sum^(c).T @ S.T @ S @ C_trans,
144
+ where S denotes the permutation matrix that changes the index order to
145
+ (a, b, j, i). Using this permutation, the translational sum rules are
146
+ represented as
147
+ C_sum^(c).T @ S.T = [
148
+ [1_N.T, 0_N.T, 0_N.T, ...]
149
+ [0_N.T, 1_N.T, 0_N.T, ...]
150
+ [0_N.T, 0_N.T, 1_N.T, ...]
151
+ ...
152
+ ],
153
+ where 1_N and 0_N are column vectors of size N with all elements
154
+ equal to one and zero, respectively.
155
+ (Example) C_sum^(c).T @ S.T = [
156
+ [1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 ...]
157
+ [0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 ...]
158
+ [0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 ...]
159
+ ...
160
+ ]
161
+ In this function, the permutation is achieved by using matrix reshapes.
162
+
163
+ 3. Set C_trans.T @ C_sum^(c) @ C_sum^(c).T @ C_trans
164
+ = [(C_trans.T @ S.T) @ (S @ C_sum^(c))] @ [(C_sum^(c).T @ S.T) @ (S @ C_trans)]
165
+ = [T_1, T_2, ..., T_N33]
166
+ @ (S @ C_sum^(c)) @ (C_sum^(c).T @ S.T)
167
+ @ [T_1, T_2, ..., T_N33].T
168
+ = \sum_i t_i @ t_i.T,
169
+ where t_i = \sum_c T_i[:, c].
170
+ t_i is represented by c_sum_cplmt.T in this function.
171
+ T_i is the submatrix of size (N, n_aN33) of permuted C_trans.
172
+
173
+ 4. Compute P^(c) = \sum_i (n_a_compress_mat.T @ t_i) @ (t_i.T @ n_a_compress_mat)
174
+
175
+ 5. Compute P = I - P^(c)
126
176
  """
127
177
  n_lp, natom = trans_perms.shape
128
178
  NN9 = natom**2 * 9
@@ -135,14 +185,15 @@ def compressed_projector_sum_rules_O2_index_atoms(
135
185
  atomic_decompr_idx = _get_atomic_lat_trans_decompr_indices(trans_perms)
136
186
 
137
187
  decompr_idx = atomic_decompr_idx.reshape((natom, natom)).T.reshape(-1) * 9
138
- if fc_cutoff is None:
139
- indep_atoms = get_indep_atoms_by_lat_trans(trans_perms)
140
- nonzero = np.zeros((natom, natom), dtype=bool)
141
- nonzero[indep_atoms, :] = True
142
- nonzero = nonzero.reshape(-1)
143
- else:
144
- nonzero = fc_cutoff.nonzero_atomic_indices_fc2()
145
- nonzero = nonzero.reshape((natom, natom)).T.reshape(-1)
188
+
189
+ indep_atoms = get_indep_atoms_by_lat_trans(trans_perms)
190
+ nonzero = np.zeros((natom, natom), dtype=bool)
191
+ nonzero[indep_atoms, :] = True
192
+ nonzero = nonzero.reshape(-1)
193
+ if fc_cutoff is not None:
194
+ nonzero_c = fc_cutoff.nonzero_atomic_indices_fc2()
195
+ nonzero_c = nonzero_c.reshape((natom, natom)).T.reshape(-1)
196
+ nonzero = nonzero & nonzero_c
146
197
 
147
198
  batch_size = optimize_batch_size_sum_rules_O2(natom, n_batch=n_batch)
148
199
  ab = np.arange(9)
@@ -171,11 +222,11 @@ def compressed_projector_sum_rules_O2_index_atoms(
171
222
  c_sum_cplmt = dot_product_sparse(c_sum_cplmt, n_a_compress_mat, use_mkl=use_mkl)
172
223
  proj_cplmt += dot_product_sparse(c_sum_cplmt.T, c_sum_cplmt, use_mkl=use_mkl)
173
224
 
174
- proj_cplmt /= n_lp * natom
225
+ proj_cplmt /= natom
175
226
  return scipy.sparse.identity(proj_cplmt.shape[0]) - proj_cplmt
176
227
 
177
228
 
178
- def compressed_projector_sum_rules_O2(
229
+ def compressed_projector_sum_rules_O2_stable(
179
230
  trans_perms: np.ndarray,
180
231
  n_a_compress_mat: csr_array,
181
232
  atomic_decompr_idx: Optional[np.ndarray] = None,
@@ -183,18 +234,66 @@ def compressed_projector_sum_rules_O2(
183
234
  n_batch: int = 1,
184
235
  use_mkl: bool = False,
185
236
  ) -> csr_array:
186
- """Return projection matrix for sum rule.
237
+ r"""Return projection matrix for translational sum rule.
187
238
 
188
- Calculate a complementary projector for sum rules.
189
- This is compressed by C_trans and n_a_compress_mat without
190
- allocating C_trans.
191
- Memory efficient version using get_atomic_lat_trans_decompr_indices_O3.
239
+ Calculate a compressed projector for translational sum rules.
240
+ This compression is achieved using C_trans and n_a_compress_mat,
241
+ without the need to allocate C_trans. The implementation utilizes
242
+ get_atomic_lat_trans_decompr_indices_O3 to ensure efficient memory usage.
192
243
 
193
244
  Return
194
245
  ------
195
- Compressed projector I - P^(c)
196
- P^(c) = n_a_compress_mat.T @ C_trans.T @ C_sum^(c)
197
- @ C_sum^(c).T @ C_trans @ n_a_compress_mat
246
+ Compressed projector I - P^(c).
247
+ I - P^(c)
248
+ = n_a_compress_mat.T @ C_trans.T
249
+ @ [I - C_sum^(c) @ C_sum^(c).T] @ C_trans @ n_a_compress_mat
250
+ = I - [n_a_compress_mat.T @ C_trans.T @ C_sum^(c)]
251
+ @ [C_sum^(c).T @ C_trans @ n_a_compress_mat]
252
+
253
+ Algorithm
254
+ ---------
255
+ 1. C_sum^(c).T = [I, I, I, ...] of size (27N, 27N^2).
256
+ I denotes the unit matrix of size (27N, 27N).
257
+ C_sum^(c).T is composed of N unit matrices.
258
+ In this representation, the translational sum rules are given by
259
+ \sum_i FC2(i, j, a, b) = 0.
260
+
261
+ 2. To divide the computation of a compressed projector into several batches,
262
+ C_sum^(c) and C_trans are permuted from the index order of (i, j, a, b)
263
+ to (a, b, j, i).
264
+ This is represented by C_sum^(c).T @ C_trans = C_sum^(c).T @ S.T @ S @ C_trans,
265
+ where S denotes the permutation matrix that changes the index order to
266
+ (a, b, j, i). Using this permutation, the translational sum rules are
267
+ represented as
268
+ C_sum^(c).T @ S.T = [
269
+ [1_N.T, 0_N.T, 0_N.T, ...]
270
+ [0_N.T, 1_N.T, 0_N.T, ...]
271
+ [0_N.T, 0_N.T, 1_N.T, ...]
272
+ ...
273
+ ],
274
+ where 1_N and 0_N are column vectors of size N with all elements
275
+ equal to one and zero, respectively.
276
+ (Example) C_sum^(c).T @ S.T = [
277
+ [1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 ...]
278
+ [0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 ...]
279
+ [0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 ...]
280
+ ...
281
+ ]
282
+ In this function, the permutation is achieved by using matrix reshapes.
283
+
284
+ 3. Set C_trans.T @ C_sum^(c) @ C_sum^(c).T @ C_trans
285
+ = [(C_trans.T @ S.T) @ (S @ C_sum^(c))] @ [(C_sum^(c).T @ S.T) @ (S @ C_trans)]
286
+ = [T_1, T_2, ..., T_N33]
287
+ @ (S @ C_sum^(c)) @ (C_sum^(c).T @ S.T)
288
+ @ [T_1, T_2, ..., T_N33].T
289
+ = \sum_i t_i @ t_i.T,
290
+ where t_i = \sum_c T_i[:, c].
291
+ t_i is represented by c_sum_cplmt.T in this function.
292
+ T_i is the submatrix of size (N, n_aN33) of permuted C_trans.
293
+
294
+ 4. Compute P^(c) = \sum_i (n_a_compress_mat.T @ t_i) @ (t_i.T @ n_a_compress_mat)
295
+
296
+ 5. Compute P = I - P^(c)
198
297
  """
199
298
  n_lp, natom = trans_perms.shape
200
299
  NN9 = natom**2 * 9
@@ -7,7 +7,8 @@ import scipy
7
7
  from scipy.sparse import csr_array, vstack
8
8
 
9
9
  from symfc.utils.cutoff_tools import FCCutoff
10
- from symfc.utils.matrix_tools import get_combinations, permutation_dot_lat_trans
10
+ from symfc.utils.matrix_tools import permutation_dot_lat_trans
11
+ from symfc.utils.permutation_tools import get_combinations
11
12
  from symfc.utils.solver_funcs import get_batch_slice
12
13
  from symfc.utils.utils import get_indep_atoms_by_lat_trans
13
14
  from symfc.utils.utils_O3 import get_atomic_lat_trans_decompr_indices_O3
@@ -308,7 +309,7 @@ def optimize_batch_size_sum_rules_O3(natom: int, n_batch: Optional[int] = None):
308
309
  return batch_size
309
310
 
310
311
 
311
- def compressed_projector_sum_rules_O3_indep_atoms(
312
+ def compressed_projector_sum_rules_O3(
312
313
  trans_perms: np.ndarray,
313
314
  n_a_compress_mat: csr_array,
314
315
  atomic_decompr_idx: Optional[np.ndarray] = None,
@@ -317,18 +318,67 @@ def compressed_projector_sum_rules_O3_indep_atoms(
317
318
  use_mkl: bool = False,
318
319
  verbose: bool = False,
319
320
  ) -> csr_array:
320
- """Return projection matrix for sum rule.
321
+ r"""Return projection matrix for translational sum rule.
321
322
 
322
- Calculate a complementary projector for sum rules.
323
- This is compressed by C_trans and n_a_compress_mat without
324
- allocating C_trans.
325
- Memory efficient version using get_atomic_lat_trans_decompr_indices_O3.
323
+ Calculate a compressed projector for translational sum rules
324
+ efficiently using independent atom with respect to lattice translations.
325
+ This compression is achieved using C_trans and n_a_compress_mat,
326
+ without the need to allocate C_trans. The implementation utilizes
327
+ get_atomic_lat_trans_decompr_indices_O3 to ensure efficient memory usage.
326
328
 
327
329
  Return
328
330
  ------
329
- Compressed projector I - P^(c)
330
- P^(c) = n_a_compress_mat.T @ C_trans.T @ C_sum^(c)
331
- @ C_sum^(c).T @ C_trans @ n_a_compress_mat
331
+ Compressed projector I - P^(c).
332
+ I - P^(c)
333
+ = n_a_compress_mat.T @ C_trans.T
334
+ @ [I - C_sum^(c) @ C_sum^(c).T] @ C_trans @ n_a_compress_mat
335
+ = I - [n_a_compress_mat.T @ C_trans.T @ C_sum^(c)]
336
+ @ [C_sum^(c).T @ C_trans @ n_a_compress_mat]
337
+
338
+ Algorithm
339
+ ---------
340
+ 1. C_sum^(c).T = [I, I, I, ...] of size (27N^2, 27N^3).
341
+ I denotes the unit matrix of size (27N^2, 27N^2).
342
+ C_sum^(c).T is composed of N unit matrices.
343
+ In this representation, the translational sum rules are given by
344
+ \sum_i FC3(i, j, k, a, b, c) = 0.
345
+
346
+ 2. To divide the computation of a compressed projector into several batches,
347
+ C_sum^(c) and C_trans are permuted from the index order of (i, j, k, a, b, c)
348
+ to (a, b, c, j, k, i).
349
+ This is represented by C_sum^(c).T @ C_trans = C_sum^(c).T @ S.T @ S @ C_trans,
350
+ where S denotes the permutation matrix that changes the index order to
351
+ (a, b, c, j, k, i). Using this permutation, the translational sum rules are
352
+ represented as
353
+ C_sum^(c).T @ S.T = [
354
+ [1_N.T, 0_N.T, 0_N.T, ...]
355
+ [0_N.T, 1_N.T, 0_N.T, ...]
356
+ [0_N.T, 0_N.T, 1_N.T, ...]
357
+ ...
358
+ ],
359
+ where 1_N and 0_N are column vectors of size N with all elements
360
+ equal to one and zero, respectively.
361
+ (Example) C_sum^(c).T @ S.T = [
362
+ [1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 ...]
363
+ [0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 ...]
364
+ [0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 ...]
365
+ ...
366
+ ]
367
+ In this function, the permutation is achieved by using matrix reshapes.
368
+
369
+ 3. Set C_trans.T @ C_sum^(c) @ C_sum^(c).T @ C_trans
370
+ = [(C_trans.T @ S.T) @ (S @ C_sum^(c))] @ [(C_sum^(c).T @ S.T) @ (S @ C_trans)]
371
+ = [T_1, T_2, ..., T_NN333]
372
+ @ (S @ C_sum^(c)) @ (C_sum^(c).T @ S.T)
373
+ @ [T_1, T_2, ..., T_NN333].T
374
+ = \sum_i t_i @ t_i.T,
375
+ where t_i = \sum_c T_i[:, c].
376
+ t_i is represented by c_sum_cplmt.T in this function.
377
+ T_i is the submatrix of size (N, n_aNN333) of permuted C_trans.
378
+
379
+ 4. Compute P^(c) = \sum_i (n_a_compress_mat.T @ t_i) @ (t_i.T @ n_a_compress_mat)
380
+
381
+ 5. Compute P = I - P^(c)
332
382
  """
333
383
  n_lp, natom = trans_perms.shape
334
384
  NNN27 = natom**3 * 27
@@ -343,14 +393,14 @@ def compressed_projector_sum_rules_O3_indep_atoms(
343
393
 
344
394
  decompr_idx = atomic_decompr_idx.reshape((natom, NN)).T.reshape(-1) * 27
345
395
 
346
- if fc_cutoff is None:
347
- indep_atoms = get_indep_atoms_by_lat_trans(trans_perms)
348
- nonzero = np.zeros((natom, natom, natom), dtype=bool)
349
- nonzero[indep_atoms, :, :] = True
350
- nonzero = nonzero.reshape(-1)
351
- else:
352
- nonzero = fc_cutoff.nonzero_atomic_indices_fc3()
353
- nonzero = nonzero.reshape((natom, NN)).T.reshape(-1)
396
+ indep_atoms = get_indep_atoms_by_lat_trans(trans_perms)
397
+ nonzero = np.zeros((natom, natom, natom), dtype=bool)
398
+ nonzero[indep_atoms, :, :] = True
399
+ nonzero = nonzero.reshape(-1)
400
+ if fc_cutoff is not None:
401
+ nonzero_c = fc_cutoff.nonzero_atomic_indices_fc3()
402
+ nonzero_c = nonzero_c.reshape((natom, NN)).T.reshape(-1)
403
+ nonzero = nonzero & nonzero_c
354
404
 
355
405
  batch_size = optimize_batch_size_sum_rules_O3(natom, n_batch=n_batch)
356
406
  abc = np.arange(27)
@@ -381,11 +431,11 @@ def compressed_projector_sum_rules_O3_indep_atoms(
381
431
  c_sum_cplmt = dot_product_sparse(c_sum_cplmt, n_a_compress_mat, use_mkl=use_mkl)
382
432
  proj_cplmt += dot_product_sparse(c_sum_cplmt.T, c_sum_cplmt, use_mkl=use_mkl)
383
433
 
384
- proj_cplmt /= n_lp * natom
434
+ proj_cplmt /= natom
385
435
  return scipy.sparse.identity(proj_cplmt.shape[0]) - proj_cplmt
386
436
 
387
437
 
388
- def compressed_projector_sum_rules_O3(
438
+ def compressed_projector_sum_rules_O3_stable(
389
439
  trans_perms: np.ndarray,
390
440
  n_a_compress_mat: csr_array,
391
441
  atomic_decompr_idx: Optional[np.ndarray] = None,
@@ -394,18 +444,66 @@ def compressed_projector_sum_rules_O3(
394
444
  use_mkl: bool = False,
395
445
  verbose: bool = False,
396
446
  ) -> csr_array:
397
- """Return projection matrix for sum rule.
447
+ r"""Return projection matrix for translational sum rule.
398
448
 
399
- Calculate a complementary projector for sum rules.
400
- This is compressed by C_trans and n_a_compress_mat without
401
- allocating C_trans.
402
- Memory efficient version using get_atomic_lat_trans_decompr_indices_O3.
449
+ Calculate a compressed projector for translational sum rules.
450
+ This compression is achieved using C_trans and n_a_compress_mat,
451
+ without the need to allocate C_trans. The implementation utilizes
452
+ get_atomic_lat_trans_decompr_indices_O3 to ensure efficient memory usage.
403
453
 
404
454
  Return
405
455
  ------
406
- Compressed projector I - P^(c)
407
- P^(c) = n_a_compress_mat.T @ C_trans.T @ C_sum^(c)
408
- @ C_sum^(c).T @ C_trans @ n_a_compress_mat
456
+ Compressed projector I - P^(c).
457
+ I - P^(c)
458
+ = n_a_compress_mat.T @ C_trans.T
459
+ @ [I - C_sum^(c) @ C_sum^(c).T] @ C_trans @ n_a_compress_mat
460
+ = I - [n_a_compress_mat.T @ C_trans.T @ C_sum^(c)]
461
+ @ [C_sum^(c).T @ C_trans @ n_a_compress_mat]
462
+
463
+ Algorithm
464
+ ---------
465
+ 1. C_sum^(c).T = [I, I, I, ...] of size (27N^2, 27N^3).
466
+ I denotes the unit matrix of size (27N^2, 27N^2).
467
+ C_sum^(c).T is composed of N unit matrices.
468
+ In this representation, the translational sum rules are given by
469
+ \sum_i FC3(i, j, k, a, b, c) = 0.
470
+
471
+ 2. To divide the computation of a compressed projector into several batches,
472
+ C_sum^(c) and C_trans are permuted from the index order of (i, j, k, a, b, c)
473
+ to (a, b, c, j, k, i).
474
+ This is represented by C_sum^(c).T @ C_trans = C_sum^(c).T @ S.T @ S @ C_trans,
475
+ where S denotes the permutation matrix that changes the index order to
476
+ (a, b, c, j, k, i). Using this permutation, the translational sum rules are
477
+ represented as
478
+ C_sum^(c).T @ S.T = [
479
+ [1_N.T, 0_N.T, 0_N.T, ...]
480
+ [0_N.T, 1_N.T, 0_N.T, ...]
481
+ [0_N.T, 0_N.T, 1_N.T, ...]
482
+ ...
483
+ ],
484
+ where 1_N and 0_N are column vectors of size N with all elements
485
+ equal to one and zero, respectively.
486
+ (Example) C_sum^(c).T @ S.T = [
487
+ [1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 ...]
488
+ [0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 ...]
489
+ [0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 ...]
490
+ ...
491
+ ]
492
+ In this function, the permutation is achieved by using matrix reshapes.
493
+
494
+ 3. Set C_trans.T @ C_sum^(c) @ C_sum^(c).T @ C_trans
495
+ = [(C_trans.T @ S.T) @ (S @ C_sum^(c))] @ [(C_sum^(c).T @ S.T) @ (S @ C_trans)]
496
+ = [T_1, T_2, ..., T_NN333]
497
+ @ (S @ C_sum^(c)) @ (C_sum^(c).T @ S.T)
498
+ @ [T_1, T_2, ..., T_NN333].T
499
+ = \sum_i t_i @ t_i.T,
500
+ where t_i = \sum_c T_i[:, c].
501
+ t_i is represented by c_sum_cplmt.T in this function.
502
+ T_i is the submatrix of size (N, n_aNN333) of permuted C_trans.
503
+
504
+ 4. Compute P^(c) = \sum_i (n_a_compress_mat.T @ t_i) @ (t_i.T @ n_a_compress_mat)
505
+
506
+ 5. Compute P = I - P^(c)
409
507
  """
410
508
  n_lp, natom = trans_perms.shape
411
509
  NNN27 = natom**3 * 27