diff --git a/CMakeLists.txt b/CMakeLists.txt index efffad5..acfdb88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,8 +113,8 @@ set(QIREE_RUNTIME_OUTPUT_DIRECTORY enable_language(C) # Needed for LLVM find_package(LLVM REQUIRED) if((LLVM_VERSION VERSION_LESS 14) - OR (LLVM_VERSION VERSION_GREATER_EQUAL 20)) - message(WARNING "QIR-EE is only tested with LLVM 14-19: found version ${LLVM_VERSION}") + OR (LLVM_VERSION VERSION_GREATER_EQUAL 21)) + message(WARNING "QIR-EE is only tested with LLVM 14-20: found version ${LLVM_VERSION}") endif() if(QIREE_USE_QSIM) diff --git a/app/qir-qsim.cc b/app/qir-qsim.cc index 57368d0..f9f5dd5 100644 --- a/app/qir-qsim.cc +++ b/app/qir-qsim.cc @@ -3,7 +3,7 @@ // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //---------------------------------------------------------------------------// -//! \file qir-xacc/qir-xacc.cc +//! \file qir-qsim/qir-qsim.cc //---------------------------------------------------------------------------// #include #include @@ -13,8 +13,8 @@ #include "qiree/Executor.hh" #include "qiree/Module.hh" #include "qiree/ResultDistribution.hh" -#include "qirqsim/QsimDefaultRuntime.hh" #include "qirqsim/QsimQuantum.hh" +#include "qirqsim/QsimRuntime.hh" using namespace std::string_view_literals; @@ -30,7 +30,7 @@ void run(std::string const& filename, int num_shots) // Set up qsim QsimQuantum sim(std::cout, 0); - QsimDefaultRuntime rt(std::cout, sim); + QsimRuntime rt(std::cout, sim); ResultDistribution distribution; // Run several time = shots (default 1) diff --git a/src/qiree/CMakeLists.txt b/src/qiree/CMakeLists.txt index 88ad986..5dbe211 100644 --- a/src/qiree/CMakeLists.txt +++ b/src/qiree/CMakeLists.txt @@ -19,6 +19,7 @@ qiree_add_library(qiree Module.cc Executor.cc ResultDistribution.cc + SingleResultRuntime.cc QuantumNotImpl.cc ) target_compile_features(qiree PUBLIC cxx_std_17) diff --git a/src/qiree/QuantumInterface.hh b/src/qiree/QuantumInterface.hh index ae2e69b..0de15cf 100644 --- a/src/qiree/QuantumInterface.hh +++ b/src/qiree/QuantumInterface.hh @@ -61,7 +61,7 @@ class QuantumInterface virtual Result measure(Array, Array) = 0; //!< body virtual Result mresetz(Qubit) = 0; //!< body virtual void mz(Qubit, Result) = 0; //!< body - virtual QState read_result(Result) = 0; //!< body + virtual QState read_result(Result) const = 0; //!< body //@} //@{ diff --git a/src/qiree/QuantumNotImpl.cc b/src/qiree/QuantumNotImpl.cc index 7b28840..94fccd2 100644 --- a/src/qiree/QuantumNotImpl.cc +++ b/src/qiree/QuantumNotImpl.cc @@ -28,7 +28,7 @@ void QuantumNotImpl::mz(Qubit, Result) { QIREE_NOT_IMPLEMENTED("quantum instruction 'mz.body'"); } -QState QuantumNotImpl::read_result(Result) +QState QuantumNotImpl::read_result(Result) const { QIREE_NOT_IMPLEMENTED("quantum instruction 'read_result.body'"); } diff --git a/src/qiree/QuantumNotImpl.hh b/src/qiree/QuantumNotImpl.hh index b6a93cd..2e1633c 100644 --- a/src/qiree/QuantumNotImpl.hh +++ b/src/qiree/QuantumNotImpl.hh @@ -25,7 +25,7 @@ class QuantumNotImpl : virtual public QuantumInterface Result measure(Array, Array) override; Result mresetz(Qubit) override; void mz(Qubit, Result) override; - QState read_result(Result) override; + QState read_result(Result) const override; //@} //@{ diff --git a/src/qiree/RecordedResult.hh b/src/qiree/RecordedResult.hh index 78320ad..5822cb7 100644 --- a/src/qiree/RecordedResult.hh +++ b/src/qiree/RecordedResult.hh @@ -37,7 +37,7 @@ class RecordedResult RecordedResult() = default; // Construct with size and optional label - RecordedResult(std::size_t count, OptionalCString label); + inline RecordedResult(std::size_t count, OptionalCString label); explicit RecordedResult(std::size_t count) : RecordedResult{count, nullptr} { diff --git a/src/qiree/SingleResultRuntime.cc b/src/qiree/SingleResultRuntime.cc new file mode 100644 index 0000000..0912b8f --- /dev/null +++ b/src/qiree/SingleResultRuntime.cc @@ -0,0 +1,37 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2025 UT-Battelle, LLC, and other QIR-EE developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +//---------------------------------------------------------------------------// +//! \file qiree/SingleResultRuntime.cc +//---------------------------------------------------------------------------// +#include "SingleResultRuntime.hh" + +#include "QuantumInterface.hh" + +namespace qiree +{ +//---------------------------------------------------------------------------// +//! Mark the following N results as being part of an array named tag +void SingleResultRuntime::array_record_output(size_type size, + OptionalCString tag) +{ + result_ = RecordedResult(size, tag); +} + +//! Mark the following N results as being part of a tuple named tag +void SingleResultRuntime::tuple_record_output(size_type size, + OptionalCString tag) +{ + result_ = RecordedResult(size, tag); +} + +//! Save one result +void SingleResultRuntime::result_record_output(Result result, + OptionalCString tag) +{ + result_.push_back(sim_->read_result(result), tag); +} + +//---------------------------------------------------------------------------// +} // namespace qiree diff --git a/src/qiree/SingleResultRuntime.hh b/src/qiree/SingleResultRuntime.hh new file mode 100644 index 0000000..c0cc039 --- /dev/null +++ b/src/qiree/SingleResultRuntime.hh @@ -0,0 +1,46 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2025 UT-Battelle, LLC, and other QIR-EE developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +//---------------------------------------------------------------------------// +//! \file qiree/SingleResultRuntime.hh +//---------------------------------------------------------------------------// +#pragma once + +#include "RecordedResult.hh" +#include "RuntimeInterface.hh" +#include "qiree/Assert.hh" + +namespace qiree +{ +class QuantumInterface; +//---------------------------------------------------------------------------// +/*! + * Interface class for recording a single shot per execution. + */ +class SingleResultRuntime : public RuntimeInterface +{ + public: + // Mark the following N results as being part of an array named tag + void array_record_output(size_type size, OptionalCString tag) final; + + // Mark the following N results as being part of a tuple named tag + void tuple_record_output(size_type size, OptionalCString tag) final; + + // Save one result + void result_record_output(Result result, OptionalCString tag) final; + + //! Access the saved results + RecordedResult const& result() const { return result_; } + + protected: + // This class should only be constructed from a daughter + explicit SingleResultRuntime(QuantumInterface const& sim) : sim_{&sim} {} + + private: + QuantumInterface const* sim_; + RecordedResult result_; +}; + +//---------------------------------------------------------------------------// +} // namespace qiree diff --git a/src/qirqsim/CMakeLists.txt b/src/qirqsim/CMakeLists.txt index 0d81dec..1b28bda 100644 --- a/src/qirqsim/CMakeLists.txt +++ b/src/qirqsim/CMakeLists.txt @@ -7,7 +7,7 @@ # Adding qsim as a library to qiree qiree_add_library(qirqsim QsimQuantum.cc - QsimDefaultRuntime.cc + QsimRuntime.cc ) #Link the qsim library to qiree and any other relevant libraries diff --git a/src/qirqsim/QsimDefaultRuntime.hh b/src/qirqsim/QsimDefaultRuntime.hh deleted file mode 100644 index f4e8e4d..0000000 --- a/src/qirqsim/QsimDefaultRuntime.hh +++ /dev/null @@ -1,76 +0,0 @@ -//----------------------------------*-C++-*----------------------------------// -// Copyright 2024 UT-Battelle, LLC, and other QIR-EE developers. -// See the top-level COPYRIGHT file for details. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -//---------------------------------------------------------------------------// -//! \file qirqsim/QsimDefaultRuntime.hh -//---------------------------------------------------------------------------// -#pragma once - -#include "QsimQuantum.hh" -#include "qiree/RecordedResult.hh" - -namespace qiree -{ - -/*! - * Print per-qubit measurement statistics. - * - * Example for three qubits: - * \code - * Measurement output: - * ------------------- - * Number of shots: 1024 - * Number of qubits: 3 - * q0 {0: 542, 1: 482} - * q1 {0: 521, 1: 503} - * q2 {0: 0, 1: 1024} - * - * \endcode - */ - -class QsimDefaultRuntime final : virtual public RuntimeInterface -{ - public: - /*! - * Construct \c QsimDefaultRuntime. - */ - QsimDefaultRuntime(std::ostream& output, QsimQuantum& sim) - : output_(output), sim_(sim) - { - } - - //!@{ - //! \name Runtime interface - - // Initialize the execution environment, resetting qubits - void initialize(OptionalCString env) override; - - //! Mark the following N results as being part of an array named tag - void array_record_output(size_type size, OptionalCString tag) final - { - result_ = RecordedResult(size, tag); - } - - //! Mark the following N results as being part of a tuple named tag - void tuple_record_output(size_type size, OptionalCString tag) final - { - result_ = RecordedResult(size, tag); - } - - //! Save one result - void result_record_output(Result result, OptionalCString tag) final - { - result_.push_back(sim_.get_result(result), tag); - } - //!@} - - RecordedResult const& result() const { return result_; } - - private: - std::ostream& output_; - QsimQuantum& sim_; - RecordedResult result_; -}; - -} // namespace qiree diff --git a/src/qirqsim/QsimQuantum.cc b/src/qirqsim/QsimQuantum.cc index ebccbab..1962fa2 100644 --- a/src/qirqsim/QsimQuantum.cc +++ b/src/qirqsim/QsimQuantum.cc @@ -191,9 +191,11 @@ void QsimQuantum::mz(Qubit q, Result r) * \todo We could add assertions to check that we actually measured into the * given result. */ -QState QsimQuantum::read_result(Result r) +QState QsimQuantum::read_result(Result r) const { - return this->get_result(r); + QIREE_EXPECT(r.value < results_.size()); + auto result_bool = static_cast(results_[r.value]); + return static_cast(result_bool); } //---------------------------------------------------------------------------// diff --git a/src/qirqsim/QsimQuantum.hh b/src/qirqsim/QsimQuantum.hh index 7f2b2bb..44aebc5 100644 --- a/src/qirqsim/QsimQuantum.hh +++ b/src/qirqsim/QsimQuantum.hh @@ -41,8 +41,6 @@ class QsimQuantum final : virtual public QuantumNotImpl //! Number of classical result registers size_type num_results() const { return results_.size(); } - // Get the result from a classical register - inline QState get_result(Result r) const; //!@} //!@{ @@ -57,7 +55,7 @@ class QsimQuantum final : virtual public QuantumNotImpl void mz(Qubit, Result) final; // Read the value of a result. - QState read_result(Result) final; + QState read_result(Result) const final; //!@} //!@{ @@ -110,15 +108,4 @@ class QsimQuantum final : virtual public QuantumNotImpl void add_gate(Ts&&... args); }; -//---------------------------------------------------------------------------// -/*! - * Get the result from a classical register. - */ -QState QsimQuantum::get_result(Result r) const -{ - QIREE_EXPECT(r.value < results_.size()); - auto result_bool = static_cast(results_[r.value]); - return static_cast(result_bool); -} - } // namespace qiree diff --git a/src/qirqsim/QsimDefaultRuntime.cc b/src/qirqsim/QsimRuntime.cc similarity index 64% rename from src/qirqsim/QsimDefaultRuntime.cc rename to src/qirqsim/QsimRuntime.cc index 99fca6a..ce9e65b 100644 --- a/src/qirqsim/QsimDefaultRuntime.cc +++ b/src/qirqsim/QsimRuntime.cc @@ -3,21 +3,31 @@ // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //---------------------------------------------------------------------------// -//! \file qirqsim/QsimDefaultRuntime.cc +//! \file qirqsim/QsimRuntime.cc //---------------------------------------------------------------------------// -#include "QsimDefaultRuntime.hh" +#include "QsimRuntime.hh" #include +#include "QsimQuantum.hh" #include "qiree/Assert.hh" namespace qiree { +//---------------------------------------------------------------------------// +/*! + * Construct with quantum reference to access classical registers. + */ +QsimRuntime::QsimRuntime(std::ostream& output, QsimQuantum const& sim) + : SingleResultRuntime{sim}, output_(output) +{ +} + //---------------------------------------------------------------------------// /*! * Initialize the execution environment, resetting qubits. */ -void QsimDefaultRuntime::initialize(OptionalCString env) +void QsimRuntime::initialize(OptionalCString env) { if (env) { diff --git a/src/qirqsim/QsimRuntime.hh b/src/qirqsim/QsimRuntime.hh new file mode 100644 index 0000000..9bad27e --- /dev/null +++ b/src/qirqsim/QsimRuntime.hh @@ -0,0 +1,37 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2024 UT-Battelle, LLC, and other QIR-EE developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +//---------------------------------------------------------------------------// +//! \file qirqsim/QsimRuntime.hh +//---------------------------------------------------------------------------// +#pragma once + +#include "qiree/SingleResultRuntime.hh" + +namespace qiree +{ +//---------------------------------------------------------------------------// +class QsimQuantum; + +//---------------------------------------------------------------------------// + +class QsimRuntime final : virtual public SingleResultRuntime +{ + public: + // Construct with quantum reference to access classical registers + QsimRuntime(std::ostream& output, QsimQuantum const& sim); + + //!@{ + //! \name Runtime interface + + // Initialize the execution environment, resetting qubits + void initialize(OptionalCString env) override; + + //!@} + + private: + std::ostream& output_; +}; + +} // namespace qiree diff --git a/src/qirxacc/XaccQuantum.cc b/src/qirxacc/XaccQuantum.cc index 336ba9a..13e35c9 100644 --- a/src/qirxacc/XaccQuantum.cc +++ b/src/qirxacc/XaccQuantum.cc @@ -143,7 +143,7 @@ continue: ; preds = %else, %then * * */ -QState XaccQuantum::read_result(Result r) +QState XaccQuantum::read_result(Result r) const { QIREE_EXPECT(r.value < this->num_results()); diff --git a/src/qirxacc/XaccQuantum.hh b/src/qirxacc/XaccQuantum.hh index 5a0c77c..0d8edca 100644 --- a/src/qirxacc/XaccQuantum.hh +++ b/src/qirxacc/XaccQuantum.hh @@ -70,7 +70,7 @@ class XaccQuantum final : virtual public QuantumNotImpl void mz(Qubit, Result) final; // Read the value of a result. - QState read_result(Result) final; + QState read_result(Result) const final; //!@} //!@{ diff --git a/test/qiree/QuantumTestImpl.cc b/test/qiree/QuantumTestImpl.cc index a02a222..f8cc498 100644 --- a/test/qiree/QuantumTestImpl.cc +++ b/test/qiree/QuantumTestImpl.cc @@ -60,7 +60,7 @@ void QuantumTestImpl::mz(Qubit q, Result r) /*! * Read the value of a result. */ -QState QuantumTestImpl::read_result(Result r) +QState QuantumTestImpl::read_result(Result r) const { EXPECT_LT(r.value, this->num_results_); tr_->commands << "read_result(" << r << ")\n"; diff --git a/test/qiree/QuantumTestImpl.hh b/test/qiree/QuantumTestImpl.hh index f89732f..caadb1e 100644 --- a/test/qiree/QuantumTestImpl.hh +++ b/test/qiree/QuantumTestImpl.hh @@ -44,7 +44,7 @@ class QuantumTestImpl final : public QuantumInterface void mz(Qubit, Result) final; // Read the value of a result. - QState read_result(Result) final; + QState read_result(Result) const final; //// Gates //// diff --git a/test/qirqsim/QsimQuantum.test.cc b/test/qirqsim/QsimQuantum.test.cc index 7d2a15a..a0435b7 100644 --- a/test/qirqsim/QsimQuantum.test.cc +++ b/test/qirqsim/QsimQuantum.test.cc @@ -11,7 +11,7 @@ #include "qiree/Types.hh" #include "qiree_test.hh" -#include "qirqsim/QsimDefaultRuntime.hh" +#include "qirqsim/QsimRuntime.hh" namespace qiree { @@ -43,7 +43,7 @@ TEST_F(QsimQuantumTest, sim_dynamicbv) // Create a simulator that will write to the string stream QsimQuantum qsim_sim{os, 0}; - QsimDefaultRuntime qsim_rt{os, qsim_sim}; + QsimRuntime qsim_rt{os, qsim_sim}; // Call functions in the same sequence that dynamicbv.ll would qsim_sim.set_up([] { @@ -67,8 +67,8 @@ TEST_F(QsimQuantumTest, sim_dynamicbv) qsim_rt.array_record_output(2, ""); qsim_rt.result_record_output(R{0}, ""); qsim_rt.result_record_output(R{1}, ""); - EXPECT_EQ(QState::one, qsim_sim.get_result(R{0})); - EXPECT_EQ(QState::one, qsim_sim.get_result(R{1})); + EXPECT_EQ(QState::one, qsim_sim.read_result(R{0})); + EXPECT_EQ(QState::one, qsim_sim.read_result(R{1})); qsim_sim.h(Q{0}); qsim_sim.x(Q{1}); @@ -80,8 +80,8 @@ TEST_F(QsimQuantumTest, sim_dynamicbv) qsim_rt.array_record_output(2, ""); qsim_rt.result_record_output(R{0}, ""); qsim_rt.result_record_output(R{1}, ""); - EXPECT_EQ(QState::zero, qsim_sim.get_result(R{0})); - EXPECT_EQ(QState::zero, qsim_sim.get_result(R{1})); + EXPECT_EQ(QState::zero, qsim_sim.read_result(R{0})); + EXPECT_EQ(QState::zero, qsim_sim.read_result(R{1})); qsim_sim.h(Q{0}); qsim_sim.x(Q{1}); @@ -95,8 +95,8 @@ TEST_F(QsimQuantumTest, sim_dynamicbv) qsim_rt.array_record_output(2, ""); qsim_rt.result_record_output(R{0}, ""); qsim_rt.result_record_output(R{1}, ""); - EXPECT_EQ(QState::one, qsim_sim.get_result(R{0})); - EXPECT_EQ(QState::zero, qsim_sim.get_result(R{1})); + EXPECT_EQ(QState::one, qsim_sim.read_result(R{0})); + EXPECT_EQ(QState::zero, qsim_sim.read_result(R{1})); qsim_sim.tear_down(); } @@ -111,7 +111,7 @@ TEST_F(QsimQuantumTest, result_order) // Create a simulator that will write to the string stream QsimQuantum qis{os, 0}; - QsimDefaultRuntime rt{os, qis}; + QsimRuntime rt{os, qis}; // Call functions in the same sequence that dynamicbv.ll would qis.set_up([] { @@ -124,9 +124,9 @@ TEST_F(QsimQuantumTest, result_order) qis.mz(Q{1}, R{1}); qis.mz(Q{2}, R{0}); std::vector expected; - expected.push_back(static_cast(qis.get_result(R{2}))); - expected.push_back(static_cast(qis.get_result(R{0}))); - expected.push_back(static_cast(qis.get_result(R{1}))); + expected.push_back(static_cast(qis.read_result(R{2}))); + expected.push_back(static_cast(qis.read_result(R{0}))); + expected.push_back(static_cast(qis.read_result(R{1}))); // So the internal result "buffer" is now {true, false, true} rt.array_record_output(3, "array"); rt.result_record_output(R{2}, "foo"); // pushes true