Skip to content

Commit

Permalink
Improving simulation class (#6)
Browse files Browse the repository at this point in the history
* Adding ability to retrieve a ref to dirac operator from simulation class.

This change is the start of making this library actually useful for calculations.

* Add an eigenvalue recorder for DiracOperator

A new method was added to DiracOperator to compute its eigenvalues. Additionally, a Recorder class was created in the Type13Metropolis example to log these eigenvalues into the chosen output file. This enhancement will aid in debugging, performance monitoring, and further scientific analyses during the simulation process.

* Add HDF5 support and save eigenvalues to file

Added Armadillo's HDF5 support in both 'CMakeLists.txt' and 'Type13Metropolis.cpp'. 'Type13Metropolis.cpp' now includes a 'Recorder' class which can save simulation data to file in HDF5 format. This change aids data storage and analysis as HDF5 allows for easy recall of larger datasets. Also updated CMake files to find and link with HDF5 libraries.

* Added getEigenvalues method and updated dependencies

In the DiracOperator.cpp and DiracOperator.hpp files, the getEigenvalues method was extracted from the header file and moved to the cpp file for better code organization and encapsulation. This function returns the eigenvalues of the Dirac Operator.

Also, the library 'libhdf5-serial-dev' was added to the list of dependencies in .github/workflows/compatability_tests.yml and .github/workflows/build_and_test.yml to ensure successful compilation and testing across different platforms. This library provides the necessary tools for working with hdf5 data files, which are used in this application for data storage and manipulation.

The build and test stages were also renamed in the compatibility tests workflow for clarity and consistency. This renaming helps to avoid confusion when viewing the results in GitHub Actions.

* Add EigenvalueRecorder and refactor HDF5-related options

Added the EigenvalueRecorder class to record and save eigenvalues. This class takes a "DiracOperator" object, a coupling constant "g2", and a "simulationId" string to record the eigenvalues from the Dirac operator into a HDF5 file labelled by the simulation id. It was created to provide a more effective and organized way to handle and record eigenvalues for different simulations.

Furthermore, the definition of ARMA_USE_HDF5 macro was moved from the global CMakeLists.txt file to the EigenvalueRecorder.hpp so that it's only defined where actually needed. This was done to avoid potential conflicts with other parts of the code where HDF5 is not required.

Lastly, the EigenvalueRecorder files were added into the CMakeLists.txt file to ensure they are included in the build.

* Refactor Type13Metropolis.cpp, update build dependencies, and correct a comment typo

Refactored Type13Metropolis.cpp file to simplify the code. A large portion of hand-written HDF5 I/O code was replaced with the more streamlined EigenvalueRecorder class, which reduced the length of the file significantly.

In the build_and_test.yml file, a long line of dependency installation commands was broken down into multiple lines for better readability and easier maintenance.

A minor typo in Simulation.hpp header file comment was corrected for improved code documentation clarity.

These changes were made to make the codebase more maintainable and the comments more accurate.

* Add documentation to EigenvalueRecorder class

Added detailed documentation to EigenvalueRecorder class to enhance code readability and understanding. The comments provide a clear understanding of the purpose and functionality of EigenvalueRecorder class and its recordEigenvalues method. These improvements aim to ease the process of code maintenance and modification.

* Add eigenvalue test and update DiracOperator comments

Added a unit test for DiracOperator to verify that the eigenvalues are being calculated correctly.

* "Refactor Simulation testing and update DiracOperator and Hamiltonian classes

The Simulation unit test has been updated to create a temporary variable `dirac` of a Dirac operator, and validate not only its type but also if the Dirac matrix is correct.

The `Hamiltonian` class was improved by replacing the description, adding more comments to empty `TODO` areas, and replacing dynamic allocation of `double` arrays with `std::vectors`. This change provides safer memory management and prevents memory leaks.

The `DiracOperator` class got a copy constructor. This constructor makes a deep copy of all aspects of the operator, ensuring accurate copying of state details.

Memory allocation for storing previous configuration was improved by replacing a dynamic array `mat_bk` with a vector, leading to cleaner and memory safe code.

Furthermore, the `Hamiltonian` class got updated with safer memory handling by using `std::vector<double>` instead of raw pointers. Raw pointers were deleted later in the code causing potential memory leaks.

The Clifford-type was moved to private data members of DiracOperator for encapsulation.

Added the task in TODO file for making an interface for DiracOperator"

* Tidying github actions files
  • Loading branch information
pauldruce authored Nov 21, 2023
1 parent 2f6b7c0 commit dd67eac
Show file tree
Hide file tree
Showing 45 changed files with 1,307 additions and 567 deletions.
92 changes: 40 additions & 52 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,59 +4,22 @@ on:
workflow_dispatch:
push:
branches:
- "**"
pull_request:
branches:
- main
- "*"

jobs:
generate_matrix:
name: Generate test matrix
runs-on: ubuntu-latest
outputs:
matrix_includes: ${{steps.set-matrix.outputs.matrix_includes}}
steps:
- uses: actions/checkout@v3
- id: set-matrix
shell: bash
run: |
echo "Seed for random selection is = ${{github.run_number}}"
echo "${{github.event_name}}"
case "${{github.event_name}}" in
"pull_request")
includes=$(python3 -u .github/workflows/combination_selection.py "all")
echo "matrix_includes=${includes}" >> $GITHUB_OUTPUT
;;
"push")
includes=$(python3 -u .github/workflows/combination_selection.py ${{github.run_number}} 3)
echo "matrix_includes=${includes}" >> $GITHUB_OUTPUT
;;
esac
check-matrix:
runs-on: ubuntu-latest
needs: generate_matrix
steps:
- name: Check matrix definition
run: |
includes='${{ needs.generate_matrix.outputs.matrix_includes }}'
echo "Json received is = $includes"
echo "Check that the json can be converted using GitHubs fromJSON() without error"
matrix_json='${{fromJson(needs.generate_matrix.outputs.matrix_includes)}}'
build_and_test:
needs: [generate_matrix, check-matrix]
strategy:
fail-fast: false
matrix:
BUILD_TYPE: [Release]
OS: [ubuntu-22.04]
ARMA_VERSION: [11.2.3]
include: ${{fromJSON(needs.generate_matrix.outputs.matrix_includes)}}
BUILD_TYPE: [ Release ]
OS: [ ubuntu-latest, macos-latest ]
ARMA_VERSION: [ 12.6.6 ]

