Skip to content
This repository has been archived by the owner on Dec 20, 2023. It is now read-only.

Gather DDSIM benchmarks #12

Draft
wants to merge 30 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ac5da11
Add seed to CircuitSimulatorExecutor
tyi1025 Jun 14, 2023
200ac3c
Add general purpose simulators
tyi1025 Jun 14, 2023
d18d2f3
Add rudimentary tests
tyi1025 Jun 15, 2023
c0c3975
Add quantum algorithm tests
tyi1025 Jun 15, 2023
b7c2a84
Separate tests and benchmarks
tyi1025 Jun 16, 2023
984c665
Split benchmark and test
tyi1025 Jun 26, 2023
45bafa1
Refactor determnoisesimexec and add a test
tyi1025 Jun 26, 2023
5d05049
import clean-up
tyi1025 Jun 26, 2023
9ab6f20
Attempt to fix the CI linter error
tyi1025 Jul 5, 2023
dfc92bc
Fix CI
tyi1025 Jul 19, 2023
bee7e17
Merge the hybrid executors together to avoid code duplication
tyi1025 Jul 24, 2023
39885e5
Refactor magic number seed into global constant
tyi1025 Jul 24, 2023
d0edbe2
Rename typoed class
tyi1025 Jul 24, 2023
fdadb63
Clean-up
tyi1025 Jul 24, 2023
9aec66f
Fix typo
tyi1025 Jul 24, 2023
eb183d3
Fix typo
tyi1025 Jul 24, 2023
52756e7
Merge two unitary simulator executors into one
tyi1025 Jul 24, 2023
b1f0fe8
Fix cmake
tyi1025 Jul 24, 2023
9574955
Fix coverage
tyi1025 Jul 24, 2023
1e86792
Refactor to reduce code duplication for two executors
tyi1025 Jul 26, 2023
206321a
Remove redundant unitary executor
tyi1025 Jul 26, 2023
a234b9f
Fix unitary executor
tyi1025 Jul 26, 2023
668f36d
Refactor the rest of the executors for code duplication
tyi1025 Jul 30, 2023
5683b0b
Move qc construction to the base class
tyi1025 Jul 30, 2023
3931e6f
Remove unnecessary comment
tyi1025 Jul 30, 2023
9a8472c
Merge branch 'main' into 5-gather-ddsim-benchmarks
tyi1025 Aug 8, 2023
f1b0634
Merge branch 'main' into 5-gather-ddsim-benchmarks
tyi1025 Aug 8, 2023
2188a03
DDSIM with WState
tyi1025 Aug 9, 2023
3246ec7
Added circ sim exec test
tyi1025 Aug 17, 2023
77a1505
Add other simulator executor tests
tyi1025 Aug 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,10 @@ if(BUILD_DD_EVAL_TESTS)
include(GoogleTest)
add_subdirectory(test)
endif()

option(BUILD_DD_EVAL_BENCHMARKS "Also build benchmarks for DDEval project")
if(BUILD_DD_EVAL_BENCHMARKS)
enable_testing()
include(GoogleTest)
add_subdirectory(benchmarks)
endif()
Comment on lines +38 to +43
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want the cpp-linter to work properly, you also have to set that option in the corresponding CI workflow (.github/workflows/cpp-linter.yaml)

16 changes: 16 additions & 0 deletions benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
if(NOT TARGET gtest OR NOT TARGET gmock)
# Prevent overriding the parent project's compiler/linker settings on Windows
set(gtest_force_shared_crt # cmake-lint: disable=C0103
ON
CACHE BOOL "" FORCE)

# store path to googletest in variable
set(GTEST_PATH "extern/ddsim/extern/qfr/extern/dd_package/extern/googletest")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that the googletest path is subject to change once you rebase the QFR (now MQT Core) PR and the DSSIM/QCEC PRs. Then this becomes: extern/ddsim/extern/mqt-core/extern/googletest

add_subdirectory("${PROJECT_SOURCE_DIR}/${GTEST_PATH}" "${GTEST_PATH}"
EXCLUDE_FROM_ALL)
endif()

package_add_test(
${PROJECT_NAME}_sim_benchmark ${PROJECT_NAME} benchmark_simexec_qpe.cpp
benchmark_simexec_ghz.cpp benchmark_simexec_berstein.cpp
benchmark_simexec_grover.cpp)
60 changes: 60 additions & 0 deletions benchmarks/benchmark_simexec_berstein.cpp
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just commenting on this file, but everything here holds for the other files as well:
Similar to the test, I would split the benchmarks per executor and not by algorithm.

Furthermore, the benchmarks should really test a broad range of qubits, from really small to really large to cover the whole range of circuit sizes and complexity.
It's not enough to just benchmark a handful of circuits here.

