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.
- faster_diffbloch/__init__.py +14 -0
- faster_diffbloch/backend.py +149 -0
- faster_diffbloch/builder.py +58 -0
- faster_diffbloch/cli.py +21 -0
- faster_diffbloch/native/batch_cgemm.c +214 -0
- faster_diffbloch/native/batch_cgemm.h +142 -0
- faster_diffbloch/native/batch_cgemm.metal +374 -0
- faster_diffbloch/native/bridge_lib.c +701 -0
- faster_diffbloch/native/metal_batch_cgemm.m +776 -0
- faster_diffbloch/native/native_scattering.c +233 -0
- faster_diffbloch/native/native_scattering.h +60 -0
- faster_diffbloch-0.1.0.dist-info/METADATA +98 -0
- faster_diffbloch-0.1.0.dist-info/RECORD +16 -0
- faster_diffbloch-0.1.0.dist-info/WHEEL +4 -0
- faster_diffbloch-0.1.0.dist-info/entry_points.txt +3 -0
- faster_diffbloch-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -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))
|
faster_diffbloch/cli.py
ADDED
|
@@ -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 */
|