From 47dfabfa72a5041072546e0ce59fd87a2902edb1 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Sat, 1 Apr 2023 13:32:03 +0200 Subject: [PATCH 01/10] =?UTF-8?q?=F0=9F=9A=B8=20replace=20`thread`=20with?= =?UTF-8?q?=20`future`=20and=20`async`=20for=20exception=20propagation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Burgholzer --- src/EquivalenceCheckingManager.cpp | 85 +++++++++++++----------------- 1 file changed, 36 insertions(+), 49 deletions(-) diff --git a/src/EquivalenceCheckingManager.cpp b/src/EquivalenceCheckingManager.cpp index dfbfbf19..4c5b19a2 100644 --- a/src/EquivalenceCheckingManager.cpp +++ b/src/EquivalenceCheckingManager.cpp @@ -10,6 +10,7 @@ #include "zx/FunctionalityConstruction.hpp" #include +#include #include #include #include @@ -469,54 +470,54 @@ void EquivalenceCheckingManager::checkParallel() { ThreadSafeQueue queue{}; std::size_t id = 0U; - // reserve space for the threads - std::vector threads{}; - threads.reserve(effectiveThreads); + // reserve space for the futures received from the async calls + std::vector> futures{}; + futures.reserve(effectiveThreads); if (configuration.execution.runAlternatingChecker) { // start a new thread that constructs and runs the alternating check - threads.emplace_back([this, &queue, id] { + futures.emplace_back(std::async(std::launch::async, [this, &queue, id] { checkers[id] = std::make_unique(qc1, qc2, configuration); checkers[id]->run(); queue.push(id); - }); + })); ++id; } if (configuration.execution.runConstructionChecker && !done) { // start a new thread that constructs and runs the construction check - threads.emplace_back([this, &queue, id] { + futures.emplace_back(std::async(std::launch::async, [this, &queue, id] { checkers[id] = std::make_unique(qc1, qc2, configuration); if (!done) { checkers[id]->run(); } queue.push(id); - }); + })); ++id; } if (configuration.execution.runZXChecker && !done) { // start a new thread that constructs and runs the ZX checker - threads.emplace_back([this, &queue, id] { + futures.emplace_back(std::async(std::launch::async, [this, &queue, id] { checkers[id] = std::make_unique(qc1, qc2, configuration); if (!done) { checkers[id]->run(); } queue.push(id); - }); + })); ++id; } if (configuration.execution.runSimulationChecker) { - const auto effectiveThreadsLeft = effectiveThreads - threads.size(); + const auto effectiveThreadsLeft = effectiveThreads - futures.size(); const auto simulationsToStart = std::min(effectiveThreadsLeft, configuration.simulation.maxSims); // launch as many simulations as possible for (std::size_t i = 0; i < simulationsToStart && !done; ++i) { - threads.emplace_back([this, &queue, id] { + futures.emplace_back(std::async(std::launch::async, [this, &queue, id] { checkers[id] = std::make_unique(qc1, qc2, configuration); auto* const checker = @@ -529,7 +530,7 @@ void EquivalenceCheckingManager::checkParallel() { checkers[id]->run(); } queue.push(id); - }); + })); ++id; ++results.startedSimulations; } @@ -552,8 +553,9 @@ void EquivalenceCheckingManager::checkParallel() { } // otherwise, a checker has finished its execution - // join the respective thread (which should return immediately) - threads.at(*completedID).join(); + // get the result of the future (which should be ready) + // this makes sure exceptions are thrown if necessary + futures.at(*completedID).get(); // in case non-equivalence has been shown, the execution can be stopped const auto* const checker = checkers.at(*completedID).get(); @@ -685,18 +687,19 @@ void EquivalenceCheckingManager::checkParallel() { // it has to be checked, whether further simulations shall be // conducted if (results.startedSimulations < configuration.simulation.maxSims) { - threads[*completedID] = std::thread([&, this, id = *completedID] { - auto* const simChecker = - dynamic_cast(checkers[id].get()); - { - const std::lock_guard stateGeneratorLock(stateGeneratorMutex); - simChecker->setRandomInitialState(stateGenerator); - } - if (!done) { - checkers[id]->run(); - } - queue.push(id); - }); + futures[*completedID] = + std::async(std::launch::async, [this, &queue, id = *completedID] { + auto* const simChecker = + dynamic_cast(checkers[id].get()); + { + const std::lock_guard stateGeneratorLock(stateGeneratorMutex); + simChecker->setRandomInitialState(stateGenerator); + } + if (!done) { + checkers[id]->run(); + } + queue.push(id); + }); ++results.startedSimulations; } } @@ -705,29 +708,13 @@ void EquivalenceCheckingManager::checkParallel() { const auto end = std::chrono::steady_clock::now(); results.checkTime = std::chrono::duration(end - start).count(); - // cleanup threads that are still running by joining them - // start by joining all the completed threads, which should succeed - // instantly - while (!queue.empty()) { - const auto completedID = queue.waitAndPop(); - auto& thread = threads.at(*completedID); - if (thread.joinable()) { - thread.join(); - } - } - - // afterwards, join all threads that are still (potentially) running. - // at the moment there seems to be no solution for prematurely killing - // running threads without risking synchronisation issues. on the positive - // side, joining should avoid all of these potential issues on the - // negative side, one of the threads might still be stuck in a - // long-running operation and does not check for the `done` signal until - // this operation completes - for (auto& thread : threads) { - if (thread.joinable()) { - thread.join(); - } - } + // Futures are not explicitly waited for here, since the destructor of the + // `std::future` object will block until the associated thread has finished. + // If any thread is still stuck in a long-running operation, this might take a + // while, but the program will terminate anyway. C++20 introduces + // `std::jthread`, which allows to explicitly cancel a thread. This could be a + // solution for the future to avoid this problem (and reduce the number of + // `isDone` checks). } void EquivalenceCheckingManager::checkSymbolic() { From f95343ec7ce06ad5555759c01e767a72342c1910 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Sat, 1 Apr 2023 13:32:21 +0200 Subject: [PATCH 02/10] =?UTF-8?q?=F0=9F=9A=A8=20more=20explicit=20lambda?= =?UTF-8?q?=20captures?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Burgholzer --- src/EquivalenceCheckingManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/EquivalenceCheckingManager.cpp b/src/EquivalenceCheckingManager.cpp index 4c5b19a2..e3046038 100644 --- a/src/EquivalenceCheckingManager.cpp +++ b/src/EquivalenceCheckingManager.cpp @@ -723,11 +723,11 @@ void EquivalenceCheckingManager::checkSymbolic() { // sets the `done` flag after the timeout has passed std::thread timeoutThread{}; if (configuration.execution.timeout > 0.) { - timeoutThread = std::thread([&, timeout = std::chrono::duration( - configuration.execution.timeout)] { + timeoutThread = std::thread([this, timeout = std::chrono::duration( + configuration.execution.timeout)] { std::unique_lock doneLock(doneMutex); auto finished = - doneCond.wait_for(doneLock, timeout, [&] { return done; }); + doneCond.wait_for(doneLock, timeout, [this] { return done; }); // if the thread has already finished within the timeout, // nothing has to be done if (!finished) { From 8e980d7fe4977d190b39707d15b4d887460178a9 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Sat, 1 Apr 2023 19:14:48 +0200 Subject: [PATCH 03/10] =?UTF-8?q?=F0=9F=A9=B9=20fix=20constructor=20errone?= =?UTF-8?q?ously=20being=20marked=20`noexcept`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Burgholzer --- include/checker/dd/DDSimulationChecker.hpp | 2 +- src/checker/dd/DDSimulationChecker.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/checker/dd/DDSimulationChecker.hpp b/include/checker/dd/DDSimulationChecker.hpp index 486f9219..ce581196 100644 --- a/include/checker/dd/DDSimulationChecker.hpp +++ b/include/checker/dd/DDSimulationChecker.hpp @@ -14,7 +14,7 @@ class DDSimulationChecker final public: DDSimulationChecker(const qc::QuantumComputation& circ1, const qc::QuantumComputation& circ2, - Configuration configuration) noexcept; + Configuration configuration); void setRandomInitialState(StateGenerator& generator); diff --git a/src/checker/dd/DDSimulationChecker.cpp b/src/checker/dd/DDSimulationChecker.cpp index 02328004..1c9bd5d6 100644 --- a/src/checker/dd/DDSimulationChecker.cpp +++ b/src/checker/dd/DDSimulationChecker.cpp @@ -8,7 +8,7 @@ namespace ec { DDSimulationChecker::DDSimulationChecker(const qc::QuantumComputation& circ1, const qc::QuantumComputation& circ2, - Configuration config) noexcept + Configuration config) : DDEquivalenceChecker(circ1, circ2, std::move(config)) { initialState = dd->makeZeroState(static_cast(nqubits)); initializeApplicationScheme(configuration.application.simulationScheme); From 4240600f86a2f18bfff0aa0a691df46c8fde0606 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Sat, 1 Apr 2023 19:20:13 +0200 Subject: [PATCH 04/10] =?UTF-8?q?=E2=9C=85=20add=20test=20for=20exception?= =?UTF-8?q?=20propagation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Burgholzer --- test/python/test_verify.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/python/test_verify.py b/test/python/test_verify.py index 6ae13538..1fbf861d 100644 --- a/test/python/test_verify.py +++ b/test/python/test_verify.py @@ -76,3 +76,20 @@ def test_compiled_circuit_without_measurements() -> None: result = qcec.verify(qc, qc_compiled) assert result.equivalence == qcec.EquivalenceCriterion.equivalent + + +def test_cpp_exception_propagation() -> None: + """Test that exceptions thrown in the C++ code are propagated correctly.""" + qc = QuantumCircuit(1) + qc.x(0) + + config = qcec.Configuration() + config.execution.run_alternating_checker = False + config.execution.run_simulation_checker = True + config.execution.run_construction_checker = False + config.execution.run_zx_checker = False + config.application.simulation_scheme = qcec.ApplicationScheme.lookahead + config.simulation.max_sims = 1 + + with pytest.raises(ValueError, match="Lookahead application scheme can only be used for matrices."): + qcec.verify(qc, qc, configuration=config) From 76f6eb95ae7d0a6c0dc9cba20af34e30891f54fc Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Sun, 2 Apr 2023 12:01:40 +0200 Subject: [PATCH 05/10] =?UTF-8?q?=F0=9F=A9=B9=20fix=20constructor=20errone?= =?UTF-8?q?ously=20being=20marked=20`noexcept`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Burgholzer --- include/checker/dd/DDEquivalenceChecker.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/checker/dd/DDEquivalenceChecker.hpp b/include/checker/dd/DDEquivalenceChecker.hpp index b018aace..9b9b4122 100644 --- a/include/checker/dd/DDEquivalenceChecker.hpp +++ b/include/checker/dd/DDEquivalenceChecker.hpp @@ -21,7 +21,7 @@ class DDEquivalenceChecker : public EquivalenceChecker { public: DDEquivalenceChecker(const qc::QuantumComputation& circ1, const qc::QuantumComputation& circ2, - Configuration config) noexcept + Configuration config) : EquivalenceChecker(circ1, circ2, std::move(config)), dd(std::make_unique>(nqubits)), taskManager1(TaskManager(circ1, dd)), From dd2ec00b1527578bfa193ba8f8bab163e057ae75 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Sun, 2 Apr 2023 12:03:30 +0200 Subject: [PATCH 06/10] =?UTF-8?q?=F0=9F=A9=B9=20add=20`try/catch`=20block?= =?UTF-8?q?=20around=20parallel=20code=20regions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Burgholzer --- src/EquivalenceCheckingManager.cpp | 93 +++++++++++++++++++----------- 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/src/EquivalenceCheckingManager.cpp b/src/EquivalenceCheckingManager.cpp index e3046038..c7a03a9b 100644 --- a/src/EquivalenceCheckingManager.cpp +++ b/src/EquivalenceCheckingManager.cpp @@ -477,10 +477,15 @@ void EquivalenceCheckingManager::checkParallel() { if (configuration.execution.runAlternatingChecker) { // start a new thread that constructs and runs the alternating check futures.emplace_back(std::async(std::launch::async, [this, &queue, id] { - checkers[id] = - std::make_unique(qc1, qc2, configuration); - checkers[id]->run(); - queue.push(id); + try { + checkers[id] = + std::make_unique(qc1, qc2, configuration); + checkers[id]->run(); + queue.push(id); + } catch (const std::exception& e) { + queue.push(id); + throw; + } })); ++id; } @@ -488,12 +493,17 @@ void EquivalenceCheckingManager::checkParallel() { if (configuration.execution.runConstructionChecker && !done) { // start a new thread that constructs and runs the construction check futures.emplace_back(std::async(std::launch::async, [this, &queue, id] { - checkers[id] = - std::make_unique(qc1, qc2, configuration); - if (!done) { - checkers[id]->run(); + try { + checkers[id] = + std::make_unique(qc1, qc2, configuration); + if (!done) { + checkers[id]->run(); + } + queue.push(id); + } catch (const std::exception& e) { + queue.push(id); + throw; } - queue.push(id); })); ++id; } @@ -501,12 +511,17 @@ void EquivalenceCheckingManager::checkParallel() { if (configuration.execution.runZXChecker && !done) { // start a new thread that constructs and runs the ZX checker futures.emplace_back(std::async(std::launch::async, [this, &queue, id] { - checkers[id] = - std::make_unique(qc1, qc2, configuration); - if (!done) { - checkers[id]->run(); + try { + checkers[id] = + std::make_unique(qc1, qc2, configuration); + if (!done) { + checkers[id]->run(); + } + queue.push(id); + } catch (const std::exception& e) { + queue.push(id); + throw; } - queue.push(id); })); ++id; } @@ -518,18 +533,23 @@ void EquivalenceCheckingManager::checkParallel() { // launch as many simulations as possible for (std::size_t i = 0; i < simulationsToStart && !done; ++i) { futures.emplace_back(std::async(std::launch::async, [this, &queue, id] { - checkers[id] = - std::make_unique(qc1, qc2, configuration); - auto* const checker = - dynamic_cast(checkers[id].get()); - { - const std::lock_guard stateGeneratorLock(stateGeneratorMutex); - checker->setRandomInitialState(stateGenerator); - } - if (!done) { - checkers[id]->run(); + try { + checkers[id] = + std::make_unique(qc1, qc2, configuration); + auto* const checker = + dynamic_cast(checkers[id].get()); + { + const std::lock_guard stateGeneratorLock(stateGeneratorMutex); + checker->setRandomInitialState(stateGenerator); + } + if (!done) { + checkers[id]->run(); + } + queue.push(id); + } catch (const std::exception& e) { + queue.push(id); + throw; } - queue.push(id); })); ++id; ++results.startedSimulations; @@ -689,16 +709,21 @@ void EquivalenceCheckingManager::checkParallel() { if (results.startedSimulations < configuration.simulation.maxSims) { futures[*completedID] = std::async(std::launch::async, [this, &queue, id = *completedID] { - auto* const simChecker = - dynamic_cast(checkers[id].get()); - { - const std::lock_guard stateGeneratorLock(stateGeneratorMutex); - simChecker->setRandomInitialState(stateGenerator); - } - if (!done) { - checkers[id]->run(); + try { + auto* const simChecker = + dynamic_cast(checkers[id].get()); + { + const std::lock_guard stateGeneratorLock(stateGeneratorMutex); + simChecker->setRandomInitialState(stateGenerator); + } + if (!done) { + checkers[id]->run(); + } + queue.push(id); + } catch (const std::exception& e) { + queue.push(id); + throw; } - queue.push(id); }); ++results.startedSimulations; } From cf120c42a2510450d65b143ff6dd3b6289966c1c Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Sun, 2 Apr 2023 12:04:23 +0200 Subject: [PATCH 07/10] =?UTF-8?q?=E2=9C=85=20add=20further=20test=20for=20?= =?UTF-8?q?exception=20propagation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Burgholzer --- test/python/test_verify.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/test/python/test_verify.py b/test/python/test_verify.py index 1fbf861d..9f43a2e3 100644 --- a/test/python/test_verify.py +++ b/test/python/test_verify.py @@ -78,8 +78,8 @@ def test_compiled_circuit_without_measurements() -> None: assert result.equivalence == qcec.EquivalenceCriterion.equivalent -def test_cpp_exception_propagation() -> None: - """Test that exceptions thrown in the C++ code are propagated correctly.""" +def test_cpp_exception_propagation_internal() -> None: + """Test that C++ exceptions caused by code within QCEC are propagated correctly.""" qc = QuantumCircuit(1) qc.x(0) @@ -89,7 +89,18 @@ def test_cpp_exception_propagation() -> None: config.execution.run_construction_checker = False config.execution.run_zx_checker = False config.application.simulation_scheme = qcec.ApplicationScheme.lookahead - config.simulation.max_sims = 1 with pytest.raises(ValueError, match="Lookahead application scheme can only be used for matrices."): qcec.verify(qc, qc, configuration=config) + + +def test_cpp_exception_propagation_external() -> None: + """Test that C++ exceptions caused by code outside of QCEC are propagated correctly.""" + qc = QuantumCircuit(129) + qc.x(range(129)) + + config = qcec.Configuration() + config.execution.run_zx_checker = False + + with pytest.raises(ValueError, match="Requested too many qubits from package."): + qcec.verify(qc, qc, configuration=config) From ae615421d56da29e8dd9487a791950b88ff11ac0 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Sun, 2 Apr 2023 12:20:30 +0200 Subject: [PATCH 08/10] =?UTF-8?q?=E2=9C=85=20add=20tests=20on=20the=20C++?= =?UTF-8?q?=20side=20as=20well?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Burgholzer --- test/test_equality.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/test_equality.cpp b/test/test_equality.cpp index d8361e6d..bfa66bb4 100644 --- a/test/test_equality.cpp +++ b/test/test_equality.cpp @@ -165,3 +165,30 @@ TEST_F(EqualityTest, AutomaticSwitchToConstructionChecker) { ecm.setParallel(false); EXPECT_THROW(ecm.run(), std::invalid_argument); } + +TEST_F(EqualityTest, ExceptionInParallelThread) { + qc1.x(0); + + config = ec::Configuration{}; + config.execution.runAlternatingChecker = false; + config.execution.runConstructionChecker = false; + config.execution.runSimulationChecker = true; + config.execution.runZXChecker = false; + config.application.simulationScheme = ec::ApplicationSchemeType::Lookahead; + + ec::EquivalenceCheckingManager ecm(qc1, qc1, config); + EXPECT_THROW(ecm.run(), std::invalid_argument); +} + +TEST_F(EqualityTest, ExceptionInParallelThread2) { + qc1.addQubitRegister(128U); + for (auto i = 0U; i <= 128U; ++i) { + qc1.x(i); + } + + config = ec::Configuration{}; + config.execution.runZXChecker = false; + + ec::EquivalenceCheckingManager ecm(qc1, qc1, config); + EXPECT_THROW(ecm.run(), std::invalid_argument); +} From 1684c7318a5010c16ef240bd65e185057eb5342b Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Sun, 2 Apr 2023 13:00:24 +0200 Subject: [PATCH 09/10] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20extract=20asynchrono?= =?UTF-8?q?us=20creation=20and=20starting=20of=20checkers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Burgholzer --- include/EquivalenceCheckingManager.hpp | 44 ++++++++++++++ src/EquivalenceCheckingManager.cpp | 80 ++------------------------ 2 files changed, 49 insertions(+), 75 deletions(-) diff --git a/include/EquivalenceCheckingManager.hpp b/include/EquivalenceCheckingManager.hpp index 2fe2fd84..b071b460 100644 --- a/include/EquivalenceCheckingManager.hpp +++ b/include/EquivalenceCheckingManager.hpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -277,6 +278,49 @@ class EquivalenceCheckingManager { } } + /// \brief Run an EquivalenceChecker asynchronously + /// + /// This function is used to asynchronously run an EquivalenceChecker. It also + /// takes care of creating the checker if it does not exist yet. Additionally, + /// it takes care that the checker signals the main thread when it is done + /// (even in case of an exception). + /// + /// \tparam Checker The type of the checker (must be derived from the + /// EquivalenceChecker class). + /// \param id The id in the checkers vector where the checker is stored. + /// \param queue The queue to which the checker shall push its id + /// once it is done. + /// \return A future that can be used to wait for the checker to finish. + template + std::future asyncRunChecker(const std::size_t id, + ThreadSafeQueue& queue) { + static_assert(std::is_base_of_v, + "Checker must be derived from EquivalenceChecker"); + return std::async(std::launch::async, [this, id, &queue]() { + try { + auto& checker = checkers[id]; + if (!checker) { + checker = std::make_unique(qc1, qc2, configuration); + } + + if constexpr (std::is_same_v) { + auto* const simChecker = + dynamic_cast(checker.get()); + const std::lock_guard stateGeneratorLock(stateGeneratorMutex); + simChecker->setRandomInitialState(stateGenerator); + } + + if (!done) { + checker->run(); + } + queue.push(id); + } catch (const std::exception& e) { + queue.push(id); + throw; + } + }); + } + [[nodiscard]] bool simulationsFinished() const { return results.performedSimulations == configuration.simulation.maxSims; } diff --git a/src/EquivalenceCheckingManager.cpp b/src/EquivalenceCheckingManager.cpp index c7a03a9b..8200b9b3 100644 --- a/src/EquivalenceCheckingManager.cpp +++ b/src/EquivalenceCheckingManager.cpp @@ -10,7 +10,6 @@ #include "zx/FunctionalityConstruction.hpp" #include -#include #include #include #include @@ -476,53 +475,19 @@ void EquivalenceCheckingManager::checkParallel() { if (configuration.execution.runAlternatingChecker) { // start a new thread that constructs and runs the alternating check - futures.emplace_back(std::async(std::launch::async, [this, &queue, id] { - try { - checkers[id] = - std::make_unique(qc1, qc2, configuration); - checkers[id]->run(); - queue.push(id); - } catch (const std::exception& e) { - queue.push(id); - throw; - } - })); + futures.emplace_back(asyncRunChecker(id, queue)); ++id; } if (configuration.execution.runConstructionChecker && !done) { // start a new thread that constructs and runs the construction check - futures.emplace_back(std::async(std::launch::async, [this, &queue, id] { - try { - checkers[id] = - std::make_unique(qc1, qc2, configuration); - if (!done) { - checkers[id]->run(); - } - queue.push(id); - } catch (const std::exception& e) { - queue.push(id); - throw; - } - })); + futures.emplace_back(asyncRunChecker(id, queue)); ++id; } if (configuration.execution.runZXChecker && !done) { // start a new thread that constructs and runs the ZX checker - futures.emplace_back(std::async(std::launch::async, [this, &queue, id] { - try { - checkers[id] = - std::make_unique(qc1, qc2, configuration); - if (!done) { - checkers[id]->run(); - } - queue.push(id); - } catch (const std::exception& e) { - queue.push(id); - throw; - } - })); + futures.emplace_back(asyncRunChecker(id, queue)); ++id; } @@ -532,25 +497,7 @@ void EquivalenceCheckingManager::checkParallel() { std::min(effectiveThreadsLeft, configuration.simulation.maxSims); // launch as many simulations as possible for (std::size_t i = 0; i < simulationsToStart && !done; ++i) { - futures.emplace_back(std::async(std::launch::async, [this, &queue, id] { - try { - checkers[id] = - std::make_unique(qc1, qc2, configuration); - auto* const checker = - dynamic_cast(checkers[id].get()); - { - const std::lock_guard stateGeneratorLock(stateGeneratorMutex); - checker->setRandomInitialState(stateGenerator); - } - if (!done) { - checkers[id]->run(); - } - queue.push(id); - } catch (const std::exception& e) { - queue.push(id); - throw; - } - })); + futures.emplace_back(asyncRunChecker(id, queue)); ++id; ++results.startedSimulations; } @@ -707,24 +654,7 @@ void EquivalenceCheckingManager::checkParallel() { // it has to be checked, whether further simulations shall be // conducted if (results.startedSimulations < configuration.simulation.maxSims) { - futures[*completedID] = - std::async(std::launch::async, [this, &queue, id = *completedID] { - try { - auto* const simChecker = - dynamic_cast(checkers[id].get()); - { - const std::lock_guard stateGeneratorLock(stateGeneratorMutex); - simChecker->setRandomInitialState(stateGenerator); - } - if (!done) { - checkers[id]->run(); - } - queue.push(id); - } catch (const std::exception& e) { - queue.push(id); - throw; - } - }); + futures[*completedID] = asyncRunChecker(id, queue); ++results.startedSimulations; } } From 4e867e854fc19bda7d68dc4679b86366432a54ee Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Sun, 2 Apr 2023 13:39:54 +0200 Subject: [PATCH 10/10] =?UTF-8?q?=F0=9F=A9=B9=20fix=20ID=20passed=20to=20s?= =?UTF-8?q?imulation=20checker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Burgholzer --- src/EquivalenceCheckingManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/EquivalenceCheckingManager.cpp b/src/EquivalenceCheckingManager.cpp index 8200b9b3..1d073119 100644 --- a/src/EquivalenceCheckingManager.cpp +++ b/src/EquivalenceCheckingManager.cpp @@ -654,7 +654,8 @@ void EquivalenceCheckingManager::checkParallel() { // it has to be checked, whether further simulations shall be // conducted if (results.startedSimulations < configuration.simulation.maxSims) { - futures[*completedID] = asyncRunChecker(id, queue); + futures[*completedID] = + asyncRunChecker(*completedID, queue); ++results.startedSimulations; } }