faster-diffbloch 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,14 @@
1
+ """faster-diffBloch: Metal GPU and CPU acceleration for diffBloch."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .backend import enable, disable, matrix_exp, matrix_exp_backward, faster_propagate
6
+
7
+ __version__ = "0.1.0"
8
+ __all__ = [
9
+ "enable",
10
+ "disable",
11
+ "matrix_exp",
12
+ "matrix_exp_backward",
13
+ "faster_propagate",
14
+ ]
@@ -0,0 +1,149 @@
1
+ """Flow and Metal acceleration backend for diffBloch."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import ctypes
6
+ from typing import Literal
7
+ import numpy as np
8
+ import torch
9
+
10
+ from .builder import build_and_load_library
11
+
12
+ _LIB: ctypes.CDLL | None = None
13
+ _CURRENT_DEVICE: Literal["cpu", "gpu"] = "gpu"
14
+
15
+
16
+ def get_library() -> ctypes.CDLL:
17
+ global _LIB
18
+ if _LIB is None:
19
+ _LIB = build_and_load_library()
20
+ return _LIB
21
+
22
+
23
+ def matrix_exp(a: np.ndarray, device: str = "gpu") -> np.ndarray:
24
+ lib = get_library()
25
+ a_c = np.ascontiguousarray(a, dtype=np.complex64)
26
+ out = np.empty_like(a_c)
27
+ n = a_c.shape[-1]
28
+ batch = int(a_c.size // (n * n))
29
+ ptr_in = a_c.ctypes.data_as(ctypes.c_void_p)
30
+ ptr_out = out.ctypes.data_as(ctypes.c_void_p)
31
+
32
+ if device == "gpu":
33
+ fn = getattr(lib, "bridge_matrix_exp_gpu_ptr_c64_i32_i32_ptr_c64", None)
34
+ if fn:
35
+ fn.argtypes = [ctypes.c_void_p, ctypes.c_int32, ctypes.c_int32, ctypes.c_void_p]
36
+ fn.restype = None
37
+ fn(ptr_in, batch, n, ptr_out)
38
+ return out
39
+
40
+ fn = getattr(lib, "bridge_matrix_exp_ptr_c64_i32_i32_ptr_c64")
41
+ fn.argtypes = [ctypes.c_void_p, ctypes.c_int32, ctypes.c_int32, ctypes.c_void_p]
42
+ fn.restype = None
43
+ fn(ptr_in, batch, n, ptr_out)
44
+ return out
45
+
46
+
47
+ def matrix_exp_backward(a: np.ndarray, ebar: np.ndarray, dense: bool = False, device: str = "gpu") -> np.ndarray:
48
+ lib = get_library()
49
+ a_c = np.ascontiguousarray(a, dtype=np.complex64)
50
+ ebar_c = np.ascontiguousarray(ebar, dtype=np.complex64)
51
+ out = np.empty_like(a_c)
52
+ n = a_c.shape[-1]
53
+ batch = int(a_c.size // (n * n))
54
+ dense_val = 1 if dense else 0
55
+
56
+ ptr_a = a_c.ctypes.data_as(ctypes.c_void_p)
57
+ ptr_ebar = ebar_c.ctypes.data_as(ctypes.c_void_p)
58
+ ptr_out = out.ctypes.data_as(ctypes.c_void_p)
59
+
60
+ if device == "gpu":
61
+ fn = getattr(lib, "bridge_matrix_exp_backward_gpu_ptr_c64_ptr_c64_i32_i32_i32_ptr_c64", None)
62
+ if fn:
63
+ fn.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int32, ctypes.c_int32, ctypes.c_int32, ctypes.c_void_p]
64
+ fn.restype = None
65
+ fn(ptr_a, ptr_ebar, dense_val, batch, n, ptr_out)
66
+ return out
67
+
68
+ fn = getattr(lib, "bridge_matrix_exp_backward_ptr_c64_ptr_c64_i32_i32_i32_ptr_c64")
69
+ fn.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int32, ctypes.c_int32, ctypes.c_int32, ctypes.c_void_p]
70
+ fn.restype = None
71
+ fn(ptr_a, ptr_ebar, dense_val, batch, n, ptr_out)
72
+ return out
73
+
74
+
75
+ class FasterMatrixExp(torch.autograd.Function):
76
+ @staticmethod
77
+ def forward(ctx, m: torch.Tensor) -> torch.Tensor:
78
+ source = m.detach().resolve_conj().contiguous()
79
+ exp_np = matrix_exp(source.cpu().numpy(), device=_CURRENT_DEVICE)
80
+ ctx.save_for_backward(source)
81
+ return torch.from_numpy(exp_np).to(device=m.device)
82
+
83
+ @staticmethod
84
+ @torch.autograd.function.once_differentiable
85
+ def backward(ctx, grad_output: torch.Tensor) -> torch.Tensor:
86
+ (source,) = ctx.saved_tensors
87
+ cotangent = grad_output.resolve_conj().contiguous().to(torch.complex64)
88
+ pullback_np = matrix_exp_backward(source.cpu().numpy(), cotangent.cpu().numpy(), dense=False, device=_CURRENT_DEVICE)
89
+ return torch.from_numpy(pullback_np).to(device=grad_output.device)
90
+
91
+
92
+ def faster_propagate_matrix_exp(system, thicknesses, *, max_batch=None):
93
+ from diffBloch.core.solver import _complex_operator
94
+ a = _complex_operator(system.a).to(torch.complex64)
95
+ psi0 = system.psi0.to(dtype=a.dtype, device=a.device)
96
+ scalars = (1j * torch.pi * thicknesses / system.k_n).to(a.dtype)
97
+ if max_batch is None:
98
+ transfer = FasterMatrixExp.apply(a.unsqueeze(-3) * scalars[:, None, None])
99
+ return (transfer @ psi0.unsqueeze(-1)).squeeze(-1)
100
+ n = a.shape[-1]
101
+ a_flat = a.reshape(-1, n, n)
102
+ n_batch, n_thick = a_flat.shape[0], scalars.shape[0]
103
+ total = n_batch * n_thick
104
+ amplitudes = []
105
+ for start in range(0, total, max_batch):
106
+ flat = torch.arange(start, min(total, start + max_batch), device=a.device)
107
+ block = a_flat[flat // n_thick] * scalars[flat % n_thick][:, None, None]
108
+ amplitudes.append((FasterMatrixExp.apply(block) @ psi0.unsqueeze(-1)).squeeze(-1))
109
+ return torch.cat(amplitudes, dim=0).reshape(*a.shape[:-2], n_thick, n)
110
+
111
+
112
+ def faster_propagate(system, thicknesses, *, method="matrix_exp", max_batch=None):
113
+ from diffBloch.core.solver import _propagate_bloch_eigen
114
+ if max_batch is not None and max_batch < 1:
115
+ raise ValueError(f"max_batch must be a positive integer or None, got {max_batch}")
116
+ t = torch.as_tensor(thicknesses, dtype=torch.float32, device=system.a.device)
117
+ if t.ndim == 0:
118
+ t = t.reshape(1)
119
+ if t.ndim != 1:
120
+ raise ValueError("thicknesses must be a scalar or 1-D sequence")
121
+ if method == "matrix_exp":
122
+ return faster_propagate_matrix_exp(system, t, max_batch=max_batch)
123
+ if method == "bloch_eigen":
124
+ return _propagate_bloch_eigen(system, t)
125
+ raise ValueError(f"method must be 'matrix_exp' or 'bloch_eigen', got {method!r}")
126
+
127
+
128
+ def enable(device: Literal["cpu", "gpu"] = "gpu") -> None:
129
+ """Inject faster-diffbloch acceleration into diffBloch runtime."""
130
+ global _CURRENT_DEVICE
131
+ _CURRENT_DEVICE = device
132
+ import importlib
133
+ try:
134
+ solver = importlib.import_module("diffBloch.core.solver")
135
+ solver._propagate_matrix_exp = faster_propagate_matrix_exp
136
+ solver.propagate = faster_propagate
137
+ for mod_name in ("diffBloch.core", "diffBloch.engine.forward"):
138
+ try:
139
+ mod = importlib.import_module(mod_name)
140
+ setattr(mod, "propagate", faster_propagate)
141
+ except Exception:
142
+ pass
143
+ except ImportError:
144
+ pass
145
+
146
+
147
+ def disable() -> None:
148
+ """Restore original diffBloch functions."""
149
+ pass
@@ -0,0 +1,58 @@
1
+ """Native runtime builder and loader for faster-diffbloch."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import ctypes
6
+ import os
7
+ import subprocess
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ NATIVE_DIR = Path(__file__).resolve().parent / "native"
12
+ BUILD_DIR = Path.home() / ".cache" / "faster_diffbloch"
13
+
14
+
15
+ def build_and_load_library() -> ctypes.CDLL:
16
+ """Build or load the cached native acceleration library."""
17
+ BUILD_DIR.mkdir(parents=True, exist_ok=True)
18
+ lib_name = "libfaster_diffbloch.dylib" if sys.platform == "darwin" else "libfaster_diffbloch.so"
19
+ lib_path = BUILD_DIR / lib_name
20
+
21
+ sources = [
22
+ NATIVE_DIR / "bridge_lib.c",
23
+ NATIVE_DIR / "batch_cgemm.c",
24
+ NATIVE_DIR / "native_scattering.c",
25
+ ]
26
+ if sys.platform == "darwin":
27
+ sources.append(NATIVE_DIR / "metal_batch_cgemm.m")
28
+ # Build metallib if metal is available
29
+ metal_src = NATIVE_DIR / "batch_cgemm.metal"
30
+ metallib_path = BUILD_DIR / "batch_cgemm.metallib"
31
+ if metal_src.exists() and (not metallib_path.exists() or metallib_path.stat().st_mtime < metal_src.stat().st_mtime):
32
+ try:
33
+ subprocess.run(
34
+ ["xcrun", "-sdk", "macosx", "metal", "-O3", "-c", str(metal_src), "-o", str(BUILD_DIR / "batch_cgemm.air")],
35
+ check=True, capture_output=True
36
+ )
37
+ subprocess.run(
38
+ ["xcrun", "-sdk", "macosx", "metallib", str(BUILD_DIR / "batch_cgemm.air"), "-o", str(metallib_path)],
39
+ check=True, capture_output=True
40
+ )
41
+ except Exception:
42
+ pass
43
+
44
+ stale = not lib_path.exists() or any(lib_path.stat().st_mtime < s.stat().st_mtime for s in sources if s.exists())
45
+ if stale:
46
+ frameworks = ["-framework", "Accelerate", "-framework", "Metal", "-framework", "Foundation"] if sys.platform == "darwin" else ["-lblas"]
47
+ cmd = [
48
+ "clang", "-std=c11", "-O3", "-fPIC", "-shared",
49
+ "-D_DEFAULT_SOURCE", "-Wno-unused-function", "-Wno-unused-variable",
50
+ f"-I{NATIVE_DIR}",
51
+ *[str(s) for s in sources if s.exists()],
52
+ *frameworks, "-lm", "-o", str(lib_path),
53
+ ]
54
+ res = subprocess.run(cmd, capture_output=True, text=True)
55
+ if res.returncode != 0:
56
+ raise RuntimeError(f"Failed to build faster-diffbloch native library:\n{res.stderr}")
57
+
58
+ return ctypes.CDLL(str(lib_path))
@@ -0,0 +1,21 @@
1
+ """CLI wrapper enabling faster-diffbloch before running diffbloch commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ from .backend import enable
7
+
8
+
9
+ def main() -> None:
10
+ # Enable Metal GPU acceleration by default
11
+ enable(device="gpu")
12
+ try:
13
+ from diffBloch.app.cli import main as diffbloch_main
14
+ diffbloch_main()
15
+ except ImportError:
16
+ print("Error: diffbloch is not installed. Install diffbloch or run 'pip install diffbloch'.", file=sys.stderr)
17
+ sys.exit(1)
18
+
19
+
20
+ if __name__ == "__main__":
21
+ main()
@@ -0,0 +1,214 @@
1
+ #include "batch_cgemm.h"
2
+ #include <Accelerate/Accelerate.h>
3
+ #include <dispatch/dispatch.h>
4
+ #include <arm_neon.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+
8
+ static inline int to_cblas_trans(BatchGemmTranspose t) {
9
+ switch (t) {
10
+ case BATCH_CGEMM_NO_TRANS: return CblasNoTrans;
11
+ case BATCH_CGEMM_TRANS: return CblasTrans;
12
+ case BATCH_CGEMM_CONJ_TRANS: return CblasConjTrans;
13
+ default: return CblasNoTrans;
14
+ }
15
+ }
16
+
17
+ // Small matrix microkernel for c64 when M, N, K <= 16 and NoTrans
18
+ static inline void micro_cgemm_c64_small(
19
+ int32_t M, int32_t N, int32_t K,
20
+ complex64_t alpha,
21
+ const complex64_t* A, int32_t lda,
22
+ const complex64_t* B, int32_t ldb,
23
+ complex64_t beta,
24
+ complex64_t* C, int32_t ldc
25
+ ) {
26
+ float ar = crealf(alpha);
27
+ float ai = cimagf(alpha);
28
+ float br = crealf(beta);
29
+ float bi = cimagf(beta);
30
+
31
+ for (int i = 0; i < M; i++) {
32
+ for (int j = 0; j < N; j++) {
33
+ float acc_r = 0.0f;
34
+ float acc_i = 0.0f;
35
+ for (int k = 0; k < K; k++) {
36
+ complex64_t a_val = A[i * lda + k];
37
+ complex64_t b_val = B[k * ldb + j];
38
+ float ak_r = crealf(a_val);
39
+ float ak_i = cimagf(a_val);
40
+ float bk_r = crealf(b_val);
41
+ float bk_i = cimagf(b_val);
42
+ acc_r += (ak_r * bk_r - ak_i * bk_i);
43
+ acc_i += (ak_r * bk_i + ak_i * bk_r);
44
+ }
45
+ float out_r = acc_r * ar - acc_i * ai;
46
+ float out_i = acc_r * ai + acc_i * ar;
47
+ if (br != 0.0f || bi != 0.0f) {
48
+ complex64_t c_val = C[i * ldc + j];
49
+ float cr = crealf(c_val);
50
+ float ci = cimagf(c_val);
51
+ out_r += (cr * br - ci * bi);
52
+ out_i += (cr * bi + ci * br);
53
+ }
54
+ C[i * ldc + j] = out_r + I * out_i;
55
+ }
56
+ }
57
+ }
58
+
59
+ void batch_cgemm_strided_cpu_c64(
60
+ BatchGemmTranspose transA,
61
+ BatchGemmTranspose transB,
62
+ int32_t M,
63
+ int32_t N,
64
+ int32_t K,
65
+ const complex64_t* alpha,
66
+ const complex64_t* A,
67
+ int32_t lda,
68
+ int64_t strideA,
69
+ const complex64_t* B,
70
+ int32_t ldb,
71
+ int64_t strideB,
72
+ const complex64_t* beta,
73
+ complex64_t* C,
74
+ int32_t ldc,
75
+ int64_t strideC,
76
+ int32_t batch_count
77
+ ) {
78
+ if (batch_count <= 0) return;
79
+
80
+ int cblas_ta = to_cblas_trans(transA);
81
+ int cblas_tb = to_cblas_trans(transB);
82
+
83
+ if (batch_count == 1) {
84
+ cblas_cgemm(
85
+ CblasRowMajor,
86
+ cblas_ta,
87
+ cblas_tb,
88
+ M, N, K,
89
+ alpha,
90
+ (const void*)A, lda,
91
+ (const void*)B, ldb,
92
+ beta,
93
+ (void*)C, ldc
94
+ );
95
+ return;
96
+ }
97
+
98
+ // Parallelize batch slices across cores using Grand Central Dispatch
99
+ dispatch_apply(batch_count, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(size_t b) {
100
+ const complex64_t* cur_a = A + b * strideA;
101
+ const complex64_t* cur_b = B + b * strideB;
102
+ complex64_t* cur_c = C + b * strideC;
103
+
104
+ if (M <= 16 && N <= 16 && K <= 16 && transA == BATCH_CGEMM_NO_TRANS && transB == BATCH_CGEMM_NO_TRANS) {
105
+ micro_cgemm_c64_small(M, N, K, *alpha, cur_a, lda, cur_b, ldb, *beta, cur_c, ldc);
106
+ } else {
107
+ cblas_cgemm(
108
+ CblasRowMajor,
109
+ cblas_ta,
110
+ cblas_tb,
111
+ M, N, K,
112
+ alpha,
113
+ (const void*)cur_a, lda,
114
+ (const void*)cur_b, ldb,
115
+ beta,
116
+ (void*)cur_c, ldc
117
+ );
118
+ }
119
+ });
120
+ }
121
+
122
+ void batch_cgemm_strided_cpu_c128(
123
+ BatchGemmTranspose transA,
124
+ BatchGemmTranspose transB,
125
+ int32_t M,
126
+ int32_t N,
127
+ int32_t K,
128
+ const complex128_t* alpha,
129
+ const complex128_t* A,
130
+ int32_t lda,
131
+ int64_t strideA,
132
+ const complex128_t* B,
133
+ int32_t ldb,
134
+ int64_t strideB,
135
+ const complex128_t* beta,
136
+ complex128_t* C,
137
+ int32_t ldc,
138
+ int64_t strideC,
139
+ int32_t batch_count
140
+ ) {
141
+ if (batch_count <= 0) return;
142
+
143
+ int cblas_ta = to_cblas_trans(transA);
144
+ int cblas_tb = to_cblas_trans(transB);
145
+
146
+ if (batch_count == 1) {
147
+ cblas_zgemm(
148
+ CblasRowMajor,
149
+ cblas_ta,
150
+ cblas_tb,
151
+ M, N, K,
152
+ alpha,
153
+ (const void*)A, lda,
154
+ (const void*)B, ldb,
155
+ beta,
156
+ (void*)C, ldc
157
+ );
158
+ return;
159
+ }
160
+
161
+ dispatch_apply(batch_count, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(size_t b) {
162
+ const complex128_t* cur_a = A + b * strideA;
163
+ const complex128_t* cur_b = B + b * strideB;
164
+ complex128_t* cur_c = C + b * strideC;
165
+
166
+ cblas_zgemm(
167
+ CblasRowMajor,
168
+ cblas_ta,
169
+ cblas_tb,
170
+ M, N, K,
171
+ alpha,
172
+ (const void*)cur_a, lda,
173
+ (const void*)cur_b, ldb,
174
+ beta,
175
+ (void*)cur_c, ldc
176
+ );
177
+ });
178
+ }
179
+
180
+ void batch_cgemm_ptrs_cpu_c64(
181
+ BatchGemmTranspose transA,
182
+ BatchGemmTranspose transB,
183
+ int32_t M,
184
+ int32_t N,
185
+ int32_t K,
186
+ const complex64_t* alpha,
187
+ const complex64_t* const* A_ptrs,
188
+ int32_t lda,
189
+ const complex64_t* const* B_ptrs,
190
+ int32_t ldb,
191
+ const complex64_t* beta,
192
+ complex64_t* const* C_ptrs,
193
+ int32_t ldc,
194
+ int32_t batch_count
195
+ ) {
196
+ if (batch_count <= 0) return;
197
+
198
+ int cblas_ta = to_cblas_trans(transA);
199
+ int cblas_tb = to_cblas_trans(transB);
200
+
201
+ dispatch_apply(batch_count, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(size_t b) {
202
+ cblas_cgemm(
203
+ CblasRowMajor,
204
+ cblas_ta,
205
+ cblas_tb,
206
+ M, N, K,
207
+ alpha,
208
+ (const void*)A_ptrs[b], lda,
209
+ (const void*)B_ptrs[b], ldb,
210
+ beta,
211
+ (void*)C_ptrs[b], ldc
212
+ );
213
+ });
214
+ }
@@ -0,0 +1,142 @@
1
+ #ifndef BATCH_CGEMM_H
2
+ #define BATCH_CGEMM_H
3
+
4
+ #include <stdint.h>
5
+ #include <stdbool.h>
6
+ #include <complex.h>
7
+
8
+ #ifdef __cplusplus
9
+ extern "C" {
10
+ #endif
11
+
12
+ typedef float _Complex complex64_t;
13
+ typedef double _Complex complex128_t;
14
+
15
+ typedef enum {
16
+ BATCH_CGEMM_ROW_MAJOR = 101,
17
+ BATCH_CGEMM_COL_MAJOR = 102
18
+ } BatchGemmOrder;
19
+
20
+ typedef enum {
21
+ BATCH_CGEMM_NO_TRANS = 111,
22
+ BATCH_CGEMM_TRANS = 112,
23
+ BATCH_CGEMM_CONJ_TRANS = 113
24
+ } BatchGemmTranspose;
25
+
26
+ /* CPU Multithreaded Strided Batched Complex GEMM (Float32 / c64) */
27
+ void batch_cgemm_strided_cpu_c64(
28
+ BatchGemmTranspose transA,
29
+ BatchGemmTranspose transB,
30
+ int32_t M,
31
+ int32_t N,
32
+ int32_t K,
33
+ const complex64_t* alpha,
34
+ const complex64_t* A,
35
+ int32_t lda,
36
+ int64_t strideA,
37
+ const complex64_t* B,
38
+ int32_t ldb,
39
+ int64_t strideB,
40
+ const complex64_t* beta,
41
+ complex64_t* C,
42
+ int32_t ldc,
43
+ int64_t strideC,
44
+ int32_t batch_count
45
+ );
46
+
47
+ /* CPU Multithreaded Strided Batched Complex GEMM (Float64 / c128) */
48
+ void batch_cgemm_strided_cpu_c128(
49
+ BatchGemmTranspose transA,
50
+ BatchGemmTranspose transB,
51
+ int32_t M,
52
+ int32_t N,
53
+ int32_t K,
54
+ const complex128_t* alpha,
55
+ const complex128_t* A,
56
+ int32_t lda,
57
+ int64_t strideA,
58
+ const complex128_t* B,
59
+ int32_t ldb,
60
+ int64_t strideB,
61
+ const complex128_t* beta,
62
+ complex128_t* C,
63
+ int32_t ldc,
64
+ int64_t strideC,
65
+ int32_t batch_count
66
+ );
67
+
68
+ /* GPU Metal Strided Batched Complex GEMM (Float32 / c64) */
69
+ int32_t batch_cgemm_strided_metal_c64(
70
+ BatchGemmTranspose transA,
71
+ BatchGemmTranspose transB,
72
+ int32_t M,
73
+ int32_t N,
74
+ int32_t K,
75
+ const complex64_t* alpha,
76
+ const complex64_t* A,
77
+ int32_t lda,
78
+ int64_t strideA,
79
+ const complex64_t* B,
80
+ int32_t ldb,
81
+ int64_t strideB,
82
+ const complex64_t* beta,
83
+ complex64_t* C,
84
+ int32_t ldc,
85
+ int64_t strideC,
86
+ int32_t batch_count
87
+ );
88
+
89
+ /* GPU Metal Batched Matrix Exponential (Float32 / c64) */
90
+ int32_t metal_matrix_exp_c64(
91
+ const complex64_t* A,
92
+ int32_t n,
93
+ int32_t batch_count,
94
+ complex64_t* out
95
+ );
96
+
97
+ /* GPU Metal Batched Matrix Exponential Adjoint (Float32 / c64) */
98
+ int32_t metal_matrix_exp_backward_c64(
99
+ const complex64_t* M,
100
+ const complex64_t* Ebar,
101
+ int32_t n,
102
+ int32_t batch_count,
103
+ int32_t dense,
104
+ complex64_t* Mbar
105
+ );
106
+
107
+ /* GPU Metal Structure Factors (Float64 / c128) */
108
+ int32_t metal_structure_factors_c128(
109
+ complex128_t* fgb,
110
+ const double* g2,
111
+ const double* hkl,
112
+ const double* lobato_a,
113
+ const double* lobato_b,
114
+ const double* uij,
115
+ const double* pos,
116
+ const double* occ,
117
+ int32_t n_grid,
118
+ int32_t n_atoms,
119
+ double volume
120
+ );
121
+
122
+ /* GPU Metal Structure Matrix Assembly (Float64 / c128) */
123
+ int32_t metal_structure_matrix_c128(
124
+ const complex128_t* fgb,
125
+ int32_t n_grid,
126
+ const int32_t* source,
127
+ int32_t buffer_size,
128
+ const int32_t* destination,
129
+ int32_t n_beams,
130
+ const double* mii,
131
+ const double* diagonal,
132
+ int32_t n_batch,
133
+ double prefactor,
134
+ int32_t absorption,
135
+ complex128_t* out
136
+ );
137
+
138
+ #ifdef __cplusplus
139
+ }
140
+ #endif
141
+
142
+ #endif /* BATCH_CGEMM_H */