-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathREADME.md.bak
502 lines (392 loc) · 15.6 KB
/
README.md.bak
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
# libsparseir
[](https://github.com/SpM-lab/libsparseir/actions/workflows/CI_cmake.yml)
> [!WARNING]
> This C++ project is still under construction. Please use other repositories:
> - https://github.com/SpM-lab/sparse-ir
> - https://github.com/SpM-lab/SparseIR.jl
> - https://github.com/SpM-lab/sparse-ir-fortran
## Description
This C++ library provides routines for constructing and working with the intermediate representation of correlation functions. It provides:
- on-the-fly computation of basis functions for arbitrary cutoff Λ
- basis functions and singular values are accurate to full precision
- routines for sparse sampling
We use [tuwien-cms/libxprec](https://github.com/tuwien-cms/libxprec) as a double-double precision arithmetic library.
## Building and Installation
### Dependencies
- **CMake** (>= 3.10)
- **C++ compiler** with C++11 support
- **Fortran compiler** (optional, for Fortran bindings)
All other dependencies (including libxprec) are automatically downloaded and built during the build process using CMake's FetchContent feature. You do not need to install these manually.
### Using Build Scripts
Three build scripts are provided for easy building and installation:
1. **build_capi.sh**: Builds and installs only the C API
```bash
./build_capi.sh
```
2. **build_fortran.sh**: Builds and installs the C API and Fortran bindings
```bash
./build_fortran.sh
```
3. **build_with_tests.sh**: Builds everything including tests
```bash
./build_with_tests.sh
# After testing, you can install with:
cd build && cmake --install .
```
By default, all scripts will install to `$HOME/opt/libsparseir`. You can override this by setting the `CMAKE_INSTALL_PREFIX` environment variable:
```bash
CMAKE_INSTALL_PREFIX=/usr/local ./build_capi.sh
```
### Manual Build
If you prefer to build manually, you can use the following commands:
```bash
mkdir -p build
cd build
# For C API only
cmake .. -DSPARSEIR_BUILD_FORTRAN=OFF -DSPARSEIR_BUILD_TESTING=OFF
# For C API and Fortran bindings
cmake .. -DSPARSEIR_BUILD_FORTRAN=ON -DSPARSEIR_BUILD_TESTING=OFF
# For everything including tests
cmake .. -DSPARSEIR_BUILD_FORTRAN=ON -DSPARSEIR_BUILD_TESTING=ON
# Build
cmake --build .
# Install
cmake --install .
```
### Quick Test Build
For a quick test build with all options enabled:
```sh
rm -rf ./build && cmake -S . -B ./build -DSPARSEIR_BUILD_TESTING=ON && cmake --build ./build -j && ./build/test/libsparseirtests
```
### Testing Fortran Bindings
After building with Fortran bindings enabled, you can run the Fortran test:
```bash
cd build
./test_kernel
```
## Generating documentation with Doxygen
Install `doxygen` and `graphviz`. Then, run the following command:
```bash
bash generate_docs.sh
```
This will create the `docs/html` directory. Open `docs/html/index.html` with your browser to see it.
# libsparseir C-API Documentation
This document describes how to use the C-API of libsparseir. The C-API provides a way to use the sparseir library from C or other languages that can interface with C. All objects are immutable.
## Basic Usage
Please refer [`test/cinterface.cxx`](test/cinterface.cxx) to learn more.
### Basic Working Example
The following example demonstrates how to create a fermionic finite-temperature basis using the logistic kernel,
and perform transformations of a single-variable Green's function between Matsubara frequency and imaginary-time domains.
For fitting, we use the `spir_sampling_fit_XY`, where `X` is the element type of the input data, and `Y` is that of the output data: `z` corresponds to `c_complex`, `d` to `double`.
The same naming convention is used for evaluation: `spir_sampling_evaluate_XY`.
The logistic kernel is defined as
$
K^\mathrm{L}(\tau, \omega) = \frac{e^{-\tau \omega}}{1 + e^{-\beta\omega}},
$
which corresponds to the normal Fermi-Dirac distribution at temperature $\beta^{-1}$.
For more details, see [SparseIR Tutorial](https://spm-lab.github.io/sparse-ir-tutorial/).
```c
#include <complex.h>
#include <sparseir/sparseir.h>
// Create a fermionic finite temperature basis
double beta = 10.0; // Inverse temperature
double omega_max = 10.0; // Ultraviolet cutoff
double epsilon = 1e-8; // Accuracy target
spir_fermionic_finite_temp_basis* basis =
spir_fermionic_finite_temp_basis_new(beta, omega_max, epsilon);
// Create sampling objects for imaginary-time and Matsubara domains
spir_sampling* tau_sampling = spir_fermionic_tau_sampling_new(basis);
spir_sampling* matsubara_sampling = spir_fermionic_matsubara_sampling_new(basis);
// Create Green's function with a pole at 0.5*omega_max
int n_matsubara;
int status = spir_sampling_get_num_points(matsubara_sampling, &n_matsubara);
assert(status == SPIR_COMPUTATION_SUCCESS);
c_complex* g_matsubara = (c_complex*)malloc(n_matsubara * sizeof(c_complex));
int* matsubara_indices = (int*)malloc(n_matsubara * sizeof(int));
// Get Matsubara frequency indices
status = spir_sampling_get_matsubara_points(matsubara_sampling, matsubara_indices);
assert(status == SPIR_COMPUTATION_SUCCESS);
// Set pole position
const double pole_position = 0.5 * omega_max;
// Initialize Green's function in Matsubara frequencies
// G(iω_n) = 1/(iω_n - ε) = ε/(ω_n^2 + ε^2) - iω_n/(ω_n^2 + ε^2)
for (int i = 0; i < n_matsubara; ++i) {
double i_n = (2 * matsubara_indices[i] + 1) * M_PI / beta; // Fermionic Matsubara frequency
double denominator = i_n * i_n + pole_position * pole_position;
g_matsubara[i] = c_complex{
pole_position / denominator, // Real part: ε/(ω_n^2 + ε^2)
-i_n / denominator // Imaginary part: -ω_n/(ω_n^2 + ε^2)
};
}
int target_dim = 0; // target dimension for evaluation and fit
// Matsubara sampling points to basis coefficients
int n_basis;
status = spir_fermionic_finite_temp_basis_get_size(basis, &n_basis);
assert(status == SPIR_COMPUTATION_SUCCESS);
c_complex* g_fit = (c_complex*)malloc(n_basis * sizeof(c_complex));
int dims[1] = {n_matsubara};
status = spir_sampling_fit_zz(matsubara_sampling, SPIR_ORDER_COLUMN_MAJOR,
1, dims, target_dim, g_matsubara, g_fit);
assert(status == SPIR_COMPUTATION_SUCCESS);
// Evaluate the basis coefficients at imaginary times
{
double tau = 0.1 * beta;
double expected = -exp(-tau * pole_position) / (1.0 + exp(-beta * pole_position));
spir_polyvector* u = spir_fermionic_finite_temp_basis_get_u(basis);
double* uval = (double*)malloc(n_basis * sizeof(double));
status = spir_evaluate_funcs(u, tau, uval);
assert(status == SPIR_COMPUTATION_SUCCESS);
double actual = 0.0;
for (int i = 0; i < n_basis; ++i) {
actual += creal(g_fit[i]) * uval[i];
}
assert(fabs(actual - expected) < epsilon);
free(uval);
spir_destroy_polyvector(u);
}
// Basis coefficients to imaginary-time sampling points
int n_tau;
status = spir_sampling_get_num_points(tau_sampling, &n_tau);
assert(status == SPIR_COMPUTATION_SUCCESS);
c_complex* g_tau = (c_complex*)malloc(n_tau * sizeof(c_complex));
status = spir_sampling_evaluate_zz(tau_sampling, SPIR_ORDER_COLUMN_MAJOR,
1, dims, target_dim, g_fit, g_tau);
assert(status == SPIR_COMPUTATION_SUCCESS);
// Compare with expected result:
// G(tau) = -exp(-tau * pole_position) / (1 + exp(-beta * pole_position))
double* tau_points = (double*)malloc(n_tau * sizeof(double));
status = spir_sampling_get_tau_points(tau_sampling, tau_points);
assert(status == SPIR_COMPUTATION_SUCCESS);
for (int i = 0; i < n_tau; ++i) {
double tau = tau_points[i];
double expected = -exp(-tau * pole_position) / (1.0 + exp(-beta * pole_position));
assert(fabs(g_tau[i].real - expected) < epsilon);
assert(fabs(g_tau[i].imag) < epsilon);
}
// Imaginary-time sampling points to basis coefficients
c_complex* g_fit2 = (c_complex*)malloc(n_basis * sizeof(c_complex));
status = spir_sampling_fit_zz(tau_sampling, SPIR_ORDER_COLUMN_MAJOR,
1, dims, target_dim, g_tau, g_fit2);
assert(status == SPIR_COMPUTATION_SUCCESS);
// Basis coefficients to Matsubara Green's function
c_complex* g_matsubara_reconstructed = (c_complex*)malloc(n_matsubara * sizeof(c_complex));
status = spir_sampling_evaluate_zz(matsubara_sampling, SPIR_ORDER_COLUMN_MAJOR,
1, dims, target_dim, g_fit2, g_matsubara_reconstructed);
assert(status == SPIR_COMPUTATION_SUCCESS);
for (int i = 0; i < n_matsubara; ++i) {
assert(fabs(g_matsubara_reconstructed[i].real2 - g_matsubara[i].real) < epsilon);
assert(fabs(g_matsubara_reconstructed[i].imag - g_matsubara[i].imag) < epsilon);
}
// Clean up (order is arbitrary)
free(matsubara_indices);
free(g_matsubara);
free(g_fit);
free(g_tau);
spir_destroy_fermionic_finite_temp_basis(basis);
spir_destroy_sampling(tau_sampling);
spir_destroy_sampling(matsubara_sampling);
```
We can create a bosonic basis using the logistic kernel as discussed in the [SparseIR Tutorial](https://spm-lab.github.io/sparse-ir-tutorial/).
This can be achived by replacing `fermionic` by `bosonic` in the above code.
### Kernel Creation and Domain
```c
#include <sparseir/sparseir.h>
// Create kernels for different statistics
spir_kernel* fermionic_kernel = spir_logistic_kernel_new(9.0);
spir_kernel* bosonic_kernel = spir_regularized_bose_kernel_new(9.0);
// Get kernel domain
double xmin, xmax, ymin, ymax;
spir_kernel_domain(fermionic_kernel, &xmin, &xmax, &ymin, &ymax);
// Clean up
spir_destroy_kernel(fermionic_kernel);
spir_destroy_kernel(bosonic_kernel);
```
### Basis Construction and Sampling
```c
#include <sparseir/sparseir.h>
// Create a fermionic finite temperature basis
double beta = 10.0; // Inverse temperature
double omega_max = 10.0; // Frequency cutoff
double epsilon = 1e-8; // Accuracy target
spir_fermionic_finite_temp_basis* basis =
spir_fermionic_finite_temp_basis_new(beta, omega_max, epsilon);
// Create sampling objects for different domains
spir_sampling* tau_sampling = spir_fermionic_tau_sampling_new(basis);
spir_sampling* matsubara_sampling = spir_fermionic_matsubara_sampling_new(basis);
// Create Green's function with a pole at 0.5*omega_max
int n_matsubara;
int status = spir_sampling_get_num_points(matsubara_sampling, &n_matsubara);
if (status != 0) {
// Handle error
exit(-1);
}
c_complex* g_matsubara = (c_complex*)malloc(n_matsubara * sizeof(c_complex));
int* matsubara_indices = (int*)malloc(n_matsubara * sizeof(int));
// Get Matsubara frequency indices
status = spir_sampling_get_matsubara_points(matsubara_sampling, matsubara_indices);
if (status != 0) {
// Handle error
free(matsubara_indices);
free(g_matsubara);
exit(-1);
}
// Set pole position
const double pole_position = 0.5 * omega_max;
// Initialize Green's function in Matsubara frequencies
// G(iω_n) = 1/(iω_n - ε) = ε/(ω_n^2 + ε^2) - iω_n/(ω_n^2 + ε^2)
for (int i = 0; i < n_matsubara; ++i) {
double i_n = (2 * matsubara_indices[i] + 1) * M_PI / beta; // Fermionic Matsubara frequency
double denominator = i_n * i_n + pole_position * pole_position;
g_matsubara[i] = c_complex{
pole_position / denominator, // Real part: ε/(ω_n^2 + ε^2)
-i_n / denominator // Imaginary part: -ω_n/(ω_n^2 + ε^2)
};
}
// Clean up
free(matsubara_indices);
free(g_matsubara);
spir_destroy_fermionic_finite_temp_basis(basis);
spir_destroy_sampling(tau_sampling);
spir_destroy_sampling(matsubara_sampling);
```
### Sampling Operations
```c
#include <sparseir/sparseir.h>
// Create basis and sampling objects
double beta = 10.0;
double omega_max = 10.0;
double epsilon = 1e-8;
spir_fermionic_finite_temp_basis* basis =
spir_fermionic_finite_temp_basis_new(beta, omega_max, epsilon);
spir_sampling* tau_sampling = spir_fermionic_tau_sampling_new(basis);
// Example of evaluating basis coefficients at sampling points
int32_t ndim = 2;
int32_t input_dims[] = {3, 4}; // Example dimensions
int32_t target_dim = 0;
double input[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0};
double output[12];
// Real to real transformation
spir_sampling_evaluate_dd(
tau_sampling,
SPIR_ORDER_COLUMN_MAJOR,
ndim,
input_dims,
target_dim,
input,
output
);
// Fit values back to basis coefficients
spir_sampling_fit_dd(
tau_sampling,
SPIR_ORDER_COLUMN_MAJOR,
ndim,
input_dims,
target_dim,
output,
input
);
// Clean up
spir_destroy_fermionic_finite_temp_basis(basis);
spir_destroy_sampling(tau_sampling);
```
### Discrete Lehmann Representation (DLR)
```c
#include <sparseir/sparseir.h>
#include <stdlib.h> // rand
double beta = 100.0;
double wmax = 1.0;
double epsilon = 1e-12;
spir_fermionic_finite_temp_basis *basis =
spir_fermionic_finite_temp_basis_new(beta, wmax, epsilon);
spir_fermionic_dlr *dlr = spir_fermionic_dlr_new(basis);
int npoles = 10;
double poles[npoles];
double coeffs[npoles];
for (int i = 0; i < npoles; i++) {
double r = (double)rand() / (double)RAND_MAX;
poles[i] = wmax * (2.0 * r - 1.0);
r = (double)rand() / (double)RAND_MAX;
coeffs[i] = 2.0 * r - 1.0;
}
spir_fermionic_dlr *dlr_with_poles =
spir_fermionic_dlr_new_with_poles(basis, npoles, poles);
int fitmat_rows = spir_fermionic_dlr_fitmat_rows(dlr_with_poles);
int fitmat_cols = spir_fermionic_dlr_fitmat_cols(dlr_with_poles);
double *Gl = (double *)malloc(fitmat_rows * sizeof(double));
int32_t to_ir_input_dims[1] = {npoles};
int status_to_IR =
spir_fermionic_dlr_to_IR(dlr_with_poles, SPIR_ORDER_COLUMN_MAJOR, 1,
to_ir_input_dims, coeffs, Gl);
double *g_dlr = (double *)malloc(fitmat_rows * sizeof(double));
int32_t from_ir_input_dims[1] = {static_cast<int32_t>(fitmat_rows)};
int status_from_IR = spir_fermionic_dlr_from_IR(
dlr, SPIR_ORDER_COLUMN_MAJOR, 1, from_ir_input_dims, Gl, g_dlr);
// Clean up
free(Gl);
free(g_dlr);
spir_destroy_fermionic_finite_temp_basis(basis);
spir_destroy_fermionic_dlr(dlr);
spir_destroy_fermionic_dlr(dlr_with_poles);
```
### Complex Number Operations
```c
#include <sparseir/sparseir.h>
#include <complex.h>
// Create basis and sampling objects
double beta = 10.0;
double omega_max = 10.0;
double epsilon = 1e-8;
spir_fermionic_finite_temp_basis* basis =
spir_fermionic_finite_temp_basis_new(beta, omega_max, epsilon);
spir_sampling* matsubara_sampling = spir_fermionic_matsubara_sampling_new(basis);
// Setup dimensions and data
int32_t ndim = 2;
int32_t input_dims[] = {3, 4};
int32_t target_dim = 0;
// Initialize complex input data
c_complex complex_input[12];
c_complex complex_output[12];
for (int i = 0; i < 12; i++) {
// Complex numbers with real and imaginary parts
complex_input[i] = c_complex{(double)i, (double)i};
}
// Complex to complex transformation
spir_sampling_evaluate_zz(
matsubara_sampling,
SPIR_ORDER_COLUMN_MAJOR,
ndim,
input_dims,
target_dim,
complex_input,
complex_output
);
// Fit complex values back to basis coefficients
c_complex recovered_input[12];
spir_sampling_fit_zz(
matsubara_sampling,
SPIR_ORDER_COLUMN_MAJOR,
ndim,
input_dims,
target_dim,
complex_output,
recovered_input
);
// Clean up
spir_destroy_fermionic_finite_temp_basis(basis);
spir_destroy_sampling(matsubara_sampling);
```
# libsparseir Fortran Bindings Documentation
This document describes how to use the Fortran bindings of libsparseir. The Fortran bindings provide a way to use the sparseir library from Fortran. All objects are immutable.
## Basic Usage
```fortran
use sparseir
implicit none
type(spir_kernel) :: kernel
real(8) :: lambda, xmin, xmax, ymin, ymax
integer :: stat
! Create a logistic kernel
lambda = 9.0d0
kernel = spir_logistic_kernel_new(lambda)
! Get kernel domain
stat = spir_kernel_domain(kernel, xmin, xmax, ymin, ymax)
```