A C++ implementation of the Differential Evolution for Analytic Continuation (DEAC) algorithm which uses self adaptive differential evolution to reconstruct the dynamic structure factor from imaginary time density-density correlations.
DEAC uses CMake for build, test and installation automation. For details on using CMake consult https://cmake.org/documentation/. In short, the following steps should work on UNIX-like systems:
git clone git@github.com:nscottnichols/deac-cpp.git
cd deac-cpp
mkdir build
cd build
cmake ../src
make
sudo make install
On Windows try:
git clone git@github.com:nscottnichols/deac-cpp.git
cd deac-cpp
md build
cd build
cmake ../src
cmake --build . --config Release
cmake --build . --target install
As above, and with further details below, but you should consider using the following CMake options with the appropriate value instead of xxx :
-D DEAC_MODEL=standard|hyperbolic|normalizationchoose the spectral-function model. The default isstandard, where S'(ω)=S(ω). Thehyperbolicmodel uses S'(ω)=2S(ω)e^(-βω/2), and thenormalizationmodel uses S'(ω)=S(ω)(1 + e^(-βω)).-D GPU_BACKEND=none|cuda|hip|syclchoose the GPU backend. The default isnone.-D GPU_BLOCK_SIZE=xxxequal to the maximum threadblock/workgroup size for GPU builds-D SUB_GROUP_SIZE=xxxequal to the subgroup size for SYCL GPU builds-D MAX_GPU_STREAMS=xxxequal to maximum number of concurrent streams or queues on GPU device-D USE_BLAS=1use backend BLAS libraries for GPU matrix operations-D MKLROOT=xxxoneMKL installation root when using-D GPU_BACKEND=sycl -D USE_BLAS=1andMKLROOTis not already set in the environment-D USE_BOSONIC_DETAILED_BALANCE_CONDITION_DSF=1build the bosonic detailed-balance DSF kernel variant-D SINGLE_PARTICLE_FERMIONIC_SPECTRAL_FUNCTION=1enable single-particle fermionic spectral-function behavior-D USE_ALLOW_NEGATIVE_SPECTRAL_WEIGHT=1allow negative spectral weights-D USE_SYCL_MATMUL_WA=1enable the SYCL matrix-multiplication workaround-D CMAKE_CUDA_ARCHITECTURES=xxxequal to CUDA device architecture if not properly detected by CMake-D SYCL_FLAGS="xxx"target architecture and device flags for SYCL builds-D CMAKE_C_COMPILER=xxxequal to the name of the C99 Compiler you wish to use (or the environment variableCC)-D CMAKE_CXX_COMPILER=xxxequal to the name of the C++20 compiler you wish to use (or the environment variableCXX)-D CMAKE_PREFIX_PATH=xxxto add a non-standard location for CMake to search for libraries, headers or programs-D CMAKE_INSTALL_PREFIX=xxxto install deac to a non-standard location-D STATIC=1to enable a static build-D CMAKE_BUILD_TYPE=Debugto build deac in debug mode (deacd.e)-D CMAKE_BUILD_TYPE=ZeroTto build deac for zero temperature (deac-zT.e)-D CMAKE_BUILD_TYPE=ZeroTDebugto build deac for zero temperature in debug mode (deac-zTd.e)-E env CXXFLAGS="xxx"add additional compiler flags-E env LDFLAGS="xxx"add additional linker flags
Executables will be installed to CMAKE_INSTALL_PREFIX location or, if the install is skipped, they will be located in build/deac.
Executables produced are deac.e, deacd.e, deac-zT.e, and deac-zTd.e for CMAKE_BUILD_TYPE=Release|Debug|ZeroT|ZeroTDebug respectively.
deac.e --version (or -v) retains the legacy one-line semantic-version
output. For provenance checks, every executable also provides a byte-stable,
single-line JSON identity:
$ deac.e --build-identity
{"schema_version":1,"semantic_version":"2.0.0-rc1","source_sha":"0123456789abcdef0123456789abcdef01234567","source_state":"clean"}Schema 1 has exactly four fields in the order shown. source_sha is the full,
lowercase 40-hex commit at build time when Git metadata is trustworthy.
source_state is clean when the tracked commit and build-relevant VERSION
and src/ inputs agree, or dirty when those inputs contain staged,
unstaged, or untracked changes (Git-ignored files do not count). A source
archive with no matching repository metadata reports source_sha: null and
source_state: "unavailable"; it never borrows the SHA of an enclosing Git
checkout.
CMake writes the same canonical bytes to
build/deac/deac-build-identity.json. Each ordinary cmake --build build
runs a small identity refresh, recompiles its tiny identity-only source, and
relinks the executable, while also watching the relevant source files plus
worktree-aware Git HEAD, index, packed refs, and loose refs. This intentional
identity rebuild avoids filesystem-timestamp races, so
editing, staging, reverting, committing (including an empty commit after
git pack-refs), or checking out source updates the executable and receipt in
that same build without a manually repeated configure command. Git identity
probes ignore inherited repository-redirection environment variables; archive
builds therefore cannot be assigned metadata from an unrelated checkout.
ZeroT and ZeroTDebug restore the original zero-temperature problem: one
non-negative-frequency population represents S(omega) on the supplied
frequency grid, and the forward model is the one-sided Laplace transform
F(tau) = integral_0^infinity exp(-tau*omega) S(omega) d omega.
There is no independently evolved negative-frequency population, no beta or
finite-temperature periodicity factor, and the frequency and spectrum outputs
each contain exactly genome_size doubles. The fixed --spectra_type positive
value is the default, --temperature is ignored and recorded as zero, and
result filenames retain the historical deac-zT_* prefix.
The supported ZeroT configuration is currently the CPU backend:
cmake -S src -B build-zerot \
-DCMAKE_BUILD_TYPE=ZeroT -DGPU_BACKEND=none
cmake --build build-zerot --parallel
ctest --test-dir build-zerot --output-on-failureThe CUDA, HIP, and SYCL ZeroT combinations are not release-tested and are not claimed as supported by this documentation. Their finite-temperature support is independent of the CPU ZeroT mode.
If you run into problems, failures with linking etc., common errors may include
not properly setting your LD_LIBRARY_PATH or LIBRARY_PATH and not starting from a clean build
directory (issue make clean or rm -rf ./* inside the build directory).
- get data into numpy arrays (imaginary_time_array, intermediate_scattering_function_array, intermediate_scattering_function_error_array)
- save data as npz file
np.savez(filename, tau = imaginary_time_array, isf = intermediate_scattering_function_array, error = intermediate_scattering_function_error_array) - run converter script in
toolsdirectory to convert.npzfile to binary format used by deac/path/to/DEAC_TOOLS_DIR/convert_isf_data.py /path/to/isf_npz_file /path/to/isf_bin_file
A single reconstruction of the dynamic structure factor can be generated using the input data from step 1. For example:
deac.e --number_of_generations 1600000 --temperature 1.35 --population_size 8 --genome_size 4096 --normalize --spectra_type bfull --omega_max 512.0 --save_directory deac_results --seed 1 --stop_minimum_fitness 1.0 isf.binThis command will save the generated spectrum in the deac_results directory after 1600000 steps or if the desired fitness cutoff of 1.0 is reached. Please see deac.e --help for more command line arguments and further description.
For every model and backend, --normalize uses the first ISF value as the
target zeroth moment. The target must be finite, positive, and at least the
smallest normal binary64 value. It must also produce a normal initial scale for
the selected model and frequency grid; this additional lower bound is checked
before output creation because it depends on the grid's quadrature weights.
Zero, negative, non-finite, subnormal, and unrepresentably small targets are
therefore rejected before the solver creates its result directory or starts
evolution. Builds that allow negative spectral weights reject --normalize
because a signed population does not guarantee a positive denominator. Choose
a kernel convention with a positive equal-time correlation, such as bfull,
bdsf, or the ZeroT positive-frequency kernel; the solver does not silently
flip the sign of a single-particle correlation. An invalid initial population
normalization is fatal because there is no valid incumbent. During evolution,
a candidate with a zero, non-finite, or otherwise unrepresentable denominator
or scale is assigned noncompetitive fitness and rejected; it cannot contaminate
the incumbent population or its statistics.
When --first_moment is non-negative, it is an active constraint, including
the valid target value zero. The fitness contribution is
((candidate_first_moment - target_first_moment) / 1.0)^2 on every backend.
The unit standard deviation is fixed because the CLI does not yet expose a
first-moment uncertainty; negative --first_moment values disable the
constraint.
The general recommendation is to generate several spectra using different seeds (--seed) and average the final results. A sample bash script to generate a command file with multiple seeds can be found in the tools directory tools/generate_commands.sh.
The data generated by DEAC is in binary format and can be loaded into Python using numpy.
frequency_filename = "/path/to/deac_frequency_file.bin"
dynamic_structure_factor_filename = "/path/to/deac_dsf_file.bin"
frequency = np.fromfile(frequency_filename, dtype=np.double)
dsf = np.fromfile(dynamic_structure_factor_filename, dtype=np.double)An example script to plot the average for multiple spectra using many seeds (with results saved in the same directory) can be found in the tools directory (tools/plot_simple_average_deac_results.py).
See deac --help for more details.