diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index af84b93ce5..6413faa7eb 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -23,4 +23,4 @@ install (FILES nvqir/CircuitSimulator.h nvqir/QIRTypes.h nvqir/Gates.h DESTINATION include/nvqir) -install (FILES cudaq.h DESTINATION include) +install (FILES cudaq.h host_config.h DESTINATION include) diff --git a/runtime/cudaq.h b/runtime/cudaq.h index c797fc9d42..69244dd99d 100644 --- a/runtime/cudaq.h +++ b/runtime/cudaq.h @@ -10,7 +10,7 @@ #include "common/NoiseModel.h" #include "cudaq/qis/qubit_qis.h" - +#include "host_config.h" #include #include @@ -118,9 +118,16 @@ std::string get_kernel_template_function_name(const std::string &funcName) { /// These get_quake overloads can be used for introspection, to look up the /// Quake IR for a specific kernel by providing an instance of the kernel, etc. +#if CUDAQ_USE_STD20 template >, bool> = true> +#else +template >>, + bool> = true> +#endif std::string get_quake(QuantumKernel &&kernel) { // See comment below. if (__internal__::globalFalse) { @@ -135,9 +142,16 @@ std::string get_quake(QuantumKernel &&kernel) { MemberArgs...>()); } +#if CUDAQ_USE_STD20 template >, bool> = true> +#else +template >>, + bool> = true> +#endif std::string get_quake(QuantumKernel &&kernel) { if constexpr (hasToQuakeMethod::value) { return kernel.to_quake(); @@ -172,8 +186,6 @@ inline std::string get_quake(std::string &&functionName) { typedef std::size_t (*KernelArgsCreator)(void **, void **); KernelArgsCreator getArgsCreator(const std::string &kernelName); -/// @brief -/// @return bool kernelHasConditionalFeedback(const std::string &kernelName); /// @brief Provide a hook to set the target backend. diff --git a/runtime/cudaq/algorithms/broadcast.h b/runtime/cudaq/algorithms/broadcast.h index f99019b1f5..aafc96ae16 100644 --- a/runtime/cudaq/algorithms/broadcast.h +++ b/runtime/cudaq/algorithms/broadcast.h @@ -9,22 +9,22 @@ #pragma once #include "cudaq/platform.h" +#include "host_config.h" namespace cudaq { void set_random_seed(std::size_t); std::size_t get_random_seed(); -/// @brief An ArgumentSet is a tuple of vectors of general -/// arguments to a CUDA Quantum kernel. The ith vector of the tuple -/// corresponds to the ith argument of the kernel. The jth element of -/// the ith vector corresponds to the jth batch of arguments to evaluate -/// the kernel at. +/// @brief An ArgumentSet is a tuple of vectors of general arguments to a CUDA +/// Quantum kernel. The `i-th` vector of the tuple corresponds to the `i-th` +/// argument of the kernel. The `j-th` element of the `i-th` vector corresponds +/// to the `j-th` batch of arguments to evaluate the kernel at. template using ArgumentSet = std::tuple...>; -/// @brief Create a new ArgumentSet from a variadic list of -/// vectors of general args. +/// @brief Create a new ArgumentSet from a variadic list of vectors of general +/// arguments. template auto make_argset(const std::vector &...args) { return std::make_tuple(args...); @@ -35,9 +35,9 @@ template using BroadcastFunctorType = const std::function; -/// @brief Given the input BroadcastFunctorType, apply it to all -/// argument sets in the provided ArgumentSet `params`. Distribute the -/// work over the provided number of QPUs. +/// @brief Given the input BroadcastFunctorType, apply it to all argument sets +/// in the provided ArgumentSet `params`. Distribute the work over the provided +/// number of QPUs. template std::vector broadcastFunctionOverArguments(std::size_t numQpus, quantum_platform &platform, @@ -97,9 +97,19 @@ broadcastFunctionOverArguments(std::size_t numQpus, quantum_platform &platform, // Fill the argument tuple with the actual arguments. cudaq::tuple_for_each_with_idx( - params, [&](auto &&element, IDX_TYPE &&idx) { + params, +#if CUDAQ_USE_STD20 + [&](auto &&element, IDX_TYPE &&idx) { std::get(currentArgs) = element[i]; - }); + } +#else + [&](auto &&element, auto &&idx) { + std::get>::value + + 3>(currentArgs) = element[i]; + } +#endif + ); // Call observe/sample with the current set of arguments // (provided as a tuple) @@ -126,4 +136,4 @@ broadcastFunctionOverArguments(std::size_t numQpus, quantum_platform &platform, return allResults; } } // namespace details -} // namespace cudaq \ No newline at end of file +} // namespace cudaq diff --git a/runtime/cudaq/algorithms/observe.h b/runtime/cudaq/algorithms/observe.h index 2075a6de6f..a526e4db29 100644 --- a/runtime/cudaq/algorithms/observe.h +++ b/runtime/cudaq/algorithms/observe.h @@ -8,18 +8,17 @@ #pragma once +#include "common/ExecutionContext.h" +#include "common/ObserveResult.h" +#include "cudaq/algorithms/broadcast.h" +#include "cudaq/concepts.h" #include "cudaq/spin_op.h" - +#include "host_config.h" #include #include #include #include -#include "common/ExecutionContext.h" -#include "common/ObserveResult.h" -#include "cudaq/algorithms/broadcast.h" -#include "cudaq/concepts.h" - namespace cudaq { namespace mpi { @@ -43,12 +42,14 @@ struct thread {}; } // namespace parallel +#if CUDAQ_USE_STD20 /// @brief Define a combined sample function validation concept. /// These concepts provide much better error messages than old-school SFINAE template concept ObserveCallValid = ValidArgumentsPassed && HasVoidReturnType>; +#endif /// Observe options to provide as an argument to the `observe()`, /// `async_observe()` functions. @@ -178,7 +179,12 @@ inline auto distributeComputations( // Observe each sub-spin_op asynchronously std::vector asyncResults; +#if CUDAQ_USE_STD20 for (std::size_t i = 0; auto &op : spins) { +#else + std::size_t i = 0; + for (auto &op : spins) { +#endif asyncResults.emplace_back(asyncLauncher(i, op)); i++; } @@ -200,25 +206,39 @@ inline auto distributeComputations( } // namespace details /// \brief Compute the expected value of `H` with respect to `kernel(Args...)`. +#if CUDAQ_USE_STD20 template requires ObserveCallValid +#else +template >> +#endif observe_result observe(QuantumKernel &&kernel, spin_op H, Args &&...args) { // Run this SHOTS times auto &platform = cudaq::get_platform(); auto shots = platform.get_shots().value_or(-1); auto kernelName = cudaq::getKernelName(kernel); return details::runObservation( - [&kernel, &args...]() { kernel(std::forward(args)...); }, H, - platform, shots, kernelName) + [&kernel, &args...]() mutable { + kernel(std::forward(args)...); + }, + H, platform, shots, kernelName) .value(); } /// @brief Compute the expected value of every `spin_op` provided in /// `SpinOpContainer` (a range concept) with respect to `kernel(Args...)`. /// Return a `std::vector`. +#if CUDAQ_USE_STD20 template requires ObserveCallValid && std::ranges::range +#else +template >> +#endif std::vector observe(QuantumKernel &&kernel, const SpinOpContainer &termList, Args &&...args) { @@ -235,11 +255,12 @@ std::vector observe(QuantumKernel &&kernel, op -= spin_op(); // Run the observation - auto result = - details::runObservation( - [&kernel, &args...]() { kernel(std::forward(args)...); }, op, - platform, shots, kernelName) - .value(); + auto result = details::runObservation( + [&kernel, &args...]() mutable { + kernel(std::forward(args)...); + }, + op, platform, shots, kernelName) + .value(); // Convert back to a vector of results std::vector results; @@ -255,8 +276,14 @@ std::vector observe(QuantumKernel &&kernel, /// single-node platforms, or multi-node no-GPU platforms. Programmers must /// indicate the distribution type via the corresponding template types /// (cudaq::mgmn, cudaq::mgsn, cudaq::mn). +#if CUDAQ_USE_STD20 template requires ObserveCallValid +#else +template >> +#endif observe_result observe(std::size_t shots, QuantumKernel &&kernel, spin_op H, Args &&...args) { // Run this SHOTS times @@ -273,13 +300,29 @@ observe_result observe(std::size_t shots, QuantumKernel &&kernel, spin_op H, printf( "[cudaq::observe warning] distributed observe requested but only 1 " "QPU available. no speedup expected.\n"); - // Let's distribute the work among the QPUs on this node +#if CUDAQ_USE_STD20 + // Let's distribute the work among the QPUs on this node. return details::distributeComputations( - [&kernel, shots, &args...](std::size_t i, spin_op &op) { + [&kernel, shots, ... args = std::forward(args)]( + std::size_t i, spin_op &op) mutable { return observe_async(shots, i, std::forward(kernel), op, std::forward(args)...); }, H, nQpus); +#else + return details::distributeComputations( + [&kernel, shots, + args = std::forward_as_tuple(std::forward(args)...)]( + std::size_t i, spin_op &op) mutable { + return std::apply( + [&](auto &&...args) { + observe_async(shots, i, std::forward(kernel), op, + std::forward(args)...); + }, + std::move(args)); + }, + H, nQpus); +#endif } else if (std::is_same_v) { // This is an MPI distribution, where each node has N GPUs. @@ -305,10 +348,24 @@ observe_result observe(std::size_t shots, QuantumKernel &&kernel, spin_op H, // Distribute locally, i.e. to the local nodes QPUs auto localRankResult = details::distributeComputations( - [&kernel, shots, &args...](std::size_t i, spin_op &op) mutable { +#if CUDAQ_USE_STD20 + [&kernel, shots, ... args = std::forward(args)]( + std::size_t i, spin_op &op) mutable { return observe_async(shots, i, std::forward(kernel), op, std::forward(args)...); }, +#else + [&kernel, shots, + args = std::forward_as_tuple(std::forward(args)...)]( + std::size_t i, spin_op &op) mutable { + return std::apply( + [&](auto &&...args) { + observe_async(shots, i, std::forward(kernel), op, + std::forward(args)...); + }, + std::move(args)); + }, +#endif localH, nQpus); // combine all the data via an all_reduce @@ -320,8 +377,14 @@ observe_result observe(std::size_t shots, QuantumKernel &&kernel, spin_op H, throw std::runtime_error("Invalid cudaq::par execution type."); } +#if CUDAQ_USE_STD20 template requires ObserveCallValid +#else +template >> +#endif observe_result observe(QuantumKernel &&kernel, spin_op H, Args &&...args) { auto &platform = cudaq::get_platform(); auto shots = platform.get_shots().value_or(-1); @@ -331,8 +394,14 @@ observe_result observe(QuantumKernel &&kernel, spin_op H, Args &&...args) { /// \brief Compute the expected value of `H` with respect to `kernel(Args...)`. /// Specify the number of shots. +#if CUDAQ_USE_STD20 template requires ObserveCallValid +#else +template >> +#endif observe_result observe(std::size_t shots, QuantumKernel &&kernel, spin_op H, Args &&...args) { // Run this SHOTS times @@ -343,22 +412,44 @@ observe_result observe(std::size_t shots, QuantumKernel &&kernel, spin_op H, // If so, let's distribute the work among the QPUs if (auto nQpus = platform.num_qpus(); nQpus > 1) return details::distributeComputations( - [&kernel, shots, &args...](std::size_t i, spin_op &op) { +#if CUDAQ_USE_STD20 + [&kernel, shots, ... args = std::forward(args)]( + std::size_t i, spin_op &op) mutable { return observe_async(shots, i, std::forward(kernel), op, std::forward(args)...); }, +#else + [&kernel, shots, + args = std::forward_as_tuple(std::forward(args)...)]( + std::size_t i, spin_op &op) mutable { + return std::apply( + [&](auto &&...args) { + observe_async(shots, i, std::forward(kernel), op, + std::forward(args)...); + }, + std::move(args)); + }, +#endif H, nQpus); return details::runObservation( - [&kernel, &args...]() { kernel(std::forward(args)...); }, H, - platform, shots, kernelName) + [&kernel, &args...]() mutable { + kernel(std::forward(args)...); + }, + H, platform, shots, kernelName) .value(); } /// \brief Compute the expected value of `H` with respect to `kernel(Args...)`. /// Specify the observation options +#if CUDAQ_USE_STD20 template requires ObserveCallValid +#else +template >> +#endif observe_result observe(const observe_options &options, QuantumKernel &&kernel, spin_op H, Args &&...args) { auto &platform = cudaq::get_platform(); @@ -368,7 +459,9 @@ observe_result observe(const observe_options &options, QuantumKernel &&kernel, platform.set_noise(&options.noise); auto ret = details::runObservation( - [&kernel, &args...]() { kernel(std::forward(args)...); }, + [&kernel, &args...]() mutable { + kernel(std::forward(args)...); + }, H, platform, shots, kernelName) .value(); @@ -378,8 +471,14 @@ observe_result observe(const observe_options &options, QuantumKernel &&kernel, /// \brief Asynchronously compute the expected value of `H` with respect to /// `kernel(Args...)`. +#if CUDAQ_USE_STD20 template requires ObserveCallValid +#else +template >> +#endif auto observe_async(const std::size_t qpu_id, QuantumKernel &&kernel, spin_op &H, Args &&...args) { // Run this SHOTS times @@ -387,30 +486,64 @@ auto observe_async(const std::size_t qpu_id, QuantumKernel &&kernel, spin_op &H, auto shots = platform.get_shots().value_or(-1); auto kernelName = cudaq::getKernelName(kernel); +#if CUDAQ_USE_STD20 return details::runObservationAsync( - [&kernel, &args...]() { kernel(std::forward(args)...); }, H, - platform, shots, kernelName, qpu_id); + [&kernel, ... args = std::forward(args)]() mutable { + kernel(std::forward(args)...); + }, + H, platform, shots, kernelName, qpu_id); +#else + return details::runObservationAsync( + [&kernel, + args = std::forward_as_tuple(std::forward(args)...)]() mutable { + std::apply(std::move(kernel), std::move(args)); + }, + H, platform, shots, kernelName, qpu_id); +#endif } /// \brief Asynchronously compute the expected value of `H` with respect to /// `kernel(Args...)`. Specify the shots. +#if CUDAQ_USE_STD20 template requires ObserveCallValid +#else +template >> +#endif auto observe_async(std::size_t shots, std::size_t qpu_id, QuantumKernel &&kernel, spin_op &H, Args &&...args) { // Run this SHOTS times auto &platform = cudaq::get_platform(); auto kernelName = cudaq::getKernelName(kernel); +#if CUDAQ_USE_STD20 + return details::runObservationAsync( + [&kernel, ... args = std::forward(args)]() mutable { + kernel(std::forward(args)...); + }, + H, platform, shots, kernelName, qpu_id); +#else return details::runObservationAsync( - [&kernel, &args...]() { kernel(std::forward(args)...); }, H, - platform, shots, kernelName, qpu_id); + [&kernel, + args = std::forward_as_tuple(std::forward(args)...)]() mutable { + std::apply(std::move(kernel), std::move(args)); + }, + H, platform, shots, kernelName, qpu_id); +#endif } /// \brief Asynchronously compute the expected value of \p H with respect to /// `kernel(Args...)`. Default to the `0-th` QPU. +#if CUDAQ_USE_STD20 template requires ObserveCallValid +#else +template >> +#endif auto observe_async(QuantumKernel &&kernel, spin_op &H, Args &&...args) { return observe_async(0, std::forward(kernel), H, std::forward(args)...); @@ -423,8 +556,14 @@ auto observe_async(QuantumKernel &&kernel, spin_op &H, Args &&...args) { /// equal length, and the `i-th` element of each vector is used `i-th` /// execution of the standard observe function. Results are collected /// from the execution of every argument set and returned. +#if CUDAQ_USE_STD20 template requires ObserveCallValid +#else +template >> +#endif std::vector observe(QuantumKernel &&kernel, spin_op H, ArgumentSet &¶ms) { // Get the platform and query the number of quantum computers @@ -439,7 +578,7 @@ std::vector observe(QuantumKernel &&kernel, spin_op H, auto shots = platform.get_shots().value_or(-1); auto kernelName = cudaq::getKernelName(kernel); auto ret = details::runObservation( - [&kernel, &singleIterParameters...]() { + [&kernel, &singleIterParameters...]() mutable { kernel(std::forward(singleIterParameters)...); }, H, platform, shots, kernelName, qpuId, nullptr, counter, N) @@ -460,8 +599,14 @@ std::vector observe(QuantumKernel &&kernel, spin_op H, /// execution of the standard observe function. Results are collected /// from the execution of every argument set and returned. This overload /// allows the number of circuit executions (shots) to be specified. +#if CUDAQ_USE_STD20 template requires ObserveCallValid +#else +template >> +#endif std::vector observe(std::size_t shots, QuantumKernel &&kernel, spin_op H, ArgumentSet &¶ms) { // Get the platform and query the number of quantum computers @@ -475,7 +620,7 @@ std::vector observe(std::size_t shots, QuantumKernel &&kernel, Args &...singleIterParameters) -> observe_result { auto kernelName = cudaq::getKernelName(kernel); auto ret = details::runObservation( - [&kernel, &singleIterParameters...]() { + [&kernel, &singleIterParameters...]() mutable { kernel(std::forward(singleIterParameters)...); }, H, platform, shots, kernelName, qpuId, nullptr, counter, N) @@ -496,8 +641,14 @@ std::vector observe(std::size_t shots, QuantumKernel &&kernel, /// execution of the standard observe function. Results are collected /// from the execution of every argument set and returned. This overload /// allows the `observe_options` to be specified. +#if CUDAQ_USE_STD20 template requires ObserveCallValid +#else +template >> +#endif std::vector observe(cudaq::observe_options &options, QuantumKernel &&kernel, spin_op H, ArgumentSet &¶ms) { @@ -515,7 +666,7 @@ std::vector observe(cudaq::observe_options &options, Args &...singleIterParameters) -> observe_result { auto kernelName = cudaq::getKernelName(kernel); auto ret = details::runObservation( - [&kernel, &singleIterParameters...]() { + [&kernel, &singleIterParameters...]() mutable { kernel(std::forward(singleIterParameters)...); }, H, platform, shots, kernelName, qpuId, nullptr, counter, N) @@ -538,8 +689,14 @@ std::vector observe(cudaq::observe_options &options, /// equal length, and the `i-th` element of each vector is used `i-th` /// execution of the standard observe function. Results are collected /// from the execution of every argument set and returned. +#if CUDAQ_USE_STD20 template requires ObserveCallValid +#else +template >> +#endif [[deprecated("Use observe() overload instead")]] std::vector observe_n(QuantumKernel &&kernel, spin_op H, ArgumentSet &¶ms) { // Get the platform and query the number of quantum computers @@ -554,7 +711,7 @@ observe_n(QuantumKernel &&kernel, spin_op H, ArgumentSet &¶ms) { auto shots = platform.get_shots().value_or(-1); auto kernelName = cudaq::getKernelName(kernel); auto ret = details::runObservation( - [&kernel, &singleIterParameters...]() { + [&kernel, &singleIterParameters...]() mutable { kernel(std::forward(singleIterParameters)...); }, H, platform, shots, kernelName, qpuId, nullptr, counter, N) @@ -575,8 +732,14 @@ observe_n(QuantumKernel &&kernel, spin_op H, ArgumentSet &¶ms) { /// execution of the standard observe function. Results are collected /// from the execution of every argument set and returned. This overload /// allows the number of circuit executions (shots) to be specified. +#if CUDAQ_USE_STD20 template requires ObserveCallValid +#else +template >> +#endif [[deprecated("Use observe() overload instead")]] std::vector observe_n(std::size_t shots, QuantumKernel &&kernel, spin_op H, ArgumentSet &¶ms) { @@ -591,7 +754,7 @@ observe_n(std::size_t shots, QuantumKernel &&kernel, spin_op H, Args &...singleIterParameters) -> observe_result { auto kernelName = cudaq::getKernelName(kernel); auto ret = details::runObservation( - [&kernel, &singleIterParameters...]() { + [&kernel, &singleIterParameters...]() mutable { kernel(std::forward(singleIterParameters)...); }, H, platform, shots, kernelName, qpuId, nullptr, counter, N) diff --git a/runtime/cudaq/algorithms/sample.h b/runtime/cudaq/algorithms/sample.h index b433eb933a..fdc2851b0c 100644 --- a/runtime/cudaq/algorithms/sample.h +++ b/runtime/cudaq/algorithms/sample.h @@ -12,6 +12,7 @@ #include "common/MeasureCounts.h" #include "cudaq/algorithms/broadcast.h" #include "cudaq/concepts.h" +#include "host_config.h" namespace cudaq { bool kernelHasConditionalFeedback(const std::string &); @@ -21,12 +22,14 @@ bool isKernelGenerated(const std::string &); /// @brief Return type for asynchronous sampling. using async_sample_result = async_result; +#if CUDAQ_USE_STD20 /// @brief Define a combined sample function validation concept. /// These concepts provide much better error messages than old-school SFINAE template concept SampleCallValid = ValidArgumentsPassed && HasVoidReturnType>; +#endif namespace details { @@ -194,10 +197,15 @@ struct sample_options { /// the corresponding quantum circuit generated by the kernel /// expression, returning the mapping of bits observed to number /// of times it was observed. +#if CUDAQ_USE_STD20 template requires SampleCallValid +#else +template >> +#endif sample_result sample(QuantumKernel &&kernel, Args &&...args) { - // Need the code to be lowered to llvm and the kernel to be registered // so that we can check for conditional feedback / mid circ measurement if constexpr (has_name::value) { @@ -208,12 +216,19 @@ sample_result sample(QuantumKernel &&kernel, Args &&...args) { auto &platform = cudaq::get_platform(); auto shots = platform.get_shots().value_or(1000); auto kernelName = cudaq::getKernelName(kernel); +#if CUDAQ_USE_STD20 return details::runSampling( [&kernel, ... args = std::forward(args)]() mutable { kernel(std::forward(args)...); }, platform, kernelName, shots) .value(); +#else + return details::runSampling( + [&]() mutable { kernel(std::forward(args)...); }, platform, + kernelName, shots) + .value(); +#endif } /// @brief Sample the given quantum kernel expression and return the @@ -229,10 +244,15 @@ sample_result sample(QuantumKernel &&kernel, Args &&...args) { /// the corresponding quantum circuit generated by the kernel /// expression, returning the mapping of bits observed to number /// of times it was observed. +#if CUDAQ_USE_STD20 template requires SampleCallValid +#else +template >> +#endif auto sample(std::size_t shots, QuantumKernel &&kernel, Args &&...args) { - // Need the code to be lowered to llvm and the kernel to be registered // so that we can check for conditional feedback / mid circ measurement if constexpr (has_name::value) { @@ -242,12 +262,19 @@ auto sample(std::size_t shots, QuantumKernel &&kernel, Args &&...args) { // Run this SHOTS times auto &platform = cudaq::get_platform(); auto kernelName = cudaq::getKernelName(kernel); +#if CUDAQ_USE_STD20 return details::runSampling( [&kernel, ... args = std::forward(args)]() mutable { kernel(std::forward(args)...); }, platform, kernelName, shots) .value(); +#else + return details::runSampling( + [&]() mutable { kernel(std::forward(args)...); }, platform, + kernelName, shots) + .value(); +#endif } /// @brief Sample the given quantum kernel expression and return the @@ -263,8 +290,14 @@ auto sample(std::size_t shots, QuantumKernel &&kernel, Args &&...args) { /// the corresponding quantum circuit generated by the kernel /// expression, returning the mapping of bits observed to number /// of times it was observed. +#if CUDAQ_USE_STD20 template requires SampleCallValid +#else +template >> +#endif sample_result sample(const sample_options &options, QuantumKernel &&kernel, Args &&...args) { @@ -278,13 +311,19 @@ sample_result sample(const sample_options &options, QuantumKernel &&kernel, auto shots = options.shots; auto kernelName = cudaq::getKernelName(kernel); platform.set_noise(&options.noise); +#if CUDAQ_USE_STD20 auto ret = details::runSampling( [&kernel, ... args = std::forward(args)]() mutable { kernel(std::forward(args)...); }, platform, kernelName, shots) .value(); - +#else + auto ret = details::runSampling( + [&]() mutable { kernel(std::forward(args)...); }, + platform, kernelName, shots) + .value(); +#endif platform.reset_noise(); return ret; } @@ -303,8 +342,14 @@ sample_result sample(const sample_options &options, QuantumKernel &&kernel, /// the corresponding quantum circuit generated by the kernel /// expression, returning the mapping of bits observed to number /// of times it was observed. +#if CUDAQ_USE_STD20 template requires SampleCallValid +#else +template >> +#endif async_sample_result sample_async(const std::size_t qpu_id, QuantumKernel &&kernel, Args &&...args) { // Need the code to be lowered to llvm and the kernel to be registered @@ -318,11 +363,20 @@ async_sample_result sample_async(const std::size_t qpu_id, auto shots = platform.get_shots().value_or(1000); auto kernelName = cudaq::getKernelName(kernel); +#if CUDAQ_USE_STD20 return details::runSamplingAsync( [&kernel, ... args = std::forward(args)]() mutable { kernel(std::forward(args)...); }, platform, kernelName, shots, qpu_id); +#else + return details::runSamplingAsync( + [&kernel, + args = std::forward_as_tuple(std::forward(args)...)]() mutable { + std::apply(std::move(kernel), std::move(args)); + }, + platform, kernelName, shots, qpu_id); +#endif } /// @brief Sample the given kernel expression asynchronously and return @@ -340,8 +394,14 @@ async_sample_result sample_async(const std::size_t qpu_id, /// the corresponding quantum circuit generated by the kernel /// expression, returning the mapping of bits observed to number /// of times it was observed. +#if CUDAQ_USE_STD20 template requires SampleCallValid +#else +template >> +#endif async_sample_result sample_async(std::size_t shots, std::size_t qpu_id, QuantumKernel &&kernel, Args &&...args) { // Need the code to be lowered to llvm and the kernel to be registered @@ -354,11 +414,20 @@ async_sample_result sample_async(std::size_t shots, std::size_t qpu_id, auto &platform = cudaq::get_platform(); auto kernelName = cudaq::getKernelName(kernel); +#if CUDAQ_USE_STD20 return details::runSamplingAsync( [&kernel, ... args = std::forward(args)]() mutable { kernel(std::forward(args)...); }, platform, kernelName, shots, qpu_id); +#else + return details::runSamplingAsync( + [&kernel, + args = std::forward_as_tuple(std::forward(args)...)]() mutable { + std::apply(std::move(kernel), std::move(args)); + }, + platform, kernelName, shots, qpu_id); +#endif } /// @brief Sample the given kernel expression asynchronously and return @@ -374,8 +443,14 @@ async_sample_result sample_async(std::size_t shots, std::size_t qpu_id, /// the corresponding quantum circuit generated by the kernel /// expression, returning the mapping of bits observed to number /// of times it was observed. +#if CUDAQ_USE_STD20 template requires SampleCallValid +#else +template >> +#endif auto sample_async(QuantumKernel &&kernel, Args &&...args) { return sample_async(0, std::forward(kernel), std::forward(args)...); @@ -388,8 +463,14 @@ auto sample_async(QuantumKernel &&kernel, Args &&...args) { /// equal length, and element `i` of each vector is used in /// execution `i` of the standard sample function. Results are collected /// from the execution of every argument set and returned. +#if CUDAQ_USE_STD20 template requires SampleCallValid +#else +template >> +#endif std::vector sample(QuantumKernel &&kernel, ArgumentSet &¶ms) { // Get the platform and query the number of qpus @@ -404,7 +485,7 @@ std::vector sample(QuantumKernel &&kernel, auto shots = platform.get_shots().value_or(1000); auto kernelName = cudaq::getKernelName(kernel); auto ret = details::runSampling( - [&kernel, &singleIterParameters...]() { + [&kernel, &singleIterParameters...]() mutable { kernel(std::forward(singleIterParameters)...); }, platform, kernelName, shots, qpuId, nullptr, counter, N) @@ -425,8 +506,14 @@ std::vector sample(QuantumKernel &&kernel, /// execution `i` of the standard sample function. Results are collected /// from the execution of every argument set and returned. This overload /// allows the number of circuit executions (shots) to be specified. +#if CUDAQ_USE_STD20 template requires SampleCallValid +#else +template >> +#endif std::vector sample(std::size_t shots, QuantumKernel &&kernel, ArgumentSet &¶ms) { // Get the platform and query the number of QPUs @@ -440,7 +527,7 @@ std::vector sample(std::size_t shots, QuantumKernel &&kernel, Args &...singleIterParameters) -> sample_result { auto kernelName = cudaq::getKernelName(kernel); auto ret = details::runSampling( - [&kernel, &singleIterParameters...]() { + [&kernel, &singleIterParameters...]() mutable { kernel(std::forward(singleIterParameters)...); }, platform, kernelName, shots, qpuId, nullptr, counter, N) @@ -461,8 +548,14 @@ std::vector sample(std::size_t shots, QuantumKernel &&kernel, /// execution `i` of the standard sample function. Results are collected /// from the execution of every argument set and returned. This overload /// allows the `sample_options` to be specified. +#if CUDAQ_USE_STD20 template requires SampleCallValid +#else +template >> +#endif std::vector sample(const sample_options &options, QuantumKernel &&kernel, ArgumentSet &¶ms) { @@ -480,7 +573,7 @@ std::vector sample(const sample_options &options, Args &...singleIterParameters) -> sample_result { auto kernelName = cudaq::getKernelName(kernel); auto ret = details::runSampling( - [&kernel, &singleIterParameters...]() { + [&kernel, &singleIterParameters...]() mutable { kernel(std::forward(singleIterParameters)...); }, platform, kernelName, shots, qpuId, nullptr, counter, N) @@ -503,8 +596,14 @@ std::vector sample(const sample_options &options, /// equal length, and the element `i` of each vector is used in /// execution `i` of the standard sample function. Results are collected /// from the execution of every argument set and returned. +#if CUDAQ_USE_STD20 template requires SampleCallValid +#else +template >> +#endif [[deprecated("Use sample() overload instead")]] std::vector sample_n(QuantumKernel &&kernel, ArgumentSet &¶ms) { // Get the platform and query the number of qpus @@ -519,7 +618,7 @@ sample_n(QuantumKernel &&kernel, ArgumentSet &¶ms) { auto shots = platform.get_shots().value_or(1000); auto kernelName = cudaq::getKernelName(kernel); auto ret = details::runSampling( - [&kernel, &singleIterParameters...]() { + [&kernel, &singleIterParameters...]() mutable { kernel(std::forward(singleIterParameters)...); }, platform, kernelName, shots, qpuId, nullptr, counter, N) @@ -540,8 +639,14 @@ sample_n(QuantumKernel &&kernel, ArgumentSet &¶ms) { /// execution `i` of the standard sample function. Results are collected /// from the execution of every argument set and returned. This overload /// allows the number of circuit executions (shots) to be specified. +#if CUDAQ_USE_STD20 template requires SampleCallValid +#else +template >> +#endif [[deprecated("Use sample() overload instead")]] std::vector sample_n(std::size_t shots, QuantumKernel &&kernel, ArgumentSet &¶ms) { @@ -556,7 +661,7 @@ sample_n(std::size_t shots, QuantumKernel &&kernel, Args &...singleIterParameters) -> sample_result { auto kernelName = cudaq::getKernelName(kernel); auto ret = details::runSampling( - [&kernel, &singleIterParameters...]() { + [&kernel, &singleIterParameters...]() mutable { kernel(std::forward(singleIterParameters)...); }, platform, kernelName, shots, qpuId, nullptr, counter, N) diff --git a/runtime/cudaq/algorithms/state.h b/runtime/cudaq/algorithms/state.h index 2bbcb910ef..8f398901a2 100644 --- a/runtime/cudaq/algorithms/state.h +++ b/runtime/cudaq/algorithms/state.h @@ -12,13 +12,14 @@ #include "cudaq/concepts.h" #include "cudaq/platform.h" #include "cudaq/platform/QuantumExecutionQueue.h" +#include "host_config.h" #include #include namespace cudaq { -/// @brief The cudaq::state encapsulate backend simulation state -/// vector or density matrix data. +/// @brief The cudaq::state encapsulate backend simulation state vector or +/// density matrix data. class state { private: @@ -52,11 +53,13 @@ class state { double overlap(state &other); }; +#if CUDAQ_USE_STD20 /// @brief Define a valid kernel concept template concept KernelCallValid = ValidArgumentsPassed && HasVoidReturnType>; +#endif namespace details { @@ -119,8 +122,8 @@ auto runGetStateAsync(KernelFunctor &&wrappedKernel, } } // namespace details -/// @brief Return the state representation generated by -/// the kernel at the given runtime arguments. +/// @brief Return the state representation generated by the kernel at the given +/// runtime arguments. template auto get_state(QuantumKernel &&kernel, Args &&...args) { return details::extractState( @@ -132,16 +135,22 @@ auto get_state(QuantumKernel &&kernel, Args &&...args) { /// @brief Return type for asynchronous `get_state`. using async_state_result = std::future; -/// \brief Return the state representation generated by -/// the kernel at the given runtime arguments asynchronously. +/// \brief Return the state representation generated by the kernel at the given +/// runtime arguments asynchronously. /// -/// \param qpu_id the id of the QPU to run asynchronously on -/// \param kernel the kernel expression, must contain final measurements -/// \param args the variadic concrete arguments for evaluation of the kernel. +/// @param `qpu_id` the id of the QPU to run asynchronously on +/// @param kernel the kernel expression, must contain final measurements +/// @param `args` the variadic concrete arguments for evaluation of the kernel. /// \returns state future, A std::future containing the resultant state vector /// +#if CUDAQ_USE_STD20 template requires KernelCallValid +#else +template >> +#endif async_state_result get_state_async(std::size_t qpu_id, QuantumKernel &&kernel, Args &&...args) { auto &platform = cudaq::get_platform(); @@ -152,16 +161,21 @@ async_state_result get_state_async(std::size_t qpu_id, QuantumKernel &&kernel, platform, qpu_id); } -/// \brief Return the state representation generated by -/// the kernel at the given runtime arguments asynchronously on the default QPU -/// (id = 0). +/// \brief Return the state representation generated by the kernel at the given +/// runtime arguments asynchronously on the default QPU (id = 0). /// -/// \param kernel the kernel expression, must contain final measurements -/// \param args the variadic concrete arguments for evaluation of the kernel. +/// @param kernel the kernel expression, must contain final measurements +/// @param `args` the variadic concrete arguments for evaluation of the kernel. /// \returns state future, A std::future containing the resultant state vector /// +#if CUDAQ_USE_STD20 template requires KernelCallValid +#else +template >> +#endif async_state_result get_state_async(QuantumKernel &&kernel, Args &&...args) { return get_state_async(0, std::forward(kernel), std::forward(args)...); diff --git a/runtime/cudaq/builder/QuakeValue.h b/runtime/cudaq/builder/QuakeValue.h index 63a9c0d176..8bb4e69e5a 100644 --- a/runtime/cudaq/builder/QuakeValue.h +++ b/runtime/cudaq/builder/QuakeValue.h @@ -7,6 +7,8 @@ ******************************************************************************/ #pragma once + +#include "host_config.h" #include #include #include @@ -138,11 +140,12 @@ class QuakeValue { QuakeValue inverse() const; }; +#if CUDAQ_USE_STD20 /// @brief Concept constraining the input type below to be a QuakeValue template concept IsQuakeValue = std::is_convertible_v; -/// @brief Concept constraining the LHS args to be numeric below +/// Concept constraining the LHS arguments to be numeric below. template concept IsNumericType = requires(T param) { std::is_convertible_v; }; @@ -163,4 +166,43 @@ QuakeValue operator+(IsNumericType auto &&d, IsQuakeValue auto &&q) { QuakeValue operator/(IsNumericType auto &&d, IsQuakeValue auto &&q) { return q.inverse() * d; } + +#else +// C++ 2011 compatible definitions. +template >, + typename = std::enable_if_t>> +QuakeValue operator*(N &&d, Q &&q) { + return q * d; +} + +template >, + typename = std::enable_if_t>> +QuakeValue operator*(Q &&q, N &&d) { + return q * d; +} + +template >, + typename = std::enable_if_t>> +QuakeValue operator-(N &&d, Q &&q) { + return -q + d; +} + +template >, + typename = std::enable_if_t>> +QuakeValue operator+(N &&d, Q &&q) { + return q + d; +} + +template >, + typename = std::enable_if_t>> +QuakeValue operator/(N &&d, Q &&q) { + return q.inverse() * d; +} +#endif + } // namespace cudaq diff --git a/runtime/cudaq/builder/kernel_builder.h b/runtime/cudaq/builder/kernel_builder.h index 0bc88da9d0..2c5f1af2e3 100644 --- a/runtime/cudaq/builder/kernel_builder.h +++ b/runtime/cudaq/builder/kernel_builder.h @@ -8,10 +8,12 @@ #pragma once +#include "cudaq/builder/QuakeValue.h" #include "cudaq/qis/modifiers.h" #include "cudaq/qis/qreg.h" #include "cudaq/qis/qvector.h" #include "cudaq/utils/cudaq_utils.h" +#include "host_config.h" #include #include #include @@ -22,8 +24,6 @@ #include #include -#include "QuakeValue.h" - // Goal here is to keep MLIR out of user code! namespace mlir { class Type; @@ -41,13 +41,14 @@ using namespace mlir; namespace cudaq { std::string get_quake_by_name(const std::string &); +#if CUDAQ_USE_STD20 /// @brief Define a floating point concept template concept NumericType = requires(T param) { std::is_floating_point_v; }; -/// @brief Define a Quake-constructible floating point value concept -// i.e., it could be a `QuakeValue` type or a floating point number (convertible -// to a `QuakeValue` with `ConstantFloatOp`). +/// @brief Define a Quake-`constructable` floating point value concept; i.e., it +/// could be a `QuakeValue` type or a floating point number (convertible +/// to a `QuakeValue` with `ConstantFloatOp`). template concept QuakeValueOrNumericType = requires(T param) { std::is_floating_point_v || @@ -63,8 +64,8 @@ template concept KernelBuilderArgTypeIsValid = std::disjunction_v...>; -// If you want to add to the list of valid kernel argument types -// first add it here, then add `details::mapArgToType()` function +// If you want to add to the list of valid kernel argument types first add it +// here, then add `details::mapArgToType()` function #define CUDAQ_VALID_BUILDER_ARGS_FOLD() \ requires( \ KernelBuilderArgTypeIsValid< \ @@ -72,17 +73,21 @@ concept KernelBuilderArgTypeIsValid = std::vector, std::vector, std::vector, \ cudaq::qubit, cudaq::qreg<>, cudaq::qvector<>> && \ ...) +#else +// Not C++ 2020: stub these out. +#define QuakeValueOrNumericType typename +#define CUDAQ_VALID_BUILDER_ARGS_FOLD() +#endif namespace details { -// Define a `mlir::Type` generator in the `cudaq` namespace, -// this helps us keep MLIR out of this public header +// Define a `mlir::Type` generator in the `cudaq` namespace, this helps us keep +// MLIR out of this public header -/// @brief The `kernel_builder::Type` allows us to track -/// input C++ types representing the quake function argument types -/// in a way that does not expose MLIR Type to the CUDA Quantum code. -/// This type keeps track of a functor that generates the MLIR Type -/// in implementation code when create() is invoked. +/// @brief The `kernel_builder::Type` allows us to track input C++ types +/// representing the quake function argument types in a way that does not expose +/// MLIR Type to the CUDA Quantum code. This type keeps track of a functor that +/// generates the MLIR Type in implementation code when create() is invoked. class KernelBuilderType { protected: /// @brief For this type instance, create an MLIR Type @@ -129,27 +134,26 @@ KernelBuilderType mapArgToType(cudaq::qreg<> &e); /// @brief Map a `qvector` to a `KernelBuilderType` KernelBuilderType mapArgToType(cudaq::qvector<> &e); -/// @brief Initialize the `MLIRContext`, return the raw -/// pointer which we'll wrap in an `unique_ptr`. +/// @brief Initialize the `MLIRContext`, return the raw pointer which we'll wrap +/// in an `unique_ptr`. MLIRContext *initializeContext(); -/// @brief Delete function for the context pointer, -/// also given to the `unique_ptr` +/// @brief Delete function for the context pointer, also given to the +/// `unique_ptr` void deleteContext(MLIRContext *); -/// @brief Initialize the `OpBuilder`, return the raw -/// pointer which we'll wrap in an `unique_ptr`. +/// @brief Initialize the `OpBuilder`, return the raw pointer which we'll wrap +/// in an `unique_ptr`. ImplicitLocOpBuilder *initializeBuilder(MLIRContext *, std::vector &, std::vector &, std::string &kernelName); -/// @brief Delete function for the builder pointer, -/// also given to the `unique_ptr` +/// @brief Delete function for the builder pointer, also given to the +/// `unique_ptr` void deleteBuilder(ImplicitLocOpBuilder *builder); -/// @brief Delete function for the JIT pointer, -/// also given to the `unique_ptr` +/// @brief Delete function for the JIT pointer, also given to the `unique_ptr` void deleteJitEngine(ExecutionEngine *jit); /// @brief Allocate a single `qubit` @@ -164,8 +168,8 @@ QuakeValue qalloc(ImplicitLocOpBuilder &builder, QuakeValue &size); /// @brief Create a QuakeValue representing a constant floating-point number QuakeValue constantVal(ImplicitLocOpBuilder &builder, double val); -// In the following macros + instantiations, we define the functions -// that create Quake Quantum Ops + Measures +// In the following macros + instantiations, we define the functions that create +// Quake Quantum Ops + Measures #define CUDAQ_DETAILS_QIS_DECLARATION(NAME) \ void NAME(ImplicitLocOpBuilder &builder, std::vector &ctrls, \ @@ -209,15 +213,15 @@ void reset(ImplicitLocOpBuilder &builder, const QuakeValue &qubitOrQvec); void c_if(ImplicitLocOpBuilder &builder, QuakeValue &conditional, std::function &thenFunctor); -/// @brief Return the name of this `kernel_builder`, -/// it is also the name of the function +/// @brief Return the name of this `kernel_builder`, it is also the name of the +/// function std::string name(std::string_view kernelName); /// @brief Apply our MLIR passes before JIT execution void applyPasses(PassManager &); -/// @brief Create the `ExecutionEngine` and return a raw -/// pointer, which we will wrap in a `unique_ptr` +/// @brief Create the `ExecutionEngine` and return a raw pointer, which we will +/// wrap in a `unique_ptr` std::tuple jitCode(ImplicitLocOpBuilder &, ExecutionEngine *, std::unordered_map &, std::string, @@ -241,43 +245,43 @@ void control(ImplicitLocOpBuilder &builder, std::string &name, void adjoint(ImplicitLocOpBuilder &builder, std::string &name, std::string &quakeCode, std::vector &values); -/// @brief Add a for loop that starts from the given `start` integer index, -/// ends at the given `end` integer index, and applies the given `body` as a -/// callable function. This callable function must take as input an index -/// variable that can be used within the body. +/// @brief Add a for loop that starts from the given `start` integer index, ends +/// at the given `end` integer index, and applies the given `body` as a callable +/// function. This callable function must take as input an index variable that +/// can be used within the body. void forLoop(ImplicitLocOpBuilder &builder, std::size_t start, std::size_t end, std::function &body); -/// @brief Add a for loop that starts from the given `start` integer index, -/// ends at the given `end` index, and applies the given `body` as a callable +/// @brief Add a for loop that starts from the given `start` integer index, ends +/// at the given `end` index, and applies the given `body` as a callable /// function. This callable function must take as input an index variable that /// can be used within the body. void forLoop(ImplicitLocOpBuilder &builder, std::size_t start, QuakeValue &end, std::function &body); -/// @brief Add a for loop that starts from the given `start` index, -/// ends at the given `end` integer index, and applies the given `body` as a -/// callable function. This callable function must take as input an index -/// variable that can be used within the body. +/// @brief Add a for loop that starts from the given `start` index, ends at the +/// given `end` integer index, and applies the given `body` as a callable +/// function. This callable function must take as input an index variable that +/// can be used within the body. void forLoop(ImplicitLocOpBuilder &builder, QuakeValue &start, std::size_t end, std::function &body); -/// @brief Add a for loop that starts from the given `start` index, -/// ends at the given `end` index, and applies the given `body` as a -/// callable function. This callable function must take as input an index -/// variable that can be used within the body. +/// @brief Add a for loop that starts from the given `start` index, ends at the +/// given `end` index, and applies the given `body` as a callable function. This +/// callable function must take as input an index variable that can be used +/// within the body. void forLoop(ImplicitLocOpBuilder &builder, QuakeValue &start, QuakeValue &end, std::function &body); /// @brief Return the quake representation as a string std::string to_quake(ImplicitLocOpBuilder &builder); -/// @brief Returns `true` if the argument to the `kernel_builder` -/// is a `cc::StdvecType`. Returns `false` otherwise. +/// @brief Returns `true` if the argument to the `kernel_builder` is a +/// `cc::StdvecType`. Returns `false` otherwise. bool isArgStdVec(std::vector &args, std::size_t idx); -/// @brief The `ArgumentValidator` provides a way validate the input -/// arguments when the kernel is invoked (via a fold expression). +/// @brief The `ArgumentValidator` provides a way validate the input arguments +/// when the kernel is invoked (via a fold expression). template struct ArgumentValidator { static void validate(std::size_t &argCounter, std::vector &args, @@ -287,9 +291,9 @@ struct ArgumentValidator { } }; -/// @brief The `ArgumentValidator` provides a way validate the input -/// arguments when the kernel is invoked (via a fold expression). Here -/// we explicitly validate `std::vector` and its size. +/// @brief The `ArgumentValidator` provides a way validate the input arguments +/// when the kernel is invoked (via a fold expression). Here we explicitly +/// validate `std::vector` and its size. template struct ArgumentValidator> { static void validate(std::size_t &argCounter, std::vector &args, @@ -313,17 +317,17 @@ struct ArgumentValidator> { } }; -/// @brief The `kernel_builder_base` provides a -/// base type for the templated kernel builder so that -/// we can get a single handle on an instance within the runtime. +/// @brief The `kernel_builder_base` provides a base type for the templated +/// kernel builder so that we can get a single handle on an instance within the +/// runtime. class kernel_builder_base { public: virtual std::string to_quake() const = 0; virtual void jitCode(std::vector extraLibPaths = {}) = 0; virtual ~kernel_builder_base() = default; - /// @brief Write the kernel_builder to the given output stream. - /// This outputs the Quake representation. + /// @brief Write the kernel_builder to the given output stream. This outputs + /// the Quake representation. friend std::ostream &operator<<(std::ostream &stream, const kernel_builder_base &builder) { stream << builder.to_quake(); @@ -333,6 +337,7 @@ class kernel_builder_base { } // namespace details +#if CUDAQ_USE_STD20 template concept AllAreQuakeValues = sizeof...(Ts) < 2 || @@ -341,24 +346,22 @@ concept AllAreQuakeValues = std::is_same_v< std::remove_reference_t>>, QuakeValue>); +#endif template class kernel_builder : public details::kernel_builder_base { private: - /// @brief Handle to the MLIR Context, stored - /// as a pointer here to keep implementation details - /// out of CUDA Quantum code + /// @brief Handle to the MLIR Context, stored as a pointer here to keep + /// implementation details out of CUDA Quantum code std::unique_ptr context; - /// @brief Handle to the MLIR `OpBuilder`, stored - /// as a pointer here to keep implementation details - /// out of CUDA Quantum code + /// @brief Handle to the MLIR `OpBuilder`, stored as a pointer here to keep + /// implementation details out of CUDA Quantum code std::unique_ptr opBuilder; - /// @brief Handle to the MLIR `ExecutionEngine`, stored - /// as a pointer here to keep implementation details - /// out of CUDA Quantum code + /// @brief Handle to the MLIR `ExecutionEngine`, stored as a pointer here to + /// keep implementation details out of CUDA Quantum code std::unique_ptr jitEngine; /// @brief Map created ExecutionEngines to a unique hash of the @@ -368,14 +371,12 @@ class kernel_builder : public details::kernel_builder_base { /// @brief Name of the CUDA Quantum kernel Quake function std::string kernelName = "__nvqpp__mlirgen____nvqppBuilderKernel"; - /// @brief The CUDA Quantum Quake function arguments stored - /// as `QuakeValue`s. + /// @brief The CUDA Quantum Quake function arguments stored as `QuakeValue`s. std::vector arguments; public: - /// @brief The constructor, takes the input - /// `KernelBuilderType`s which is used to create the MLIR - /// function type + /// @brief The constructor, takes the input `KernelBuilderType`s which is used + /// to create the MLIR function type kernel_builder(std::vector &types) : context(details::initializeContext(), details::deleteContext), opBuilder(nullptr, [](ImplicitLocOpBuilder *) {}), @@ -388,11 +389,10 @@ class kernel_builder : public details::kernel_builder_base { } /// @brief Return the `QuakeValue` arguments - /// @return auto &getArguments() { return arguments; } - /// @brief Return `true` if the argument to the - /// kernel is a `std::vector`, `false` otherwise. + /// @brief Return `true` if the argument to the kernel is a `std::vector`, + /// `false` otherwise. bool isArgStdVec(std::size_t idx) { return details::isArgStdVec(arguments, idx); } @@ -412,8 +412,8 @@ class kernel_builder : public details::kernel_builder_base { return details::qalloc(*opBuilder.get(), nQubits); } - /// @brief Return a `QuakeValue` representing the allocated `Veq`, - /// size is from a pre-allocated size `QuakeValue` or `BlockArgument`. + /// @brief Return a `QuakeValue` representing the allocated `Veq`, size is + /// from a pre-allocated size `QuakeValue` or `BlockArgument`. QuakeValue qalloc(QuakeValue size) { return details::qalloc(*opBuilder.get(), size); } @@ -590,14 +590,14 @@ class kernel_builder : public details::kernel_builder_base { /// @brief Reset the given qubit or qubits. void reset(const QuakeValue &qubit) { details::reset(*opBuilder, qubit); } - /// @brief Apply a conditional statement on a - /// measure result, if true apply the `thenFunctor`. + /// @brief Apply a conditional statement on a measure result, if true apply + /// the `thenFunctor`. void c_if(QuakeValue result, std::function &&thenFunctor) { details::c_if(*opBuilder, result, thenFunctor); } - /// @brief Apply a general Pauli rotation, exp(i theta P), - /// takes a QuakeValue representing a register of qubits. + /// @brief Apply a general Pauli rotation, exp(i theta P), takes a QuakeValue + /// representing a register of qubits. template void exp_pauli(const ParamT &theta, const QuakeValue &qubits, const std::string &pauliWord) { @@ -609,8 +609,8 @@ class kernel_builder : public details::kernel_builder_base { details::exp_pauli(*opBuilder, theta, qubitValues, pauliWord); } - /// @brief Apply a general Pauli rotation, exp(i theta P), - /// takes a variadic list of QuakeValues representing a individual qubits. + /// @brief Apply a general Pauli rotation, exp(i theta P), takes a variadic + /// list of QuakeValues representing a individual qubits. template void exp_pauli(const ParamT &theta, const std::string &pauliWord, QubitArgs &&...qubits) { @@ -642,17 +642,23 @@ class kernel_builder : public details::kernel_builder_base { /// @brief Apply the given `otherKernel` with the provided `QuakeValue` /// arguments. +#if CUDAQ_USE_STD20 template - requires(AllAreQuakeValues) + requires AllAreQuakeValues +#else + template , cudaq::QuakeValue>...>>> +#endif void call(OtherKernelBuilder &&kernel, QuakeValues &...values) { // static_assert(kernel) std::vector vecValues{values...}; call(kernel, vecValues); } - /// @brief Apply the given kernel controlled on the provided qubit value. - /// This overload takes a vector of `QuakeValue`s and is primarily meant - /// to be used internally. + /// @brief Apply the given kernel controlled on the provided qubit value. This + /// overload takes a vector of `QuakeValue`s and is primarily meant to be used + /// internally. template void control(OtherKernelBuilder &kernel, QuakeValue &control, std::vector &args) { @@ -671,17 +677,22 @@ class kernel_builder : public details::kernel_builder_base { } /// @brief Apply the given kernel controlled on the provided qubit value. +#if CUDAQ_USE_STD20 template - requires(AllAreQuakeValues) + requires AllAreQuakeValues +#else + template , cudaq::QuakeValue>...>>> +#endif void control(OtherKernelBuilder &kernel, QuakeValue &ctrl, QuakeValues &...values) { std::vector vecValues{values...}; control(kernel, ctrl, vecValues); } - /// @brief Apply the adjoint of the given kernel. - /// This overload takes a vector of `QuakeValue`s and is primarily meant - /// to be used internally. + /// @brief Apply the adjoint of the given kernel. This overload takes a vector + /// of `QuakeValue`s and is primarily meant to be used internally. template void adjoint(OtherKernelBuilder &kernel, std::vector &args) { std::string name = "", quake = ""; @@ -699,8 +710,14 @@ class kernel_builder : public details::kernel_builder_base { } /// @brief Apply the adjoint of the given kernel. +#if CUDAQ_USE_STD20 template - requires(AllAreQuakeValues) + requires AllAreQuakeValues +#else + template , cudaq::QuakeValue>...>>> +#endif void adjoint(OtherKernelBuilder &kernel, QuakeValues &...values) { std::vector vecValues{values...}; adjoint(kernel, vecValues); @@ -719,14 +736,12 @@ class kernel_builder : public details::kernel_builder_base { return details::to_quake(*opBuilder); } - /// @brief Lower the Quake code to the LLVM Dialect, call - /// `PassManager`. + /// @brief Lower the Quake code to the LLVM Dialect, call `PassManager`. void jitCode(std::vector extraLibPaths = {}) override { auto [wasChanged, ptr] = details::jitCode(*opBuilder, jitEngine.get(), jitEngineToModuleHash, kernelName, extraLibPaths); - // If we had a jitEngine, but the code changed, - // delete the one we had. + // If we had a jitEngine, but the code changed, delete the one we had. if (jitEngine && wasChanged) details::deleteJitEngine(jitEngine.release()); @@ -751,8 +766,8 @@ class kernel_builder : public details::kernel_builder_base { extraLibPaths); } - /// @brief The call operator for the kernel_builder, - /// takes as input the constructed function arguments. + /// @brief The call operator for the kernel_builder, takes as input the + /// constructed function arguments. void operator()(Args... args) { [[maybe_unused]] std::size_t argCounter = 0; (details::ArgumentValidator::validate(argCounter, arguments, args), @@ -761,12 +776,12 @@ class kernel_builder : public details::kernel_builder_base { return operator()(argsArr); } - /// @brief Call operator that takes an array of opaque pointers - /// for the function arguments + /// @brief Call operator that takes an array of opaque pointers for the + /// function arguments void operator()(void **argsArray) { jitAndInvoke(argsArray); } - /// Expose the `get()` method necessary for - /// enabling structured bindings on a custom type + /// Expose the `get()` method necessary for enabling structured bindings on + /// a custom type template decltype(auto) get() { if constexpr (N == 0) @@ -777,10 +792,9 @@ class kernel_builder : public details::kernel_builder_base { }; } // namespace cudaq -/// The following std functions are necessary to enable -/// structured bindings on the `kernel_builder` type. -/// e.g. -/// `auto [kernel, theta, phi] = std::make_kernel();` +/// The following std functions are necessary to enable structured bindings on +/// the `kernel_builder` type. +/// e.g. `auto [kernel, theta, phi] = std::make_kernel();` namespace std { template diff --git a/runtime/cudaq/concepts.h b/runtime/cudaq/concepts.h index d2871281ab..dfa2095025 100644 --- a/runtime/cudaq/concepts.h +++ b/runtime/cudaq/concepts.h @@ -8,8 +8,10 @@ #pragma once +#include "host_config.h" #include +#if CUDAQ_USE_STD20 namespace cudaq { /// @brief Sample or observe calls need to have valid trailing runtime arguments @@ -23,3 +25,4 @@ template concept HasVoidReturnType = std::is_void_v; } // namespace cudaq +#endif diff --git a/runtime/cudaq/cudaq.cpp b/runtime/cudaq/cudaq.cpp index c093b31e2f..3a4ae49cf2 100644 --- a/runtime/cudaq/cudaq.cpp +++ b/runtime/cudaq/cudaq.cpp @@ -341,7 +341,7 @@ void __nvqpp_initializer_list_to_vector_bool(std::vector &result, char *p = initList; for (std::size_t i = 0; i < size; ++i, ++p) result.push_back(static_cast(*p)); - // Free the initialization list, which was stack allocated. + // Free the initialization list, which was heap allocated. free(initList); } } diff --git a/runtime/cudaq/qis/qarray.h b/runtime/cudaq/qis/qarray.h index 6f0a1cf67c..78055856a6 100644 --- a/runtime/cudaq/qis/qarray.h +++ b/runtime/cudaq/qis/qarray.h @@ -8,22 +8,27 @@ #pragma once -#include "qview.h" +#include "cudaq/qis/qview.h" +#include "host_config.h" namespace cudaq { +#if CUDAQ_USE_STD20 namespace details { -/// qarray for N < 1 should be a compile error +/// `qarray` for N < 1 should be a compile error template concept ValidQArraySize = N > 0; } // namespace details +#endif /// @brief A `qarray` is an owning, compile-time sized container for qudits. /// The semantics of the `qarray` follows that of a `std::array` for qudits. It /// is templated on the number of qudits contained and the number of levels for /// the held qudits. template +#if CUDAQ_USE_STD20 requires(details::ValidQArraySize) +#endif class qarray { public: /// @brief Useful typedef indicating the underlying qudit type @@ -55,25 +60,37 @@ class qarray { /// @brief Returns the qudit at `idx`. value_type &operator[](const std::size_t idx) { return qudits[idx]; } - /// @brief Returns the `[0, count)` qudits as a non-owning qview. + /// @return the `[0, count)` qudits as a non-owning `qview`. qview front(std::size_t count) { +#if CUDAQ_USE_STD20 return std::span(qudits).subspan(0, count); +#else + return {qudits.begin(), count}; +#endif } - /// @brief Returns the first qudit. + /// @return the first qudit. value_type &front() { return qudits.front(); } - /// @brief Returns the `[count, size())` qudits as a non-owning qview + /// @return the `[count, size())` qudits as a non-owning `qview`. qview back(std::size_t count) { +#if CUDAQ_USE_STD20 return std::span(qudits).subspan(size() - count, count); +#else + return {qudits.end() - count, count}; +#endif } /// @brief Returns the last qudit. value_type &back() { return qudits.back(); } - /// @brief Returns the `[start, start+size)` qudits as a non-owning qview + /// @return the `[start, start+size)` qudits as a non-owning `qview` qview slice(std::size_t start, std::size_t size) { +#if CUDAQ_USE_STD20 return std::span(qudits).subspan(start, size); +#else + return {qudits.begin() + start, size}; +#endif } /// @brief Returns the number of contained qudits. diff --git a/runtime/cudaq/qis/qreg.h b/runtime/cudaq/qis/qreg.h index 65016f8cc6..161c80afb3 100644 --- a/runtime/cudaq/qis/qreg.h +++ b/runtime/cudaq/qis/qreg.h @@ -8,60 +8,75 @@ #pragma once -#include "qspan.h" +#include "cudaq/qis/qspan.h" +#include "host_config.h" namespace cudaq { +#if CUDAQ_USE_STD20 namespace details { -/// qreg for N < 1 should be a compile error +/// `qreg` for N < 1 should be a compile error template concept ValidQregSize = N > 0; } // namespace details +#endif -/// @brief A qreg is a container for qudits. This container can be -/// dynamic or compile-time-size specified. By default, -/// the qreg is constructed as a dynamic register (vector-like) -/// of qubits (2-level). This can be changed via the qreg type -/// template parameters. +/// @brief A `qreg` is a container for qudits. This container can be dynamic or +/// compile-time-size specified. By default, the `qreg` is constructed as a +/// dynamic register (vector-like) of qubits (2-level). This can be changed via +/// the `qreg` type template parameters. +#if CUDAQ_USE_STD20 template requires(details::ValidQregSize) +#else +template 0)>> +#endif class qreg { public: /// @brief Useful typedef indicating the underlying qudit type using value_type = qudit; private: +#if CUDAQ_USE_STD20 /// @brief If the size is dynamic, then we use vector of qudits, /// if not dynamic, use an array. std::conditional_t, std::array> qudits; +#else + std::vector qudits; +#endif public: - /// @brief Construct a qreg with `size` qudits in the |0> state. - /// Can only be used for dyn sized qregs +#if CUDAQ_USE_STD20 + /// Construct a `qreg` with \p size qudits in the |0> state. Can only be used + /// for `dyn` sized `qregs`. qreg(std::size_t size) requires(N == dyn) : qudits(size) {} - /// Nullary constructor - /// can only be used for qreg q; + /// Nullary constructor. Can only be used for `qreg` q; qreg() requires(N != dyn) {} /// @cond /// Nullary constructor - /// meant to be used with kernel_builder> + /// meant to be used with `kernel_builder>` + /// @endcond qreg() requires(N == dyn) : qudits(1) {} +#else + qreg(std::size_t size) : qudits(size) {} - /// @endcond + qreg() {} +#endif - /// @brief qregs cannot be copied + // A `qreg` cannot be copied. qreg(qreg const &) = delete; - /// @brief qregs cannot be moved + // A `qreg` cannot be moved. qreg(qreg &&) = delete; /// @brief Iterator interface, begin. @@ -73,7 +88,11 @@ class qreg { /// @brief Returns the `[0, count)` qudits. qspan front(std::size_t count) { +#if CUDAQ_USE_STD20 return std::span(qudits).subspan(0, count); +#else + return {qudits.begin(), count}; +#endif } /// @brief Returns the first qudit. @@ -81,7 +100,11 @@ class qreg { /// @brief Returns the `[count, size())` qudits. qspan back(std::size_t count) { +#if CUDAQ_USE_STD20 return std::span(qudits).subspan(size() - count, count); +#else + return {qudits.end() - count, count}; +#endif } /// @brief Returns the last qudit. @@ -89,7 +112,11 @@ class qreg { /// @brief Returns the `[start, start+size)` qudits. qspan slice(std::size_t start, std::size_t size) { +#if CUDAQ_USE_STD20 return std::span(qudits).subspan(start, size); +#else + return {qudits.begin() + start, size}; +#endif } /// @brief Returns the number of contained qudits. @@ -99,6 +126,11 @@ class qreg { void clear() { qudits.clear(); } }; +#if !CUDAQ_USE_STD20 +template <> +qreg::qreg() : qudits(1) {} +#endif + // Provide the default qreg q(SIZE) deduction guide qreg(std::size_t) -> qreg; } // namespace cudaq diff --git a/runtime/cudaq/qis/qspan.h b/runtime/cudaq/qis/qspan.h index 08f02177dc..882e55d2c2 100644 --- a/runtime/cudaq/qis/qspan.h +++ b/runtime/cudaq/qis/qspan.h @@ -8,12 +8,19 @@ #pragma once -#include "qudit.h" +#include "cudaq/qis/qudit.h" +#include "host_config.h" +#if CUDAQ_USE_STD20 #include #include +#endif namespace cudaq { +#if CUDAQ_USE_STD20 inline constexpr auto dyn = std::dynamic_extent; +#else +inline constexpr std::size_t dyn = ~0; +#endif // The qspan represents a non-owning container of qudits. As such // it models both dynamically allocated qudit registers as well as @@ -25,6 +32,7 @@ class qspan { // that this span contains. using value_type = qudit; +#if CUDAQ_USE_STD20 private: // Reference to the non-owning span of qudits. std::span qudits; @@ -53,6 +61,7 @@ class qspan { // Returns the `[count, size())` qudits. qspan back(std::size_t count) { return qudits.last(count); } + // Returns the last qudit. value_type &back() { return qudits.back(); } @@ -68,5 +77,39 @@ class qspan { // Returns the number of contained qudits. std::size_t size() const { return qudits.size(); } + +#else + // C++11 reimplementation of a std::span. + +private: + value_type *qudits = nullptr; + std::size_t qusize = 0; + +public: + qspan(value_type *otherQudits, std::size_t otherQusize) + : qudits(otherQudits), qusize(otherQusize) {} + template + qspan(Iterator &&otherQudits, std::size_t otherQusize) + : qudits(&*otherQudits), qusize(otherQusize) {} + template + qspan(R &&other) + : qudits(&*other.begin()), + qusize(std::distance(other.begin(), other.end())) {} + qspan(qspan const &other) : qudits(other.qudits), qusize(other.qusize) {} + + value_type *begin() { return qudits; } + value_type *end() { return qudits + qusize; } + value_type &operator[](const std::size_t idx) { return qudits[idx]; } + qspan front(std::size_t count) { return {qudits, count}; } + value_type &front() { return *qudits; } + qspan back(std::size_t count) { + return {qudits + qusize - count, count}; + } + value_type &back() { return *(qudits + qusize - 1); } + qspan slice(std::size_t start, std::size_t count) { + return {qudits + start, count}; + } + std::size_t size() const { return qusize; } +#endif }; } // namespace cudaq diff --git a/runtime/cudaq/qis/qubit_qis.h b/runtime/cudaq/qis/qubit_qis.h index 2a267afbd9..60d72cf7a1 100644 --- a/runtime/cudaq/qis/qubit_qis.h +++ b/runtime/cudaq/qis/qubit_qis.h @@ -9,11 +9,12 @@ #pragma once #include "common/MeasureCounts.h" +#include "cudaq/qis/modifiers.h" +#include "cudaq/qis/qarray.h" +#include "cudaq/qis/qreg.h" +#include "cudaq/qis/qvector.h" #include "cudaq/spin_op.h" -#include "modifiers.h" -#include "qarray.h" -#include "qreg.h" -#include "qvector.h" +#include "host_config.h" #include #include @@ -103,8 +104,12 @@ void oneQubitApply(QubitArgs &...args) { /// @brief This function will apply a multi-controlled operation with the given /// control register on the single qubit target. +#if CUDAQ_USE_STD20 template requires(std::ranges::range) +#else +template +#endif void oneQubitApplyControlledRange(QubitRange &ctrls, qubit &target) { // Get the name of the operation auto gateName = QuantumOp::name(); @@ -119,6 +124,18 @@ void oneQubitApplyControlledRange(QubitRange &ctrls, qubit &target) { {cudaq::qubitToQuditInfo(target)}); } +#if CUDAQ_USE_STD20 +#define TEMPLATE(SORT) \ + template \ + requires(std::ranges::range) +#else +#define TEMPLATE(SORT) \ + template >, \ + cudaq::qubit>>> +#endif + #define CUDAQ_QIS_ONE_TARGET_QUBIT_(NAME) \ namespace types { \ struct NAME { \ @@ -129,20 +146,17 @@ void oneQubitApplyControlledRange(QubitRange &ctrls, qubit &target) { void NAME(QubitArgs &...args) { \ oneQubitApply(args...); \ } \ - template \ - requires(std::ranges::range) \ + TEMPLATE(ctrl) \ void NAME(QubitRange &ctrls, qubit &target) { \ oneQubitApplyControlledRange(ctrls, target); \ } \ - template \ - requires(std::ranges::range) \ + TEMPLATE(base) \ void NAME(QubitRange &qr) { \ for (auto &q : qr) { \ NAME(q); \ } \ } \ - template \ - requires(std::ranges::range) \ + TEMPLATE(base) \ void NAME(QubitRange &&qr) { \ for (auto &q : qr) { \ NAME(q); \ @@ -156,6 +170,7 @@ CUDAQ_QIS_ONE_TARGET_QUBIT_(y) CUDAQ_QIS_ONE_TARGET_QUBIT_(z) CUDAQ_QIS_ONE_TARGET_QUBIT_(t) CUDAQ_QIS_ONE_TARGET_QUBIT_(s) +#undef TEMPLATE template @@ -188,9 +203,17 @@ void oneQubitSingleParameterApply(ScalarAngle angle, QubitArgs &...args) { std::is_same_v); } +#if CUDAQ_USE_STD20 template requires(std::ranges::range) +#else +template < + typename QuantumOp, typename mod = ctrl, typename ScalarAngle, + typename QubitRange, + typename = std::enable_if_t>, cudaq::qubit>>> +#endif void oneQubitSingleParameterControlledRange(ScalarAngle angle, QubitRange &ctrls, qubit &target) { // Get the name of the operation @@ -206,6 +229,18 @@ void oneQubitSingleParameterControlledRange(ScalarAngle angle, {qubitToQuditInfo(target)}); } +#if CUDAQ_USE_STD20 +#define TEMPLATE(SORT) \ + template \ + requires(std::ranges::range) +#else +#define TEMPLATE(SORT) \ + template >, \ + cudaq::qubit>>> +#endif + #define CUDAQ_QIS_PARAM_ONE_TARGET_(NAME) \ namespace types { \ struct NAME { \ @@ -216,8 +251,7 @@ void oneQubitSingleParameterControlledRange(ScalarAngle angle, void NAME(ScalarAngle angle, QubitArgs &...args) { \ oneQubitSingleParameterApply(angle, args...); \ } \ - template \ - requires(std::ranges::range) \ + TEMPLATE(ctrl) \ void NAME(ScalarAngle angle, QubitRange &ctrls, qubit &target) { \ oneQubitSingleParameterControlledRange( \ angle, ctrls, target); \ @@ -229,6 +263,7 @@ CUDAQ_QIS_PARAM_ONE_TARGET_(rx) CUDAQ_QIS_PARAM_ONE_TARGET_(ry) CUDAQ_QIS_PARAM_ONE_TARGET_(rz) CUDAQ_QIS_PARAM_ONE_TARGET_(r1) +#undef TEMPLATE // Define the swap gate instruction and control versions of it namespace types { @@ -257,8 +292,15 @@ void swap(QubitArgs &...args) { getExecutionManager()->apply("swap", {}, controls, targets); } +#if CUDAQ_USE_STD20 template requires(std::ranges::range) +#else +template >, + cudaq::qubit>>> +#endif void swap(QuantumRegister &ctrls, qubit &src, qubit &target) { std::vector controls; std::transform(ctrls.begin(), ctrls.end(), std::back_inserter(controls), @@ -277,10 +319,17 @@ inline void cs(qubit &q, qubit &r) { s(q, r); } inline void ct(qubit &q, qubit &r) { t(q, r); } inline void ccx(qubit &q, qubit &r, qubit &s) { x(q, r, s); } -/// @brief Apply a general Pauli rotation, takes a qubit register and the -/// size must be equal to the pauli word length. +/// @brief Apply a general Pauli rotation, takes a qubit register and the size +/// must be equal to the Pauli word length. +#if CUDAQ_USE_STD20 template requires(std::ranges::range) +#else +template < + typename QubitRange, + typename = std::enable_if_t>, cudaq::qubit>>> +#endif void exp_pauli(double theta, QubitRange &&qubits, const char *pauliWord) { std::vector quditInfos; std::transform(qubits.begin(), qubits.end(), std::back_inserter(quditInfos), @@ -290,7 +339,7 @@ void exp_pauli(double theta, QubitRange &&qubits, const char *pauliWord) { } /// @brief Apply a general Pauli rotation, takes a variadic set of -/// qubits, and the number of qubits must be equal to the pauli word length. +/// qubits, and the number of qubits must be equal to the Pauli word length. template void exp_pauli(double theta, const char *pauliWord, QubitArgs &...qubits) { @@ -305,9 +354,17 @@ void exp_pauli(double theta, const char *pauliWord, QubitArgs &...qubits) { } /// @brief Apply a general Pauli rotation with control qubits and a variadic set -/// of qubits. The number of qubits must be equal to the pauli word length. +/// of qubits. The number of qubits must be equal to the Pauli word length. +#if CUDAQ_USE_STD20 template requires(std::ranges::range) +#else +template >, + qubit>>> +#endif void exp_pauli(QuantumRegister &ctrls, double theta, const char *pauliWord, QubitArgs &...qubits) { std::vector controls; @@ -346,8 +403,15 @@ inline void reset(qubit &q) { } // Measure all qubits in the range, return vector of 0,1 +#if CUDAQ_USE_STD20 template - requires(std::ranges::range) + requires std::ranges::range +#else +template < + typename QubitRange, + typename = std::enable_if_t>, cudaq::qubit>>> +#endif std::vector mz(QubitRange &q) { std::vector b; for (auto &qq : q) { @@ -359,8 +423,15 @@ std::vector mz(QubitRange &q) { template std::vector mz(qubit &q, Qs &&...qs); +#if CUDAQ_USE_STD20 template requires(std::ranges::range) +#else +template < + typename QubitRange, typename... Qs, + typename = std::enable_if_t>, cudaq::qubit>>> +#endif std::vector mz(QubitRange &qr, Qs &&...qs) { std::vector result = mz(qr); auto rest = mz(std::forward(qs)...); @@ -412,6 +483,7 @@ inline int64_t to_integer(std::string bitString) { return std::stoull(bitString, nullptr, 2); } +#if CUDAQ_USE_STD20 // This concept tests if `Kernel` is a `Callable` that takes the arguments, // `Args`, and returns `void`. template @@ -427,10 +499,17 @@ concept takes_qubit = signature; template concept takes_qreg = signature &)>; +#endif // Control the given cudaq kernel on the given control qubit +#if CUDAQ_USE_STD20 template requires isCallableVoidKernel +#else +template >> +#endif void control(QuantumKernel &&kernel, qubit &control, Args &&...args) { std::vector ctrls{control.id()}; getExecutionManager()->startCtrlRegion(ctrls); @@ -439,9 +518,18 @@ void control(QuantumKernel &&kernel, qubit &control, Args &&...args) { } // Control the given cudaq kernel on the given register of control qubits +#if CUDAQ_USE_STD20 template requires std::ranges::range && isCallableVoidKernel +#else +template >, + cudaq::qubit> && + std::is_invocable_r_v>> +#endif void control(QuantumKernel &&kernel, QuantumRegister &&ctrl_qubits, Args &&...args) { std::vector ctrls; @@ -455,8 +543,14 @@ void control(QuantumKernel &&kernel, QuantumRegister &&ctrl_qubits, // Control the given cudaq kernel on the given list of references to control // qubits. +#if CUDAQ_USE_STD20 template requires isCallableVoidKernel +#else +template >> +#endif void control(QuantumKernel &&kernel, std::vector> &&ctrl_qubits, Args &&...args) { @@ -470,8 +564,14 @@ void control(QuantumKernel &&kernel, } // Apply the adjoint of the given cudaq kernel +#if CUDAQ_USE_STD20 template requires isCallableVoidKernel +#else +template >> +#endif void adjoint(QuantumKernel &&kernel, Args &&...args) { // static_assert(true, "adj not implemented yet."); getExecutionManager()->startAdjointRegion(); @@ -482,9 +582,16 @@ void adjoint(QuantumKernel &&kernel, Args &&...args) { /// Instantiate this type to affect C A C^dag, where the user /// provides cudaq Kernels C and A (compute, action). // struct compute_action { +#if CUDAQ_USE_STD20 template requires isCallableVoidKernel && isCallableVoidKernel +#else +template < + typename ComputeFunction, typename ActionFunction, + typename = std::enable_if_t && + std::is_invocable_r_v>> +#endif void compute_action(ComputeFunction &&c, ActionFunction &&a) { c(); a(); @@ -494,9 +601,16 @@ void compute_action(ComputeFunction &&c, ActionFunction &&a) { /// Instantiate this type to affect C^dag A C, where the user /// provides cudaq Kernels C and A (compute, action). // struct compute_dag_action { +#if CUDAQ_USE_STD20 template requires isCallableVoidKernel && isCallableVoidKernel +#else +template < + typename ComputeFunction, typename ActionFunction, + typename = std::enable_if_t && + std::is_invocable_r_v>> +#endif void compute_dag_action(ComputeFunction &&c, ActionFunction &&a) { adjoint(c); a(); @@ -505,8 +619,12 @@ void compute_dag_action(ComputeFunction &&c, ActionFunction &&a) { /// Helper function to extract a slice of a `std::vector` to be used within /// CUDA Quantum kernels. +#if CUDAQ_USE_STD20 template requires(std::is_arithmetic_v) +#else +template >> +#endif std::vector slice_vector(std::vector &original, std::size_t start, std::size_t count) { std::vector ret(original.begin() + start, diff --git a/runtime/cudaq/qis/qvector.h b/runtime/cudaq/qis/qvector.h index eebdbae9f6..499c119286 100644 --- a/runtime/cudaq/qis/qvector.h +++ b/runtime/cudaq/qis/qvector.h @@ -8,7 +8,8 @@ #pragma once -#include "qview.h" +#include "cudaq/qis/qview.h" +#include "host_config.h" namespace cudaq { @@ -53,25 +54,37 @@ class qvector { /// @brief Returns the qudit at `idx`. value_type &operator[](const std::size_t idx) { return qudits[idx]; } - /// @brief Returns the `[0, count)` qudits as a non-owning qview. + /// @brief Returns the `[0, count)` qudits as a non-owning `qview`. qview front(std::size_t count) { +#if CUDAQ_USE_STD20 return std::span(qudits).subspan(0, count); +#else + return {qudits.begin(), count}; +#endif } /// @brief Returns the first qudit. value_type &front() { return qudits.front(); } - /// @brief Returns the `[count, size())` qudits as a non-owning qview + /// @brief Returns the `[count, size())` qudits as a non-owning `qview` qview back(std::size_t count) { +#if CUDAQ_USE_STD20 return std::span(qudits).subspan(size() - count, count); +#else + return {qudits.end() - count, count}; +#endif } /// @brief Returns the last qudit. value_type &back() { return qudits.back(); } - /// @brief Returns the `[start, start+size)` qudits as a non-owning qview + /// @brief Returns the `[start, start+size)` qudits as a non-owning `qview` qview slice(std::size_t start, std::size_t size) { +#if CUDAQ_USE_STD20 return std::span(qudits).subspan(start, size); +#else + return {qudits.begin() + start, size}; +#endif } /// @brief Returns the number of contained qudits. diff --git a/runtime/cudaq/qis/qview.h b/runtime/cudaq/qis/qview.h index d73e74f142..5b8777703c 100644 --- a/runtime/cudaq/qis/qview.h +++ b/runtime/cudaq/qis/qview.h @@ -8,26 +8,30 @@ #pragma once -#include "qudit.h" +#include "cudaq/qis/qudit.h" +#include "host_config.h" #include +#if CUDAQ_USE_STD20 #include +#endif namespace cudaq { -// The qview represents a non-owning container of qudits. +/// The `qview` represents a non-owning container of qudits. template class qview { public: - // Useful typedef exposing the underlying qudit type - // that this qview contains. + /// Useful typedef exposing the underlying qudit type that this `qview` + /// contains. using value_type = qudit; +#if CUDAQ_USE_STD20 private: /// @brief Reference to the non-owning span of qudits std::span qudits; public: - /// @brief Construct a qview that refers to the qudits in `other`. + /// @brief Construct a `qview` that refers to the qudits in `other`. template requires(std::ranges::range) qview(R &&other) : qudits(other.begin(), other.end()) {} @@ -44,7 +48,7 @@ class qview { /// @brief Returns the qudit at `idx`. value_type &operator[](const std::size_t idx) { return qudits[idx]; } - /// @brief Returns the `[0, count)` qudits as a new qview. + /// @return the `[0, count)` qudits as a new `qview`. qview front(std::size_t count) { return qudits.first(count); } /// @brief Returns the first qudit. @@ -55,7 +59,6 @@ class qview { // Returns the last qudit. value_type &back() { return qudits.back(); } - /// @brief Returns the `[start, start+count)` qudits. qview slice(std::size_t start, std::size_t count) { return qudits.subspan(start, count); @@ -63,5 +66,39 @@ class qview { /// @brief Returns the number of contained qudits. std::size_t size() const { return qudits.size(); } + +#else + // C++11 reimplementation of qview. + +private: + value_type *qudits = nullptr; + std::size_t qusize = 0; + +public: + qview(value_type *otherQudits, std::size_t otherQusize) + : qudits(otherQudits), qusize(otherQusize) {} + template + qview(Iterator &&otherQudits, std::size_t otherQusize) + : qudits(&*otherQudits), qusize(otherQusize) {} + template + qview(R &&other) + : qudits(&*other.begin()), + qusize(std::distance(other.begin(), other.end())) {} + qview(qview const &other) : qudits(other.qudits), qusize(other.qusize) {} + + value_type *begin() { return qudits; } + value_type *end() { return qudits + qusize; } + value_type &operator[](const std::size_t idx) { return qudits[idx]; } + qview front(std::size_t count) { return {qudits, count}; } + value_type &front() { return *qudits; } + qview back(std::size_t count) { + return {qudits + qusize - count, count}; + } + value_type &back() { return *(qudits + qusize - 1); } + qview slice(std::size_t start, std::size_t count) { + return {qudits + start, count}; + } + std::size_t size() const { return qusize; } +#endif }; } // namespace cudaq diff --git a/runtime/host_config.h b/runtime/host_config.h new file mode 100644 index 0000000000..6fb1908029 --- /dev/null +++ b/runtime/host_config.h @@ -0,0 +1,12 @@ +/****************************************************************-*- C++ -*-**** + * Copyright (c) 2022 - 2023 NVIDIA Corporation & Affiliates. * + * All rights reserved. * + * * + * This source code and the accompanying materials are made available under * + * the terms of the Apache License 2.0 which accompanies this distribution. * + ******************************************************************************/ + +#pragma once + +#define CUDAQ_USE_STD20 (__cplusplus >= 202002L) +#define CUDAQ_APPLE_CLANG (defined(__apple_build_version__)) diff --git a/scripts/build_docs.sh b/scripts/build_docs.sh index 09db21d1a9..e4a0e76fc8 100644 --- a/scripts/build_docs.sh +++ b/scripts/build_docs.sh @@ -134,6 +134,7 @@ sed 's@${CUDAQ_REPO_ROOT}@'"${repo_root}"'@' > "${doxygen_output_dir}/Doxyfile" "$doxygen_exe" "${doxygen_output_dir}/Doxyfile" 2> "$logs_dir/doxygen_error.txt" 1> "$logs_dir/doxygen_output.txt" doxygen_exit_code=$? if [ ! "$doxygen_exit_code" -eq "0" ]; then + cat "$logs_dir/doxygen_output.txt" "$logs_dir/doxygen_error.txt" echo "Failed to generate documentation using doxygen." echo "Doxygen exit code: $doxygen_exit_code" docs_exit_code=11 diff --git a/test/NVQPP/IQPE_conditionals.cpp b/test/NVQPP/IQPE_conditionals.cpp index f8feeb7261..dd248e21e0 100644 --- a/test/NVQPP/IQPE_conditionals.cpp +++ b/test/NVQPP/IQPE_conditionals.cpp @@ -6,8 +6,9 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --enable-mlir %s -o %basename_t.x && ./%basename_t.x | FileCheck %s && rm %basename_t.x -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s && rm %basename_t.x +// RUN: nvq++ --enable-mlir %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include diff --git a/test/NVQPP/auto_kernel.cpp b/test/NVQPP/auto_kernel.cpp index 89abc244af..a22c0e5b34 100644 --- a/test/NVQPP/auto_kernel.cpp +++ b/test/NVQPP/auto_kernel.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --enable-mlir -v %s -o out_auto_kernel.x && ./out_auto_kernel.x | FileCheck %s +// RUN: nvq++ --enable-mlir -v %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s #include diff --git a/test/NVQPP/bug_qubit.cpp b/test/NVQPP/bug_qubit.cpp index 70d3298a7f..b28953521d 100644 --- a/test/NVQPP/bug_qubit.cpp +++ b/test/NVQPP/bug_qubit.cpp @@ -9,10 +9,11 @@ // This code is from Issue 251. // clang-format off -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // RUN: cudaq-quake %s | cudaq-opt --promote-qubit-allocation | FileCheck --check-prefixes=MLIR %s #include diff --git a/test/NVQPP/callable_kernel_arg.cpp b/test/NVQPP/callable_kernel_arg.cpp index 8b96f9cebe..d507aff768 100644 --- a/test/NVQPP/callable_kernel_arg.cpp +++ b/test/NVQPP/callable_kernel_arg.cpp @@ -7,10 +7,11 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/conditional_sample.cpp b/test/NVQPP/conditional_sample.cpp index c96d37ce08..b7695ad4d2 100644 --- a/test/NVQPP/conditional_sample.cpp +++ b/test/NVQPP/conditional_sample.cpp @@ -7,8 +7,10 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --enable-mlir %s -o %basename_t.x && ./%basename_t.x -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x +// RUN: nvq++ --enable-mlir %s -o %t && %t +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t +// clang-format on // The test here is the assert statement. diff --git a/test/NVQPP/cudaq_observe.cpp b/test/NVQPP/cudaq_observe.cpp index 48b8885378..03a608d631 100644 --- a/test/NVQPP/cudaq_observe.cpp +++ b/test/NVQPP/cudaq_observe.cpp @@ -7,12 +7,14 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s // 2 different IQM machines for 2 different topologies -// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t +// clang-format on #include #include @@ -48,4 +50,5 @@ int main() { // Note: seeds 2 and 12 will push this to -2 instead of -1. All all other // seeds in 1-100 range will be -1.x. + // CHECK: Energy is -1. diff --git a/test/NVQPP/device_code_loaded.cpp b/test/NVQPP/device_code_loaded.cpp index b596250cd1..be9fd1d6cc 100644 --- a/test/NVQPP/device_code_loaded.cpp +++ b/test/NVQPP/device_code_loaded.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --enable-mlir %s -o out_testdcl.x && ./out_testdcl.x | FileCheck %s +// RUN: nvq++ --enable-mlir %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s #include diff --git a/test/NVQPP/graph_coloring-1.cpp b/test/NVQPP/graph_coloring-1.cpp index 488170889d..ba2b38a57d 100644 --- a/test/NVQPP/graph_coloring-1.cpp +++ b/test/NVQPP/graph_coloring-1.cpp @@ -7,7 +7,9 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ -v %s -o %basename_t.x --target quantinuum --emulate && ./%basename_t.x | FileCheck %s +// RUN: nvq++ -v %s -o %t --target quantinuum --emulate && %t | FileCheck %s +// RUN: nvq++ -std=c++17 %s --enable-mlir -o %t +// clang-format on #include #include diff --git a/test/NVQPP/graph_coloring.cpp b/test/NVQPP/graph_coloring.cpp index ee16fcfec5..c94d79536f 100644 --- a/test/NVQPP/graph_coloring.cpp +++ b/test/NVQPP/graph_coloring.cpp @@ -7,7 +7,9 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ -v %s -o %basename_t.x --target quantinuum --emulate && ./%basename_t.x | FileCheck %s +// RUN: nvq++ -v %s -o %t --target quantinuum --emulate && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t +// clang-format on #include #include diff --git a/test/NVQPP/if_jit.cpp b/test/NVQPP/if_jit.cpp index c08c3fb348..e8f3b2476c 100644 --- a/test/NVQPP/if_jit.cpp +++ b/test/NVQPP/if_jit.cpp @@ -8,10 +8,13 @@ // This code is from Issue 296. -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// clang-format off +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t +// clang-format on #include #include @@ -35,4 +38,4 @@ int main() { return 0; } -// CHECK: 1 \ No newline at end of file +// CHECK: 1 diff --git a/test/NVQPP/include.cpp b/test/NVQPP/include.cpp index 23b00724b3..a10d8c8c08 100644 --- a/test/NVQPP/include.cpp +++ b/test/NVQPP/include.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --enable-mlir %s -o include.x && ./include.x | FileCheck %s +// RUN: nvq++ --enable-mlir %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s #include "include/include.h" #include diff --git a/test/NVQPP/int8_t.cpp b/test/NVQPP/int8_t.cpp index a1127995fb..6574c5dd44 100644 --- a/test/NVQPP/int8_t.cpp +++ b/test/NVQPP/int8_t.cpp @@ -7,10 +7,12 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t +// clang-format on #include #include diff --git a/test/NVQPP/int8_t_free_func.cpp b/test/NVQPP/int8_t_free_func.cpp index 89a21cf6fe..b315d0d61c 100644 --- a/test/NVQPP/int8_t_free_func.cpp +++ b/test/NVQPP/int8_t_free_func.cpp @@ -7,10 +7,12 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t +// clang-format on #include #include diff --git a/test/NVQPP/lambda_introspection.cpp b/test/NVQPP/lambda_introspection.cpp index 0252b8c9df..7580590321 100644 --- a/test/NVQPP/lambda_introspection.cpp +++ b/test/NVQPP/lambda_introspection.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --enable-mlir %s -o out_testlambdaI.x && ./out_testlambdaI.x | FileCheck %s +// RUN: nvq++ --enable-mlir %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s #include diff --git a/test/NVQPP/load_value.cpp b/test/NVQPP/load_value.cpp index e3a7c86a30..32ef9e157b 100644 --- a/test/NVQPP/load_value.cpp +++ b/test/NVQPP/load_value.cpp @@ -7,11 +7,13 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t +// clang-format on #include #include diff --git a/test/NVQPP/mapping_test-1.cpp b/test/NVQPP/mapping_test-1.cpp index f7a3c1b174..7aad08109c 100644 --- a/test/NVQPP/mapping_test-1.cpp +++ b/test/NVQPP/mapping_test-1.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ -v %s -o %basename_t.x --target oqc --emulate && CUDAQ_DUMP_JIT_IR=1 ./%basename_t.x |& FileCheck %s +// RUN: nvq++ -v %s -o %t --target oqc --emulate && CUDAQ_DUMP_JIT_IR=1 %t |& FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/mapping_test-2.cpp b/test/NVQPP/mapping_test-2.cpp index 80f55ee569..2592656ac8 100644 --- a/test/NVQPP/mapping_test-2.cpp +++ b/test/NVQPP/mapping_test-2.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ -v %s -o %basename_t.x --target oqc --emulate && CUDAQ_DUMP_JIT_IR=1 ./%basename_t.x |& FileCheck %s +// RUN: nvq++ -v %s -o %t --target oqc --emulate && CUDAQ_DUMP_JIT_IR=1 %t |& FileCheck %s +// RUN: nvq++ -std=c++20 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/other_introspection.cpp b/test/NVQPP/other_introspection.cpp index a65701e27b..648806293e 100644 --- a/test/NVQPP/other_introspection.cpp +++ b/test/NVQPP/other_introspection.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --enable-mlir %s -o introspection.x && ./introspection.x | grep lookhere | FileCheck %s +// RUN: nvq++ --enable-mlir %s -o %t && %t | grep lookhere | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/phase_estimation.cpp b/test/NVQPP/phase_estimation.cpp index a6425056ac..95084dab9e 100644 --- a/test/NVQPP/phase_estimation.cpp +++ b/test/NVQPP/phase_estimation.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && CUDAQ_DUMP_JIT_IR=1 ./%basename_t.x &> %basename_t.ir && cat %basename_t.ir | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && CUDAQ_DUMP_JIT_IR=1 %t &> %basename_t.ir && cat %basename_t.ir | FileCheck %s && rm -f %basename_t.ir +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/predefined_lib_mode.cpp b/test/NVQPP/predefined_lib_mode.cpp index 92c02e6a8e..1fc315ba5e 100644 --- a/test/NVQPP/predefined_lib_mode.cpp +++ b/test/NVQPP/predefined_lib_mode.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ // clang-format off -// RUN: nvq++ -DTEST_DEF -DMY_VAR=\"CUDAQ\" %s -o out_test_predefined_lib_mode.x && ./out_test_predefined_lib_mode.x | FileCheck %s +// RUN: nvq++ -DTEST_DEF -DMY_VAR=\"CUDAQ\" %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir -DTEST_DEF -DMY_VAR=\"CUDAQ\" %s -o %t // clang-format on #include diff --git a/test/NVQPP/predefined_mlir_mode.cpp b/test/NVQPP/predefined_mlir_mode.cpp index 09db332d67..7e859ea9d2 100644 --- a/test/NVQPP/predefined_mlir_mode.cpp +++ b/test/NVQPP/predefined_mlir_mode.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ // clang-format off -// RUN: nvq++ --enable-mlir -DTEST_DEF -DMY_VAR=\"CUDAQ\" %s -o out_test_predefined_mlir_mode.x && ./out_test_predefined_mlir_mode.x | FileCheck %s +// RUN: nvq++ --enable-mlir -DTEST_DEF -DMY_VAR=\"CUDAQ\" %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir -DTEST_DEF -DMY_VAR=\"CUDAQ\" %s -o %t // clang-format on #include diff --git a/test/NVQPP/preprocessor_defines.cpp b/test/NVQPP/preprocessor_defines.cpp index 6d078c7bed..1db8653baa 100644 --- a/test/NVQPP/preprocessor_defines.cpp +++ b/test/NVQPP/preprocessor_defines.cpp @@ -6,8 +6,9 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --enable-mlir %s -o out_defines.x && ./out_defines.x | FileCheck %s && rm out_defines.x -// RUN: nvq++ --enable-mlir -DCUDAQ_HELLO_WORLD %s -o out_defines2.x && ./out_defines2.x | FileCheck --check-prefixes=DEFINE_ON %s && rm out_defines2.x +// RUN: nvq++ --enable-mlir %s -o %t && %t | FileCheck %s +// RUN: nvq++ --enable-mlir -DCUDAQ_HELLO_WORLD %s -o %t && %t | FileCheck --check-prefixes=DEFINE_ON %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s #include "cudaq.h" diff --git a/test/NVQPP/qir_cond_for_break.cpp b/test/NVQPP/qir_cond_for_break.cpp index 6bdaa1cac4..347d3b9868 100644 --- a/test/NVQPP/qir_cond_for_break.cpp +++ b/test/NVQPP/qir_cond_for_break.cpp @@ -6,8 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && \ -// RUN: ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/qir_cond_for_loop-1.cpp b/test/NVQPP/qir_cond_for_loop-1.cpp index c4ce859cb7..4699dcd59e 100644 --- a/test/NVQPP/qir_cond_for_loop-1.cpp +++ b/test/NVQPP/qir_cond_for_loop-1.cpp @@ -7,7 +7,8 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // clang-format on #include diff --git a/test/NVQPP/qir_cond_for_loop-2.cpp b/test/NVQPP/qir_cond_for_loop-2.cpp index a28ae47ac9..80719d5797 100644 --- a/test/NVQPP/qir_cond_for_loop-2.cpp +++ b/test/NVQPP/qir_cond_for_loop-2.cpp @@ -7,7 +7,8 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // clang-format on #include diff --git a/test/NVQPP/qir_cond_for_loop-3.cpp b/test/NVQPP/qir_cond_for_loop-3.cpp index 93df11eaa8..6d13b967d2 100644 --- a/test/NVQPP/qir_cond_for_loop-3.cpp +++ b/test/NVQPP/qir_cond_for_loop-3.cpp @@ -7,7 +7,8 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // clang-format on #include diff --git a/test/NVQPP/qir_cond_for_loop-4.cpp b/test/NVQPP/qir_cond_for_loop-4.cpp index 87fba77c0d..3f5508b76d 100644 --- a/test/NVQPP/qir_cond_for_loop-4.cpp +++ b/test/NVQPP/qir_cond_for_loop-4.cpp @@ -7,7 +7,8 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // XFAIL: * // ^^^^^ This probably needs an issue posted. It's not setting qubitMeasurementFeedback. // It passes on H1-1E but not --emulate diff --git a/test/NVQPP/qir_cond_for_loop-5.cpp b/test/NVQPP/qir_cond_for_loop-5.cpp index ab8160f4c6..f8003c682e 100644 --- a/test/NVQPP/qir_cond_for_loop-5.cpp +++ b/test/NVQPP/qir_cond_for_loop-5.cpp @@ -7,13 +7,15 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // XFAIL: * // ^^^^^ This probably needs an issue posted. It's not setting qubitMeasurementFeedback. // It passes on H1-1E but not --emulate // clang-format on #include +#include #define NUM_ITERATIONS 5 diff --git a/test/NVQPP/qir_cond_for_loop-6.cpp b/test/NVQPP/qir_cond_for_loop-6.cpp index d4ede9f4b2..0fa49ebc30 100644 --- a/test/NVQPP/qir_cond_for_loop-6.cpp +++ b/test/NVQPP/qir_cond_for_loop-6.cpp @@ -7,7 +7,8 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // clang-format on #include diff --git a/test/NVQPP/qir_if_base.cpp b/test/NVQPP/qir_if_base.cpp index 4ad184e290..1acd9b3663 100644 --- a/test/NVQPP/qir_if_base.cpp +++ b/test/NVQPP/qir_if_base.cpp @@ -7,7 +7,8 @@ ******************************************************************************/ // Note: change |& to 2>&1 if running in bash -// RUN: nvq++ -v %s -o %basename_t.x --target ionq --emulate && ./%basename_t.x |& FileCheck %s +// RUN: nvq++ -v %s -o %t --target ionq --emulate && %t |& FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/qir_op1_after_measure.cpp b/test/NVQPP/qir_op1_after_measure.cpp index 4152420690..b84489a756 100644 --- a/test/NVQPP/qir_op1_after_measure.cpp +++ b/test/NVQPP/qir_op1_after_measure.cpp @@ -7,7 +7,8 @@ ******************************************************************************/ // Note: change |& to 2>&1 if running in bash -// RUN: nvq++ -v %s -o %basename_t.x --target oqc --emulate && ./%basename_t.x |& FileCheck %s +// RUN: nvq++ -v %s -o %t --target oqc --emulate && %t |& FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/qir_op2_after_measure.cpp b/test/NVQPP/qir_op2_after_measure.cpp index 289f3d5357..3842241431 100644 --- a/test/NVQPP/qir_op2_after_measure.cpp +++ b/test/NVQPP/qir_op2_after_measure.cpp @@ -7,7 +7,8 @@ ******************************************************************************/ // Note: change |& to 2>&1 if running in bash -// RUN: nvq++ -v %s -o %basename_t.x --target oqc --emulate && ./%basename_t.x |& FileCheck %s +// RUN: nvq++ -v %s -o %t --target oqc --emulate && %t |& FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/qir_op3_after_measure.cpp b/test/NVQPP/qir_op3_after_measure.cpp index 44d5854cf7..8906078307 100644 --- a/test/NVQPP/qir_op3_after_measure.cpp +++ b/test/NVQPP/qir_op3_after_measure.cpp @@ -7,7 +7,8 @@ ******************************************************************************/ // Note: change |& to 2>&1 if running in bash -// RUN: nvq++ -v %s -o %basename_t.x --target oqc --emulate && ./%basename_t.x |& FileCheck %s +// RUN: nvq++ -v %s -o %t --target oqc --emulate && %t |& FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/qir_range_err_compiler.cpp b/test/NVQPP/qir_range_err_compiler.cpp index fad3b2aeeb..5b33af2e4b 100644 --- a/test/NVQPP/qir_range_err_compiler.cpp +++ b/test/NVQPP/qir_range_err_compiler.cpp @@ -8,6 +8,7 @@ // Note: change |& to 2>&1| if running in bash // RUN: cudaq-quake %s |& FileCheck %s +// RUN: cudaq-quake -std=c++17 %s |& FileCheck %s #include #include diff --git a/test/NVQPP/qir_range_err_runtime.cpp b/test/NVQPP/qir_range_err_runtime.cpp index 5a99d20e20..8b06ae1c12 100644 --- a/test/NVQPP/qir_range_err_runtime.cpp +++ b/test/NVQPP/qir_range_err_runtime.cpp @@ -7,8 +7,9 @@ ******************************************************************************/ // Note: change |& to 2>&1| if running in bash -// RUN: nvq++ %s -o %basename_t.x --target quantinuum --emulate && ./%basename_t.x |& FileCheck %s -// RUN: nvq++ %s -o %basename_t.x --target oqc --emulate && ./%basename_t.x |& FileCheck %s +// RUN: nvq++ %s -o %t --target quantinuum --emulate && %t |& FileCheck %s +// RUN: nvq++ %s -o %t --target oqc --emulate && %t |& FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/qir_simple_cond-1.cpp b/test/NVQPP/qir_simple_cond-1.cpp index 3c44434eca..fde2af5e51 100644 --- a/test/NVQPP/qir_simple_cond-1.cpp +++ b/test/NVQPP/qir_simple_cond-1.cpp @@ -7,7 +7,8 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // clang-format on #include diff --git a/test/NVQPP/qir_simple_cond-2.cpp b/test/NVQPP/qir_simple_cond-2.cpp index ec748047b5..23a0ff1693 100644 --- a/test/NVQPP/qir_simple_cond-2.cpp +++ b/test/NVQPP/qir_simple_cond-2.cpp @@ -7,7 +7,8 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // XFAIL: * // ^^^^^ This is caused by this error: invalid instruction found: %2 = xor i1 %0, true // This error is reasonable given the current version of the Adaptive diff --git a/test/NVQPP/qir_string_labels.cpp b/test/NVQPP/qir_string_labels.cpp index 5ba9ec32e3..5b9a955fd9 100644 --- a/test/NVQPP/qir_string_labels.cpp +++ b/test/NVQPP/qir_string_labels.cpp @@ -7,8 +7,9 @@ ******************************************************************************/ // Note: change |& to 2>&1 if running in bash -// RUN: nvq++ -v %s -o %basename_t.x --target quantinuum --emulate && CUDAQ_DUMP_JIT_IR=1 ./%basename_t.x |& FileCheck %s -// RUN: nvq++ -v %s -o %basename_t.x --target ionq --emulate && CUDAQ_DUMP_JIT_IR=1 ./%basename_t.x |& FileCheck --check-prefix IONQ %s +// RUN: nvq++ -v %s -o %t --target quantinuum --emulate && CUDAQ_DUMP_JIT_IR=1 %t |& FileCheck %s +// RUN: nvq++ -v %s -o %t --target ionq --emulate && CUDAQ_DUMP_JIT_IR=1 %t |& FileCheck --check-prefix IONQ %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // Note: iqm not currently tested because it does not currently use QIR #include diff --git a/test/NVQPP/qpp_cpu_target.cpp b/test/NVQPP/qpp_cpu_target.cpp index 64d5132976..0eee5adbea 100644 --- a/test/NVQPP/qpp_cpu_target.cpp +++ b/test/NVQPP/qpp_cpu_target.cpp @@ -6,10 +6,11 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --target qpp-cpu %s -o %basename_t.x && CUDAQ_LOG_LEVEL=info ./%basename_t.x | FileCheck --check-prefix=CHECK-QPP %s -// RUN: CUDAQ_DEFAULT_SIMULATOR="density-matrix-cpu" nvq++ %s -o %basename_t.x && CUDAQ_LOG_LEVEL=info ./%basename_t.x | FileCheck --check-prefix=CHECK-DM %s -// RUN: CUDAQ_DEFAULT_SIMULATOR="foo" nvq++ %s -o %basename_t.x && CUDAQ_LOG_LEVEL=info ./%basename_t.x | FileCheck %s -// RUN: CUDAQ_DEFAULT_SIMULATOR="qpp-cpu" nvq++ --target quantinuum --emulate %s -o %basename_t.x && CUDAQ_LOG_LEVEL=info ./%basename_t.x | FileCheck --check-prefix=CHECK-QPP %s +// RUN: nvq++ --target qpp-cpu %s -o %t && CUDAQ_LOG_LEVEL=info %t | FileCheck --check-prefix=CHECK-QPP %s +// RUN: CUDAQ_DEFAULT_SIMULATOR="density-matrix-cpu" nvq++ %s -o %t && CUDAQ_LOG_LEVEL=info %t | FileCheck --check-prefix=CHECK-DM %s +// RUN: CUDAQ_DEFAULT_SIMULATOR="foo" nvq++ %s -o %t && CUDAQ_LOG_LEVEL=info %t | FileCheck %s +// RUN: CUDAQ_DEFAULT_SIMULATOR="qpp-cpu" nvq++ --target quantinuum --emulate %s -o %t && CUDAQ_LOG_LEVEL=info %t | FileCheck --check-prefix=CHECK-QPP %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include diff --git a/test/NVQPP/qspan_slices.cpp b/test/NVQPP/qspan_slices.cpp index 453e5420b3..b58043988c 100644 --- a/test/NVQPP/qspan_slices.cpp +++ b/test/NVQPP/qspan_slices.cpp @@ -7,13 +7,14 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s // Tests for --disable-qubit-mapping: -// RUN: nvq++ -v %s -o %basename_t.x --target oqc --emulate --disable-qubit-mapping && CUDAQ_MLIR_PRINT_EACH_PASS=1 ./%basename_t.x |& FileCheck --check-prefix=DISABLE %s -// RUN: nvq++ -v %s -o %basename_t.x --target iqm --iqm-machine Adonis --emulate --disable-qubit-mapping && CUDAQ_MLIR_PRINT_EACH_PASS=1 ./%basename_t.x |& FileCheck --check-prefix=DISABLE %s +// RUN: nvq++ -v %s -o %t --target oqc --emulate --disable-qubit-mapping && CUDAQ_MLIR_PRINT_EACH_PASS=1 %t |& FileCheck --check-prefix=DISABLE %s +// RUN: nvq++ -v %s -o %t --target iqm --iqm-machine Adonis --emulate --disable-qubit-mapping && CUDAQ_MLIR_PRINT_EACH_PASS=1 %t |& FileCheck --check-prefix=DISABLE %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s #include #include diff --git a/test/NVQPP/sudoku_2x2-1.cpp b/test/NVQPP/sudoku_2x2-1.cpp index 79c1dc4e5e..ec06e221f8 100644 --- a/test/NVQPP/sudoku_2x2-1.cpp +++ b/test/NVQPP/sudoku_2x2-1.cpp @@ -7,10 +7,11 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/sudoku_2x2-bit_names.cpp b/test/NVQPP/sudoku_2x2-bit_names.cpp index fc599f75f5..81bb3f7dca 100644 --- a/test/NVQPP/sudoku_2x2-bit_names.cpp +++ b/test/NVQPP/sudoku_2x2-bit_names.cpp @@ -7,10 +7,12 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t +// clang-format on #include #include diff --git a/test/NVQPP/sudoku_2x2-reg_name.cpp b/test/NVQPP/sudoku_2x2-reg_name.cpp index 6358a70c38..819ac7e11a 100644 --- a/test/NVQPP/sudoku_2x2-reg_name.cpp +++ b/test/NVQPP/sudoku_2x2-reg_name.cpp @@ -7,10 +7,11 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/sudoku_2x2.cpp b/test/NVQPP/sudoku_2x2.cpp index 4602c43b3f..84484dfdf1 100644 --- a/test/NVQPP/sudoku_2x2.cpp +++ b/test/NVQPP/sudoku_2x2.cpp @@ -7,10 +7,11 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Apollo --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/swap_gate.cpp b/test/NVQPP/swap_gate.cpp index f76f9c8f18..1f781bcce0 100644 --- a/test/NVQPP/swap_gate.cpp +++ b/test/NVQPP/swap_gate.cpp @@ -7,10 +7,11 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s #include "cudaq.h" #include diff --git a/test/NVQPP/template_introspection.cpp b/test/NVQPP/template_introspection.cpp index fbe400383c..8f4a195657 100644 --- a/test/NVQPP/template_introspection.cpp +++ b/test/NVQPP/template_introspection.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --enable-mlir %s -o out_testTemplateI.x && ./out_testTemplateI.x | FileCheck %s +// RUN: nvq++ --enable-mlir %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include diff --git a/test/NVQPP/test-3.cpp b/test/NVQPP/test-3.cpp index 6294487f81..910006963b 100644 --- a/test/NVQPP/test-3.cpp +++ b/test/NVQPP/test-3.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ -v %s -o %basename_t.x --target quantinuum --emulate && ./%basename_t.x | FileCheck %s +// RUN: nvq++ -v %s -o %t --target quantinuum --emulate && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t // XFAIL: * #include diff --git a/test/NVQPP/test-6.cpp b/test/NVQPP/test-6.cpp index f99e91deb5..ce3008d991 100644 --- a/test/NVQPP/test-6.cpp +++ b/test/NVQPP/test-6.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --target quantinuum --emulate -v %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate -v %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include #include diff --git a/test/NVQPP/to_integer.cpp b/test/NVQPP/to_integer.cpp index 0a34f2cf3d..9277a12b85 100644 --- a/test/NVQPP/to_integer.cpp +++ b/test/NVQPP/to_integer.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --enable-mlir %s -o out_testToInt.x && ./out_testToInt.x && rm out_testToInt.x +// RUN: nvq++ --enable-mlir %s -o %t && %t +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t #include diff --git a/test/NVQPP/variable_size_qreg.cpp b/test/NVQPP/variable_size_qreg.cpp index 2b37e4072f..70551eed1f 100644 --- a/test/NVQPP/variable_size_qreg.cpp +++ b/test/NVQPP/variable_size_qreg.cpp @@ -7,10 +7,12 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ --target ionq --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target oqc --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s -// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target iqm --iqm-machine Adonis --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ -std=c++17 --enable-mlir %s -o %t +// clang-format on #include #include diff --git a/tools/cudaq-quake/cudaq-quake.cpp b/tools/cudaq-quake/cudaq-quake.cpp index 1af96530a5..34688d2c3e 100644 --- a/tools/cudaq-quake/cudaq-quake.cpp +++ b/tools/cudaq-quake/cudaq-quake.cpp @@ -111,6 +111,11 @@ static cl::list static cl::list extraClangArgs("Xcudaq", cl::desc("Extra options to pass to clang++")); +static cl::opt stdCpp( + "std", + cl::desc("Specify the C++ standard (c++17, c++20). The default is c++20."), + cl::init("c++20")); + inline bool isStdinInput(StringRef str) { return str == "-"; } //===----------------------------------------------------------------------===// @@ -344,7 +349,7 @@ int main(int argc, char **argv) { }); // Process arguments. - std::vector clArgs = {"-std=c++20", "-resource-dir", + std::vector clArgs = {"-std=" + stdCpp, "-resource-dir", resourceDirPath.string()}; if (verboseClang) clArgs.push_back("-v"); @@ -372,20 +377,18 @@ int main(int argc, char **argv) { clArgs.push_back(LLVM_LIBCXX_INCLUDE_DIR); } - // If the cudaq.h does not exist in the installation directory, - // fallback onto the source install. + // If the cudaq.h does not exist in the installation directory, fallback onto + // the source install. std::filesystem::path cudaqIncludeDir = cudaqInstallPath / "include"; auto cudaqHeader = cudaqIncludeDir / "cudaq.h"; if (!std::filesystem::exists(cudaqHeader)) // need to fall back to the build environment. cudaqIncludeDir = std::string(FALLBACK_CUDAQ_INCLUDE_DIR); - // One final check here, do we have this header, - // if not we cannot proceed. + // One final check here, do we have this header, if not we cannot proceed. if (!std::filesystem::exists(cudaqIncludeDir / "cudaq.h")) { llvm::errs() << "Invalid CUDA Quantum install configuration, cannot find " - "CUDA Quantum " - "include directory.\n"; + "CUDA Quantum include directory.\n"; return 1; } @@ -419,8 +422,7 @@ int main(int argc, char **argv) { for (auto &xtra : extraClangArgs) clArgs.push_back(xtra); - // Allow a user to specify extra args for clang via - // an environment variable. + // Allow a user to specify extra args for clang via an environment variable. if (auto extraArgs = std::getenv("CUDAQ_CLANG_EXTRA_ARGS")) { std::stringstream ss; ss << extraArgs; diff --git a/tools/nvqpp/nvq++.in b/tools/nvqpp/nvq++.in index 0973e37b69..8a2f45bb74 100644 --- a/tools/nvqpp/nvq++.in +++ b/tools/nvqpp/nvq++.in @@ -207,7 +207,7 @@ if [ -d "${llvm_install_dir}/bin" -a \ fi # Compiler and linker flags -COMPILER_FLAGS="-std=c++20 -I${CUDAQ_INCLUDE_PATH} ${CUDAQ_CLANG_EXTRA_ARGS}" +COMPILER_FLAGS="-I${CUDAQ_INCLUDE_PATH} ${CUDAQ_CLANG_EXTRA_ARGS}" CLANG_RESOURCE_DIR="" # If we are a relocatable package, we want to # add compiler flags that will point clang to our repackaged @@ -232,11 +232,9 @@ LINKLIBS="-lcudaq -lcudaq-common -lcudaq-mlir-runtime -lcudaq-builder -lcudaq-en # Add any plugin libraries to the link stage CUDAQ_PLUGIN_DIR=${install_dir}/lib/plugins -if [ -d "$CUDAQ_PLUGIN_DIR" ] && [ -n "$(ls -A $CUDAQ_PLUGIN_DIR)" ] -then +if [ -d "$CUDAQ_PLUGIN_DIR" ] && [ -n "$(ls -A $CUDAQ_PLUGIN_DIR)" ]; then CUDAQ_PLUGIN_LIBS=`ls ${install_dir}/lib/plugins/*` - for entry in $CUDAQ_PLUGIN_LIBS - do + for entry in $CUDAQ_PLUGIN_LIBS; do PLUGIN_NAME=$(basename $entry) PLUGIN_NAME=${PLUGIN_NAME#lib} PLUGIN_NAME=${PLUGIN_NAME%@CMAKE_SHARED_LIBRARY_SUFFIX@} @@ -270,6 +268,7 @@ SHOW_HELP=false LIST_TARGETS=false DISABLE_QUBIT_MAPPING=false NVQIR_LIBS="-lnvqir -lnvqir-" +CPPSTD=-std=c++20 # Provide a default backend, user can override NVQIR_SIMULATION_BACKEND="qpp" @@ -464,6 +463,10 @@ while [ $# -ne 0 ]; do -v) ECHO=true ;; + -std=*) + CPPSTD="$1" + CUDAQ_QUAKE_ARGS="${CUDAQ_QUAKE_ARGS} $1" + ;; *.o | *.so | *.bundle) OBJS="${OBJS} $1" ;; @@ -500,6 +503,8 @@ function delete_temp_files { } trap delete_temp_files EXIT +COMPILER_FLAGS="${CPPSTD} ${COMPILER_FLAGS}" + # Goal here is to parse the backend config file, get the # platform library name, and any boolean flags, and setup # the resultant binary to target that specified backend. @@ -517,7 +522,7 @@ if [ -n "${TARGET_CONFIG}" ]; then TARGET_CONFIG="${TARGET_CONFIG};disable_qubit_mapping;${DISABLE_QUBIT_MAPPING}" TARGET_CONFIG="${TARGET_CONFIG}${PLATFORM_EXTRA_ARGS}" OUTFILENAME=$(mktemp nvqppGenTargetBackend.XXXXXX.o) - run ${CXX} -DNVQPP_TARGET_BACKEND_CONFIG="\"${TARGET_CONFIG}\"" -o $OUTFILENAME -c -x c++ ${install_dir}/targets/backendConfig.cpp + run ${CXX} ${CPPSTD} -DNVQPP_TARGET_BACKEND_CONFIG="\"${TARGET_CONFIG}\"" -o $OUTFILENAME -c -x c++ ${install_dir}/targets/backendConfig.cpp OBJS_TO_MERGE="${OUTFILENAME}" TMPFILES="${TMPFILES} ${OUTFILENAME}" fi diff --git a/unittests/integration/adjoint_tester.cpp b/unittests/integration/adjoint_tester.cpp index ec09050ff4..836fecefd3 100644 --- a/unittests/integration/adjoint_tester.cpp +++ b/unittests/integration/adjoint_tester.cpp @@ -131,7 +131,7 @@ CUDAQ_TEST(AdjointTester, checkNestedAdjoint) { void operator()(cudaq::qspan<> q) __qpu__ { cudaq::compute_action([&]() { xxxh_gates{}(q); }, - [&] { x(q[0], q[1], q[2]); }); + [&]() { x(q[0], q[1], q[2]); }); } };