Last but not least, this is missing quite some algorithms that are directly available in our libraries. There should be a parity between the algorithms tested in this repo and the algorithms used for benchmarking.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be clear you mean that I should run the same algorithms both for test and benchmark with the only difference being benchmark being more thorough (more tests with different numbers of qubits), right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. The tests can just cover certain instances of each benchmark, while the benchmarks should cover a broad range.

Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "QuantumComputation.hpp"
#include "algorithms/BernsteinVazirani.hpp"
#include "executors/CircuitSimulatorExecutor.hpp"
#include "executors/HybridSimulatorAmplitudeExecutor.hpp"
#include "executors/HybridSimulatorDDExecutor.hpp"
#include "executors/StochasticNoiseSimulatorExecutor.hpp"
#include "tasks/SimulationTask.hpp"

#include "gtest/gtest.h"

TEST(SimExecBenchmarkBerstein, HybridSimulatorAmplitudeExec) {
auto hybridSimulatorAmplitudeExecutor =
std::make_unique<HybridSimulatorAmplitudeExecutor>();
std::size_t const n = 25;
auto qc = std::make_unique<qc::BernsteinVazirani>(n, false);
SimulationTask const simulationTask(std::move(qc));
const auto result = hybridSimulatorAmplitudeExecutor->execute(simulationTask);
std::cout << result << "\n";
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() >
1000000);
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() <
300000000);
}

TEST(SimExecBenchmarkBerstein, HybridSimulatorDDExec) {
auto hybridSimulatorDDExecutor =
std::make_unique<HybridSimulatorDDExecutor>();
std::size_t const n = 40;
auto qc = std::make_unique<qc::BernsteinVazirani>(n, false);
SimulationTask const simulationTask(std::move(qc));
const auto result = hybridSimulatorDDExecutor->execute(simulationTask);
std::cout << result << "\n";
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() >
1000000);
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() <
300000000);
}

TEST(SimExecBenchmarkBerstein, StochasticNoiseSimulatorExec) {
auto stochasticNoiseSimulatorExecutor =
std::make_unique<StochasticNoiseSimulatorExecutor>();
std::size_t const n = 30;
auto qc = std::make_unique<qc::BernsteinVazirani>(n, false);
SimulationTask const simulationTask(std::move(qc));
const auto result = stochasticNoiseSimulatorExecutor->execute(simulationTask);
std::cout << result << "\n";
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() >
1000000);
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() <
300000000);
}

// Gives "C++ exception with description "Unsupported non-unitary functionality
// 'Rst '." thrown in the test body." when run in dynamic
39 changes: 39 additions & 0 deletions benchmarks/benchmark_simexec_ghz.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "QuantumComputation.hpp"
#include "algorithms/Entanglement.hpp"
#include "executors/CircuitSimulatorExecutor.hpp"
#include "executors/DeterministicNoiseSimExecutor.hpp"
#include "executors/HybridSimulatorAmplitudeExecutor.hpp"
#include "tasks/SimulationTask.hpp"

#include "gtest/gtest.h"

TEST(SimExecBenchmarkGHZ, HybridSimulatorAmplitudeExec) {
auto hybridSimulatorAmplitudeExecutor =
std::make_unique<HybridSimulatorAmplitudeExecutor>();
auto qc = std::make_unique<qc::Entanglement>(25);
SimulationTask const simulationTask(std::move(qc));
const auto result = hybridSimulatorAmplitudeExecutor->execute(simulationTask);
std::cout << result << "\n";
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() >
1000000);
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() <
300000000);
}

TEST(SimExecBenchmarkGHZ, DeterministicNoiseSimExec) {
auto deterministicNoiseSimulatorExecutor =
std::make_unique<DeterministicNoiseSimExecutor>();
auto qc = std::make_unique<qc::Entanglement>(20);
SimulationTask const simulationTask(std::move(qc));
const auto result =
deterministicNoiseSimulatorExecutor->execute(simulationTask);
std::cout << result << "\n";
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() >
1000000);
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() <
300000000);
}
55 changes: 55 additions & 0 deletions benchmarks/benchmark_simexec_grover.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "QuantumComputation.hpp"
#include "algorithms/Grover.hpp"
#include "executors/CircuitSimulatorExecutor.hpp"
#include "executors/UnitarySimRecursiveExecutor.hpp"
#include "executors/UnitarySimSequentialExecutor.hpp"
#include "tasks/SimulationTask.hpp"

#include "gtest/gtest.h"