# The CMake configure and build commands are platform-agnostic and should work equally well on Windows or Mac.
# You can convert this to a matrix build if you need cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix

# The CMake configure and build commands are platform-agnostic and should
# work equally well on Windows or Mac. You can convert this to a matrix
# build if you need cross-platform coverage. See:
# https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix

name: "${{matrix.BUILD_TYPE}}, ${{matrix.OS}}, Armadillo v${{matrix.ARMA_VERSION}}."
runs-on: ${{matrix.OS}}
Expand All @@ -70,17 +33,40 @@ jobs:
if: startsWith(matrix.OS,'ubuntu')
run: |
sudo apt-get update -y
sudo apt-get install -y cmake libopenblas-dev liblapack-dev libarpack2-dev libsuperlu-dev wget libgsl-dev doxygen graphviz
sudo apt-get install -y \
cmake \
libopenblas-dev \
liblapack-dev \
libarpack2-dev \
libsuperlu-dev \
wget \
libgsl-dev \
doxygen \
graphviz \
libhdf5-serial-dev
- name: Install macOS dependencies
if: startsWith(matrix.OS,'macos')
run: |
brew update
brew install cmake doxygen graphviz wget
brew install arpack hdf5 libaec openblas superlu pkg-config gsl
brew install \
cmake \
doxygen \
graphviz \
wget \
arpack \
hdf5 \
libaec \
openblas \
superlu \
pkg-config \
gsl || true
- name: Download Armadillo from SourceForge
run: mkdir armadillo && cd armadillo && wget -O armadillo.tar.xz https://sourceforge.net/projects/arma/files/armadillo-${{matrix.ARMA_VERSION}}.tar.xz/download
run: |
mkdir armadillo
cd armadillo
wget -O armadillo.tar.xz https://sourceforge.net/projects/arma/files/armadillo-${{matrix.ARMA_VERSION}}.tar.xz/download
- name: Unzip Armadillo tarball and create build directory
working-directory: armadillo
Expand All @@ -107,8 +93,10 @@ jobs:
sudo cmake --install .
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only
# required if you are using a single-configuration generator such as
# make. See:
# https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.BUILD_TYPE}}

