diff --git a/.github/workflows/config/spelling_allowlist.txt b/.github/workflows/config/spelling_allowlist.txt index 16171c90a70..f8fa9f09d92 100644 --- a/.github/workflows/config/spelling_allowlist.txt +++ b/.github/workflows/config/spelling_allowlist.txt @@ -354,6 +354,7 @@ toolchain toolchains toolset transmon +transpile trotterization uccsd unary diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index e58173f48b6..77cf4e24033 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -637,7 +637,7 @@ jobs: ;; iqm) - nvq++ -DSYNTAX_CHECK --target iqm --iqm-machine Crystal_5 $filename + nvq++ -DSYNTAX_CHECK --target iqm $filename test_status=$? if [ $test_status -eq 0 ]; then ./a.out diff --git a/.github/workflows/test_in_devenv.yml b/.github/workflows/test_in_devenv.yml index 02286774351..a22d0e0dd44 100644 --- a/.github/workflows/test_in_devenv.yml +++ b/.github/workflows/test_in_devenv.yml @@ -91,7 +91,7 @@ jobs: shell: bash run: | cd $CUDAQ_REPO_ROOT - python3 -m pip install iqm-client==16.1 + python3 -m pip install iqm-client==28.0.0 python3 -m pytest -v --durations=0 build/python/tests/interop/ pytest_status=$? if [ ! $pytest_status -eq 0 ]; then @@ -136,7 +136,7 @@ jobs: # Rerun the MPI plugin test cd $CUDAQ_REPO_ROOT ctest --test-dir build -R MPIApiTest -V - external_plugin_status=$? + external_plugin_status=$? if [ ! $external_plugin_status -eq 0 ] ; then echo "::error file=test_in_devenv.yml::Test CUDA Quantum MPI Plugin Activation failed with status $external_plugin_status." exit 1 @@ -153,7 +153,7 @@ jobs: docker run --name cuda-quantum-dev cuda-quantum-dev:local docker export cuda-quantum-dev > $output_directory/$filename.tar docker rm -f cuda-quantum-dev - + echo "filename=$filename" >> $GITHUB_OUTPUT echo "output_directory=$output_directory" >> $GITHUB_OUTPUT @@ -265,9 +265,9 @@ jobs: if [ ! $pytest_status -eq 0 ] && [ ! $pytest_status -eq 5 ]; then echo "::error file=test_in_devenv.yml::Python $backendTest tests failed with status $pytest_status." exit 1 - fi - done - + fi + done + - name: Save environment id: env_save if: inputs.export_environment @@ -279,7 +279,7 @@ jobs: docker run --name dev_env dev_env:local docker export dev_env > $output_directory/$filename.tar docker rm -f dev_env - + echo "filename=$filename" >> $GITHUB_OUTPUT echo "output_directory=$output_directory" >> $GITHUB_OUTPUT diff --git a/docs/sphinx/targets/cpp/iqm.cpp b/docs/sphinx/targets/cpp/iqm.cpp index 0951a83b574..30580387fb9 100644 --- a/docs/sphinx/targets/cpp/iqm.cpp +++ b/docs/sphinx/targets/cpp/iqm.cpp @@ -1,6 +1,6 @@ // Compile and run with: // ``` -// nvq++ --target iqm iqm.cpp --iqm-machine Crystal_5 -o out.x && ./out.x +// nvq++ --target iqm iqm.cpp -o out.x && ./out.x // ``` // Assumes a valid set of credentials have been stored. diff --git a/docs/sphinx/targets/python/iqm.py b/docs/sphinx/targets/python/iqm.py index 95eaf2b2066..9f5018a90ce 100644 --- a/docs/sphinx/targets/python/iqm.py +++ b/docs/sphinx/targets/python/iqm.py @@ -4,9 +4,7 @@ # for every execution call on your kernel. # To use different targets in the same file, you must update # it via another call to `cudaq.set_target()` -cudaq.set_target("iqm", - url="http://localhost/cocos", - **{"qpu-architecture": "Crystal_5"}) +cudaq.set_target("iqm", url="http://localhost/") # Crystal_5 QPU architecture: # QB1 diff --git a/docs/sphinx/using/backends/hardware/backend_iqm.rst b/docs/sphinx/using/backends/hardware/backend_iqm.rst new file mode 100644 index 00000000000..be6a4b3b488 --- /dev/null +++ b/docs/sphinx/using/backends/hardware/backend_iqm.rst @@ -0,0 +1,113 @@ +IQM Backend Advanced Use Cases +============================== + +On this page advanced uses cases which are supported by the IQM backend integration are described. + + +Emulation Mode +++++++++++++++ + +.. tab:: Python + + To emulate the IQM Server locally, without submitting to the IQM Server, you can set the ``emulate`` flag to ``True``. + This will emit any target specific compiler diagnostics, before running a noise free emulation. + + .. code:: python + + cudaq.set_target('iqm', emulate=True, url="https:///") + + Emulation mode will still contact the configured IQM Server to retrieve the dynamic quantum architecture resulting from the active calibration unless a QPU architecture file is explicitly specified. + This can be done by setting `mapping_file` to point to a file describing the QPU architecture which should be emulated. + If an architecture is specified no server URL is needed anymore. + + .. code:: python + + cudaq.set_target('iqm', emulate=True, mapping_file="") + + The folder ``targettests/Target/IQM/`` contains sample QPU architecture files. + Find there files for the IQM Crystal architecture as well as files from real life QPUs which can be found on the IQM Resonance portal. + + The QPU quantum architecture of a test with a real life IQM QPU can be saved for later use in emulation runs. + To do so the environment variable ``IQM_SAVE_QPU_QA`` must be set to point to a filename in addition to setting the URL of a Resonance server. + The test can even run as emulation as long as a server URL is given to retrieve the current dynamic quantum architecture from. + + .. code:: bash + + IQM_SERVER_URL="https://demo.qc.iqm.fi/" IQM_SAVE_QPU_QA="" python3 program.py + + + The file will be created with the given name. If the file already exists the test is aborted with an error. + + +.. tab:: C++ + + To emulate the IQM machine locally, without submitting to the IQM Server, you can pass the ``--emulate`` option to ``nvq++``. + This will emit any target specific compiler diagnostics, before running a noise free emulation. + + .. code:: bash + + nvq++ --target iqm --emulate src.cpp -o program + IQM_SERVER_URL="https://demo.qc.iqm.fi/" ./program + + Emulation mode will still contact the configured IQM Server to retrieve the dynamic quantum architecture resulting from the active calibration unless a QPU architecture file is explicitly specified. + This can be done by specifying a file with the architecture either at compile time or in an variable in the environment executing the binary. + If an architecture is specified no server URL is needed anymore. + + .. code:: bash + + // With this binary multiple QPU architectures can be tested without recompilation. + nvq++ --target iqm --emulate src.cpp -o program + IQM_QPU_QA="" ./program + + .. code:: bash + + // This binary will use the given QPU architecture file until overwritten by environment variable "IQM_QPU_QA". + nvq++ --target iqm --emulate --mapping-file src.cpp -o program + ./program + + The folder ``targettests/Target/IQM/`` contains sample QPU architecture files. + Find there files for the IQM Crystal architecture as well as files from real life QPUs which can be found on the IQM Resonance portal. + + The QPU architecture of a test with an IQM server can be saved for later use in emulation runs. + To do so the environment variable ``IQM_SAVE_QPU_QA`` must be set to point to a filename in addition to setting the URL of a Resonance server. + The test can even run as emulation as long as a server URL is given to retrieve the current dynamic quantum architecture from. + + .. code:: bash + + nvq++ --target iqm --emulate src.cpp -o program + IQM_SERVER_URL="https://demo.qc.iqm.fi/" IQM_SAVE_QPU_QA="" ./program + + +To see a complete example, take a look at :ref:`IQM examples `. + + +Setting the Number of Shots ++++++++++++++++++++++++++++ + +.. tab:: Python + + The number of shots for a kernel execution can be set through + the ``shots_count`` argument to ``cudaq.sample`` or ``cudaq.observe``. By default, + the ``shots_count`` is set to 1000. + + .. code:: python + + cudaq.sample(kernel, shots_count=10000) + + +Using Credentials Saved in a File ++++++++++++++++++++++++++++++++++ + +The preferred way to pass the "API Token" to the IQM backend is through the environment variable ``IQM_TOKEN``. For compatibility the earlier used storage of the "API Token" in a file can still be used as follows: + +The previously used ``IQM_TOKENS_FILE`` environment variable can still be used to point to a tokens file but will be ignored if the ``IQM_TOKEN`` variable is set. +The tokens file cannot be generated by the ``iqmclient`` tool anymore but can be created manually using the "API Token" obtained from the Resonance profile page. +A tokens file can be created and the environment variable set like this: + +.. code:: bash + + echo '{ "access_token": "" }' > resonance-token.json + export IQM_TOKENS_FILE="path/to/resonance-token.json" + +When storing the "API Token" in a file please make sure to restrict access to this file to only the account running tests. +No other user or group on the computer must have any access to this file. diff --git a/docs/sphinx/using/backends/hardware/superconducting.rst b/docs/sphinx/using/backends/hardware/superconducting.rst index 21830bc7a15..d6197b6d52f 100644 --- a/docs/sphinx/using/backends/hardware/superconducting.rst +++ b/docs/sphinx/using/backends/hardware/superconducting.rst @@ -109,89 +109,74 @@ To see a complete example, take a look at :ref:`Anyon examples ` IQM -+++++++++ ++++ .. _iqm-backend: -Support for submissions to IQM is currently under development. -In particular, two-qubit gates can only be performed on adjacent qubits. For more information, we refer to the respective hardware documentation. -Support for automatically injecting the necessary operations during compilation to execute arbitrary multi-qubit gates will be added in future versions. +`IQM Resonance `__ offers access to various different IQM quantum computers. +The machines available there will be constantly extended as development progresses. +Programmers of CUDA-Q may use IQM Resonance with either C++ or Python. -Setting Credentials -````````````````````````` +With this version it is no longer necessary to define the target QPU architecture in the code or at compile time. +The IQM backend integration now contacts at runtime the configured IQM server and fetches the active dynamic quantum architecture of the QPU. +This is then used as input to transpile the quantum kernel code just-in-time for the target QPU topology. +By setting the environment variable ``IQM_SERVER_URL`` the target server can be selected just before executing the program. +As result the python script or the compiled C++ program can be executed on different QPUs without recompilation or code changes. -Programmers of CUDA-Q may access the IQM Server from either C++ or Python. Following the `quick start guide `__, install `iqm-cortex-cli` and login to initialize the tokens file. -The path to the tokens file can either be passed explicitly via an environment variable or it will be loaded automatically if located in -the default location :code:`~/.cache/iqm-cortex-cli/tokens.json`. +Please find also more documentation after logging in to the IQM Resonance portal. -.. code:: bash - export IQM_TOKENS_FILE="path/to/tokens.json" +Setting Credentials +``````````````````` + +Create a free account on the `IQM Resonance portal `__ and log-in. +Navigate to the account profile (top right). There generate an "API Token" and copy the generated token-string. +Set the environment variable ``IQM_TOKEN`` to contain the value of the token-string. +The IQM backend integration will use this as authorization token at the IQM server. - Submitting -````````````````````````` - -.. tab:: Python - - The target to which quantum kernels are submitted - can be controlled with the ``cudaq.set_target()`` function. +`````````` - .. code:: python +.. tab:: Python - cudaq.set_target("iqm", url="https:///cocos",**{"qpu-architecture": "Crystal_5"}) + The target to which quantum kernels are submitted can be controlled with the ``cudaq.set_target()`` function. - To emulate the IQM Server locally, without submitting to the IQM Server, - you can also set the ``emulate`` flag to ``True``. This will emit any target - specific compiler diagnostics, before running a noise free emulation. + .. code:: python - .. code:: python + cudaq.set_target("iqm", url="https:///") - cudaq.set_target('iqm', emulate=True) + Please note that setting the environment variable ``IQM_SERVER_URL`` takes precedence over the URL configured in the code. - The number of shots for a kernel execution can be set through - the ``shots_count`` argument to ``cudaq.sample`` or ``cudaq.observe``. By default, - the ``shots_count`` is set to 1000. - .. code:: python - - cudaq.sample(kernel, shots_count=10000) - .. tab:: C++ - - To target quantum kernel code for execution on an IQM Server, - pass the ``--target iqm`` flag to the ``nvq++`` compiler, along with a specified ``--iqm-machine``. - .. note:: - The ``--iqm-machine`` is a mandatory argument. This provided architecture must match - the device architecture that the program has been compiled against. The hardware architecture for a - specific IQM Server may be checked via `https:///cocos/quantum-architecture`. + To target quantum kernel code for execution on an IQM Server, pass the ``--target iqm`` option to the ``nvq++`` compiler. - .. code:: bash + .. code:: bash - nvq++ --target iqm --iqm-machine Crystal_5 src.cpp + nvq++ --target iqm src.cpp - Once the binary for a specific IQM QPU architecture is compiled, it can be executed against any IQM Server with the same QPU architecture: + Once the binary for an IQM QPU is compiled, it can be executed against any IQM Server by setting the environment variable ``IQM_SERVER_URL`` as shown here: - .. code:: bash + .. code:: bash - nvq++ --target iqm --iqm-machine Crystal_5 src.cpp -o program - IQM_SERVER_URL="https://demo.qc.iqm.fi/cocos" ./program + nvq++ --target iqm src.cpp -o program + IQM_SERVER_URL="https://demo.qc.iqm.fi/" ./program - # Executing the same program against an IQM Server with a different underlying QPU - # architecture will result in an error. - IQM_SERVER_URL="https:///cocos" ./program - To emulate the IQM machine locally, without submitting to the IQM Server, - you can also pass the ``--emulate`` flag to ``nvq++``. This will emit any target - specific compiler diagnostics, before running a noise free emulation. +To see a complete example for using IQM server backends, take a look at :ref:`IQM examples `. - .. code:: bash - nvq++ --emulate --target iqm --iqm-machine Crystal_5 src.cpp +Advanced use cases +`````````````````` + +The IQM backend integration offers more options for advanced use cases. Please find these here: + +.. toctree:: + :maxdepth: 2 -To see a complete example, take a look at :ref:`IQM examples `. + IQM backend advanced use cases OQC diff --git a/lib/Optimizer/CodeGen/TranslateToIQMJson.cpp b/lib/Optimizer/CodeGen/TranslateToIQMJson.cpp index cf97cfa8800..ffe134f7b0d 100644 --- a/lib/Optimizer/CodeGen/TranslateToIQMJson.cpp +++ b/lib/Optimizer/CodeGen/TranslateToIQMJson.cpp @@ -1,6 +1,7 @@ /******************************************************************************* * Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. * * All rights reserved. * + * Copyright 2025 IQM Quantum Computers * * * * This source code and the accompanying materials are made available under * * the terms of the Apache License 2.0 which accompanies this distribution. * @@ -121,10 +122,10 @@ static LogicalResult emitOperation(nlohmann::json &json, emitter.getOrAssignName(optor->getResult(1), emitter.getOrAssignName(optor.getTarget(0)).str()); } else { - json["name"] = name; + json["name"] = "prx"; if (optor.getParameters().size() != 2) - optor.emitError("IQM phased_rx gate expects exactly two parameters."); + optor.emitError("IQM prx gate expects exactly two parameters."); auto parameter0 = cudaq::getParameterValueAsDouble(optor.getParameters()[0]); @@ -154,7 +155,7 @@ static LogicalResult emitOperation(nlohmann::json &json, static LogicalResult emitOperation(nlohmann::json &json, cudaq::Emitter &emitter, quake::MzOp op) { - json["name"] = "measurement"; + json["name"] = "measure"; std::vector qubits; for (auto target : op.getTargets()) qubits.push_back(emitter.getOrAssignName(target).str()); diff --git a/python/tests/backends/test_IQM.py b/python/tests/backends/test_IQM.py index dd043341855..8e1b81c3c18 100644 --- a/python/tests/backends/test_IQM.py +++ b/python/tests/backends/test_IQM.py @@ -1,6 +1,7 @@ # ============================================================================ # # Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. # # All rights reserved. # +# Copyright 2025 IQM Quantum Computers # # # # This source code and the accompanying materials are made available under # # the terms of the Apache License 2.0 which accompanies this distribution. # @@ -30,21 +31,6 @@ # Define the port for the mock server port = 62443 -# If we're in a git repo, test that we can provide a filename with spaces. -# If we are not in a git repo, then simply test without overriding -# mapping_file. (Testing a mapping_file with spaces is done elsewhere, and -# that isn't the main point of these tests.) -with os.popen("git rev-parse --show-toplevel") as f: - git_top = f.read().strip() - if os.path.isdir(git_top): - target_config_origin = os.path.join( - f"{git_top}", "runtime/cudaq/platform/default/rest/helpers/iqm") - target_config_dest = os.path.join(f"{git_top}", "targettests") - shutil.copy(os.path.join(target_config_origin, "Crystal_5.txt"), - os.path.join(target_config_dest, "Crystal_5_Variant.txt")) - shutil.copy(os.path.join(target_config_origin, "Crystal_20.txt"), - os.path.join(target_config_dest, "Crystal_20_Variant.txt")) - def assert_close(want, got, tolerance=1.0e-5) -> bool: return abs(want - got) < tolerance @@ -68,11 +54,7 @@ def startUpMockServer(): cudaq.set_random_seed(13) # Set the targeted QPU os.environ["IQM_TOKENS_FILE"] = tmp_tokens_file.name - kwargs = {"qpu-architecture": "Crystal_20"} - if os.path.isdir(git_top): - mapping_file = f"{git_top}/targettests/Crystal_20_Variant.txt" - kwargs["mapping_file"] = mapping_file - cudaq.set_target("iqm", url="http://localhost:{}".format(port), **kwargs) + cudaq.set_target("iqm", url="http://localhost:{}".format(port)) yield "Running the tests." diff --git a/runtime/cudaq/platform/default/rest/helpers/iqm/CMakeLists.txt b/runtime/cudaq/platform/default/rest/helpers/iqm/CMakeLists.txt index 59c648c2dbd..a4b83a9bf0f 100644 --- a/runtime/cudaq/platform/default/rest/helpers/iqm/CMakeLists.txt +++ b/runtime/cudaq/platform/default/rest/helpers/iqm/CMakeLists.txt @@ -7,16 +7,13 @@ # ============================================================================ # target_sources(cudaq-rest-qpu PRIVATE IQMServerHelper.cpp) add_target_config(iqm) -add_target_mapping_arch(iqm "Crystal_5.txt") -add_target_mapping_arch(iqm "Crystal_20.txt") -add_target_mapping_arch(iqm "Crystal_54.txt") add_library(cudaq-serverhelper-iqm SHARED IQMServerHelper.cpp ) target_link_libraries(cudaq-serverhelper-iqm - PUBLIC - cudaq-common - fmt::fmt-header-only + PUBLIC + cudaq-common + fmt::fmt-header-only ) install(TARGETS cudaq-serverhelper-iqm DESTINATION lib) diff --git a/runtime/cudaq/platform/default/rest/helpers/iqm/IQMServerHelper.cpp b/runtime/cudaq/platform/default/rest/helpers/iqm/IQMServerHelper.cpp index bcb68e233eb..93ad285c4d4 100644 --- a/runtime/cudaq/platform/default/rest/helpers/iqm/IQMServerHelper.cpp +++ b/runtime/cudaq/platform/default/rest/helpers/iqm/IQMServerHelper.cpp @@ -1,6 +1,7 @@ /******************************************************************************* * Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. * * All rights reserved. * + * Copyright 2025 IQM Quantum Computers * * * * This source code and the accompanying materials are made available under * * the terms of the Apache License 2.0 which accompanies this distribution. * @@ -12,27 +13,44 @@ #include "nlohmann/json.hpp" +#include #include #include +#include +#include +#include +#include #include #include namespace cudaq { class IQMServerHelper : public ServerHelper { + + struct qubitOrder { + // Lightweight comparison for sorting strings ending in a number in + // natural order. This assumes that all strings have either none or + // the same prefix and there is a number. No checks on the string + // composition is done for performance reasons. + bool operator()(const std::string &a, const std::string &b) const { + if (a.size() < b.size()) + return true; + if (a.size() > b.size()) + return false; + return a.compare(b) < 0; + } + }; + protected: /// @brief The base URL - std::string iqmServerUrl = "http://localhost/cocos/"; + std::string iqmServerUrl = "http://localhost/"; - /// @brief IQM QPU architecture, provided during the compile-time - std::string qpuArchitecture = "Crystal_5"; + /// @brief Authorization token + std::optional authToken = std::nullopt; /// @brief The default cortex-cli tokens file path std::optional tokensFilePath = std::nullopt; - /// @brief Program target QPU architecture - std::string targetArchitecture = ""; - /// @brief Return the headers required for the REST calls RestHeaders generateRequestHeader() const; @@ -53,9 +71,32 @@ class IQMServerHelper : public ServerHelper { nlohmann::json tokens; tokensFile >> tokens; tokensFile.close(); + + if (!tokens.count("access_token")) { + throw std::runtime_error("No 'access_token' found in tokens file: " + + unwrappedTokensFilePath); + } return tokens["access_token"].get(); } + /// @brief Lookup table for translating the qubit names to index numbers + std::map qubitNameMap; + + /// @brief Adjacency map for each qubit + std::vector> qubitAdjacencyMap; + + /// @brief full path+name of the file containing the quantum architecture + std::string quantumArchitectureFilePath; + + /// @brief flag indicating that architecture file should be removed on exit + bool cleanupQuantumArchitectureFilePath = true; + + /// @brief Fetch the quantum architecture from server + void fetchQuantumArchitecture(); + + /// @brief Write the dynamic quantum architecture file + std::string writeQuantumArchitectureFile(void); + /// @brief Get server quantum architecture name std::string getQuantumArchitectureName() const { RestClient client; @@ -76,79 +117,10 @@ class IQMServerHelper : public ServerHelper { /// @brief Return the name of this server helper, must be the /// same as the qpu config file. const std::string name() const override { return "iqm"; } - RestHeaders getHeaders() override; - void initialize(BackendConfig config) override { - backendConfig = config; + RestHeaders getHeaders() override { return generateRequestHeader(); } - bool emulate = false; - auto iter = backendConfig.find("emulate"); - if (iter != backendConfig.end()) { - emulate = iter->second == "true"; - } - - // Set QPU architecture - iter = backendConfig.find("qpu-architecture"); - if (iter == backendConfig.end()) { - throw std::runtime_error("QPU architecture is not provided"); - } - qpuArchitecture = iter->second; - std::replace(qpuArchitecture.begin(), qpuArchitecture.end(), '_', ' '); - CUDAQ_DBG("qpuArchitecture = {}", qpuArchitecture); - - // Set an alternate base URL if provided. - iter = backendConfig.find("url"); - if (iter != backendConfig.end()) { - iqmServerUrl = iter->second; - // For running unittests - if (iqmServerUrl.find("localhost") != std::string::npos) { - std::replace(qpuArchitecture.begin(), qpuArchitecture.end(), ' ', '_'); - CUDAQ_DBG("qpuArchitecture = {}", qpuArchitecture); - } - } - - // Allow overriding IQM Server Url, the compiled program will still work if - // architecture matches. This is useful in case we're using the same program - // against different backends, for example simulated and actually connected - // to the hardware. - auto envIqmServerUrl = getenv("IQM_SERVER_URL"); - if (envIqmServerUrl) { - iqmServerUrl = std::string(envIqmServerUrl); - } - - if (!iqmServerUrl.ends_with("/")) - iqmServerUrl += "/"; - CUDAQ_DBG("iqmServerUrl = {}", iqmServerUrl); - - if (emulate) { - CUDAQ_INFO("Emulation is enabled, ignore tokens file and IQM Server URL"); - return; - } - - // Set alternative cortex-cli tokens file path if provided via env var - auto envTokenFilePath = getenv("IQM_TOKENS_FILE"); - auto defaultTokensFilePath = - std::string(getenv("HOME")) + "/.cache/iqm-cortex-cli/tokens.json"; - CUDAQ_DBG("defaultTokensFilePath = {}", defaultTokensFilePath); - if (envTokenFilePath) { - tokensFilePath = std::string(envTokenFilePath); - } else if (cudaq::fileExists(defaultTokensFilePath)) { - tokensFilePath = defaultTokensFilePath; - } - CUDAQ_DBG("tokensFilePath = {}", tokensFilePath.value_or("not set")); - - // Fetch quantum-architecture program was compiled with - auto configuredTargetArchitecture = getQuantumArchitectureName(); - CUDAQ_DBG("configuredTargetArchitecture = {}", - configuredTargetArchitecture); - - // Does it match the compiled architecture? - if (qpuArchitecture != configuredTargetArchitecture) { - throw std::runtime_error( - "IQM QPU architecture mismatch: " + qpuArchitecture + - " != " + configuredTargetArchitecture); - } - } + void initialize(BackendConfig config) override; /// @brief Create a job payload for the provided quantum codes ServerJobPayload @@ -175,8 +147,64 @@ class IQMServerHelper : public ServerHelper { /// @brief Update `passPipeline` with architecture-specific pass options void updatePassPipeline(const std::filesystem::path &platformPath, std::string &passPipeline) override; + + /// @brief Default destructor removes the dynamic quantum architecture file + ~IQMServerHelper() { + if ((cleanupQuantumArchitectureFilePath == true) && + (!quantumArchitectureFilePath.empty())) { + if (unlink(quantumArchitectureFilePath.c_str()) != 0) { + CUDAQ_INFO("Failed to delete {} with error: {}", + quantumArchitectureFilePath, std::string(strerror(errno))); + } + } + } }; +void IQMServerHelper::initialize(BackendConfig config) { + backendConfig = config; + + // Set an alternate base URL if provided. + auto iter = backendConfig.find("url"); + if (iter != backendConfig.end()) { + iqmServerUrl = iter->second; + } + + // Allow overriding IQM Server URL. This allows sending a program to any + // given URL without recompilation. + auto envIqmServerUrl = getenv("IQM_SERVER_URL"); + if (envIqmServerUrl) { + iqmServerUrl = std::string(envIqmServerUrl); + } + + if (!iqmServerUrl.ends_with("/")) + iqmServerUrl += "/"; + CUDAQ_DBG("iqmServerUrl = {}", iqmServerUrl); + + auto token = getenv("IQM_TOKEN"); + if (token) { + authToken = std::string(token); + CUDAQ_DBG("Using authorization token from environment variable"); + } else { + // Set alternative iqmclient-cli tokens file path if provided via env var + auto envTokenFilePath = getenv("IQM_TOKENS_FILE"); + auto defaultTokensFilePath = + std::string(getenv("HOME")) + "/.cache/iqm-client-cli/tokens.json"; + if (envTokenFilePath) { + tokensFilePath = std::string(envTokenFilePath); + } else if (cudaq::fileExists(defaultTokensFilePath)) { + tokensFilePath = defaultTokensFilePath; + CUDAQ_DBG("Setting default path for tokens file"); + } + CUDAQ_DBG("tokensFilePath = {}", tokensFilePath.value_or("not set")); + } + + token = getenv("IQM_SAVE_QPU_QA"); + if (token) { + quantumArchitectureFilePath = std::string(token); + cleanupQuantumArchitectureFilePath = false; + } +} + ServerJobPayload IQMServerHelper::createJob(std::vector &circuitCodes) { std::vector messages; @@ -185,9 +213,18 @@ IQMServerHelper::createJob(std::vector &circuitCodes) { // so we cannot use the batch mode for (auto &circuitCode : circuitCodes) { ServerMessage message = ServerMessage::object(); + message["qubit_mapping"] = ServerMessage::array(); message["circuits"] = ServerMessage::array(); message["shots"] = shots; + // Apply the mapping derived from the dynamic quantum architecture. + for (auto &[key, value] : qubitNameMap) { + nlohmann::json singleQubitMapping; + singleQubitMapping["logical_name"] = "QB" + std::to_string(value + 1); + singleQubitMapping["physical_name"] = key; + message["qubit_mapping"].push_back(singleQubitMapping); + } + ServerMessage yac = nlohmann::json::parse(circuitCode.code); yac["name"] = circuitCode.name; message["circuits"].push_back(yac); @@ -198,7 +235,7 @@ IQMServerHelper::createJob(std::vector &circuitCodes) { RestHeaders headers = generateRequestHeader(); // return the payload - return std::make_tuple(iqmServerUrl + "jobs", headers, messages); + return std::make_tuple(iqmServerUrl + "circuits", headers, messages); } std::string IQMServerHelper::extractJobId(ServerMessage &postResponse) { @@ -206,11 +243,11 @@ std::string IQMServerHelper::extractJobId(ServerMessage &postResponse) { } std::string IQMServerHelper::constructGetJobPath(ServerMessage &postResponse) { - return "jobs" + postResponse["id"].get() + "/counts"; + return "circuits" + postResponse["id"].get() + "/counts"; } std::string IQMServerHelper::constructGetJobPath(std::string &jobId) { - return iqmServerUrl + "jobs/" + jobId + "/counts"; + return iqmServerUrl + "circuits/" + jobId + "/counts"; } std::chrono::microseconds @@ -276,34 +313,235 @@ IQMServerHelper::generateRequestHeader() const { {"Connection", "keep-alive"}, {"User-Agent", "cudaq/IQMServerHelper"}, {"Accept", "*/*"}}; - auto apiToken = readApiToken(); - if (apiToken.has_value()) { - headers["Authorization"] = "Bearer " + apiToken.value(); - }; + + // Prefer the authorization token set in the environment variable. + if (authToken.has_value()) { + headers["Authorization"] = "Bearer " + authToken.value(); + } else { + // Fallback to authorization token from legacy JSON file. + auto apiToken = readApiToken(); + if (apiToken.has_value()) { + headers["Authorization"] = "Bearer " + apiToken.value(); + }; + } + return headers; } +/** + * Put the quantum architecture file on the transpiler commandline. + * + * The quantum architecture file is normally a temporary file generated from + * the dynamic quantum architecture which is retrieved from the configured + * IQM server URL. But it can be overwritten by specifying the 'mapping_file' + * parameter in the backend string, or even more flexible by setting the + * environment variable 'IQM_QPU_QA' to the path+filename. + */ void IQMServerHelper::updatePassPipeline( const std::filesystem::path &platformPath, std::string &passPipeline) { - // Note: the leading and trailing single quotes are needed in case there are - // spaces in the filename. std::string pathToFile; - auto iter = backendConfig.find("mapping_file"); - if (iter != backendConfig.end()) { - // Use provided path to file - pathToFile = std::string("'") + iter->second + std::string("'"); + + // For normal operation the dynamic quantum architecture is retrieved from + // the configured IQM server URL. This gives the connectivity of the + // calibrated QPU. + // For testing the file with the QPU quantum architecture can be given via + // environment variable to allow testing different architectures without + // recompilation. It can also be specified via the backend configuration. + auto filename = getenv("IQM_QPU_QA"); + if (filename) { + // Use provided string as path+filename + pathToFile = std::string(filename); } else { - // Construct path to file - pathToFile = - std::string("'") + - std::string(platformPath / std::string("mapping/iqm") / - (backendConfig["qpu-architecture"] + std::string(".txt'"))); + // Allow setting of quantum architecture file via the backend config + auto iter = backendConfig.find("mapping_file"); + if (iter != backendConfig.end()) { + // Use provided string as path+filename + pathToFile = iter->second; + } else { + // Use the dynamic quantum architecture of the configured IQM server + fetchQuantumArchitecture(); + pathToFile = writeQuantumArchitectureFile(); + } } + CUDAQ_INFO("Using quantum architecture file: {}", pathToFile); + + // Add leading and trailing single quotes to protect the filepath from + // shell glob. + pathToFile.insert(0, "'").append("'"); + passPipeline = std::regex_replace(passPipeline, std::regex("%QPU_ARCH%"), pathToFile); } -RestHeaders IQMServerHelper::getHeaders() { return generateRequestHeader(); } +/** + * Fetch the quantum architecture from the configured URL and create a qubit + * adjacency map. + * + * The qubit adjacency map contains only qubits which can be measured and can + * be used in prx-gates as well as cz-gates. As qubits pairs for cz-gates + * connect only a few qubits the information about neighbors is stored as sets + * within a vector of all qubits to save memory. + * @throws std::runtime_error thrown for any errors with the server. + */ +void IQMServerHelper::fetchQuantumArchitecture() { + try { + RestClient client; + auto headers = generateRequestHeader(); + + // From the Dynamic Quantum Architecture we need the list of qubits names, + // the list of qubit pairs which can form cz-gates, the lists of qubits + // which can do prx-gates and the list of qubits which support measurement. + auto dynamicQuantumArchitecture = client.get(iqmServerUrl, + "calibration-sets/default/" + "dynamic-quantum-architecture", + headers); + CUDAQ_DBG("Dynamic QA={}", dynamicQuantumArchitecture.dump()); + + auto &cz = dynamicQuantumArchitecture["gates"]["cz"]; + auto implementation = cz["default_implementation"]; + auto &cz_loci = cz["implementations"][implementation]["loci"]; + + auto &prx = dynamicQuantumArchitecture["gates"]["prx"]; + implementation = prx["default_implementation"]; + auto prx_loci = prx["implementations"][implementation]["loci"]; + + auto &measure = dynamicQuantumArchitecture["gates"]["measure"]; + implementation = measure["default_implementation"]; + auto &measure_loci = measure["implementations"][implementation]["loci"]; + + // For each qubit set flags to indicate whether they can be used in `cz`, + // `prx` or `measurement` operations. Then crop all qubits which are not + // capable of all three operations and enumerate the remaining ones. + + for (auto qubit : dynamicQuantumArchitecture["qubits"]) { + qubitNameMap[qubit] = 0; // initializing to zero meaning no capability + } + for (auto cz : cz_loci) { + // each cz loci has 2 qubits - mark each qubit + for (auto qubit : cz) { // cz is an array of strings + qubitNameMap[qubit] |= (1 << 0); + } + } + for (auto prx : prx_loci) { + qubitNameMap[prx[0]] |= (1 << 1); + } + for (auto measure : measure_loci) { + qubitNameMap[measure[0]] |= (1 << 2); + } + + uint idx = 0; // enumeration counter + for (auto qubit = qubitNameMap.begin(); qubit != qubitNameMap.end();) { + if (qubit->second == ((1 << 0) | (1 << 1) | (1 << 2))) { + qubit->second = idx++; // replace flags with enumeration value + qubit++; + } else { + qubit = qubitNameMap.erase(qubit); + } + } + // From here on the qubitNameMap lists only qubits which can be used + // for all operations. Starting with 0 each qubit in the list + // is enumerated. + + // The number of qubits in this dynamic quantum architecture. + uint qubitCount = qubitNameMap.size(); + CUDAQ_INFO("Server {} has {} calibrated qubits", iqmServerUrl, qubitCount); + assert(idx == qubitCount); + +#ifdef CUDAQ_DEBUG + for (auto &[key, value] : qubitNameMap) { + CUDAQ_DBG("qubit mapping: {} = {}", key, value); + } +#endif + + // Initialise the adjacency map with an empty set for each qubit + qubitAdjacencyMap.reserve(qubitCount); + for (uint i = 0; i < qubitCount; i++) { + qubitAdjacencyMap.emplace_back(); + } + + // Iterate over all cz loci and add only those to the adjacency map + // for which all qubits have passed the above tests. + for (auto cz : cz_loci) { + if (qubitNameMap.count(cz[0]) && qubitNameMap.count(cz[1])) { + CUDAQ_DBG("usable cz_loci {}", cz.dump()); + qubitAdjacencyMap[qubitNameMap[cz[0]]].insert(qubitNameMap[cz[1]]); + qubitAdjacencyMap[qubitNameMap[cz[1]]].insert(qubitNameMap[cz[0]]); + } + } // for all cz loci + } catch (const std::exception &e) { + throw std::runtime_error("Unable to get quantum architecture from \"" + + iqmServerUrl + "\": " + std::string(e.what())); + } +} // IQMServerHelper::fetchQuantumArchitecture() + +/** + * Write the content of the dynamic quantum architecture to file. + * + * If no filename is stored in 'quantumArchitectureFilePath' a unique filename + * is generated automatically with a path in the system temporary file folder. + * Next the file will be created and the dynamic quantum architecture written. + * If the file already exists an error will be thrown. On success this function + * returns the filename of the created file. + * + * @return String containing the filename of the created file. + * @throws std::runtime_error thrown when file cannot be opened for writing + * or exists already. + */ +std::string IQMServerHelper::writeQuantumArchitectureFile(void) { + uint qubitCount = qubitAdjacencyMap.size(); + int fd = -1; + + // open a file to write the dynamic quantum architecture to + if (quantumArchitectureFilePath.empty()) { + // if no filename is given a temporary unique name is generated + quantumArchitectureFilePath = + std::string(P_tmpdir) + "/qpu-architecture-XXXXXX"; + fd = mkstemp(quantumArchitectureFilePath.data()); + } else { + fd = open(quantumArchitectureFilePath.data(), O_WRONLY | O_CREAT | O_EXCL, + S_IRUSR | S_IRGRP | S_IROTH); + } + if (fd < 0) { + throw std::runtime_error("Cannot write QPU architecture file: \"" + + quantumArchitectureFilePath + "\" - " + + std::string(strerror(errno))); + } + // open also as FILE which allows easier formatting with fprintf() + FILE *file = fdopen(fd, "w"); + if (file == NULL) { + throw std::runtime_error("Cannot write QPU architecture file: \"" + + quantumArchitectureFilePath + "\" - " + + std::string(strerror(errno))); + } + + // Header + fprintf(file, "# NOTE: automatically generated for IQM server at URL: %s\n\n", + iqmServerUrl.c_str()); + fprintf(file, "Number of nodes: %u\n", qubitCount); + fprintf(file, "Number of edges: ?\n\n"); + + // Write one line for each qubit listing the adjacent qubits. + for (uint i = 0; i < qubitCount; i++) { + bool first = true; + + std::string outputLine = std::to_string(i) + " --> {"; + for (uint node : qubitAdjacencyMap[i]) { + if (first) + first = false; + else + outputLine += ", "; + outputLine += std::to_string(node); + } + outputLine += "}\n"; + + fwrite(outputLine.c_str(), outputLine.length(), 1, file); + } + + fclose(file); + close(fd); + + return quantumArchitectureFilePath; +} // IQMServerHelper::writeQuantumArchitectureFile() } // namespace cudaq diff --git a/runtime/cudaq/platform/default/rest/helpers/iqm/iqm.yml b/runtime/cudaq/platform/default/rest/helpers/iqm/iqm.yml index a5f10cea7bf..54af4936c05 100644 --- a/runtime/cudaq/platform/default/rest/helpers/iqm/iqm.yml +++ b/runtime/cudaq/platform/default/rest/helpers/iqm/iqm.yml @@ -31,8 +31,3 @@ target-arguments: type: string platform-arg: url help-string: "Specify URL." - - key: machine - required: false - type: string - platform-arg: qpu-architecture - help-string: "Specify the IQM QPU." diff --git a/scripts/generate_cc.sh b/scripts/generate_cc.sh index ad35bacd1d0..7a84d4904b4 100644 --- a/scripts/generate_cc.sh +++ b/scripts/generate_cc.sh @@ -93,7 +93,7 @@ if $gen_cpp_coverage; then use_llvm_cov=true # Run tests (C++ Unittests) - python3 -m pip install iqm-client==16.1 + python3 -m pip install iqm-client==28.0.0 ctest --output-on-failure --test-dir ${repo_root}/build -E ctest-nvqpp -E ctest-targettests ctest_status=$? /usr/local/llvm/bin/llvm-lit -v --param nvqpp_site_config=${repo_root}/build/test/lit.site.cfg.py ${repo_root}/build/test diff --git a/runtime/cudaq/platform/default/rest/helpers/iqm/Crystal_20.txt b/targettests/Target/IQM/Crystal_20.txt similarity index 100% rename from runtime/cudaq/platform/default/rest/helpers/iqm/Crystal_20.txt rename to targettests/Target/IQM/Crystal_20.txt diff --git a/runtime/cudaq/platform/default/rest/helpers/iqm/Crystal_5.txt b/targettests/Target/IQM/Crystal_5.txt similarity index 100% rename from runtime/cudaq/platform/default/rest/helpers/iqm/Crystal_5.txt rename to targettests/Target/IQM/Crystal_5.txt diff --git a/runtime/cudaq/platform/default/rest/helpers/iqm/Crystal_54.txt b/targettests/Target/IQM/Crystal_54.txt similarity index 100% rename from runtime/cudaq/platform/default/rest/helpers/iqm/Crystal_54.txt rename to targettests/Target/IQM/Crystal_54.txt diff --git a/targettests/Target/IQM/Resonance-emerald.txt b/targettests/Target/IQM/Resonance-emerald.txt new file mode 100644 index 00000000000..5f3d680dd8d --- /dev/null +++ b/targettests/Target/IQM/Resonance-emerald.txt @@ -0,0 +1,55 @@ +# NOTE: automatically generated for IQM server at URL: https://cocos.resonance.meetiqm.com/emerald/ + +Number of nodes: 50 +Number of edges: ? + +0 --> {1, 4} +1 --> {0, 5} +2 --> {3, 8} +3 --> {2, 4, 9} +4 --> {0, 3, 5, 10} +5 --> {1, 4, 6, 11} +6 --> {5} +7 --> {8, 15} +8 --> {2, 7, 9, 16} +9 --> {3, 8, 10, 17} +10 --> {4, 9, 11, 18} +11 --> {5, 10, 12, 19} +12 --> {11, 13, 20} +13 --> {12, 21} +14 --> {15, 22} +15 --> {7, 14, 16, 23} +16 --> {8, 15, 17, 24} +17 --> {9, 16, 18, 25} +18 --> {10, 17, 19} +19 --> {11, 18, 20, 26} +20 --> {12, 19, 21, 27} +21 --> {13, 20, 28} +22 --> {14, 23} +23 --> {15, 22, 24, 30} +24 --> {16, 23, 25, 31} +25 --> {17, 24, 32} +26 --> {19, 27, 34} +27 --> {20, 26, 28, 35} +28 --> {21, 27, 29} +29 --> {28, 36} +30 --> {23, 31} +31 --> {24, 30, 32, 38} +32 --> {25, 31, 33, 39} +33 --> {32, 34} +34 --> {26, 33, 35, 40} +35 --> {27, 34, 41} +36 --> {29} +37 --> {38} +38 --> {31, 37, 39, 43} +39 --> {32, 38, 44} +40 --> {34, 41} +41 --> {35, 40, 42, 46} +42 --> {41} +43 --> {38, 44} +44 --> {39, 43, 45, 47} +45 --> {44, 48} +46 --> {41} +47 --> {44, 48} +48 --> {45, 47, 49} +49 --> {48} diff --git a/targettests/Target/IQM/Resonance-garnet.txt b/targettests/Target/IQM/Resonance-garnet.txt new file mode 100644 index 00000000000..fa0297960d9 --- /dev/null +++ b/targettests/Target/IQM/Resonance-garnet.txt @@ -0,0 +1,25 @@ +# NOTE: automatically generated for IQM server at URL: https://cocos.resonance.meetiqm.com/garnet/ + +Number of nodes: 20 +Number of edges: ? + +0 --> {1, 3} +1 --> {0, 4} +2 --> {3, 7} +3 --> {0, 2, 4, 8} +4 --> {1, 3, 5, 9} +5 --> {4, 6, 10} +6 --> {5, 11} +7 --> {2, 8, 12} +8 --> {3, 7, 9, 13} +9 --> {4, 8, 10, 14} +10 --> {5, 9, 11, 15} +11 --> {6, 10, 16} +12 --> {7, 13} +13 --> {8, 12, 14, 17} +14 --> {9, 13, 15, 18} +15 --> {10, 14, 16, 19} +16 --> {11, 15} +17 --> {13, 18} +18 --> {14, 17, 19} +19 --> {15, 18} diff --git a/targettests/Target/IQM/for_loop-cpp17.cpp b/targettests/Target/IQM/for_loop-cpp17.cpp index 11f7c3bb344..e06c4063419 100644 --- a/targettests/Target/IQM/for_loop-cpp17.cpp +++ b/targettests/Target/IQM/for_loop-cpp17.cpp @@ -9,7 +9,8 @@ #include // REQUIRES: c++17 -// RUN: nvq++ %cpp_std %s --target iqm --emulate --iqm-machine Crystal_20 -o %t.x && %t.x | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t +// RUN: IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s // CHECK: { 0:{{[0-9]+}} 1:{{[0-9]+}} } diff --git a/targettests/Target/IQM/for_loop.cpp b/targettests/Target/IQM/for_loop.cpp index b3fb4828032..dfd769a884a 100644 --- a/targettests/Target/IQM/for_loop.cpp +++ b/targettests/Target/IQM/for_loop.cpp @@ -9,7 +9,8 @@ #include // REQUIRES: c++20 -// RUN: nvq++ %cpp_std %s --target iqm --emulate --iqm-machine Crystal_20 -o %t.x && %t.x | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t +// RUN: IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s // CHECK: { 0:{{[0-9]+}} 1:{{[0-9]+}} } diff --git a/targettests/Target/IQM/z_gate-cpp17.cpp b/targettests/Target/IQM/z_gate-cpp17.cpp index 1955c118634..8d2fdd06f6d 100644 --- a/targettests/Target/IQM/z_gate-cpp17.cpp +++ b/targettests/Target/IQM/z_gate-cpp17.cpp @@ -9,8 +9,9 @@ #include // REQUIRES: c++17 -// RUN: nvq++ %cpp_std %s --target iqm --emulate --iqm-machine Crystal_20 -o %t.x && %t.x | FileCheck %s -// RUN: nvq++ %cpp_std %s --target iqm --emulate --iqm-machine="Crystal_20" -o %t.x && %t.x | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t +// RUN: IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s + // CHECK: { 0:1000 } template diff --git a/targettests/Target/IQM/z_gate.cpp b/targettests/Target/IQM/z_gate.cpp index f50201271db..cc93caed71c 100644 --- a/targettests/Target/IQM/z_gate.cpp +++ b/targettests/Target/IQM/z_gate.cpp @@ -9,8 +9,9 @@ #include // REQUIRES: c++20 -// RUN: nvq++ %cpp_std %s --target iqm --emulate --iqm-machine Crystal_20 -o %t.x && %t.x | FileCheck %s -// RUN: nvq++ %cpp_std %s --target iqm --emulate --iqm-machine="Crystal_20" -o %t.x && %t.x | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t +// RUN: IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s + // CHECK: { 0:1000 } template diff --git a/targettests/execution/bug_qubit.cpp b/targettests/execution/bug_qubit.cpp index f8ef3ed3676..7229b9c6600 100644 --- a/targettests/execution/bug_qubit.cpp +++ b/targettests/execution/bug_qubit.cpp @@ -9,12 +9,15 @@ // This code is from Issue 251. // clang-format off -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t +// RUN: IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: IQM_QPU_QA=%iqm_tests_dir/Crystal_20.txt %t | FileCheck %s +// RUN: IQM_QPU_QA=%iqm_tests_dir/Crystal_54.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t diff --git a/targettests/execution/callable_kernel_arg.cpp b/targettests/execution/callable_kernel_arg.cpp index 6f4c3eb8ead..0509ace64fb 100644 --- a/targettests/execution/callable_kernel_arg.cpp +++ b/targettests/execution/callable_kernel_arg.cpp @@ -7,12 +7,12 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %quantum_machines_avail; then nvq++ %cpp_std --target quantum_machines --emulate %s -o %t && %t | FileCheck %s; fi diff --git a/targettests/execution/cudaq_observe-cpp17.cpp b/targettests/execution/cudaq_observe-cpp17.cpp index f1c3243f3a9..47ad2cd3e12 100644 --- a/targettests/execution/cudaq_observe-cpp17.cpp +++ b/targettests/execution/cudaq_observe-cpp17.cpp @@ -8,13 +8,11 @@ // REQUIRES: c++17 // clang-format off -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// 2 different IQM machines for 2 different topologies -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // clang-format on #include @@ -35,7 +33,7 @@ struct ansatz { int main() { // Build up your spin op algebraically - cudaq::spin_op h = 5.907 - 2.1433 * cudaq::spin_op::x(0) * cudaq::spin_op::x(1) - + cudaq::spin_op h = 5.907 - 2.1433 * cudaq::spin_op::x(0) * cudaq::spin_op::x(1) - 2.1433 * cudaq::spin_op::y(0) * cudaq::spin_op::y(1) + .21829 * cudaq::spin_op::z(0) - 6.125 * cudaq::spin_op::z(1); diff --git a/targettests/execution/cudaq_observe.cpp b/targettests/execution/cudaq_observe.cpp index 0106c4db392..dbbf2c13677 100644 --- a/targettests/execution/cudaq_observe.cpp +++ b/targettests/execution/cudaq_observe.cpp @@ -9,13 +9,11 @@ // REQUIRES: c++20 // clang-format off // RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target anyon --emulate %s -o %t && %t | 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 Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Crystal_20 --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++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %quantum_machines_avail; then nvq++ %cpp_std --target quantum_machines --emulate %s -o %t && %t | FileCheck %s; fi @@ -39,7 +37,7 @@ struct ansatz { int main() { // Build up your spin op algebraically - cudaq::spin_op h = 5.907 - 2.1433 * cudaq::spin_op::x(0) * cudaq::spin_op::x(1) - + cudaq::spin_op h = 5.907 - 2.1433 * cudaq::spin_op::x(0) * cudaq::spin_op::x(1) - 2.1433 * cudaq::spin_op::y(0) * cudaq::spin_op::y(1) + .21829 * cudaq::spin_op::z(0) - 6.125 * cudaq::spin_op::z(1); diff --git a/targettests/execution/cudaq_observe_qvector.cpp b/targettests/execution/cudaq_observe_qvector.cpp index 826106eb235..27acaf79323 100644 --- a/targettests/execution/cudaq_observe_qvector.cpp +++ b/targettests/execution/cudaq_observe_qvector.cpp @@ -8,13 +8,11 @@ // REQUIRES: c++20 // clang-format off -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | 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 Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Crystal_20 --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++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ --target qci --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/cudaq_observe_term.cpp b/targettests/execution/cudaq_observe_term.cpp index 3a86d658bf5..e1e93670840 100644 --- a/targettests/execution/cudaq_observe_term.cpp +++ b/targettests/execution/cudaq_observe_term.cpp @@ -8,13 +8,11 @@ // REQUIRES: c++20 // clang-format off -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | 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 Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Crystal_20 --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++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/custom_operation_adj.cpp b/targettests/execution/custom_operation_adj.cpp index 793ebf4b4b4..f81482f68b1 100644 --- a/targettests/execution/custom_operation_adj.cpp +++ b/targettests/execution/custom_operation_adj.cpp @@ -8,12 +8,12 @@ // clang-format off // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/custom_operation_basic.cpp b/targettests/execution/custom_operation_basic.cpp index 252d5ccf5cb..7f1459e355c 100644 --- a/targettests/execution/custom_operation_basic.cpp +++ b/targettests/execution/custom_operation_basic.cpp @@ -8,12 +8,12 @@ // clang-format off // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %quantum_machines_avail; then nvq++ %cpp_std --target quantum_machines --emulate %s -o %t && %t | FileCheck %s; fi diff --git a/targettests/execution/custom_operation_ctrl.cpp b/targettests/execution/custom_operation_ctrl.cpp index ac4323b2864..4d1442fed4a 100644 --- a/targettests/execution/custom_operation_ctrl.cpp +++ b/targettests/execution/custom_operation_ctrl.cpp @@ -8,11 +8,11 @@ // clang-format off // RUN: nvq++ %cpp_std --enable-mlir %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/exp_pauli.cpp b/targettests/execution/exp_pauli.cpp index 5870ff8ca50..b8dcc613526 100644 --- a/targettests/execution/exp_pauli.cpp +++ b/targettests/execution/exp_pauli.cpp @@ -16,11 +16,8 @@ // RUN: nvq++ %cpp_std -fkernel-exec-kind=2 -target ionq --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std -fkernel-exec-kind=2 -target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std -fkernel-exec-kind=2 -target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std -fkernel-exec-kind=2 -target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s // RUN: if %qci_avail; then nvq++ %cpp_std -fkernel-exec-kind=2 -target qci --emulate %s -o %t && %t | FileCheck %s; fi -// -// 2 different IQM machines for 2 different topologies -// RUN: nvq++ %cpp_std -fkernel-exec-kind=2 -target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std -fkernel-exec-kind=2 -target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t | FileCheck %s // clang-format on #include diff --git a/targettests/execution/global_reg.cpp b/targettests/execution/global_reg.cpp index fd8c05e52fa..c99d8fddddb 100644 --- a/targettests/execution/global_reg.cpp +++ b/targettests/execution/global_reg.cpp @@ -7,9 +7,9 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ %cpp_std -DNO_ADAPTIVE --target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std -DNO_ADAPTIVE --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std %s -o %t && %t | FileCheck %s // RUN: nvq++ -std=c++17 %s --enable-mlir -o %t // clang-format on diff --git a/targettests/execution/graph_coloring-1.cpp b/targettests/execution/graph_coloring-1.cpp index 1aa727cb0e4..c748f858fc1 100644 --- a/targettests/execution/graph_coloring-1.cpp +++ b/targettests/execution/graph_coloring-1.cpp @@ -9,6 +9,7 @@ // REQUIRES: c++20 // clang-format off // RUN: nvq++ %s -o %t --target infleqtion --emulate && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_20.txt %t | FileCheck %s // RUN: nvq++ %s -o %t --target quantinuum --emulate && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %s -o %t --target braket --emulate && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi diff --git a/targettests/execution/if_jit.cpp b/targettests/execution/if_jit.cpp index 2df41f79095..1d7b06be25e 100644 --- a/targettests/execution/if_jit.cpp +++ b/targettests/execution/if_jit.cpp @@ -9,12 +9,12 @@ // This code is from Issue 296. // clang-format off -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t diff --git a/targettests/execution/int8_t.cpp b/targettests/execution/int8_t.cpp index 9e1358f1e1d..a177bc0fb28 100644 --- a/targettests/execution/int8_t.cpp +++ b/targettests/execution/int8_t.cpp @@ -7,12 +7,12 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t diff --git a/targettests/execution/int8_t_free_func.cpp b/targettests/execution/int8_t_free_func.cpp index 60038a54668..25804aa9934 100644 --- a/targettests/execution/int8_t_free_func.cpp +++ b/targettests/execution/int8_t_free_func.cpp @@ -7,12 +7,12 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t diff --git a/targettests/execution/load_value.cpp b/targettests/execution/load_value.cpp index c9dee300827..a52b9fe26ed 100644 --- a/targettests/execution/load_value.cpp +++ b/targettests/execution/load_value.cpp @@ -7,13 +7,12 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t diff --git a/targettests/execution/mapping_test-1-cpp17.cpp b/targettests/execution/mapping_test-1-cpp17.cpp index 8d028e1e604..335d8a8774b 100644 --- a/targettests/execution/mapping_test-1-cpp17.cpp +++ b/targettests/execution/mapping_test-1-cpp17.cpp @@ -8,9 +8,15 @@ // REQUIRES: c++17 // RUN: nvq++ %cpp_std %s -o %t --target oqc --emulate && CUDAQ_DUMP_JIT_IR=1 %t 2> %t.txt | FileCheck %s && FileCheck --check-prefix=QUAKE %s < %t.txt -// RUN: mkdir -p %t.dir && cp "%iqm_test_src_dir/Crystal_5.txt" "%t.dir/Crystal_5_Variant.txt" && nvq++ %cpp_std %s -o %t --target iqm --iqm-machine Crystal_5 --mapping-file "%t.dir/Crystal_5_Variant.txt" --emulate && %t +// backward compatible way to define the QPU architecture already at compile time +// RUN: nvq++ %cpp_std %s -o %t --target iqm --emulate --mapping-file "%iqm_tests_dir/Crystal_5.txt" && %t | FileCheck %s +// selecting the QPU architecture at runtime allows using the same binary for all architectures +// RUN: nvq++ %cpp_std %s -o %t --target iqm --emulate +// RUN: IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: IQM_QPU_QA=%iqm_tests_dir/Crystal_20.txt %t | FileCheck %s +// RUN: IQM_QPU_QA=%iqm_tests_dir/Crystal_54.txt %t | FileCheck %s // RUN: nvq++ %cpp_std --enable-mlir %s -o %t -// RUN: rm -rf %t.txt %t.dir +// RUN: rm -f %t.txt #include #include diff --git a/targettests/execution/mapping_test-1.cpp b/targettests/execution/mapping_test-1.cpp index be5ca4cf83b..aec5b7c18ca 100644 --- a/targettests/execution/mapping_test-1.cpp +++ b/targettests/execution/mapping_test-1.cpp @@ -9,10 +9,10 @@ // REQUIRES: c++20 // clang-format off // RUN: nvq++ %cpp_std %s -o %t --target oqc --emulate && CUDAQ_DUMP_JIT_IR=1 %t 2> %t.txt | FileCheck %s && FileCheck --check-prefix=QUAKE %s < %t.txt -// RUN: mkdir -p %t.dir && cp "%iqm_test_src_dir/Crystal_5.txt" "%t.dir/Crystal_5_Variant.txt" && nvq++ %cpp_std %s -o %t --target iqm --iqm-machine Crystal_5 --mapping-file "%t.dir/Crystal_5_Variant.txt" --emulate && %t +// RUN: nvq++ %cpp_std %s -o %t --target iqm --emulate --mapping-file "%iqm_test_src_dir/Crystal_5.txt" && %t | FileCheck %s // clang-format on // RUN: nvq++ %cpp_std --enable-mlir %s -o %t -// RUN: rm -rf %t.txt %t.dir +// RUN: rm -f %t.txt #include #include diff --git a/targettests/execution/qspan_slices.cpp b/targettests/execution/qspan_slices.cpp index 821307241e1..ce296c93e66 100644 --- a/targettests/execution/qspan_slices.cpp +++ b/targettests/execution/qspan_slices.cpp @@ -8,16 +8,16 @@ // REQUIRES: c++20 // clang-format off -// RUN: nvq++ --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target anyon --anyon-machine berkeley-25q --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Crystal_5 --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++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --anyon-machine berkeley-25q --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // Tests for --disable-qubit-mapping: // 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 Crystal_5 --emulate --disable-qubit-mapping && CUDAQ_MLIR_PRINT_EACH_PASS=1 %t |& FileCheck --check-prefix=DISABLE %s +// RUN: nvq++ -v %s -o %t --target iqm --emulate --disable-qubit-mapping && CUDAQ_MLIR_PRINT_EACH_PASS=1 IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t |& FileCheck --check-prefix=DISABLE %s // clang-format on #include diff --git a/targettests/execution/qvector_init_from_state.cpp b/targettests/execution/qvector_init_from_state.cpp index 03d00f5027f..1834760e834 100644 --- a/targettests/execution/qvector_init_from_state.cpp +++ b/targettests/execution/qvector_init_from_state.cpp @@ -12,13 +12,11 @@ // RUN: nvq++ %cpp_std --library-mode %s -o %t && %t | FileCheck %s // Quantum emulators -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// 2 different IQM machines for 2 different topologies -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/qvector_init_from_state_c_func.cpp b/targettests/execution/qvector_init_from_state_c_func.cpp index 8db01eec95a..95016f61e4a 100644 --- a/targettests/execution/qvector_init_from_state_c_func.cpp +++ b/targettests/execution/qvector_init_from_state_c_func.cpp @@ -12,13 +12,11 @@ // RUN: nvq++ %cpp_std --library-mode %s -o %t && %t | FileCheck %s // Quantum emulators -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// 2 different IQM machines for 2 different topologies -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/qvector_init_from_state_pauli.cpp b/targettests/execution/qvector_init_from_state_pauli.cpp index 3c2f4b3aeaa..c773eb858f0 100644 --- a/targettests/execution/qvector_init_from_state_pauli.cpp +++ b/targettests/execution/qvector_init_from_state_pauli.cpp @@ -11,13 +11,11 @@ // RUN: nvq++ %cpp_std --enable-mlir %s -o %t && %t | FileCheck %s // Quantum emulators -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// 2 different IQM machines for 2 different topologies -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/state_preparation.cpp b/targettests/execution/state_preparation.cpp index 48a804bd384..2c03f611efc 100644 --- a/targettests/execution/state_preparation.cpp +++ b/targettests/execution/state_preparation.cpp @@ -10,18 +10,16 @@ // RUN: nvq++ %cpp_std --enable-mlir %s -o %t && %t | FileCheck %s // Quantum emulators -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// 2 different IQM machines for 2 different topologies -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %quantum_machines_avail; then nvq++ %cpp_std --target quantum_machines --emulate %s -o %t && %t | FileCheck %s; fi -#include +#include #include #include @@ -38,13 +36,13 @@ int main() { if (i > 0) vec[i-1] = 0; vec[i] = 1; - + auto result = cudaq::sample(kernel{}, vec); #ifndef SYNTAX_CHECK - std::bitset<8> binary(i); + std::bitset<8> binary(i); auto expected = binary.to_string().substr(binary.size() - 2); - + auto bits = result.most_probable(); std::reverse(bits.begin(), bits.end()); std::cout << bits << '\n'; diff --git a/targettests/execution/state_preparation_vector.cpp b/targettests/execution/state_preparation_vector.cpp index 05913075333..e3e7c121c0d 100644 --- a/targettests/execution/state_preparation_vector.cpp +++ b/targettests/execution/state_preparation_vector.cpp @@ -16,10 +16,7 @@ // RUN: nvq++ %cpp_std -target quantinuum -emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std -target ionq -emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std -target oqc -emulate %s -o %t && %t | FileCheck %s - -// 2 different IQM machines for 2 different topologies -// RUN: nvq++ %cpp_std -target iqm --iqm-machine Crystal_5 -emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std -target iqm --iqm-machine Crystal_20 -emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s // clang-format on #include diff --git a/targettests/execution/state_preparation_vector_sizes.cpp b/targettests/execution/state_preparation_vector_sizes.cpp index fd6276dabc3..97c32ecb8bc 100644 --- a/targettests/execution/state_preparation_vector_sizes.cpp +++ b/targettests/execution/state_preparation_vector_sizes.cpp @@ -10,12 +10,10 @@ // RUN: nvq++ %cpp_std --enable-mlir %s -o %t && %t | FileCheck %s // Quantum emulators -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// 2 different IQM machines for 2 different topologies -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi diff --git a/targettests/execution/sudoku_2x2-1.cpp b/targettests/execution/sudoku_2x2-1.cpp index eaca47aa4a8..cb728647d04 100644 --- a/targettests/execution/sudoku_2x2-1.cpp +++ b/targettests/execution/sudoku_2x2-1.cpp @@ -8,12 +8,12 @@ // REQUIRES: c++20 // clang-format off -// RUN: nvq++ --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Crystal_20 --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++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_20.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/sudoku_2x2-bit_names.cpp b/targettests/execution/sudoku_2x2-bit_names.cpp index 84c83289364..4065a382269 100644 --- a/targettests/execution/sudoku_2x2-bit_names.cpp +++ b/targettests/execution/sudoku_2x2-bit_names.cpp @@ -8,12 +8,12 @@ // REQUIRES: c++20 // clang-format off -// RUN: nvq++ --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Crystal_20 --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++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_20.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/sudoku_2x2-reg_name.cpp b/targettests/execution/sudoku_2x2-reg_name.cpp index 12cf5a9568e..155d0ebffca 100644 --- a/targettests/execution/sudoku_2x2-reg_name.cpp +++ b/targettests/execution/sudoku_2x2-reg_name.cpp @@ -8,12 +8,12 @@ // REQUIRES: c++20 // clang-format off -// RUN: nvq++ --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Crystal_20 --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++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_20.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/sudoku_2x2.cpp b/targettests/execution/sudoku_2x2.cpp index 530dd1da061..54ee164549a 100644 --- a/targettests/execution/sudoku_2x2.cpp +++ b/targettests/execution/sudoku_2x2.cpp @@ -8,12 +8,12 @@ // REQUIRES: c++20 // clang-format off -// RUN: nvq++ --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ --target iqm --iqm-machine Crystal_20 --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++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_20.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // clang-format on diff --git a/targettests/execution/swap_gate.cpp b/targettests/execution/swap_gate.cpp index 31ff51cbfd7..97f0bfed5dc 100644 --- a/targettests/execution/swap_gate.cpp +++ b/targettests/execution/swap_gate.cpp @@ -7,12 +7,12 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ -std=c++17 --enable-mlir %s -o %t && %t | FileCheck %s diff --git a/targettests/execution/test_explicit_measurements.cpp b/targettests/execution/test_explicit_measurements.cpp index 4ec3c1075bd..9cd238456f4 100644 --- a/targettests/execution/test_explicit_measurements.cpp +++ b/targettests/execution/test_explicit_measurements.cpp @@ -9,13 +9,13 @@ // REQUIRES: c++20 // clang-format off // RUN: nvq++ --target stim %s -o %t && CUDAQ_LOG_LEVEL=info %t | grep "Creating new Stim frame simulator" | wc -l | FileCheck %s -// RUN: nvq++ --target anyon --emulate %s -o %t && %t 2>&1 | FileCheck %s -check-prefix=FAIL +// RUN: nvq++ --target anyon --emulate %s -o %t && %t 2>&1 | FileCheck %s -check-prefix=FAIL // RUN: if %braket_avail; then nvq++ --target braket --emulate %s -o %t && %t 2>&1 | FileCheck %s -check-prefix=FAIL ; fi -// RUN: nvq++ --target infleqtion --emulate %s -o %t && %t 2>&1 | FileCheck %s -check-prefix=FAIL -// RUN: nvq++ --target ionq --emulate %s -o %t && %t 2>&1 | FileCheck %s -check-prefix=FAIL -// RUN: nvq++ --target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t 2>&1 | FileCheck %s -check-prefix=FAIL -// RUN: nvq++ --target oqc --emulate %s -o %t && %t 2>&1 | FileCheck %s -check-prefix=FAIL -// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t 2>&1 | FileCheck %s -check-prefix=FAIL +// RUN: nvq++ --target infleqtion --emulate %s -o %t && %t 2>&1 | FileCheck %s -check-prefix=FAIL +// RUN: nvq++ --target ionq --emulate %s -o %t && %t 2>&1 | FileCheck %s -check-prefix=FAIL +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t 2>&1 | FileCheck %s -check-prefix=FAIL +// RUN: nvq++ --target oqc --emulate %s -o %t && %t 2>&1 | FileCheck %s -check-prefix=FAIL +// RUN: nvq++ --target quantinuum --emulate %s -o %t && %t 2>&1 | FileCheck %s -check-prefix=FAIL // clang-format on #include diff --git a/targettests/execution/test_trotter.cpp b/targettests/execution/test_trotter.cpp index 64b007763d3..96227a82024 100644 --- a/targettests/execution/test_trotter.cpp +++ b/targettests/execution/test_trotter.cpp @@ -15,10 +15,8 @@ // RUN: nvq++ %cpp_std -target quantinuum -emulate -fkernel-exec-kind=2 %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std -target ionq -emulate -fkernel-exec-kind=2 %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std -target oqc -emulate -fkernel-exec-kind=2 %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate -fkernel-exec-kind=2 %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s // RUN: if %qci_avail; then nvq++ %cpp_std --target qci -emulate -fkernel-exec-kind=2 %s -o %t && %t | FileCheck %s; fi -// 2 different IQM machines for 2 different topologies -// RUN: nvq++ %cpp_std -target iqm --iqm-machine Crystal_5 -emulate -fkernel-exec-kind=2 %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std -target iqm --iqm-machine Crystal_20 -emulate %s -fkernel-exec-kind=2 -o %t && %t | FileCheck %s // clang-format on #include diff --git a/targettests/execution/uccsd.cpp b/targettests/execution/uccsd.cpp index 6522294606a..8cbcd0cfc28 100644 --- a/targettests/execution/uccsd.cpp +++ b/targettests/execution/uccsd.cpp @@ -9,9 +9,9 @@ // clang-format off // RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s ; fi -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_20 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_20.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s // RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // RUN: nvq++ %cpp_std --enable-mlir %s -o %t diff --git a/targettests/execution/variable_size_qreg.cpp b/targettests/execution/variable_size_qreg.cpp index 986cf84b783..a7f9f10053d 100644 --- a/targettests/execution/variable_size_qreg.cpp +++ b/targettests/execution/variable_size_qreg.cpp @@ -7,12 +7,12 @@ ******************************************************************************/ // clang-format off -// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target iqm --iqm-machine Crystal_5 --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s -// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target anyon --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target infleqtion --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target ionq --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target iqm --emulate %s -o %t && IQM_QPU_QA=%iqm_tests_dir/Crystal_5.txt %t | FileCheck %s +// RUN: nvq++ %cpp_std --target oqc --emulate %s -o %t && %t | FileCheck %s +// RUN: nvq++ %cpp_std --target quantinuum --emulate %s -o %t && %t | FileCheck %s // RUN: if %braket_avail; then nvq++ %cpp_std --target braket --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %qci_avail; then nvq++ %cpp_std --target qci --emulate %s -o %t && %t | FileCheck %s; fi // RUN: if %quantum_machines_avail; then nvq++ %cpp_std --target quantum_machines --emulate %s -o %t && %t | FileCheck %s; fi diff --git a/targettests/lit.cfg.py b/targettests/lit.cfg.py index f54cb76fe50..0448c0bfbb7 100644 --- a/targettests/lit.cfg.py +++ b/targettests/lit.cfg.py @@ -36,9 +36,7 @@ config.substitutions.append(('%cudaq_plugin_ext', config.cudaq_plugin_ext)) config.substitutions.append(('%cudaq_target_dir', config.cudaq_target_dir)) config.substitutions.append(('%cudaq_src_dir', config.cudaq_src_dir)) -config.substitutions.append( - ('%iqm_test_src_dir', - config.cudaq_src_dir + "/runtime/cudaq/platform/default/rest/helpers/iqm")) +config.substitutions.append(('%iqm_tests_dir', config.cudaq_src_dir + "/targettests/Target/IQM")) llvm_config.use_default_substitutions() diff --git a/test/Translate/IQM/basic.qke b/test/Translate/IQM/basic.qke index 48dccb0ee12..0c1014455e4 100644 --- a/test/Translate/IQM/basic.qke +++ b/test/Translate/IQM/basic.qke @@ -1,6 +1,7 @@ // ========================================================================== // // Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. // // All rights reserved. // +// Copyright 2025 IQM Quantum Computers // // // // This source code and the accompanying materials are made available under // // the terms of the Apache License 2.0 which accompanies this distribution. // @@ -51,7 +52,7 @@ module attributes {quake.mangled_name_map = {__nvqpp__mlirgen__bell = "_ZN4bellc // CHECK: "angle_t": 0.25, // CHECK: "phase_t": 0.25 // CHECK: }, -// CHECK: "name": "phased_rx", +// CHECK: "name": "prx", // CHECK: "qubits": [ // CHECK: "QB1" // CHECK: ] @@ -61,7 +62,7 @@ module attributes {quake.mangled_name_map = {__nvqpp__mlirgen__bell = "_ZN4bellc // CHECK: "angle_t": 0.5, // CHECK: "phase_t": 0.0 // CHECK: }, -// CHECK: "name": "phased_rx", +// CHECK: "name": "prx", // CHECK: "qubits": [ // CHECK: "QB1" // CHECK: ] @@ -71,7 +72,7 @@ module attributes {quake.mangled_name_map = {__nvqpp__mlirgen__bell = "_ZN4bellc // CHECK: "angle_t": 0.25, // CHECK: "phase_t": 0.25 // CHECK: }, -// CHECK: "name": "phased_rx", +// CHECK: "name": "prx", // CHECK: "qubits": [ // CHECK: "QB2" // CHECK: ] @@ -81,7 +82,7 @@ module attributes {quake.mangled_name_map = {__nvqpp__mlirgen__bell = "_ZN4bellc // CHECK: "angle_t": 0.5, // CHECK: "phase_t": 0.0 // CHECK: }, -// CHECK: "name": "phased_rx", +// CHECK: "name": "prx", // CHECK: "qubits": [ // CHECK: "QB2" // CHECK: ] @@ -99,7 +100,7 @@ module attributes {quake.mangled_name_map = {__nvqpp__mlirgen__bell = "_ZN4bellc // CHECK: "angle_t": 0.25, // CHECK: "phase_t": 0.25 // CHECK: }, -// CHECK: "name": "phased_rx", +// CHECK: "name": "prx", // CHECK: "qubits": [ // CHECK: "QB2" // CHECK: ] @@ -109,7 +110,7 @@ module attributes {quake.mangled_name_map = {__nvqpp__mlirgen__bell = "_ZN4bellc // CHECK: "angle_t": 0.5, // CHECK: "phase_t": 0.0 // CHECK: }, -// CHECK: "name": "phased_rx", +// CHECK: "name": "prx", // CHECK: "qubits": [ // CHECK: "QB2" // CHECK: ] @@ -118,7 +119,7 @@ module attributes {quake.mangled_name_map = {__nvqpp__mlirgen__bell = "_ZN4bellc // CHECK: "args": { // CHECK: "key": "m_QB1" // CHECK: }, -// CHECK: "name": "measurement", +// CHECK: "name": "measure", // CHECK: "qubits": [ // CHECK: "QB1" // CHECK: ] @@ -127,7 +128,7 @@ module attributes {quake.mangled_name_map = {__nvqpp__mlirgen__bell = "_ZN4bellc // CHECK: "args": { // CHECK: "key": "m_QB2" // CHECK: }, -// CHECK: "name": "measurement", +// CHECK: "name": "measure", // CHECK: "qubits": [ // CHECK: "QB2" // CHECK: ] diff --git a/test/Translate/IQM/extractOnConstant.qke b/test/Translate/IQM/extractOnConstant.qke index 4ddad0bc0d7..d512205ee83 100644 --- a/test/Translate/IQM/extractOnConstant.qke +++ b/test/Translate/IQM/extractOnConstant.qke @@ -1,6 +1,7 @@ // ========================================================================== // // Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. // // All rights reserved. // +// Copyright 2025 IQM Quantum Computers // // // // This source code and the accompanying materials are made available under // // the terms of the Apache License 2.0 which accompanies this distribution. // @@ -30,7 +31,7 @@ module attributes {quake.mangled_name_map = {__nvqpp__mlirgen__super = "_ZN5supe // CHECK: "angle_t": 0.25, // CHECK: "phase_t": 0.25 // CHECK: }, -// CHECK: "name": "phased_rx", +// CHECK: "name": "prx", // CHECK: "qubits": [ // CHECK: "QB1" // CHECK: ] @@ -40,7 +41,7 @@ module attributes {quake.mangled_name_map = {__nvqpp__mlirgen__super = "_ZN5supe // CHECK: "angle_t": 0.5, // CHECK: "phase_t": 0.0 // CHECK: }, -// CHECK: "name": "phased_rx", +// CHECK: "name": "prx", // CHECK: "qubits": [ // CHECK: "QB1" // CHECK: ] @@ -49,7 +50,7 @@ module attributes {quake.mangled_name_map = {__nvqpp__mlirgen__super = "_ZN5supe // CHECK: "args": { // CHECK: "key": "m_QB1" // CHECK: }, -// CHECK: "name": "measurement", +// CHECK: "name": "measure", // CHECK: "qubits": [ // CHECK: "QB1" // CHECK: ] diff --git a/unittests/backends/iqm/IQMStartServerAndTest.sh.in b/unittests/backends/iqm/IQMStartServerAndTest.sh.in index c6896b334de..0cccfa8ca24 100644 --- a/unittests/backends/iqm/IQMStartServerAndTest.sh.in +++ b/unittests/backends/iqm/IQMStartServerAndTest.sh.in @@ -3,6 +3,7 @@ # ============================================================================ # # Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. # # All rights reserved. # +# Copyright 2025 IQM Quantum Computers # # # # This source code and the accompanying materials are made available under # # the terms of the Apache License 2.0 which accompanies this distribution. # @@ -44,7 +45,11 @@ while ! checkServerConnection; do fi done # Run the tests -IQM_TOKENS_FILE=$tmp_file ./test_iqm +if [ a${IQM_SERVER_URL} = a ]; then + IQM_TOKEN="good_access_token" IQM_TOKENS_FILE=$tmp_file ./test_iqm +else + ./test_iqm +fi # Did they fail? testsPassed=$? # kill the server diff --git a/unittests/backends/iqm/IQMTester.cpp b/unittests/backends/iqm/IQMTester.cpp index 053baa4f09c..0ea9eeab7e3 100644 --- a/unittests/backends/iqm/IQMTester.cpp +++ b/unittests/backends/iqm/IQMTester.cpp @@ -2,6 +2,7 @@ /******************************************************************************* * Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. * * All rights reserved. * + * Copyright 2025 IQM Quantum Computers * * * * This source code and the accompanying materials are made available under * * the terms of the Apache License 2.0 which accompanies this distribution. * @@ -19,16 +20,10 @@ #include #include -// the mock server has Crystal_20 architecture - -std::string backendStringTemplate = - "iqm;emulate;false;qpu-architecture;{};url;" - "http://localhost:62443"; // add architecture +std::string backendString = "iqm;emulate;false;url;" + "http://localhost:62443"; CUDAQ_TEST(IQMTester, executeOneMeasuredQubitProgram) { - std::string arch = "Crystal_20"; - auto backendString = fmt::format(fmt::runtime(backendStringTemplate), arch); - auto &platform = cudaq::get_platform(); platform.setTargetBackend(backendString); @@ -45,9 +40,6 @@ CUDAQ_TEST(IQMTester, executeOneMeasuredQubitProgram) { } CUDAQ_TEST(IQMTester, executeSeveralMeasuredQubitProgram) { - std::string arch = "Crystal_20"; - auto backendString = fmt::format(fmt::runtime(backendStringTemplate), arch); - auto &platform = cudaq::get_platform(); platform.setTargetBackend(backendString); @@ -58,13 +50,11 @@ CUDAQ_TEST(IQMTester, executeSeveralMeasuredQubitProgram) { kernel.mz(qubit[1]); auto counts = cudaq::sample(kernel); - EXPECT_EQ(counts.size(), 4); + EXPECT_GE(counts.size(), 2); + EXPECT_LE(counts.size(), 4); } CUDAQ_TEST(IQMTester, executeLoopOverQubitsProgram) { - std::string arch = "Crystal_20"; - auto backendString = fmt::format(fmt::runtime(backendStringTemplate), arch); - auto &platform = cudaq::get_platform(); platform.setTargetBackend(backendString); @@ -84,9 +74,6 @@ CUDAQ_TEST(IQMTester, executeLoopOverQubitsProgram) { } CUDAQ_TEST(IQMTester, executeMultipleMeasuredQubitsProgram) { - std::string arch = "Crystal_20"; - auto backendString = fmt::format(fmt::runtime(backendStringTemplate), arch); - auto &platform = cudaq::get_platform(); platform.setTargetBackend(backendString); @@ -100,48 +87,137 @@ CUDAQ_TEST(IQMTester, executeMultipleMeasuredQubitsProgram) { kernel.mz(qubit); auto counts = cudaq::sample(kernel); - EXPECT_EQ(counts.size(), 4); + EXPECT_GE(counts.size(), 2); + EXPECT_LE(counts.size(), 4); } -CUDAQ_TEST(IQMTester, architectureMismatched) { +// Setting an arbitrary string in the IQM_TOKEN environment variable must +// trigger the response that the authentication failed. +CUDAQ_TEST(IQMTester, invalidTokenFromEnvVariable) { + char *token = getenv("IQM_TOKEN"); + EXPECT_THAT( []() { - std::string arch = "Crystal_5"; - auto backendString = - fmt::format(fmt::runtime(backendStringTemplate), arch); + setenv("IQM_TOKEN", "invalid-invalid-invalid", true); auto &platform = cudaq::get_platform(); platform.setTargetBackend(backendString); }, - testing::ThrowsMessage(testing::StrEq( - "IQM QPU architecture mismatch: Crystal_5 != Crystal_20"))); + testing::ThrowsMessage( + testing::HasSubstr("HTTP GET Error - status code 401"))); + + if (token) { + setenv("IQM_TOKEN", token, true); + } else { + unsetenv("IQM_TOKEN"); + } } CUDAQ_TEST(IQMTester, iqmServerUrlEnvOverride) { + char *url = getenv("IQM_SERVER_URL"); + EXPECT_THAT( []() { setenv("IQM_SERVER_URL", "fake-fake-fake", true); - std::string arch = "Crystal_20"; - auto backendString = - fmt::format(fmt::runtime(backendStringTemplate), arch); auto &platform = cudaq::get_platform(); platform.setTargetBackend(backendString); }, testing::ThrowsMessage( testing::HasSubstr("Could not resolve host: fake-fake-fake"))); + + if (url) { + setenv("IQM_SERVER_URL", url, true); + } else { + unsetenv("IQM_SERVER_URL"); + } } +// Without the IQM_TOKEN environment variable the fallback is to check the +// file pointed to by the IQM_TOKENS_FILE environment variable for tokens. +// If this does not exist an error will be thrown. CUDAQ_TEST(IQMTester, tokenFilePathEnvOverride) { + char *token = getenv("IQM_TOKEN"); + char *tfile = getenv("IQM_TOKENS_FILE"); + EXPECT_THAT( []() { + unsetenv("IQM_TOKEN"); setenv("IQM_TOKENS_FILE", "fake-fake-fake", true); - std::string arch = "Crystal_20"; - auto backendString = - fmt::format(fmt::runtime(backendStringTemplate), arch); auto &platform = cudaq::get_platform(); platform.setTargetBackend(backendString); }, testing::ThrowsMessage( testing::HasSubstr("Unable to open tokens file: fake-fake-fake"))); + + if (token) { + setenv("IQM_TOKEN", token, true); + } else { + unsetenv("IQM_TOKEN"); + } + if (tfile) { + setenv("IQM_TOKENS_FILE", tfile, true); + } else { + unsetenv("IQM_TOKENS_FILE"); + } +} + +CUDAQ_TEST(IQMTester, dynamicQuantumArchitectureFile) { + const char dqa_filename[] = "dqa_mock_qpu.txt"; + + unlink(dqa_filename); + + // Test 1: saving dynamic quantum architecture to file + setenv("IQM_SAVE_QPU_QA", dqa_filename, true); + + auto &platform = cudaq::get_platform(); + platform.setTargetBackend(backendString); + + auto kernel = cudaq::make_kernel(); + auto qubit = kernel.qalloc(2); + kernel.h(qubit[0]); + kernel.mz(qubit[0]); + kernel.mz(qubit[1]); + + auto counts = cudaq::sample(kernel); + + unsetenv("IQM_SAVE_QPU_QA"); + + EXPECT_GE(counts.size(), 2); + EXPECT_LE(counts.size(), 4); + + // Test 2: use quantum architecture file referenced in environment variable + setenv("IQM_QPU_QA", dqa_filename, true); + + // platform.setTargetBackend(backendString); + + auto kernel2 = cudaq::make_kernel(); + auto qubit2 = kernel2.qalloc(2); + kernel2.h(qubit2[0]); + kernel2.mz(qubit2[0]); + kernel2.mz(qubit2[1]); + + counts = cudaq::sample(kernel2); + + unsetenv("IQM_QPU_QA"); + + EXPECT_GE(counts.size(), 2); + EXPECT_LE(counts.size(), 4); + + // Test 3: quantum architecture file referenced in backend string + + platform.setTargetBackend(backendString + ";mapping_file;" + dqa_filename); + + auto kernel3 = cudaq::make_kernel(); + auto qubit3 = kernel3.qalloc(2); + kernel3.h(qubit3[0]); + kernel3.mz(qubit3[0]); + kernel3.mz(qubit3[1]); + + counts = cudaq::sample(kernel3); + + EXPECT_GE(counts.size(), 2); + EXPECT_LE(counts.size(), 4); + + unlink(dqa_filename); } int main(int argc, char **argv) { diff --git a/utils/mock_qpu/iqm/__init__.py b/utils/mock_qpu/iqm/__init__.py index 4b57168d23c..b9f946a035f 100644 --- a/utils/mock_qpu/iqm/__init__.py +++ b/utils/mock_qpu/iqm/__init__.py @@ -1,6 +1,7 @@ # ============================================================================ # # Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. # # All rights reserved. # +# Copyright 2025 IQM Quantum Computers # # # # This source code and the accompanying materials are made available under # # the terms of the Apache License 2.0 which accompanies this distribution. # @@ -22,8 +23,44 @@ good_access_token = "Bearer good_access_token" server_qpu_architecture = "Crystal_20" operations = [] # TBA -qubits = [] # TBA -qubit_connectivity = [] # TBA +qubits = [ + "QB1", "QB2", "QB3", "QB4", "QB5", "QB6", "QB7", "QB8", "QB9", "QB10", + "QB11", "QB12", "QB13", "QB14", "QB15", "QB16", "QB17", "QB18", "QB19", + "QB20" +] +qubit_connectivity = [ + ["QB1", "QB2"], + ["QB1", "QB4"], + ["QB2", "QB5"], + ["QB3", "QB4"], + ["QB3", "QB8"], + ["QB4", "QB5"], + ["QB4", "QB9"], + ["QB5", "QB6"], + ["QB5", "QB10"], + ["QB6", "QB7"], + ["QB6", "QB11"], + ["QB7", "QB12"], + ["QB8", "QB9"], + ["QB8", "QB13"], + ["QB9", "QB10"], + ["QB9", "QB14"], + ["QB10", "QB11"], + ["QB10", "QB15"], + ["QB11", "QB12"], + ["QB11", "QB16"], + ["QB12", "QB17"], + ["QB13", "QB14"], + ["QB14", "QB15"], + ["QB14", "QB18"], + ["QB15", "QB16"], + ["QB15", "QB19"], + ["QB16", "QB17"], + ["QB16", "QB20"], + ["QB18", "QB19"], + ["QB19", "QB20"], +] +computational_resonators = [] # Define the REST Server App app = FastAPI() @@ -101,9 +138,9 @@ def _make_cz_unitary_matrix() -> np.ndarray: return CZ -def _extract_qubit_position_from_qubit_name(qubit_names: str) -> int: +def _extract_qubit_position_from_qubit_name(qubit_name: str) -> int: """Extract the qubit position from the qubit name.""" - return int(qubit_names[2:]) - 1 + return int(qubit_name[2:]) - 1 def _partial_trace(N, rho, keep): @@ -129,7 +166,7 @@ def _validate_measurements(job: Job, circuit: iqm_client.Circuit) -> bool: """Check that the circuit contains measurements""" measurements = [ instruction for instruction in circuit.instructions - if instruction.name == "measurement" + if instruction.name == "measure" ] if len(measurements) == 0: job.status = iqm_client.Status.FAILED @@ -144,22 +181,36 @@ def _validate_measurements(job: Job, circuit: iqm_client.Circuit) -> bool: def _validate_connectivity(job: Job, circuit: iqm_client.Circuit) -> bool: - """C""check connectivity partially matches Crystal_20""" - qubit_pairs = [ - instruction.qubits - for instruction in circuit.instructions - if len(instruction.qubits) == 2 - ] - if ("QB2", "QB3") in qubit_pairs or ("QB3", "QB2") in qubit_pairs: - job.status = iqm_client.Status.FAILED - job.result = iqm_client.RunResult( - status=job.status, - metadata=job.metadata, - message= - "Some circuits in the batch have gates between uncoupled qubits:", - ) - createdJobs[job.id] = job - return False + """Check connectivity matches the qpu-architecture""" + request = job.metadata.request + qubit_mapping: Optional[dict[str, str]] = None + + if (request.qubit_mapping is not None) and (request.qubit_mapping): + qubit_mapping = {} + for sqm in request.qubit_mapping: + qubit_mapping[sqm.logical_name] = sqm.physical_name + + for instruction in circuit.instructions: + if len(instruction.qubits) == 2: + qubit_pair = list(instruction.qubits) + if qubit_mapping is not None: + qubit_pair[0] = qubit_mapping[qubit_pair[0]] + qubit_pair[1] = qubit_mapping[qubit_pair[1]] + reverse_qubit_pair = qubit_pair.copy() + reverse_qubit_pair.reverse() + + if qubit_pair not in qubit_connectivity \ + and reverse_qubit_pair not in qubit_connectivity: + # qubit combination not found in architecture -> abort + job.status = iqm_client.Status.FAILED + job.result = iqm_client.RunResult( + status=job.status, + metadata=job.metadata, + message="Some circuits in the batch have gates between" + + " uncoupled qubits: " + "-".join(qubit_pair), + ) + createdJobs[job.id] = job + return False return True @@ -172,7 +223,7 @@ def _gather_circuit_information( all_qubits.update( _extract_qubit_position_from_qubit_name(qb) for qb in list(instruction.qubits)) - if instruction.name == "measurement": + if instruction.name == "measure": measurement_qubits.update( _extract_qubit_position_from_qubit_name(qb) for qb in list(instruction.qubits)) @@ -183,8 +234,8 @@ def _simulate_circuit(instructions: list[iqm_client.Instruction], shots: int) -> dict[str, int]: """Simulate the circuit""" # extract qubits information from measurements - measurement_qubits_positions, number_of_qubits = _gather_circuit_information( - instructions) + measurement_qubits_positions, number_of_qubits = \ + _gather_circuit_information(instructions) # calculate circuit operator and measure qubits dims = [2] * number_of_qubits @@ -193,7 +244,7 @@ def _simulate_circuit(instructions: list[iqm_client.Instruction], operator = operator.reshape(2 * dims) for instruction in instructions: - if instruction.name == "phased_rx": + if instruction.name == "prx": qubit_position = _extract_qubit_position_from_qubit_name( instruction.qubits[0]) r_gate = _make_phased_rx_unitary_matrix( @@ -237,7 +288,7 @@ def _simulate_circuit(instructions: list[iqm_client.Instruction], measurement_qubits_positions) probabilities = np.diag(partial_trace) return { - ms: int(round(prob * shots)) for ms, prob in zip( + ms: int(np.round(np.real(prob * shots))) for ms, prob in zip( _generate_measurement_strings(len(measurement_qubits_positions)), probabilities, ) @@ -286,7 +337,78 @@ async def get_quantum_architecture( )) -@app.post("/jobs") +# Note: in this dynamic quantum architecture 2 qubits are deliberately +# excluded from the list of calibrated `prx` gates. This simulates a QPU +# with an imperfect calibration. +@app.get("/calibration-sets/default/dynamic-quantum-architecture") +async def get_dynamic_quantum_architecture( + request: Request) -> iqm_client.DynamicQuantumArchitecture: + """Get the dynamic quantum architecture""" + + access_token = request.headers.get("Authorization") + if access_token != good_access_token: + raise HTTPException(401) + + return iqm_client.DynamicQuantumArchitecture( + calibration_set_id=str(uuid.uuid4()), + qubits=qubits, + computational_resonators=computational_resonators, + gates={ + "cz": + iqm_client.GateInfo( + implementations={ + "crf_crf": + iqm_client.GateImplementationInfo(loci=tuple( + tuple(pair) for pair in qubit_connectivity)), + }, + default_implementation="crf_crf", + override_default_implementation={}, + ), + "measure": + iqm_client.GateInfo( + implementations={ + "constant": + iqm_client.GateImplementationInfo(loci=tuple( + (qubit,) for qubit in qubits)) + }, + default_implementation="constant", + override_default_implementation={}, + ), + "prx": + iqm_client.GateInfo( + implementations={ + "drag_crf": + iqm_client.GateImplementationInfo(loci=( + ("QB1",), + #("QB2",), + #("QB3",), + ( + "QB4",), + ("QB5",), + ("QB6",), + ("QB7",), + ("QB8",), + ("QB9",), + ("QB10",), + ("QB11",), + ("QB12",), + ("QB13",), + ("QB14",), + ("QB15",), + ("QB16",), + ("QB17",), + ("QB18",), + ("QB19",), + ("QB20",), + )) + }, + default_implementation="drag_crf", + override_default_implementation={}, + ), + }) + + +@app.post("/circuits") async def post_jobs(job_request: iqm_client.RunRequest, request: Request) -> PostJobsResponse: """Register a new job and start execution""" @@ -299,7 +421,7 @@ async def post_jobs(job_request: iqm_client.RunRequest, new_job_id = str(uuid.uuid4()) new_job = Job( id=new_job_id, - status=iqm_client.Status.PENDING_COMPILATION, + status=iqm_client.Status.COMPILATION_STARTED, request=job_request, metadata=metadata, ) @@ -312,7 +434,7 @@ async def post_jobs(job_request: iqm_client.RunRequest, return PostJobsResponse(id=new_job_id) -@app.get("/jobs/{job_id}/status") +@app.get("/circuits/{job_id}/status") async def get_jobs_status(job_id: str, request: Request) -> iqm_client.Status: """Get the status of a job""" @@ -326,7 +448,7 @@ async def get_jobs_status(job_id: str, request: Request) -> iqm_client.Status: return createdJobs[job_id].status -@app.get("/jobs/{job_id}/counts") +@app.get("/circuits/{job_id}/counts") async def get_jobs(job_id: str, request: Request): """Get the result of a job""" access_token = request.headers.get("Authorization")