TEST(SimExecBenchmarkGrover, CircuitSimulatorExec) {
auto circuitSimulatorExecutor = std::make_unique<CircuitSimulatorExecutor>();
std::size_t const n = 25;
auto qc = std::make_unique<qc::Grover>(n);
SimulationTask const simulationTask(std::move(qc));
const auto result = circuitSimulatorExecutor->execute(simulationTask);
std::cout << result << "\n";
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() >
1000000);
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() <
300000000);
}

TEST(SimExecBenchmarkGrover, UnitarySimSequentialExec) {
auto unitarySimSequentialExecutor =
std::make_unique<UnitarySimSequentialExecutor>();
std::size_t const n = 22;
auto qc = std::make_unique<qc::Grover>(n);
SimulationTask const simulationTask(std::move(qc));
const auto result = unitarySimSequentialExecutor->execute(simulationTask);
std::cout << result << "\n";
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() >
1000000);
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() <
300000000);
}

TEST(SimExecBenchmarkGrover, UnitarySimRecursiveExec) {
auto unitarySimRecursiveExecutor =
std::make_unique<UnitarySimRecursiveExecutor>();
std::size_t const n = 22;
auto qc = std::make_unique<qc::Grover>(n);
SimulationTask const simulationTask(std::move(qc));
const auto result = unitarySimRecursiveExecutor->execute(simulationTask);
std::cout << result << "\n";
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() >
1000000);
EXPECT_TRUE(result["construction_time"].get<int>() +
result["execution_time"].get<int>() <
300000000);
}
38 changes: 38 additions & 0 deletions benchmarks/benchmark_simexec_qpe.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include "algorithms/QPE.hpp"
#include "executors/CircuitSimulatorExecutor.hpp"
#include "executors/UnitarySimRecursiveExecutor.hpp"
#include "executors/UnitarySimSequentialExecutor.hpp"
#include "tasks/SimulationTask.hpp"

#include "gtest/gtest.h"

// QPE fails from n=65 on in ComplexTable line 151. See if later versions of the
// dd package can fix this.

TEST(SimExecBenchmarkQPE, CircuitSimulatorExec) {
auto circuitSimulatorExecutor = std::make_unique<CircuitSimulatorExecutor>();
std::size_t const n = 65;
auto qc = std::make_unique<qc::QPE>(n, true, false);
SimulationTask const simulationTask(std::move(qc));
EXPECT_DEATH(circuitSimulatorExecutor->execute(simulationTask), "Assertion");
}

TEST(SimExecBenchmarkQPE, UnitarySimRecursiveExec) {
auto unitarySimRecursiveExecutor =
std::make_unique<UnitarySimRecursiveExecutor>();
std::size_t const n = 65;
auto qc = std::make_unique<qc::QPE>(n, true, false);
SimulationTask const simulationTask(std::move(qc));
EXPECT_DEATH(unitarySimRecursiveExecutor->execute(simulationTask),
"Assertion");
}

TEST(SimExecBenchmarkQPE, UnitarySimSequentialExec) {
auto unitarySimSequentialExecutor =
std::make_unique<UnitarySimSequentialExecutor>();
std::size_t const n = 65;
auto qc = std::make_unique<qc::QPE>(n, true, false);
SimulationTask const simulationTask(std::move(qc));
EXPECT_DEATH(unitarySimSequentialExecutor->execute(simulationTask),
"Assertion");
}
13 changes: 13 additions & 0 deletions include/executors/DeterministicNoiseSimExecutor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include "Executor.hpp"
#include "tasks/SimulationTask.hpp"

class DeterministicNoiseSimExecutor : public Executor<SimulationTask> {
public:
json execute(const SimulationTask& task) override;

[[nodiscard]] std::string getIdentifier() const override {
return "deterministic_noise_simulator";
};
};
13 changes: 13 additions & 0 deletions include/executors/HybridSimulatorAmplitudeExecutor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include "Executor.hpp"
#include "tasks/SimulationTask.hpp"

class HybridSimulatorAmplitudeExecutor : public Executor<SimulationTask> {
public:
json execute(const SimulationTask& task) override;

[[nodiscard]] std::string getIdentifier() const override {
return "hybrid_schrodinger_feynman_simulator_amplitude";
};
};
13 changes: 13 additions & 0 deletions include/executors/HybridSimulatorDDExecutor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include "Executor.hpp"
#include "tasks/SimulationTask.hpp"

class HybridSimulatorDDExecutor : public Executor<SimulationTask> {
public:
json execute(const SimulationTask& task) override;

[[nodiscard]] std::string getIdentifier() const override {
return "hybrid_schrodinger_feynman_simulator_dd";
};
};
13 changes: 13 additions & 0 deletions include/executors/StochasticNoiseSimulatorExecutor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include "Executor.hpp"
#include "tasks/SimulationTask.hpp"