- name: Build the entire project
Expand Down
19 changes: 7 additions & 12 deletions .github/workflows/combination_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,20 @@ def create_new_matrix(subset):


def main(random_seed, num_selected, select_all):
build_type = ["Release", "Debug"]
build_type = ["Release"]
os_versions = [
"ubuntu-22.04",
"ubuntu-latest",
"ubuntu-20.04",
"macos-12",
"macos-11"
"macos-13",
"macos-latest"
]
armadillo_version = ["10.8.2", "11.2.3"]
armadillo_version = ["10.8.2", "11.4.4"]

list_of_lists = [build_type, os_versions, armadillo_version]

combinations = [p for p in itertools.product(*list_of_lists)]

if select_all == False:
if not select_all:
subset = create_combination_selection(combinations, random_seed, num_selected)
else:
subset = combinations
Expand Down Expand Up @@ -67,13 +67,8 @@ def main(random_seed, num_selected, select_all):
else:
random_seed = int(command_line_arguments[1])

if (len(command_line_arguments) == 3):
if len(command_line_arguments) == 3:
random_seed = int(command_line_arguments[1])
num_selected = int(command_line_arguments[2])

sys.exit(main(random_seed, num_selected, select_all))

# Proving that we can recreate the combinations by setting the random.seed
# for i in range(10):
# random.seed(1)
# print(random.sample(combinations, 3))
32 changes: 25 additions & 7 deletions .github/workflows/compatability_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ name: Compatability Tests

on:
workflow_dispatch:
# pull_request:
# branches:
# - main
pull_request:

jobs:
generate_matrix:
Expand Down Expand Up @@ -32,7 +30,7 @@ jobs:
echo "Check that the json can be converted using GitHubs fromJSON() without error"
matrix_json='${{fromJson(needs.generate_matrix.outputs.matrix_includes)}}'
build_and_test:
compatability_build_and_test:
needs: [generate_matrix, check-matrix]
strategy:
fail-fast: false
Expand All @@ -52,14 +50,34 @@ jobs:
if: startsWith(matrix.OS,'ubuntu')
run: |
sudo apt-get update -y
sudo apt-get install -y cmake libopenblas-dev liblapack-dev libarpack2-dev libsuperlu-dev wget libgsl-dev doxygen graphviz
sudo apt-get install -y \
cmake \
libopenblas-dev \
liblapack-dev \
libarpack2-dev \
libsuperlu-dev \
wget \
libgsl-dev \
doxygen \
graphviz \
libhdf5-serial-dev
- name: Install macOS dependencies
if: startsWith(matrix.OS,'macos')
run: |
brew update
brew install cmake doxygen graphviz wget
brew install arpack hdf5 libaec openblas superlu pkg-config gsl
brew install --overwrite\
cmake \
doxygen \
graphviz \
wget \
arpack \
hdf5 \
libaec \
openblas \
superlu \
pkg-config \
gsl || true
- name: Download Armadillo from SourceForge
run: mkdir armadillo && cd armadillo && wget -O armadillo.tar.xz https://sourceforge.net/projects/arma/files/armadillo-${{matrix.ARMA_VERSION}}.tar.xz/download
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ name: C++ Linter

on:
push:
branches:
- "**"

jobs:
clang-format:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ lcov*
.DS_Store
/venv/
/build-xcode/
.vscode
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Let's nicely support folders in IDEs
# Nicely supports folders in IDEs
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
enable_testing()

add_compile_options(-Wall -Wextra -Wpedantic )
add_compile_options(-Wall -Wextra -Wpedantic)
add_compile_options(-fsanitize=address )
add_link_options(-fsanitize=address )
endif()
Expand Down
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ Here are my recommended methods of installing CMake per platform:

Once you have installed the required dependencies, the RFL library can be built using CMake.

tl;dr
```bash
git clone https://github.com/pauldruce/RFL.git
cd RFL
mkdir build
cd build
cmake ..
cmake --build . --target all -j 4
ctest -j 4
```

Most C/C++ IDEs will have CMake capabilities, and CMake offers a GUI application to make this process easier.

However, to build this project via a terminal, you use the following commands:
Expand All @@ -57,8 +68,6 @@ However, to build this project via a terminal, you use the following commands:
The command should generally be `cmake /path/to/source/files` from within an empty build directory. We assumed the source files (notably, the CMakeLists.txt) are in the parent directory where we are running this command.
* The command: `cmake -B ./build .` from the root directory of this project - skipping step 1.
This is a different but handy way to create the build files. This command will create a folder `./build` and generate the build files within it.