class StochasticNoiseSimulatorExecutor : public Executor<SimulationTask> {
public:
json execute(const SimulationTask& task) override;

[[nodiscard]] std::string getIdentifier() const override {
return "stochastic_noise_simulator";
};
};
13 changes: 13 additions & 0 deletions include/executors/UnitarySimRecursiveExecutor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include "Executor.hpp"
#include "tasks/SimulationTask.hpp"

class UnitarySimRecursiveExecutor : public Executor<SimulationTask> {
public:
json execute(const SimulationTask& task) override;

[[nodiscard]] std::string getIdentifier() const override {
return "unitary_simulator_recursive";
};
};
13 changes: 13 additions & 0 deletions include/executors/UnitarySimSequentialExecutor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include "Executor.hpp"
#include "tasks/SimulationTask.hpp"

class UnitarySimSequentialExecutor : public Executor<SimulationTask> {
public:
json execute(const SimulationTask& task) override;

[[nodiscard]] std::string getIdentifier() const override {
return "unitary_simulator_sequential";
};
};
13 changes: 12 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,25 @@ if(NOT TARGET ${PROJECT_NAME})
${PROJECT_SOURCE_DIR}/include/Executor.hpp
${PROJECT_SOURCE_DIR}/include/executors/CircuitSimulatorExecutor.hpp
${PROJECT_SOURCE_DIR}/include/executors/AlternatingVerificationExecutor.hpp
${PROJECT_SOURCE_DIR}/include/executors/HybridSimulatorDDExecutor.hpp
${PROJECT_SOURCE_DIR}/include/executors/HybridSimulatorAmplitudeExecutor.hpp
${PROJECT_SOURCE_DIR}/include/executors/DeterministicNoiseSimExecutor.hpp
${PROJECT_SOURCE_DIR}/include/executors/StochasticNoiseSimulatorExecutor.hpp
${PROJECT_SOURCE_DIR}/include/executors/UnitarySimRecursiveExecutor.hpp
${PROJECT_SOURCE_DIR}/include/executors/UnitarySimSequentialExecutor.hpp
${PROJECT_SOURCE_DIR}/include/Task.hpp
${PROJECT_SOURCE_DIR}/include/tasks/SimulationTask.hpp
${PROJECT_SOURCE_DIR}/include/tasks/VerificationTask.hpp
executors/CircuitSimulatorExecutor.cpp
executors/AlternatingVerificationExecutor.cpp
executors/HybridSimulatorDDExecutor.cpp
executors/HybridSimulatorAmplitudeExecutor.cpp
executors/DeterministicNoiseSimExecutor.cpp
executors/StochasticNoiseSimulatorExecutor.cpp
executors/UnitarySimRecursiveExecutor.cpp
executors/UnitarySimSequentialExecutor.cpp
tasks/SimulationTask.cpp
tasks/VerificationTask.cpp)

# set include directories
target_include_directories(
${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include
Expand Down
3 changes: 2 additions & 1 deletion src/executors/CircuitSimulatorExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ json CircuitSimulatorExecutor::execute(const SimulationTask& task) {
auto const constructionStart = std::chrono::steady_clock::now();

auto qc = std::make_unique<qc::QuantumComputation>(task.getQc()->clone());
auto circuitSimulator = std::make_unique<CircuitSimulator<>>(std::move(qc));
auto circuitSimulator =
std::make_unique<CircuitSimulator<>>(std::move(qc), 23);

auto const executionStart = std::chrono::steady_clock::now();

Expand Down
31 changes: 31 additions & 0 deletions src/executors/DeterministicNoiseSimExecutor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "executors/DeterministicNoiseSimExecutor.hpp"

#include "DeterministicNoiseSimulator.hpp"

json DeterministicNoiseSimExecutor::execute(const SimulationTask& task) {
json result;
auto const constructionStart = std::chrono::steady_clock::now();

auto qc = std::make_unique<qc::QuantumComputation>(task.getQc()->clone());
auto circuitSimulator =
std::make_unique<DeterministicNoiseSimulator<>>(std::move(qc), 23);

auto const executionStart = std::chrono::steady_clock::now();

result["measurement_results"] = circuitSimulator->deterministicSimulate();
// Add memory usage

auto const executionStop = std::chrono::steady_clock::now();
auto const constructionTime =
std::chrono::duration_cast<std::chrono::microseconds>(executionStart -
constructionStart);
auto const execTime = std::chrono::duration_cast<std::chrono::microseconds>(
executionStop - executionStart);
result["construction_time"] = constructionTime.count();
result["execution_time"] = execTime.count();

result["executor"] = getIdentifier();
result["task"] = task.getIdentifier();

return result;
}
Loading