3. __Build the project__ This can be done by manually calling `make`, or it is equivalent in the `build` directory. Or CMake has a handy command which is platform-independent:
```bash
cmake --build . --target all
Expand Down
29 changes: 20 additions & 9 deletions RFL_source/README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
# RFL Documentation
This directory contains the source code for the original RFL library created by Mauro D'arcangelo and its modern implementation.

This directory contains the source code for the original RFL library created by Mauro D'arcangelo and its modern
implementation.

The aim is to deprecate Mauro's implementation (Original RFL) for version 1.0 of this project.
The code will be preserved under a protected branch on this repository.

## Original RFL

The source code for the original library is in `./original_source`.
The library defines only two classes: `Cliff` and `Geom24`, defined in `/include/Cliff.hpp` and `/include/Geom24.hpp`, respectively.
The library defines only two classes: `Cliff` and `Geom24`, defined in `/include/Cliff.hpp` and `/include/Geom24.hpp`,
respectively.

- `Cliff` is responsible for creating the 'gamma matrices' for a specific Clifford module.
The general way to specify a Clifford module is by setting two positive integers $p$ and $q$.
The general way to specify a Clifford module is by setting two positive integers $p$ and $q$.
- `Geom24` is the main Class for this library. It is responsible for setting up and running the simulation.

The original RFL code inherently uses an action of the form:
$$S(D) = g_2* Tr(D^2) + g_4*Tr(D^4) $$
where $g_2$ and $g_4$ are real numbers. This action is the origin of the name of the class `Geom24` as the action contains the quadratic (D^2) and quartic (D^4) traces of the Dirac operator.

where $g_2$ and $g_4$ are real numbers. This action is the origin of the name of the class `Geom24` as the action
contains the quadratic (D^2) and quartic (D^4) traces of the Dirac operator.

## New RFL
The new implementation of RFL has taken the original RFL source code and made it more flexible without compromising performance. A significant part of the refactoring was to break down the two behemoth classes into smaller classes, implement a shallow layer of inheritance of abstract classes and migrate memory management to modern C++ techniques (read smart pointers with C++17).

The new implementation of RFL has taken the original RFL source code and made it more flexible without compromising
performance. A significant part of the refactoring was to break down the two behemoth classes into smaller classes,
implement a shallow layer of inheritance of abstract classes and migrate memory management to modern C++ techniques (
read smart pointers with C++17).
The new source code is found in `./new_source`.

This refactoring allows for better testing and more flexibility for library users.
It is constantly being developed, and any improvements or enhancements are welcome. Please leave an issue on the GitHub repo.
It is constantly being developed, and any improvements or enhancements are welcome. Please leave an issue on the GitHub
repo.

The high performance that Mauro's original implementation strived to develop has been preserved.
To ensure that this performance does not degrade, a unit test that captures the difference between the original and new implementations.
This test requires that the new implementation is no more than 5% slower to run the same simulation in each implementation.
To ensure that this performance does not degrade, a unit test that captures the difference between the original and new
implementations.
This test requires that the new implementation is no more than 5% slower to run the same simulation in each
implementation.
22 changes: 11 additions & 11 deletions RFL_source/new_source/BarrettGlaser/Action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@
using namespace std;
using namespace arma;

Action::Action(double g_2) : m_g_2(g_2), m_g_4(1.0) {}
Action::Action(const double g_2) : m_g_2(g_2), m_g_4(1.0) {}

Action::Action(double g_2, double g_4) : m_g_2(g_2), m_g_4(g_4) {}
Action::Action(const double g_2, const double g_4) : m_g_2(g_2), m_g_4(g_4) {}

double Action::calculateSFromDirac(const DiracOperator& dirac) const {
cx_mat dirac_mat = dirac.getDiracMatrix();
cx_mat dirac_squared = dirac_mat * dirac_mat;
double trace_dirac_squared = trace(dirac_squared).real();
double trace_dirac_4 = trace(dirac_squared * dirac_squared).real();
double Action::calculateSFromDirac(const IDiracOperator& dirac) const {
const cx_mat dirac_mat = dirac.getDiracMatrix();
const cx_mat dirac_squared = dirac_mat * dirac_mat;
const double trace_dirac_squared = trace(dirac_squared).real();
const double trace_dirac_4 = trace(dirac_squared * dirac_squared).real();
return m_g_2 * trace_dirac_squared + m_g_4 * trace_dirac_4;
}

double Action::calculateS(const DiracOperator& dirac) const {
double Action::calculateS(const IDiracOperator& dirac) const {
return m_g_2 * dirac.traceOfDiracSquared() + m_g_4 * dirac.traceOfDirac4();
}

void Action::setParams(double g_2, double g_4) {
void Action::setParams(const double g_2, const double g_4) {
this->m_g_2 = g_2;
this->m_g_4 = g_4;
}
void Action::setG4(double value) { this->m_g_4 = value; }
void Action::setG2(double value) { this->m_g_2 = value; }
void Action::setG4(const double value) { this->m_g_4 = value; }
void Action::setG2(const double value) { this->m_g_2 = value; }
8 changes: 3 additions & 5 deletions RFL_source/new_source/BarrettGlaser/Action.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@

#ifndef RFL_ACTION_HPP
#define RFL_ACTION_HPP
#include "DiracOperator.hpp"
#include "IAction.hpp"
#include <armadillo>
#include <string>
#include "IDiracOperator.hpp"

/**
* Action implements the \f$ S(D) = g_2Tr(D^2) + g_4 Tr(D^4) \f$ action as described in the papers
Expand Down Expand Up @@ -76,15 +74,15 @@ class Action : public IAction {
* an optimised algorithm for the B-G action.
* @param dirac A reference to the Dirac operator you want to calculate the Barrett-Glaser action of.
*/
double calculateS(const DiracOperator& dirac) const override;
double calculateS(const IDiracOperator& dirac) const override;

/**
* This calculates the Barrett-Glaser action for the supplied Dirac operator by computing the full
* matrix representation of the Dirac operator and directly calculating the action. This is not an
* optimum calculation. Please make use of calculateS(...) above for faster results.
* @param dirac A reference to the Dirac operator you want to calculate the Barrett-Glaser action of.
*/
double calculateSFromDirac(const DiracOperator& dirac) const;
double calculateSFromDirac(const IDiracOperator& dirac) const;

private:
double m_g_2, m_g_4;
Expand Down
Loading

0 comments on commit dd67eac

Please sign in to comment.