From a57e6c5b4fe6fceb396d3d58142bda351dd17ee4 Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Tue, 22 Jul 2025 00:38:37 -0400 Subject: [PATCH 01/29] floyd warshall --- frontend/catalyst/device/qjit_device.py | 19 +++++- runtime/lib/capi/RuntimeCAPI.cpp | 85 ++++++++++++++++++++++++- 2 files changed, 100 insertions(+), 4 deletions(-) diff --git a/frontend/catalyst/device/qjit_device.py b/frontend/catalyst/device/qjit_device.py index 239e885fce..0701d9a4b2 100644 --- a/frontend/catalyst/device/qjit_device.py +++ b/frontend/catalyst/device/qjit_device.py @@ -191,6 +191,7 @@ def extract_backend_info( for k, v in getattr(device, "device_kwargs", {}).items(): if k not in device_kwargs: # pragma: no branch device_kwargs[k] = v + device_kwargs["coupling_map"] = capabilities.__getattribute__("coupling_map") return BackendInfo(dname, device_name, device_lpath, device_kwargs) @@ -306,9 +307,19 @@ def __init__(self, original_device): for key, value in original_device.__dict__.items(): self.__setattr__(key, value) - check_device_wires(original_device.wires) - - super().__init__(wires=original_device.wires, shots=original_device.shots) + if any([isinstance(wire_label, tuple) and (len(wire_label) >= 2) for wire_label in original_device.wires.labels]): + print("This is a coupling map") + wires_from_cmap = set() + for wire_label in original_device.wires.labels: + wires_from_cmap.add(wire_label[0]) + wires_from_cmap.add(wire_label[1]) + wires_from_cmap = qml.wires.Wires(list(wires_from_cmap)) + # check_device_wires(wires_from_cmap) not called + # since automatic qubit management + super().__init__(wires=wires_from_cmap, shots=original_device.shots) + else: + check_device_wires(original_device.wires) + super().__init__(wires=original_device.wires, shots=original_device.shots) # Capability loading device_capabilities = get_device_capabilities(original_device) @@ -322,6 +333,8 @@ def __init__(self, original_device): raise CompileError( "The device that specifies to_matrix_ops must support QubitUnitary." ) + + setattr(device_capabilities, "coupling_map", original_device.wires.labels) backend = QJITDevice.extract_backend_info(original_device, device_capabilities) diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index f6659a2037..096fb2e5d0 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -18,6 +18,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -47,6 +50,11 @@ static std::unique_ptr CTX = nullptr; */ thread_local static RTDevice *RTD_PTR = nullptr; +const int MAXIMUM = 1e9; +std::set physical_qubits; +std::map, bool> coupling_map; +std::map, int> distance_matrix; + bool getModifiersAdjoint(const Modifiers *modifiers) { return !modifiers ? false : modifiers->adjoint; @@ -256,7 +264,7 @@ void __catalyst__rt__finalize() static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, int8_t *rtd_kwargs, int64_t shots, bool auto_qubit_management) -{ +{ // Device library cannot be a nullptr RT_FAIL_IF(!rtd_lib, "Invalid device library"); RT_FAIL_IF(!CTX, "Invalid use of the global driver before initialization"); @@ -272,6 +280,81 @@ static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, if (CTX->getDeviceRecorderStatus()) { getQuantumDevicePtr()->StartTapeRecording(); } + + // Extract coupling map from the kwargs passed + // If coupling map is provided then it takes in the form {...,'coupling_map' ((a,b),(b,c))} + // else {...,'coupling_map' (a,b,c)} + size_t start = args[2].find("coupling_map': ") + 15; // Find key and opening parenthesis + size_t end = args[2].find("}", start); // Find closing parenthesis + std::string tuple_str = std::string(args[2].substr(start, end - start)); + + // std::vector> coupling_map; + // std::set physical_qubits; + // Extract provided coupling map + if (tuple_str.find("((") != std::string::npos) { + auto string_index = 1; + while(string_index < tuple_str.size() - 1) + { + size_t next_closing_bracket = tuple_str.find(")", string_index); + std::string curr_tuple_str = std::string(tuple_str.substr(string_index+1, next_closing_bracket - string_index - 1)); + std::istringstream iss(curr_tuple_str); + int first_int, second_int; + char comma; + iss >> first_int >> comma && comma == ',' && iss >> second_int; + physical_qubits.insert(first_int); + physical_qubits.insert(second_int); + coupling_map[std::make_pair(first_int, second_int)] = true; + coupling_map[std::make_pair(second_int, first_int)] = true; + string_index = next_closing_bracket + 3; + } + } + // No coupling map provided so all-to-all connectivity + else { + std::string delimiter = ","; + size_t start = 1; + size_t end = tuple_str.find(delimiter); + while (end < tuple_str.size() - 1) { + physical_qubits.insert(std::stoi(tuple_str.substr(start, end - start))); + start = end + delimiter.length(); + end = tuple_str.find(delimiter, start); + } + physical_qubits.insert(std::stoi(tuple_str.substr(start))); + // all-to-all connectivity + for (auto i_itr = physical_qubits.begin(); i_itr != physical_qubits.end(); ++i_itr) + { + for (auto j_itr = physical_qubits.begin(); j_itr != i_itr; ++j_itr ) + { + coupling_map[std::make_pair(*i_itr, *j_itr)] = true; + coupling_map[std::make_pair(*j_itr, *i_itr)] = true; + } + } + } + + // initial distances maximum + for (auto i_itr = physical_qubits.begin(); i_itr != physical_qubits.end(); i_itr++) + for (auto j_itr = physical_qubits.begin(); j_itr != physical_qubits.end(); j_itr++) + distance_matrix[std::make_pair(*i_itr, *j_itr)] = MAXIMUM; + // self-distances : 0 + for (auto i_itr = physical_qubits.begin(); i_itr != physical_qubits.end(); i_itr++) + distance_matrix[std::make_pair(*i_itr, *i_itr)] = 0; + // edge-distances : 1 + for (auto& entry : coupling_map) { + const std::pair& key = entry.first; + bool value = entry.second; + if (value) + distance_matrix[std::make_pair(key.first, key.second)] = 1; + } + // run floyd-warshall + for (auto i_itr = physical_qubits.begin(); i_itr != physical_qubits.end(); i_itr++) + for (auto j_itr = physical_qubits.begin(); j_itr != physical_qubits.end(); j_itr++ ) + for (auto k_itr = physical_qubits.begin(); k_itr != physical_qubits.end(); k_itr++ ) + if (distance_matrix[std::make_pair(*j_itr,*i_itr)] + distance_matrix[std::make_pair(*i_itr,*k_itr)] < distance_matrix[std::make_pair(*j_itr,*k_itr)] ) + distance_matrix[std::make_pair(*j_itr,*k_itr)] = distance_matrix[std::make_pair(*j_itr,*i_itr)] + distance_matrix[std::make_pair(*i_itr,*k_itr)]; + + std::cout << "Distance matrix: \n"; + for (auto i_itr = physical_qubits.begin(); i_itr != physical_qubits.end(); i_itr++) + for (auto j_itr = physical_qubits.begin(); j_itr != physical_qubits.end(); j_itr++ ) + std::cout << "i: " << *i_itr << " j: " << *j_itr << " Distance: " << distance_matrix[std::make_pair(*i_itr,*j_itr)] << "\n"; return 0; } From 3d8695f5750c466a53530448ce4094cb2299273d Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Tue, 22 Jul 2025 18:45:13 -0400 Subject: [PATCH 02/29] numm qubit for printing --- frontend/catalyst/device/qjit_device.py | 1 - runtime/lib/backend/null_qubit/NullQubit.hpp | 5 + runtime/lib/capi/RuntimeCAPI.cpp | 161 ++++++++++++++----- 3 files changed, 129 insertions(+), 38 deletions(-) diff --git a/frontend/catalyst/device/qjit_device.py b/frontend/catalyst/device/qjit_device.py index 0701d9a4b2..2d6d0f5e12 100644 --- a/frontend/catalyst/device/qjit_device.py +++ b/frontend/catalyst/device/qjit_device.py @@ -308,7 +308,6 @@ def __init__(self, original_device): self.__setattr__(key, value) if any([isinstance(wire_label, tuple) and (len(wire_label) >= 2) for wire_label in original_device.wires.labels]): - print("This is a coupling map") wires_from_cmap = set() for wire_label in original_device.wires.labels: wires_from_cmap.add(wire_label[0]) diff --git a/runtime/lib/backend/null_qubit/NullQubit.hpp b/runtime/lib/backend/null_qubit/NullQubit.hpp index eb52510933..b52c8ce30b 100644 --- a/runtime/lib/backend/null_qubit/NullQubit.hpp +++ b/runtime/lib/backend/null_qubit/NullQubit.hpp @@ -242,6 +242,11 @@ struct NullQubit final : public Catalyst::Runtime::QuantumDevice { const std::vector &controlled_wires = {}, const std::vector &controlled_values = {}) { + // Print to see what naive router does on Null qubits + std::cout << "Name:" << name << "\n"; + std::cout << "Wires : "; + for(auto i : wires) std::cout << i << ","; + std::cout << "\n"; if (this->track_resources_) { std::string prefix = ""; std::string suffix = ""; diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index 096fb2e5d0..6754583dd8 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -51,9 +51,33 @@ static std::unique_ptr CTX = nullptr; thread_local static RTDevice *RTD_PTR = nullptr; const int MAXIMUM = 1e9; -std::set physical_qubits; -std::map, bool> coupling_map; -std::map, int> distance_matrix; +std::set physicalQubits; +std::map wireMap; +std::map, bool> couplingMap; +std::map, int> distanceMatrix; +std::map, int> predecessorMatrix; + +std::vector getShortestPath(int source, int target) +{ + std::vector path; + if (predecessorMatrix.at(std::make_pair(source, target)) == -1 && source != target) { + return path; + } + + int current = target; + while (current != source) { + path.push_back(current); + current = predecessorMatrix.at(std::make_pair(source, current)); + if (current == -1 && path.size() > 0) + { + path.clear(); + return path; + } + } + path.push_back(source); + std::reverse(path.begin(), path.end()); + return path; +} bool getModifiersAdjoint(const Modifiers *modifiers) { @@ -262,6 +286,47 @@ void __catalyst__rt__finalize() CTX.reset(nullptr); } + +static std::pair getRoutedQubits(QUBIT *control, QUBIT *target, const Modifiers *modifiers) +{ + // Similar to qml.transpile implementation + // https://docs.pennylane.ai/en/stable/_modules/pennylane/transforms/transpile.html + int firstQubit = reinterpret_cast(control); + int secondQubit = reinterpret_cast(target); + + if (couplingMap[std::make_pair(firstQubit, secondQubit)]) + { + // since in each iteration, we adjust indices of each op, + // we reset logical -> phyiscal mapping + for (auto it = wireMap.begin(); it != wireMap.end(); ++it) { + wireMap[it->second] = it->second; + } + } + else + { + std::vector swapPath = getShortestPath(firstQubit, secondQubit); + // iNamedOperation("SWAP", {}, {u,v}, MODIFIERS_ARGS(modifiers)); + + for (auto it = wireMap.begin(); it != wireMap.end(); ++it) { + // update logical -> phyiscal mapping + if (wireMap[it->first] == u) + wireMap[it->first] = v; + else if (wireMap[it->first] == v) + wireMap[it->first] = u; + } + + } + firstQubit = wireMap[firstQubit]; + secondQubit = wireMap[secondQubit]; + } + return std::make_pair(firstQubit, secondQubit); +} + static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, int8_t *rtd_kwargs, int64_t shots, bool auto_qubit_management) { @@ -282,14 +347,12 @@ static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, } // Extract coupling map from the kwargs passed - // If coupling map is provided then it takes in the form {...,'coupling_map' ((a,b),(b,c))} - // else {...,'coupling_map' (a,b,c)} + // If coupling map is provided then it takes in the form {...,'couplingMap' ((a,b),(b,c))} + // else {...,'couplingMap' (a,b,c)} size_t start = args[2].find("coupling_map': ") + 15; // Find key and opening parenthesis size_t end = args[2].find("}", start); // Find closing parenthesis std::string tuple_str = std::string(args[2].substr(start, end - start)); - // std::vector> coupling_map; - // std::set physical_qubits; // Extract provided coupling map if (tuple_str.find("((") != std::string::npos) { auto string_index = 1; @@ -301,10 +364,10 @@ static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, int first_int, second_int; char comma; iss >> first_int >> comma && comma == ',' && iss >> second_int; - physical_qubits.insert(first_int); - physical_qubits.insert(second_int); - coupling_map[std::make_pair(first_int, second_int)] = true; - coupling_map[std::make_pair(second_int, first_int)] = true; + physicalQubits.insert(first_int); + physicalQubits.insert(second_int); + couplingMap[std::make_pair(first_int, second_int)] = true; + couplingMap[std::make_pair(second_int, first_int)] = true; string_index = next_closing_bracket + 3; } } @@ -314,47 +377,68 @@ static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, size_t start = 1; size_t end = tuple_str.find(delimiter); while (end < tuple_str.size() - 1) { - physical_qubits.insert(std::stoi(tuple_str.substr(start, end - start))); + physicalQubits.insert(std::stoi(tuple_str.substr(start, end - start))); start = end + delimiter.length(); end = tuple_str.find(delimiter, start); } - physical_qubits.insert(std::stoi(tuple_str.substr(start))); + physicalQubits.insert(std::stoi(tuple_str.substr(start))); // all-to-all connectivity - for (auto i_itr = physical_qubits.begin(); i_itr != physical_qubits.end(); ++i_itr) + for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); ++i_itr) { - for (auto j_itr = physical_qubits.begin(); j_itr != i_itr; ++j_itr ) + for (auto j_itr = physicalQubits.begin(); j_itr != i_itr; ++j_itr ) { - coupling_map[std::make_pair(*i_itr, *j_itr)] = true; - coupling_map[std::make_pair(*j_itr, *i_itr)] = true; + couplingMap[std::make_pair(*i_itr, *j_itr)] = true; + couplingMap[std::make_pair(*j_itr, *i_itr)] = true; } } } + + for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); i_itr++) + { + // initial mapping i->i + wireMap[*i_itr] = *i_itr; + // self-distances : 0 + distanceMatrix[std::make_pair(*i_itr, *i_itr)] = 0; + // parent(self) = self + predecessorMatrix[std::make_pair(*i_itr, *i_itr)] = *i_itr; + } // initial distances maximum - for (auto i_itr = physical_qubits.begin(); i_itr != physical_qubits.end(); i_itr++) - for (auto j_itr = physical_qubits.begin(); j_itr != physical_qubits.end(); j_itr++) - distance_matrix[std::make_pair(*i_itr, *j_itr)] = MAXIMUM; - // self-distances : 0 - for (auto i_itr = physical_qubits.begin(); i_itr != physical_qubits.end(); i_itr++) - distance_matrix[std::make_pair(*i_itr, *i_itr)] = 0; + for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); i_itr++) + { + for (auto j_itr = physicalQubits.begin(); j_itr != physicalQubits.end(); j_itr++) + { + distanceMatrix[std::make_pair(*i_itr, *j_itr)] = MAXIMUM; + predecessorMatrix[std::make_pair(*i_itr, *j_itr)] = -1; + } + } + // edge-distances : 1 - for (auto& entry : coupling_map) { + for (auto& entry : couplingMap) + { const std::pair& key = entry.first; bool value = entry.second; if (value) - distance_matrix[std::make_pair(key.first, key.second)] = 1; + { + distanceMatrix[std::make_pair(key.first, key.second)] = 1; + predecessorMatrix[std::make_pair(key.first, key.second)] = key.first; + } } // run floyd-warshall - for (auto i_itr = physical_qubits.begin(); i_itr != physical_qubits.end(); i_itr++) - for (auto j_itr = physical_qubits.begin(); j_itr != physical_qubits.end(); j_itr++ ) - for (auto k_itr = physical_qubits.begin(); k_itr != physical_qubits.end(); k_itr++ ) - if (distance_matrix[std::make_pair(*j_itr,*i_itr)] + distance_matrix[std::make_pair(*i_itr,*k_itr)] < distance_matrix[std::make_pair(*j_itr,*k_itr)] ) - distance_matrix[std::make_pair(*j_itr,*k_itr)] = distance_matrix[std::make_pair(*j_itr,*i_itr)] + distance_matrix[std::make_pair(*i_itr,*k_itr)]; - - std::cout << "Distance matrix: \n"; - for (auto i_itr = physical_qubits.begin(); i_itr != physical_qubits.end(); i_itr++) - for (auto j_itr = physical_qubits.begin(); j_itr != physical_qubits.end(); j_itr++ ) - std::cout << "i: " << *i_itr << " j: " << *j_itr << " Distance: " << distance_matrix[std::make_pair(*i_itr,*j_itr)] << "\n"; + for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); i_itr++) + { + for (auto j_itr = physicalQubits.begin(); j_itr != physicalQubits.end(); j_itr++ ) + { + for (auto k_itr = physicalQubits.begin(); k_itr != physicalQubits.end(); k_itr++ ) + { + if (distanceMatrix[std::make_pair(*j_itr,*i_itr)] + distanceMatrix[std::make_pair(*i_itr,*k_itr)] < distanceMatrix[std::make_pair(*j_itr,*k_itr)] ) + { + distanceMatrix[std::make_pair(*j_itr,*k_itr)] = distanceMatrix[std::make_pair(*j_itr,*i_itr)] + distanceMatrix[std::make_pair(*i_itr,*k_itr)]; + predecessorMatrix[std::make_pair(*j_itr,*k_itr)] = predecessorMatrix[std::make_pair(*i_itr,*k_itr)]; + } + } + } + } return 0; } @@ -686,10 +770,13 @@ void __catalyst__qis__CNOT(QUBIT *control, QUBIT *target, const Modifiers *modif { RT_FAIL_IF(control == target, "Invalid input for CNOT gate. Control and target qubit operands must be distinct."); + + std::pair routedQubits = getRoutedQubits(control, target, modifiers); getQuantumDevicePtr()->NamedOperation("CNOT", {}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, /* modifiers */ MODIFIERS_ARGS(modifiers)); + } void __catalyst__qis__CY(QUBIT *control, QUBIT *target, const Modifiers *modifiers) From ab18f545997e4c863caed47983cdc34f1b5c9780 Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Tue, 5 Aug 2025 10:17:17 -0400 Subject: [PATCH 03/29] formatting --- frontend/catalyst/device/qjit_device.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/catalyst/device/qjit_device.py b/frontend/catalyst/device/qjit_device.py index 389cfe45be..a0fe7027ca 100644 --- a/frontend/catalyst/device/qjit_device.py +++ b/frontend/catalyst/device/qjit_device.py @@ -305,7 +305,12 @@ def __init__(self, original_device): for key, value in original_device.__dict__.items(): self.__setattr__(key, value) - if any([isinstance(wire_label, tuple) and (len(wire_label) >= 2) for wire_label in original_device.wires.labels]): + if any( + [ + isinstance(wire_label, tuple) and (len(wire_label) >= 2) + for wire_label in original_device.wires.labels + ] + ): wires_from_cmap = set() for wire_label in original_device.wires.labels: wires_from_cmap.add(wire_label[0]) @@ -330,7 +335,7 @@ def __init__(self, original_device): raise CompileError( "The device that specifies to_matrix_ops must support QubitUnitary." ) - + setattr(device_capabilities, "coupling_map", original_device.wires.labels) backend = QJITDevice.extract_backend_info(original_device) From 72036f491c172be27a76ae8b591da555c448f79c Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Fri, 8 Aug 2025 11:42:29 -0400 Subject: [PATCH 04/29] clang format --- runtime/lib/capi/RuntimeCAPI.cpp | 118 ++++++++++++++----------------- 1 file changed, 53 insertions(+), 65 deletions(-) diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index eee76eb9f5..0f4c0cb715 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -16,11 +16,11 @@ #include #include #include +#include +#include #include #include -#include #include -#include #include #include #include @@ -52,12 +52,12 @@ thread_local static RTDevice *RTD_PTR = nullptr; const int MAXIMUM = 1e9; std::set physicalQubits; -std::map wireMap; -std::map, bool> couplingMap; -std::map, int> distanceMatrix; +std::map wireMap; +std::map, bool> couplingMap; +std::map, int> distanceMatrix; std::map, int> predecessorMatrix; -std::vector getShortestPath(int source, int target) +std::vector getShortestPath(int source, int target) { std::vector path; if (predecessorMatrix.at(std::make_pair(source, target)) == -1 && source != target) { @@ -68,14 +68,13 @@ std::vector getShortestPath(int source, int target) while (current != source) { path.push_back(current); current = predecessorMatrix.at(std::make_pair(source, current)); - if (current == -1 && path.size() > 0) - { - path.clear(); - return path; + if (current == -1 && path.size() > 0) { + path.clear(); + return path; } } path.push_back(source); - std::reverse(path.begin(), path.end()); + std::reverse(path.begin(), path.end()); return path; } @@ -286,32 +285,29 @@ void __catalyst__rt__finalize() CTX.reset(nullptr); } - -static std::pair getRoutedQubits(QUBIT *control, QUBIT *target, const Modifiers *modifiers) +static std::pair getRoutedQubits(QUBIT *control, QUBIT *target, + const Modifiers *modifiers) { // Similar to qml.transpile implementation // https://docs.pennylane.ai/en/stable/_modules/pennylane/transforms/transpile.html int firstQubit = reinterpret_cast(control); int secondQubit = reinterpret_cast(target); - - if (couplingMap[std::make_pair(firstQubit, secondQubit)]) - { + + if (couplingMap[std::make_pair(firstQubit, secondQubit)]) { // since in each iteration, we adjust indices of each op, // we reset logical -> phyiscal mapping for (auto it = wireMap.begin(); it != wireMap.end(); ++it) { wireMap[it->second] = it->second; } } - else - { + else { std::vector swapPath = getShortestPath(firstQubit, secondQubit); // iNamedOperation("SWAP", {}, {u,v}, MODIFIERS_ARGS(modifiers)); - + getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + for (auto it = wireMap.begin(); it != wireMap.end(); ++it) { // update logical -> phyiscal mapping if (wireMap[it->first] == u) @@ -319,7 +315,6 @@ static std::pair getRoutedQubits(QUBIT *control, QUBIT *target, const M else if (wireMap[it->first] == v) wireMap[it->first] = u; } - } firstQubit = wireMap[firstQubit]; secondQubit = wireMap[secondQubit]; @@ -329,7 +324,7 @@ static std::pair getRoutedQubits(QUBIT *control, QUBIT *target, const M static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, int8_t *rtd_kwargs, int64_t shots, bool auto_qubit_management) -{ +{ // Device library cannot be a nullptr RT_FAIL_IF(!rtd_lib, "Invalid device library"); RT_FAIL_IF(!CTX, "Invalid use of the global driver before initialization"); @@ -346,31 +341,31 @@ static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, getQuantumDevicePtr()->StartTapeRecording(); } - // Extract coupling map from the kwargs passed + // Extract coupling map from the kwargs passed // If coupling map is provided then it takes in the form {...,'couplingMap' ((a,b),(b,c))} // else {...,'couplingMap' (a,b,c)} size_t start = args[2].find("coupling_map': ") + 15; // Find key and opening parenthesis - size_t end = args[2].find("}", start); // Find closing parenthesis + size_t end = args[2].find("}", start); // Find closing parenthesis std::string tuple_str = std::string(args[2].substr(start, end - start)); // Extract provided coupling map if (tuple_str.find("((") != std::string::npos) { auto string_index = 1; - while(string_index < tuple_str.size() - 1) - { - size_t next_closing_bracket = tuple_str.find(")", string_index); - std::string curr_tuple_str = std::string(tuple_str.substr(string_index+1, next_closing_bracket - string_index - 1)); + while (string_index < tuple_str.size() - 1) { + size_t next_closing_bracket = tuple_str.find(")", string_index); + std::string curr_tuple_str = std::string( + tuple_str.substr(string_index + 1, next_closing_bracket - string_index - 1)); std::istringstream iss(curr_tuple_str); int first_int, second_int; - char comma; - iss >> first_int >> comma && comma == ',' && iss >> second_int; + char comma; + iss >> first_int >> comma &&comma == ',' && iss >> second_int; physicalQubits.insert(first_int); physicalQubits.insert(second_int); couplingMap[std::make_pair(first_int, second_int)] = true; couplingMap[std::make_pair(second_int, first_int)] = true; string_index = next_closing_bracket + 3; } - } + } // No coupling map provided so all-to-all connectivity else { std::string delimiter = ","; @@ -383,18 +378,15 @@ static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, } physicalQubits.insert(std::stoi(tuple_str.substr(start))); // all-to-all connectivity - for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); ++i_itr) - { - for (auto j_itr = physicalQubits.begin(); j_itr != i_itr; ++j_itr ) - { + for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); ++i_itr) { + for (auto j_itr = physicalQubits.begin(); j_itr != i_itr; ++j_itr) { couplingMap[std::make_pair(*i_itr, *j_itr)] = true; couplingMap[std::make_pair(*j_itr, *i_itr)] = true; } } } - - for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); i_itr++) - { + + for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); i_itr++) { // initial mapping i->i wireMap[*i_itr] = *i_itr; // self-distances : 0 @@ -404,37 +396,34 @@ static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, } // initial distances maximum - for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); i_itr++) - { - for (auto j_itr = physicalQubits.begin(); j_itr != physicalQubits.end(); j_itr++) - { + for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); i_itr++) { + for (auto j_itr = physicalQubits.begin(); j_itr != physicalQubits.end(); j_itr++) { distanceMatrix[std::make_pair(*i_itr, *j_itr)] = MAXIMUM; - predecessorMatrix[std::make_pair(*i_itr, *j_itr)] = -1; + predecessorMatrix[std::make_pair(*i_itr, *j_itr)] = -1; } } - + // edge-distances : 1 - for (auto& entry : couplingMap) - { - const std::pair& key = entry.first; + for (auto &entry : couplingMap) { + const std::pair &key = entry.first; bool value = entry.second; - if (value) - { + if (value) { distanceMatrix[std::make_pair(key.first, key.second)] = 1; predecessorMatrix[std::make_pair(key.first, key.second)] = key.first; } } // run floyd-warshall - for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); i_itr++) - { - for (auto j_itr = physicalQubits.begin(); j_itr != physicalQubits.end(); j_itr++ ) - { - for (auto k_itr = physicalQubits.begin(); k_itr != physicalQubits.end(); k_itr++ ) - { - if (distanceMatrix[std::make_pair(*j_itr,*i_itr)] + distanceMatrix[std::make_pair(*i_itr,*k_itr)] < distanceMatrix[std::make_pair(*j_itr,*k_itr)] ) - { - distanceMatrix[std::make_pair(*j_itr,*k_itr)] = distanceMatrix[std::make_pair(*j_itr,*i_itr)] + distanceMatrix[std::make_pair(*i_itr,*k_itr)]; - predecessorMatrix[std::make_pair(*j_itr,*k_itr)] = predecessorMatrix[std::make_pair(*i_itr,*k_itr)]; + for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); i_itr++) { + for (auto j_itr = physicalQubits.begin(); j_itr != physicalQubits.end(); j_itr++) { + for (auto k_itr = physicalQubits.begin(); k_itr != physicalQubits.end(); k_itr++) { + if (distanceMatrix[std::make_pair(*j_itr, *i_itr)] + + distanceMatrix[std::make_pair(*i_itr, *k_itr)] < + distanceMatrix[std::make_pair(*j_itr, *k_itr)]) { + distanceMatrix[std::make_pair(*j_itr, *k_itr)] = + distanceMatrix[std::make_pair(*j_itr, *i_itr)] + + distanceMatrix[std::make_pair(*i_itr, *k_itr)]; + predecessorMatrix[std::make_pair(*j_itr, *k_itr)] = + predecessorMatrix[std::make_pair(*i_itr, *k_itr)]; } } } @@ -779,13 +768,12 @@ void __catalyst__qis__CNOT(QUBIT *control, QUBIT *target, const Modifiers *modif { RT_FAIL_IF(control == target, "Invalid input for CNOT gate. Control and target qubit operands must be distinct."); - - std::pair routedQubits = getRoutedQubits(control, target, modifiers); + + std::pair routedQubits = getRoutedQubits(control, target, modifiers); getQuantumDevicePtr()->NamedOperation("CNOT", {}, {/* control = */ routedQubits.first, /* target = */ routedQubits.second}, /* modifiers */ MODIFIERS_ARGS(modifiers)); - } void __catalyst__qis__CY(QUBIT *control, QUBIT *target, const Modifiers *modifiers) From 83d5b33f3abc1bf82ac0a2d39c0b39ebe6c4aa29 Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Fri, 8 Aug 2025 13:29:21 -0400 Subject: [PATCH 05/29] fix ci errors --- frontend/catalyst/device/qjit_device.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/frontend/catalyst/device/qjit_device.py b/frontend/catalyst/device/qjit_device.py index a0fe7027ca..af2eb5b12c 100644 --- a/frontend/catalyst/device/qjit_device.py +++ b/frontend/catalyst/device/qjit_device.py @@ -139,7 +139,7 @@ class BackendInfo: # pylint: disable=too-many-branches @debug_logger -def extract_backend_info(device: qml.devices.QubitDevice) -> BackendInfo: +def extract_backend_info(device: qml.devices.QubitDevice, device_capabilities) -> BackendInfo: """Extract the backend info from a quantum device. The device is expected to carry a reference to a valid TOML config file.""" @@ -189,7 +189,7 @@ def extract_backend_info(device: qml.devices.QubitDevice) -> BackendInfo: for k, v in getattr(device, "device_kwargs", {}).items(): if k not in device_kwargs: # pragma: no branch device_kwargs[k] = v - device_kwargs["coupling_map"] = capabilities.__getattribute__("coupling_map") + device_kwargs["coupling_map"] = getattr(device_capabilities, "coupling_map") return BackendInfo(dname, device_name, device_lpath, device_kwargs) @@ -294,9 +294,9 @@ class QJITDevice(qml.devices.Device): @staticmethod @debug_logger - def extract_backend_info(device) -> BackendInfo: + def extract_backend_info(device, device_capabilities) -> BackendInfo: """Wrapper around extract_backend_info in the runtime module.""" - return extract_backend_info(device) + return extract_backend_info(device, device_capabilities) @debug_logger_init def __init__(self, original_device): @@ -306,10 +306,8 @@ def __init__(self, original_device): self.__setattr__(key, value) if any( - [ isinstance(wire_label, tuple) and (len(wire_label) >= 2) for wire_label in original_device.wires.labels - ] ): wires_from_cmap = set() for wire_label in original_device.wires.labels: @@ -338,7 +336,7 @@ def __init__(self, original_device): setattr(device_capabilities, "coupling_map", original_device.wires.labels) - backend = QJITDevice.extract_backend_info(original_device) + backend = QJITDevice.extract_backend_info(original_device, device_capabilities) self.backend_name = backend.c_interface_name self.backend_lib = backend.lpath From 70a11b4b19be86d5d38401c37b2359aec57b742f Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Fri, 8 Aug 2025 13:30:48 -0400 Subject: [PATCH 06/29] fix ci errors --- runtime/lib/backend/null_qubit/NullQubit.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/lib/backend/null_qubit/NullQubit.hpp b/runtime/lib/backend/null_qubit/NullQubit.hpp index 3ed2df7f72..a272806339 100644 --- a/runtime/lib/backend/null_qubit/NullQubit.hpp +++ b/runtime/lib/backend/null_qubit/NullQubit.hpp @@ -245,7 +245,8 @@ struct NullQubit final : public Catalyst::Runtime::QuantumDevice { // Print to see what naive router does on Null qubits std::cout << "Name:" << name << "\n"; std::cout << "Wires : "; - for(auto i : wires) std::cout << i << ","; + for (auto i : wires) + std::cout << i << ","; std::cout << "\n"; if (this->track_resources_) { std::string prefix = ""; From 7cffa7b0f3f720f12c276fe8beac408994795dbb Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Fri, 8 Aug 2025 13:32:31 -0400 Subject: [PATCH 07/29] fix linting errors --- frontend/catalyst/device/qjit_device.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/catalyst/device/qjit_device.py b/frontend/catalyst/device/qjit_device.py index af2eb5b12c..2ecc5d3548 100644 --- a/frontend/catalyst/device/qjit_device.py +++ b/frontend/catalyst/device/qjit_device.py @@ -306,8 +306,8 @@ def __init__(self, original_device): self.__setattr__(key, value) if any( - isinstance(wire_label, tuple) and (len(wire_label) >= 2) - for wire_label in original_device.wires.labels + isinstance(wire_label, tuple) and (len(wire_label) >= 2) + for wire_label in original_device.wires.labels ): wires_from_cmap = set() for wire_label in original_device.wires.labels: From 3eb866fb795df61c63a26a2e00c1cf15630759ff Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Fri, 8 Aug 2025 13:36:01 -0400 Subject: [PATCH 08/29] device capabilities as an optional arg --- frontend/catalyst/device/qjit_device.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/catalyst/device/qjit_device.py b/frontend/catalyst/device/qjit_device.py index 2ecc5d3548..102fdb7b26 100644 --- a/frontend/catalyst/device/qjit_device.py +++ b/frontend/catalyst/device/qjit_device.py @@ -139,7 +139,7 @@ class BackendInfo: # pylint: disable=too-many-branches @debug_logger -def extract_backend_info(device: qml.devices.QubitDevice, device_capabilities) -> BackendInfo: +def extract_backend_info(device: qml.devices.QubitDevice, device_capabilities = None) -> BackendInfo: """Extract the backend info from a quantum device. The device is expected to carry a reference to a valid TOML config file.""" @@ -294,7 +294,7 @@ class QJITDevice(qml.devices.Device): @staticmethod @debug_logger - def extract_backend_info(device, device_capabilities) -> BackendInfo: + def extract_backend_info(device, device_capabilities = None) -> BackendInfo: """Wrapper around extract_backend_info in the runtime module.""" return extract_backend_info(device, device_capabilities) From 1ca60b2bb809913673300e0a99fa4c1b0d057943 Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Fri, 8 Aug 2025 13:38:15 -0400 Subject: [PATCH 09/29] fix formatting again --- frontend/catalyst/device/qjit_device.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/catalyst/device/qjit_device.py b/frontend/catalyst/device/qjit_device.py index 102fdb7b26..8215622594 100644 --- a/frontend/catalyst/device/qjit_device.py +++ b/frontend/catalyst/device/qjit_device.py @@ -139,7 +139,7 @@ class BackendInfo: # pylint: disable=too-many-branches @debug_logger -def extract_backend_info(device: qml.devices.QubitDevice, device_capabilities = None) -> BackendInfo: +def extract_backend_info(device: qml.devices.QubitDevice, device_capabilities=None) -> BackendInfo: """Extract the backend info from a quantum device. The device is expected to carry a reference to a valid TOML config file.""" @@ -294,7 +294,7 @@ class QJITDevice(qml.devices.Device): @staticmethod @debug_logger - def extract_backend_info(device, device_capabilities = None) -> BackendInfo: + def extract_backend_info(device, device_capabilities=None) -> BackendInfo: """Wrapper around extract_backend_info in the runtime module.""" return extract_backend_info(device, device_capabilities) From 4ae4a4670874ae7e570ae8f2c6a55e547db31caa Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Tue, 12 Aug 2025 22:16:39 -0400 Subject: [PATCH 10/29] modularize and options --- runtime/lib/backend/null_qubit/NullQubit.hpp | 2 +- runtime/lib/capi/ExecutionContext.hpp | 3 + runtime/lib/capi/Routing.hpp | 180 ++++++++ runtime/lib/capi/RuntimeCAPI.cpp | 454 ++++++++++--------- 4 files changed, 430 insertions(+), 209 deletions(-) create mode 100644 runtime/lib/capi/Routing.hpp diff --git a/runtime/lib/backend/null_qubit/NullQubit.hpp b/runtime/lib/backend/null_qubit/NullQubit.hpp index a272806339..e15626f98d 100644 --- a/runtime/lib/backend/null_qubit/NullQubit.hpp +++ b/runtime/lib/backend/null_qubit/NullQubit.hpp @@ -243,7 +243,7 @@ struct NullQubit final : public Catalyst::Runtime::QuantumDevice { const std::vector &controlled_values = {}) { // Print to see what naive router does on Null qubits - std::cout << "Name:" << name << "\n"; + std::cout << "Name: " << name << "\n"; std::cout << "Wires : "; for (auto i : wires) std::cout << i << ","; diff --git a/runtime/lib/capi/ExecutionContext.hpp b/runtime/lib/capi/ExecutionContext.hpp index 56b7543980..7b13a9baed 100644 --- a/runtime/lib/capi/ExecutionContext.hpp +++ b/runtime/lib/capi/ExecutionContext.hpp @@ -289,6 +289,7 @@ class ExecutionContext final { // PRNG uint32_t *seed; + bool enable_routing{false}; std::mt19937 gen; public: @@ -308,6 +309,8 @@ class ExecutionContext final { ExecutionContext &operator=(ExecutionContext &&other) = delete; void setDeviceRecorderStatus(bool status) noexcept { initial_tape_recorder_status = status; } + void setRoutingEnable() noexcept { this->enable_routing = true; } + bool getRoutingStatus() noexcept { return this->enable_routing; } [[nodiscard]] auto getDeviceRecorderStatus() const -> bool { diff --git a/runtime/lib/capi/Routing.hpp b/runtime/lib/capi/Routing.hpp new file mode 100644 index 0000000000..b49482b0a3 --- /dev/null +++ b/runtime/lib/capi/Routing.hpp @@ -0,0 +1,180 @@ +// Copyright 2025 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mlir/ExecutionEngine/CRunnerUtils.h" + +#include "Exception.hpp" +#include "ExecutionContext.hpp" +#include "MemRefUtils.hpp" +#include "QuantumDevice.hpp" +#include "Timer.hpp" + +#include "RuntimeCAPI.h" + +const int MAXIMUM = 1e9; + +namespace Catalyst::Runtime { +class RoutingPass final { + private: + std::set physicalQubits; + std::map wireMap; + std::map, bool> couplingMap; + std::map, int> distanceMatrix; + std::map, int> predecessorMatrix; + + public: + RoutingPass(std::string tuple_str) + { + auto string_index = 1; + while (string_index < tuple_str.size() - 1) { + size_t next_closing_bracket = tuple_str.find(")", string_index); + std::string curr_tuple_str = std::string( + tuple_str.substr(string_index + 1, next_closing_bracket - string_index - 1)); + std::istringstream iss(curr_tuple_str); + int first_int, second_int; + char comma; + iss >> first_int >> comma &&comma == ',' && iss >> second_int; + this->physicalQubits.insert(first_int); + this->physicalQubits.insert(second_int); + this->couplingMap[std::make_pair(first_int, second_int)] = true; + this->couplingMap[std::make_pair(second_int, first_int)] = true; + string_index = next_closing_bracket + 3; + } + for (auto i_itr = this->physicalQubits.begin(); i_itr != this->physicalQubits.end(); + i_itr++) { + // initial mapping i->i + this->wireMap[*i_itr] = *i_itr; + // self-distances : 0 + this->distanceMatrix[std::make_pair(*i_itr, *i_itr)] = 0; + // parent(self) = self + this->predecessorMatrix[std::make_pair(*i_itr, *i_itr)] = *i_itr; + } + + // initial distances maximum + for (auto i_itr = this->physicalQubits.begin(); i_itr != this->physicalQubits.end(); + i_itr++) { + for (auto j_itr = this->physicalQubits.begin(); j_itr != this->physicalQubits.end(); + j_itr++) { + this->distanceMatrix[std::make_pair(*i_itr, *j_itr)] = MAXIMUM; + this->predecessorMatrix[std::make_pair(*i_itr, *j_itr)] = -1; + } + } + + // edge-distances : 1 + for (auto &entry : this->couplingMap) { + const std::pair &key = entry.first; + bool value = entry.second; + if (value) { + this->distanceMatrix[std::make_pair(key.first, key.second)] = 1; + this->predecessorMatrix[std::make_pair(key.first, key.second)] = key.first; + } + } + // run floyd-warshall + for (auto i_itr = this->physicalQubits.begin(); i_itr != this->physicalQubits.end(); + i_itr++) { + for (auto j_itr = this->physicalQubits.begin(); j_itr != this->physicalQubits.end(); + j_itr++) { + for (auto k_itr = this->physicalQubits.begin(); k_itr != this->physicalQubits.end(); + k_itr++) { + if (this->distanceMatrix[std::make_pair(*j_itr, *i_itr)] + + this->distanceMatrix[std::make_pair(*i_itr, *k_itr)] < + this->distanceMatrix[std::make_pair(*j_itr, *k_itr)]) { + this->distanceMatrix[std::make_pair(*j_itr, *k_itr)] = + this->distanceMatrix[std::make_pair(*j_itr, *i_itr)] + + this->distanceMatrix[std::make_pair(*i_itr, *k_itr)]; + this->predecessorMatrix[std::make_pair(*j_itr, *k_itr)] = + this->predecessorMatrix[std::make_pair(*i_itr, *k_itr)]; + } + } + } + } + } + + std::vector getShortestPath(int source, int target) + { + std::vector path; + if (this->predecessorMatrix.at(std::make_pair(source, target)) == -1 && source != target) { + return path; + } + + int current = target; + while (current != source) { + path.push_back(current); + current = this->predecessorMatrix.at(std::make_pair(source, current)); + if (current == -1 && path.size() > 0) { + path.clear(); + return path; + } + } + path.push_back(source); + std::reverse(path.begin(), path.end()); + return path; + } + + std::pair getRoutedQubits(QUBIT *control, QUBIT *target, const Modifiers *modifiers, + RTDevice *RTD_PTR, bool adjoint, + const std::vector controlledWires, + const std::vector controlledValues) + { + // Similar to qml.transpile implementation + // https://docs.pennylane.ai/en/stable/_modules/pennylane/transforms/transpile.html + int firstQubit = reinterpret_cast(control); + int secondQubit = reinterpret_cast(target); + + if (this->couplingMap[std::make_pair(firstQubit, secondQubit)]) { + // since in each iteration, we adjust indices of each op, + // we reset logical -> phyiscal mapping + for (auto it = this->wireMap.begin(); it != this->wireMap.end(); ++it) { + this->wireMap[it->second] = it->second; + } + } + else { + std::vector swapPath = this->getShortestPath(firstQubit, secondQubit); + // igetQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, adjoint, + controlledWires, controlledValues); + + for (auto it = this->wireMap.begin(); it != this->wireMap.end(); ++it) { + // update logical -> phyiscal mapping + if (this->wireMap[it->first] == u) + this->wireMap[it->first] = v; + else if (this->wireMap[it->first] == v) + this->wireMap[it->first] = u; + } + } + firstQubit = this->wireMap[firstQubit]; + secondQubit = this->wireMap[secondQubit]; + } + return std::make_pair(firstQubit, secondQubit); + } + + ~RoutingPass() = default; +}; +} // namespace Catalyst::Runtime diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index 0f4c0cb715..417f0735b9 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -16,11 +16,8 @@ #include #include #include -#include -#include #include #include -#include #include #include #include @@ -31,6 +28,7 @@ #include "ExecutionContext.hpp" #include "MemRefUtils.hpp" #include "QuantumDevice.hpp" +#include "Routing.hpp" #include "Timer.hpp" #include "RuntimeCAPI.h" @@ -50,33 +48,10 @@ static std::unique_ptr CTX = nullptr; */ thread_local static RTDevice *RTD_PTR = nullptr; -const int MAXIMUM = 1e9; -std::set physicalQubits; -std::map wireMap; -std::map, bool> couplingMap; -std::map, int> distanceMatrix; -std::map, int> predecessorMatrix; - -std::vector getShortestPath(int source, int target) -{ - std::vector path; - if (predecessorMatrix.at(std::make_pair(source, target)) == -1 && source != target) { - return path; - } - - int current = target; - while (current != source) { - path.push_back(current); - current = predecessorMatrix.at(std::make_pair(source, current)); - if (current == -1 && path.size() > 0) { - path.clear(); - return path; - } - } - path.push_back(source); - std::reverse(path.begin(), path.end()); - return path; -} +/** + * @brief Global routing pass pointer. + */ +static std::unique_ptr RUNTIME_ROUTER = nullptr; bool getModifiersAdjoint(const Modifiers *modifiers) { @@ -283,43 +258,7 @@ void __catalyst__rt__finalize() { RTD_PTR = nullptr; CTX.reset(nullptr); -} - -static std::pair getRoutedQubits(QUBIT *control, QUBIT *target, - const Modifiers *modifiers) -{ - // Similar to qml.transpile implementation - // https://docs.pennylane.ai/en/stable/_modules/pennylane/transforms/transpile.html - int firstQubit = reinterpret_cast(control); - int secondQubit = reinterpret_cast(target); - - if (couplingMap[std::make_pair(firstQubit, secondQubit)]) { - // since in each iteration, we adjust indices of each op, - // we reset logical -> phyiscal mapping - for (auto it = wireMap.begin(); it != wireMap.end(); ++it) { - wireMap[it->second] = it->second; - } - } - else { - std::vector swapPath = getShortestPath(firstQubit, secondQubit); - // iNamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); - - for (auto it = wireMap.begin(); it != wireMap.end(); ++it) { - // update logical -> phyiscal mapping - if (wireMap[it->first] == u) - wireMap[it->first] = v; - else if (wireMap[it->first] == v) - wireMap[it->first] = u; - } - } - firstQubit = wireMap[firstQubit]; - secondQubit = wireMap[secondQubit]; - } - return std::make_pair(firstQubit, secondQubit); + RUNTIME_ROUTER.reset(nullptr); } static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, int8_t *rtd_kwargs, @@ -350,83 +289,8 @@ static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, // Extract provided coupling map if (tuple_str.find("((") != std::string::npos) { - auto string_index = 1; - while (string_index < tuple_str.size() - 1) { - size_t next_closing_bracket = tuple_str.find(")", string_index); - std::string curr_tuple_str = std::string( - tuple_str.substr(string_index + 1, next_closing_bracket - string_index - 1)); - std::istringstream iss(curr_tuple_str); - int first_int, second_int; - char comma; - iss >> first_int >> comma &&comma == ',' && iss >> second_int; - physicalQubits.insert(first_int); - physicalQubits.insert(second_int); - couplingMap[std::make_pair(first_int, second_int)] = true; - couplingMap[std::make_pair(second_int, first_int)] = true; - string_index = next_closing_bracket + 3; - } - } - // No coupling map provided so all-to-all connectivity - else { - std::string delimiter = ","; - size_t start = 1; - size_t end = tuple_str.find(delimiter); - while (end < tuple_str.size() - 1) { - physicalQubits.insert(std::stoi(tuple_str.substr(start, end - start))); - start = end + delimiter.length(); - end = tuple_str.find(delimiter, start); - } - physicalQubits.insert(std::stoi(tuple_str.substr(start))); - // all-to-all connectivity - for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); ++i_itr) { - for (auto j_itr = physicalQubits.begin(); j_itr != i_itr; ++j_itr) { - couplingMap[std::make_pair(*i_itr, *j_itr)] = true; - couplingMap[std::make_pair(*j_itr, *i_itr)] = true; - } - } - } - - for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); i_itr++) { - // initial mapping i->i - wireMap[*i_itr] = *i_itr; - // self-distances : 0 - distanceMatrix[std::make_pair(*i_itr, *i_itr)] = 0; - // parent(self) = self - predecessorMatrix[std::make_pair(*i_itr, *i_itr)] = *i_itr; - } - - // initial distances maximum - for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); i_itr++) { - for (auto j_itr = physicalQubits.begin(); j_itr != physicalQubits.end(); j_itr++) { - distanceMatrix[std::make_pair(*i_itr, *j_itr)] = MAXIMUM; - predecessorMatrix[std::make_pair(*i_itr, *j_itr)] = -1; - } - } - - // edge-distances : 1 - for (auto &entry : couplingMap) { - const std::pair &key = entry.first; - bool value = entry.second; - if (value) { - distanceMatrix[std::make_pair(key.first, key.second)] = 1; - predecessorMatrix[std::make_pair(key.first, key.second)] = key.first; - } - } - // run floyd-warshall - for (auto i_itr = physicalQubits.begin(); i_itr != physicalQubits.end(); i_itr++) { - for (auto j_itr = physicalQubits.begin(); j_itr != physicalQubits.end(); j_itr++) { - for (auto k_itr = physicalQubits.begin(); k_itr != physicalQubits.end(); k_itr++) { - if (distanceMatrix[std::make_pair(*j_itr, *i_itr)] + - distanceMatrix[std::make_pair(*i_itr, *k_itr)] < - distanceMatrix[std::make_pair(*j_itr, *k_itr)]) { - distanceMatrix[std::make_pair(*j_itr, *k_itr)] = - distanceMatrix[std::make_pair(*j_itr, *i_itr)] + - distanceMatrix[std::make_pair(*i_itr, *k_itr)]; - predecessorMatrix[std::make_pair(*j_itr, *k_itr)] = - predecessorMatrix[std::make_pair(*i_itr, *k_itr)]; - } - } - } + CTX->setRoutingEnable(); + RUNTIME_ROUTER = std::make_unique(tuple_str); } return 0; } @@ -769,121 +633,274 @@ void __catalyst__qis__CNOT(QUBIT *control, QUBIT *target, const Modifiers *modif RT_FAIL_IF(control == target, "Invalid input for CNOT gate. Control and target qubit operands must be distinct."); - std::pair routedQubits = getRoutedQubits(control, target, modifiers); - getQuantumDevicePtr()->NamedOperation("CNOT", {}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("CNOT", {}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "CNOT", {}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__CY(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("CY", {}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("CY", {}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "CY", {}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__CZ(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("CZ", {}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("CZ", {}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "CZ", {}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__SWAP(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("SWAP", {}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("SWAP", {}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "SWAP", {}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__IsingXX(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("IsingXX", {theta}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("IsingXX", {theta}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "IsingXX", {theta}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__IsingYY(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("IsingYY", {theta}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("IsingYY", {theta}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "IsingYY", {theta}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__IsingXY(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("IsingXY", {theta}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("IsingXY", {theta}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "IsingXY", {theta}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__IsingZZ(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("IsingZZ", {theta}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("IsingZZ", {theta}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "IsingZZ", {theta}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__ControlledPhaseShift(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("ControlledPhaseShift", {theta}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("ControlledPhaseShift", {theta}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "ControlledPhaseShift", {theta}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__CRX(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("CRX", {theta}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("CRX", {theta}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "CRX", {theta}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__CRY(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("CRY", {theta}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("CRY", {theta}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "CRY", {theta}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__CRZ(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("CRZ", {theta}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("CRZ", {theta}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "CRZ", {theta}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__MS(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("MS", {theta}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("MS", {theta}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "MS", {theta}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__CRot(double phi, double theta, double omega, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("CRot", {phi, theta, omega}, - {/* control = */ reinterpret_cast(control), - /* target = */ reinterpret_cast(target)}, - /* modifiers */ MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("CRot", {phi, theta, omega}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "CRot", {phi, theta, omega}, + {/* control = */ reinterpret_cast(control), + /* target = */ reinterpret_cast(target)}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__CSWAP(QUBIT *control, QUBIT *aswap, QUBIT *bswap, const Modifiers *modifiers) @@ -922,17 +939,38 @@ void __catalyst__qis__MultiRZ(double theta, const Modifiers *modifiers, int64_t void __catalyst__qis__ISWAP(QUBIT *wire0, QUBIT *wire1, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation( - "ISWAP", {}, {reinterpret_cast(wire0), reinterpret_cast(wire1)}, - MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + wire0, wire1, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("ISWAP", {}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "ISWAP", {}, + {reinterpret_cast(wire0), reinterpret_cast(wire1)}, + MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__PSWAP(double phi, QUBIT *wire0, QUBIT *wire1, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation( - "PSWAP", {phi}, - {reinterpret_cast(wire0), reinterpret_cast(wire1)}, - MODIFIERS_ARGS(modifiers)); + if (CTX->getRoutingStatus()) { + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + wire0, wire1, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("PSWAP", {phi}, + {/* control = */ routedQubits.first, + /* target = */ routedQubits.second}, + /* modifiers */ MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "PSWAP", {phi}, + {reinterpret_cast(wire0), reinterpret_cast(wire1)}, + MODIFIERS_ARGS(modifiers)); + } } static void _qubitUnitary_impl(MemRefT_CplxT_double_2d *matrix, int64_t numQubits, From 4227d89fe4f3dbf432f8b253531f0137bab1400b Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Wed, 13 Aug 2025 11:55:55 -0400 Subject: [PATCH 11/29] change qubit types from int to QubitIdType --- frontend/catalyst/device/qjit_device.py | 8 +++-- runtime/lib/capi/Routing.hpp | 48 ++++++++++++------------- runtime/lib/capi/RuntimeCAPI.cpp | 2 +- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/frontend/catalyst/device/qjit_device.py b/frontend/catalyst/device/qjit_device.py index 8215622594..c4844db005 100644 --- a/frontend/catalyst/device/qjit_device.py +++ b/frontend/catalyst/device/qjit_device.py @@ -305,7 +305,7 @@ def __init__(self, original_device): for key, value in original_device.__dict__.items(): self.__setattr__(key, value) - if any( + if (original_device.wires is not None) and any( isinstance(wire_label, tuple) and (len(wire_label) >= 2) for wire_label in original_device.wires.labels ): @@ -333,8 +333,10 @@ def __init__(self, original_device): raise CompileError( "The device that specifies to_matrix_ops must support QubitUnitary." ) - - setattr(device_capabilities, "coupling_map", original_device.wires.labels) + if original_device.wires is not None: + setattr(device_capabilities, "coupling_map", original_device.wires.labels) + else: + setattr(device_capabilities, "coupling_map", None) backend = QJITDevice.extract_backend_info(original_device, device_capabilities) diff --git a/runtime/lib/capi/Routing.hpp b/runtime/lib/capi/Routing.hpp index b49482b0a3..4ec9fc410a 100644 --- a/runtime/lib/capi/Routing.hpp +++ b/runtime/lib/capi/Routing.hpp @@ -40,11 +40,11 @@ const int MAXIMUM = 1e9; namespace Catalyst::Runtime { class RoutingPass final { private: - std::set physicalQubits; - std::map wireMap; - std::map, bool> couplingMap; - std::map, int> distanceMatrix; - std::map, int> predecessorMatrix; + std::set physicalQubits; + std::map wireMap; + std::map, bool> couplingMap; + std::map, int> distanceMatrix; + std::map, int> predecessorMatrix; public: RoutingPass(std::string tuple_str) @@ -55,13 +55,13 @@ class RoutingPass final { std::string curr_tuple_str = std::string( tuple_str.substr(string_index + 1, next_closing_bracket - string_index - 1)); std::istringstream iss(curr_tuple_str); - int first_int, second_int; + QubitIdType first_qubit_id, second_qubit_id; char comma; - iss >> first_int >> comma &&comma == ',' && iss >> second_int; - this->physicalQubits.insert(first_int); - this->physicalQubits.insert(second_int); - this->couplingMap[std::make_pair(first_int, second_int)] = true; - this->couplingMap[std::make_pair(second_int, first_int)] = true; + iss >> first_qubit_id >> comma &&comma == ',' && iss >> second_qubit_id; + this->physicalQubits.insert(first_qubit_id); + this->physicalQubits.insert(second_qubit_id); + this->couplingMap[std::make_pair(first_qubit_id, second_qubit_id)] = true; + this->couplingMap[std::make_pair(second_qubit_id, first_qubit_id)] = true; string_index = next_closing_bracket + 3; } for (auto i_itr = this->physicalQubits.begin(); i_itr != this->physicalQubits.end(); @@ -86,7 +86,7 @@ class RoutingPass final { // edge-distances : 1 for (auto &entry : this->couplingMap) { - const std::pair &key = entry.first; + const std::pair &key = entry.first; bool value = entry.second; if (value) { this->distanceMatrix[std::make_pair(key.first, key.second)] = 1; @@ -114,14 +114,14 @@ class RoutingPass final { } } - std::vector getShortestPath(int source, int target) + std::vector getShortestPath(QubitIdType source, QubitIdType target) { - std::vector path; + std::vector path; if (this->predecessorMatrix.at(std::make_pair(source, target)) == -1 && source != target) { return path; } - int current = target; + QubitIdType current = target; while (current != source) { path.push_back(current); current = this->predecessorMatrix.at(std::make_pair(source, current)); @@ -135,15 +135,15 @@ class RoutingPass final { return path; } - std::pair getRoutedQubits(QUBIT *control, QUBIT *target, const Modifiers *modifiers, - RTDevice *RTD_PTR, bool adjoint, - const std::vector controlledWires, - const std::vector controlledValues) + std::pair + getRoutedQubits(QUBIT *control, QUBIT *target, const Modifiers *modifiers, RTDevice *RTD_PTR, + bool adjoint, const std::vector controlledWires, + const std::vector controlledValues) { // Similar to qml.transpile implementation // https://docs.pennylane.ai/en/stable/_modules/pennylane/transforms/transpile.html - int firstQubit = reinterpret_cast(control); - int secondQubit = reinterpret_cast(target); + QubitIdType firstQubit = reinterpret_cast(control); + QubitIdType secondQubit = reinterpret_cast(target); if (this->couplingMap[std::make_pair(firstQubit, secondQubit)]) { // since in each iteration, we adjust indices of each op, @@ -153,11 +153,11 @@ class RoutingPass final { } } else { - std::vector swapPath = this->getShortestPath(firstQubit, secondQubit); + std::vector swapPath = this->getShortestPath(firstQubit, secondQubit); // igetQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, adjoint, controlledWires, controlledValues); diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index 417f0735b9..422e5914e1 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -940,7 +940,7 @@ void __catalyst__qis__MultiRZ(double theta, const Modifiers *modifiers, int64_t void __catalyst__qis__ISWAP(QUBIT *wire0, QUBIT *wire1, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( wire0, wire1, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("ISWAP", {}, {/* control = */ routedQubits.first, From f4c7dc98b75ee05d1e95b1a985bef71ae49f3acd Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Thu, 21 Aug 2025 16:40:12 -0400 Subject: [PATCH 12/29] TODO: fix rtdptr dependancy --- runtime/lib/capi/ExecutionContext.hpp | 20 ++++++- runtime/lib/capi/Routing.hpp | 16 ++---- runtime/lib/capi/RuntimeCAPI.cpp | 78 ++++++++++++++------------- 3 files changed, 63 insertions(+), 51 deletions(-) diff --git a/runtime/lib/capi/ExecutionContext.hpp b/runtime/lib/capi/ExecutionContext.hpp index 7b13a9baed..454fe00b3e 100644 --- a/runtime/lib/capi/ExecutionContext.hpp +++ b/runtime/lib/capi/ExecutionContext.hpp @@ -30,6 +30,7 @@ #include "Exception.hpp" #include "QuantumDevice.hpp" #include "Types.h" +#include "Routing.hpp" namespace Catalyst::Runtime { @@ -170,6 +171,8 @@ class RTDevice { std::unique_ptr rtd_dylib{nullptr}; std::unique_ptr rtd_qdevice{nullptr}; + //device specific routing pass pointer. + std::unique_ptr RUNTIME_ROUTER = nullptr; RTDeviceStatus status{RTDeviceStatus::Inactive}; @@ -224,6 +227,15 @@ class RTDevice { _pl2runtime_device_info(rtd_lib, rtd_name); } + explicit RTDevice(std::string_view _rtd_lib, std::string_view _rtd_name, + std::string_view _rtd_kwargs, bool _auto_qubit_management, std::string_view coupling_map_str) + : rtd_lib(_rtd_lib), rtd_name(_rtd_name), rtd_kwargs(_rtd_kwargs), + auto_qubit_management(_auto_qubit_management) + { + RUNTIME_ROUTER = std::make_unique(coupling_map_str); + _pl2runtime_device_info(rtd_lib, rtd_name); + } + ~RTDevice() = default; RTDevice(const RTDevice &other) = delete; RTDevice &operator=(const RTDevice &other) = delete; @@ -264,6 +276,9 @@ class RTDevice { void setDeviceStatus(RTDeviceStatus new_status) noexcept { status = new_status; } bool getQubitManagementMode() { return auto_qubit_management; } + [[nodiscard]] auto getRuntimeRouter() -> std::unique_ptr { + return std::move(RUNTIME_ROUTER); + } [[nodiscard]] auto getDeviceStatus() const -> RTDeviceStatus { return status; } @@ -323,13 +338,14 @@ class ExecutionContext final { } [[nodiscard]] auto getOrCreateDevice(std::string_view rtd_lib, std::string_view rtd_name, - std::string_view rtd_kwargs, bool auto_qubit_management) + std::string_view rtd_kwargs, bool auto_qubit_management, + std::string_view coupling_map_str = {}) -> const std::shared_ptr & { std::lock_guard lock(pool_mu); auto device = - std::make_shared(rtd_lib, rtd_name, rtd_kwargs, auto_qubit_management); + std::make_shared(rtd_lib, rtd_name, rtd_kwargs, auto_qubit_management, coupling_map_str); const size_t key = device_pool.size(); for (size_t i = 0; i < key; i++) { diff --git a/runtime/lib/capi/Routing.hpp b/runtime/lib/capi/Routing.hpp index 4ec9fc410a..964c303cf0 100644 --- a/runtime/lib/capi/Routing.hpp +++ b/runtime/lib/capi/Routing.hpp @@ -25,21 +25,11 @@ #include #include -#include "mlir/ExecutionEngine/CRunnerUtils.h" - -#include "Exception.hpp" -#include "ExecutionContext.hpp" -#include "MemRefUtils.hpp" -#include "QuantumDevice.hpp" -#include "Timer.hpp" - -#include "RuntimeCAPI.h" - -const int MAXIMUM = 1e9; - namespace Catalyst::Runtime { + class RoutingPass final { private: + const int MAXIMUM = 1e9; std::set physicalQubits; std::map wireMap; std::map, bool> couplingMap; @@ -47,7 +37,7 @@ class RoutingPass final { std::map, int> predecessorMatrix; public: - RoutingPass(std::string tuple_str) + RoutingPass(std::string_view tuple_str) { auto string_index = 1; while (string_index < tuple_str.size() - 1) { diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index 422e5914e1..71e9c1eb9f 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -28,7 +28,6 @@ #include "ExecutionContext.hpp" #include "MemRefUtils.hpp" #include "QuantumDevice.hpp" -#include "Routing.hpp" #include "Timer.hpp" #include "RuntimeCAPI.h" @@ -48,11 +47,6 @@ static std::unique_ptr CTX = nullptr; */ thread_local static RTDevice *RTD_PTR = nullptr; -/** - * @brief Global routing pass pointer. - */ -static std::unique_ptr RUNTIME_ROUTER = nullptr; - bool getModifiersAdjoint(const Modifiers *modifiers) { return !modifiers ? false : modifiers->adjoint; @@ -92,6 +86,18 @@ std::vector getModifiersControlledValues(const Modifiers *modifiers) return false; } +[[nodiscard]] bool initRTDevicePtr(std::string_view rtd_lib, std::string_view rtd_name, + std::string_view rtd_kwargs, bool auto_qubit_management, + std::string_view coupling_map_str) +{ + auto &&device = CTX->getOrCreateDevice(rtd_lib, rtd_name, rtd_kwargs, auto_qubit_management, coupling_map_str); + if (device) { + RTD_PTR = device.get(); + return RTD_PTR ? true : false; + } + return false; +} + /** * @brief get the active device. */ @@ -258,7 +264,6 @@ void __catalyst__rt__finalize() { RTD_PTR = nullptr; CTX.reset(nullptr); - RUNTIME_ROUTER.reset(nullptr); } static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, int8_t *rtd_kwargs, @@ -273,24 +278,25 @@ static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, const std::vector args{ reinterpret_cast(rtd_lib), (rtd_name ? reinterpret_cast(rtd_name) : ""), (rtd_kwargs ? reinterpret_cast(rtd_kwargs) : "")}; - RT_FAIL_IF(!initRTDevicePtr(args[0], args[1], args[2], auto_qubit_management), - "Failed initialization of the backend device"); - getQuantumDevicePtr()->SetDeviceShots(shots); - if (CTX->getDeviceRecorderStatus()) { - getQuantumDevicePtr()->StartTapeRecording(); - } - + // Extract coupling map from the kwargs passed // If coupling map is provided then it takes in the form {...,'couplingMap' ((a,b),(b,c))} // else {...,'couplingMap' (a,b,c)} size_t start = args[2].find("coupling_map': ") + 15; // Find key and opening parenthesis size_t end = args[2].find("}", start); // Find closing parenthesis - std::string tuple_str = std::string(args[2].substr(start, end - start)); - - // Extract provided coupling map - if (tuple_str.find("((") != std::string::npos) { - CTX->setRoutingEnable(); - RUNTIME_ROUTER = std::make_unique(tuple_str); + std::string coupling_map_str = std::string(args[2].substr(start, end - start)); + + if (coupling_map_str.find("((") != std::string::npos) { + RT_FAIL_IF(!initRTDevicePtr(args[0], args[1], args[2], auto_qubit_management, coupling_map_str), + "Failed initialization of the backend device"); + } + else { + RT_FAIL_IF(!initRTDevicePtr(args[0], args[1], args[2], auto_qubit_management), + "Failed initialization of the backend device"); + } + getQuantumDevicePtr()->SetDeviceShots(shots); + if (CTX->getDeviceRecorderStatus()) { + getQuantumDevicePtr()->StartTapeRecording(); } return 0; } @@ -634,7 +640,7 @@ void __catalyst__qis__CNOT(QUBIT *control, QUBIT *target, const Modifiers *modif "Invalid input for CNOT gate. Control and target qubit operands must be distinct."); if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("CNOT", {}, {/* control = */ routedQubits.first, @@ -653,7 +659,7 @@ void __catalyst__qis__CNOT(QUBIT *control, QUBIT *target, const Modifiers *modif void __catalyst__qis__CY(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("CY", {}, {/* control = */ routedQubits.first, @@ -672,7 +678,7 @@ void __catalyst__qis__CY(QUBIT *control, QUBIT *target, const Modifiers *modifie void __catalyst__qis__CZ(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("CZ", {}, {/* control = */ routedQubits.first, @@ -691,7 +697,7 @@ void __catalyst__qis__CZ(QUBIT *control, QUBIT *target, const Modifiers *modifie void __catalyst__qis__SWAP(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("SWAP", {}, {/* control = */ routedQubits.first, @@ -711,7 +717,7 @@ void __catalyst__qis__IsingXX(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("IsingXX", {theta}, {/* control = */ routedQubits.first, @@ -731,7 +737,7 @@ void __catalyst__qis__IsingYY(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("IsingYY", {theta}, {/* control = */ routedQubits.first, @@ -751,7 +757,7 @@ void __catalyst__qis__IsingXY(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("IsingXY", {theta}, {/* control = */ routedQubits.first, @@ -771,7 +777,7 @@ void __catalyst__qis__IsingZZ(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("IsingZZ", {theta}, {/* control = */ routedQubits.first, @@ -791,7 +797,7 @@ void __catalyst__qis__ControlledPhaseShift(double theta, QUBIT *control, QUBIT * const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("ControlledPhaseShift", {theta}, {/* control = */ routedQubits.first, @@ -810,7 +816,7 @@ void __catalyst__qis__ControlledPhaseShift(double theta, QUBIT *control, QUBIT * void __catalyst__qis__CRX(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("CRX", {theta}, {/* control = */ routedQubits.first, @@ -829,7 +835,7 @@ void __catalyst__qis__CRX(double theta, QUBIT *control, QUBIT *target, const Mod void __catalyst__qis__CRY(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("CRY", {theta}, {/* control = */ routedQubits.first, @@ -848,7 +854,7 @@ void __catalyst__qis__CRY(double theta, QUBIT *control, QUBIT *target, const Mod void __catalyst__qis__CRZ(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("CRZ", {theta}, {/* control = */ routedQubits.first, @@ -867,7 +873,7 @@ void __catalyst__qis__CRZ(double theta, QUBIT *control, QUBIT *target, const Mod void __catalyst__qis__MS(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("MS", {theta}, {/* control = */ routedQubits.first, @@ -887,7 +893,7 @@ void __catalyst__qis__CRot(double phi, double theta, double omega, QUBIT *contro const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("CRot", {phi, theta, omega}, {/* control = */ routedQubits.first, @@ -940,7 +946,7 @@ void __catalyst__qis__MultiRZ(double theta, const Modifiers *modifiers, int64_t void __catalyst__qis__ISWAP(QUBIT *wire0, QUBIT *wire1, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( wire0, wire1, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("ISWAP", {}, {/* control = */ routedQubits.first, @@ -958,7 +964,7 @@ void __catalyst__qis__ISWAP(QUBIT *wire0, QUBIT *wire1, const Modifiers *modifie void __catalyst__qis__PSWAP(double phi, QUBIT *wire0, QUBIT *wire1, const Modifiers *modifiers) { if (CTX->getRoutingStatus()) { - std::pair routedQubits = RUNTIME_ROUTER->getRoutedQubits( + std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( wire0, wire1, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); getQuantumDevicePtr()->NamedOperation("PSWAP", {phi}, {/* control = */ routedQubits.first, From c1d738f349c23ca5b674f317478e8db73db84628 Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Thu, 21 Aug 2025 21:32:57 -0400 Subject: [PATCH 13/29] refractoring --- runtime/lib/capi/ExecutionContext.hpp | 8 +- runtime/lib/capi/Routing.hpp | 15 +- runtime/lib/capi/RuntimeCAPI.cpp | 323 +++++++++++++++++++------- 3 files changed, 251 insertions(+), 95 deletions(-) diff --git a/runtime/lib/capi/ExecutionContext.hpp b/runtime/lib/capi/ExecutionContext.hpp index 454fe00b3e..b9957bf50c 100644 --- a/runtime/lib/capi/ExecutionContext.hpp +++ b/runtime/lib/capi/ExecutionContext.hpp @@ -172,7 +172,7 @@ class RTDevice { std::unique_ptr rtd_dylib{nullptr}; std::unique_ptr rtd_qdevice{nullptr}; //device specific routing pass pointer. - std::unique_ptr RUNTIME_ROUTER = nullptr; + std::unique_ptr RUNTIME_ROUTER{nullptr}; RTDeviceStatus status{RTDeviceStatus::Inactive}; @@ -276,8 +276,8 @@ class RTDevice { void setDeviceStatus(RTDeviceStatus new_status) noexcept { status = new_status; } bool getQubitManagementMode() { return auto_qubit_management; } - [[nodiscard]] auto getRuntimeRouter() -> std::unique_ptr { - return std::move(RUNTIME_ROUTER); + [[nodiscard]] auto getRuntimeRouter() -> std::unique_ptr& { + return RUNTIME_ROUTER; } [[nodiscard]] auto getDeviceStatus() const -> RTDeviceStatus { return status; } @@ -324,8 +324,6 @@ class ExecutionContext final { ExecutionContext &operator=(ExecutionContext &&other) = delete; void setDeviceRecorderStatus(bool status) noexcept { initial_tape_recorder_status = status; } - void setRoutingEnable() noexcept { this->enable_routing = true; } - bool getRoutingStatus() noexcept { return this->enable_routing; } [[nodiscard]] auto getDeviceRecorderStatus() const -> bool { diff --git a/runtime/lib/capi/Routing.hpp b/runtime/lib/capi/Routing.hpp index 964c303cf0..7962bba538 100644 --- a/runtime/lib/capi/Routing.hpp +++ b/runtime/lib/capi/Routing.hpp @@ -125,15 +125,15 @@ class RoutingPass final { return path; } - std::pair - getRoutedQubits(QUBIT *control, QUBIT *target, const Modifiers *modifiers, RTDevice *RTD_PTR, - bool adjoint, const std::vector controlledWires, - const std::vector controlledValues) + std::tuple> + getRoutedQubits(QUBIT *control, QUBIT *target) { // Similar to qml.transpile implementation // https://docs.pennylane.ai/en/stable/_modules/pennylane/transforms/transpile.html + QubitIdType firstQubit = reinterpret_cast(control); QubitIdType secondQubit = reinterpret_cast(target); + std::vector swapPath = {}; if (this->couplingMap[std::make_pair(firstQubit, secondQubit)]) { // since in each iteration, we adjust indices of each op, @@ -143,14 +143,11 @@ class RoutingPass final { } } else { - std::vector swapPath = this->getShortestPath(firstQubit, secondQubit); + swapPath = this->getShortestPath(firstQubit, secondQubit); // igetQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, adjoint, - controlledWires, controlledValues); - for (auto it = this->wireMap.begin(); it != this->wireMap.end(); ++it) { // update logical -> phyiscal mapping if (this->wireMap[it->first] == u) @@ -162,7 +159,7 @@ class RoutingPass final { firstQubit = this->wireMap[firstQubit]; secondQubit = this->wireMap[secondQubit]; } - return std::make_pair(firstQubit, secondQubit); + return std::make_tuple(firstQubit, secondQubit, swapPath); } ~RoutingPass() = default; diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index 71e9c1eb9f..4b0730c4d2 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -638,13 +638,23 @@ void __catalyst__qis__CNOT(QUBIT *control, QUBIT *target, const Modifiers *modif { RT_FAIL_IF(control == target, "Invalid input for CNOT gate. Control and target qubit operands must be distinct."); - - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("CNOT", {}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -658,12 +668,23 @@ void __catalyst__qis__CNOT(QUBIT *control, QUBIT *target, const Modifiers *modif void __catalyst__qis__CY(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("CY", {}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -677,12 +698,22 @@ void __catalyst__qis__CY(QUBIT *control, QUBIT *target, const Modifiers *modifie void __catalyst__qis__CZ(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("CZ", {}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -696,12 +727,22 @@ void __catalyst__qis__CZ(QUBIT *control, QUBIT *target, const Modifiers *modifie void __catalyst__qis__SWAP(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("SWAP", {}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -716,12 +757,22 @@ void __catalyst__qis__SWAP(QUBIT *control, QUBIT *target, const Modifiers *modif void __catalyst__qis__IsingXX(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("IsingXX", {theta}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -736,12 +787,22 @@ void __catalyst__qis__IsingXX(double theta, QUBIT *control, QUBIT *target, void __catalyst__qis__IsingYY(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("IsingYY", {theta}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -756,12 +817,22 @@ void __catalyst__qis__IsingYY(double theta, QUBIT *control, QUBIT *target, void __catalyst__qis__IsingXY(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("IsingXY", {theta}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -776,12 +847,22 @@ void __catalyst__qis__IsingXY(double theta, QUBIT *control, QUBIT *target, void __catalyst__qis__IsingZZ(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("IsingZZ", {theta}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -796,12 +877,22 @@ void __catalyst__qis__IsingZZ(double theta, QUBIT *control, QUBIT *target, void __catalyst__qis__ControlledPhaseShift(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("ControlledPhaseShift", {theta}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -815,12 +906,22 @@ void __catalyst__qis__ControlledPhaseShift(double theta, QUBIT *control, QUBIT * void __catalyst__qis__CRX(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("CRX", {theta}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -834,12 +935,22 @@ void __catalyst__qis__CRX(double theta, QUBIT *control, QUBIT *target, const Mod void __catalyst__qis__CRY(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("CRY", {theta}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -853,12 +964,22 @@ void __catalyst__qis__CRY(double theta, QUBIT *control, QUBIT *target, const Mod void __catalyst__qis__CRZ(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("CRZ", {theta}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -872,12 +993,22 @@ void __catalyst__qis__CRZ(double theta, QUBIT *control, QUBIT *target, const Mod void __catalyst__qis__MS(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("MS", {theta}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -892,12 +1023,22 @@ void __catalyst__qis__MS(double theta, QUBIT *control, QUBIT *target, const Modi void __catalyst__qis__CRot(double phi, double theta, double omega, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - control, target, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("CRot", {phi, theta, omega}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -945,12 +1086,22 @@ void __catalyst__qis__MultiRZ(double theta, const Modifiers *modifiers, int64_t void __catalyst__qis__ISWAP(QUBIT *wire0, QUBIT *wire1, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - wire0, wire1, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(wire0, wire1); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("ISWAP", {}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { @@ -963,12 +1114,22 @@ void __catalyst__qis__ISWAP(QUBIT *wire0, QUBIT *wire1, const Modifiers *modifie void __catalyst__qis__PSWAP(double phi, QUBIT *wire0, QUBIT *wire1, const Modifiers *modifiers) { - if (CTX->getRoutingStatus()) { - std::pair routedQubits = RTD_PTR->getRuntimeRouter()->getRoutedQubits( - wire0, wire1, modifiers, RTD_PTR, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(wire0, wire1); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + if (swapPath.size() > 0) + { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + } + } getQuantumDevicePtr()->NamedOperation("PSWAP", {phi}, - {/* control = */ routedQubits.first, - /* target = */ routedQubits.second}, + {/* control = */ routedQubitFirst, + /* target = */ routedQubitSecond}, /* modifiers */ MODIFIERS_ARGS(modifiers)); } else { From db26be67f229904a639e2e0e5daacb92215411c1 Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Fri, 22 Aug 2025 10:19:52 -0400 Subject: [PATCH 14/29] fix the end permutation --- runtime/lib/capi/ExecutionContext.hpp | 6 ++++- runtime/lib/capi/Routing.hpp | 14 +++++----- runtime/lib/capi/RuntimeCAPI.cpp | 39 ++++++++++++++++----------- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/runtime/lib/capi/ExecutionContext.hpp b/runtime/lib/capi/ExecutionContext.hpp index b9957bf50c..a4a4fc2aad 100644 --- a/runtime/lib/capi/ExecutionContext.hpp +++ b/runtime/lib/capi/ExecutionContext.hpp @@ -232,7 +232,11 @@ class RTDevice { : rtd_lib(_rtd_lib), rtd_name(_rtd_name), rtd_kwargs(_rtd_kwargs), auto_qubit_management(_auto_qubit_management) { - RUNTIME_ROUTER = std::make_unique(coupling_map_str); + // Extract coupling map from the kwargs passed + // If coupling map is provided then it takes in the form {...,'couplingMap' ((a,b),(b,c))} + // else {...,'couplingMap' (a,b,c)} + if (coupling_map_str.find("((") != std::string::npos) + RUNTIME_ROUTER = std::make_unique(coupling_map_str); _pl2runtime_device_info(rtd_lib, rtd_name); } diff --git a/runtime/lib/capi/Routing.hpp b/runtime/lib/capi/Routing.hpp index 7962bba538..7ec34f5356 100644 --- a/runtime/lib/capi/Routing.hpp +++ b/runtime/lib/capi/Routing.hpp @@ -37,14 +37,14 @@ class RoutingPass final { std::map, int> predecessorMatrix; public: - RoutingPass(std::string_view tuple_str) + RoutingPass(std::string_view coupling_map_str) { auto string_index = 1; - while (string_index < tuple_str.size() - 1) { - size_t next_closing_bracket = tuple_str.find(")", string_index); - std::string curr_tuple_str = std::string( - tuple_str.substr(string_index + 1, next_closing_bracket - string_index - 1)); - std::istringstream iss(curr_tuple_str); + while (string_index < coupling_map_str.size() - 1) { + size_t next_closing_bracket = coupling_map_str.find(")", string_index); + std::string curr_coupling_map_str = std::string( + coupling_map_str.substr(string_index + 1, next_closing_bracket - string_index - 1)); + std::istringstream iss(curr_coupling_map_str); QubitIdType first_qubit_id, second_qubit_id; char comma; iss >> first_qubit_id >> comma &&comma == ',' && iss >> second_qubit_id; @@ -125,6 +125,8 @@ class RoutingPass final { return path; } + QubitIdType getMappedWire(QubitIdType wire) { return this->wireMap[wire]; } + std::tuple> getRoutedQubits(QUBIT *control, QUBIT *target) { diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index 4b0730c4d2..77c16f0ef1 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -75,20 +75,9 @@ std::vector getModifiersControlledValues(const Modifiers *modifiers) * @brief Initialize the device instance and update the value of RTD_PTR * to the new initialized device pointer. */ -[[nodiscard]] bool initRTDevicePtr(std::string_view rtd_lib, std::string_view rtd_name, - std::string_view rtd_kwargs, bool auto_qubit_management) -{ - auto &&device = CTX->getOrCreateDevice(rtd_lib, rtd_name, rtd_kwargs, auto_qubit_management); - if (device) { - RTD_PTR = device.get(); - return RTD_PTR ? true : false; - } - return false; -} - [[nodiscard]] bool initRTDevicePtr(std::string_view rtd_lib, std::string_view rtd_name, std::string_view rtd_kwargs, bool auto_qubit_management, - std::string_view coupling_map_str) + std::string_view coupling_map_str = {}) { auto &&device = CTX->getOrCreateDevice(rtd_lib, rtd_name, rtd_kwargs, auto_qubit_management, coupling_map_str); if (device) { @@ -1289,6 +1278,8 @@ RESULT *__catalyst__qis__Measure(QUBIT *wire, int32_t postselect) if (postselect != 0 && postselect != 1) { postselectOpt = std::nullopt; } + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + return getQuantumDevicePtr()->Measure(RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(wire)), postselectOpt); return getQuantumDevicePtr()->Measure(reinterpret_cast(wire), postselectOpt); } @@ -1306,7 +1297,11 @@ void __catalyst__qis__State(MemRefT_CplxT_double_1d *result, int64_t numQubits, va_start(args, numQubits); std::vector wires(numQubits); for (int64_t i = 0; i < numQubits; i++) { - wires[i] = va_arg(args, QubitIdType); + QubitIdType original_wire = va_arg(args, QubitIdType); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + wires[i] = RTD_PTR->getRuntimeRouter()->getMappedWire(original_wire); + else + wires[i] = original_wire; } va_end(args); @@ -1335,7 +1330,11 @@ void __catalyst__qis__Probs(MemRefT_double_1d *result, int64_t numQubits, ...) va_start(args, numQubits); std::vector wires(numQubits); for (int64_t i = 0; i < numQubits; i++) { - wires[i] = va_arg(args, QubitIdType); + QubitIdType original_wire = va_arg(args, QubitIdType); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + wires[i] = RTD_PTR->getRuntimeRouter()->getMappedWire(original_wire); + else + wires[i] = original_wire; } va_end(args); @@ -1366,7 +1365,11 @@ void __catalyst__qis__Sample(MemRefT_double_2d *result, int64_t numQubits, ...) va_start(args, numQubits); std::vector wires(numQubits); for (int64_t i = 0; i < numQubits; i++) { - wires[i] = va_arg(args, QubitIdType); + QubitIdType original_wire = va_arg(args, QubitIdType); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + wires[i] = RTD_PTR->getRuntimeRouter()->getMappedWire(original_wire); + else + wires[i] = original_wire; } va_end(args); @@ -1397,7 +1400,11 @@ void __catalyst__qis__Counts(PairT_MemRefT_double_int64_1d *result, int64_t numQ va_start(args, numQubits); std::vector wires(numQubits); for (int64_t i = 0; i < numQubits; i++) { - wires[i] = va_arg(args, QubitIdType); + QubitIdType original_wire = va_arg(args, QubitIdType); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + wires[i] = RTD_PTR->getRuntimeRouter()->getMappedWire(original_wire); + else + wires[i] = original_wire; } va_end(args); From 5142ce17d029a85e9d8286d788df81843a38cf2f Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Sun, 24 Aug 2025 18:59:01 -0400 Subject: [PATCH 15/29] permute end mapping --- runtime/lib/capi/Routing.hpp | 44 +++++++++++++++++++++++++++++++- runtime/lib/capi/RuntimeCAPI.cpp | 41 +++++++++++++---------------- 2 files changed, 61 insertions(+), 24 deletions(-) diff --git a/runtime/lib/capi/Routing.hpp b/runtime/lib/capi/Routing.hpp index 7ec34f5356..e21833fc98 100644 --- a/runtime/lib/capi/Routing.hpp +++ b/runtime/lib/capi/Routing.hpp @@ -125,7 +125,49 @@ class RoutingPass final { return path; } - QubitIdType getMappedWire(QubitIdType wire) { return this->wireMap[wire]; } + QubitIdType getMappedWire(QubitIdType wire, int64_t num_elements) + { + for (auto& pair : this->wireMap) { + std::cout << "Log: " << pair.first << "\n"; + std::cout << "Mapp: " << pair.second << "\n"; + } + QubitIdType numQubits = std::log2(num_elements); + std::vector binaryVector; + if (wire == 0) + binaryVector.push_back(0); + while (wire > 0) { + binaryVector.push_back(wire % 2); + wire /= 2; + } + while (binaryVector.size() < numQubits) + binaryVector.push_back(0); + std::reverse(binaryVector.begin(), binaryVector.end()); + std::vector binaryVectorCopy; + for(auto i = 0; i < binaryVector.size(); i++) + binaryVectorCopy.push_back(binaryVector[i]); + + for(auto i=0; iwireMap) { + // if (pair.second == i) + // { + // binaryVector[i] = binaryVectorCopy[pair.first]; + // break; + // } + // } + binaryVector[i] = binaryVectorCopy[this->wireMap[i]]; + } + + QubitIdType mapped_wire = 0; + int power = 0; + for (int i = binaryVector.size() - 1; i >= 0; --i) { + if (binaryVector[i] == 1) { + mapped_wire += std::pow(2, power); + } + power++; + } + return mapped_wire; + } std::tuple> getRoutedQubits(QUBIT *control, QUBIT *target) diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index 77c16f0ef1..ec517bc693 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -1278,9 +1278,6 @@ RESULT *__catalyst__qis__Measure(QUBIT *wire, int32_t postselect) if (postselect != 0 && postselect != 1) { postselectOpt = std::nullopt; } - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - return getQuantumDevicePtr()->Measure(RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(wire)), postselectOpt); - return getQuantumDevicePtr()->Measure(reinterpret_cast(wire), postselectOpt); } @@ -1297,11 +1294,7 @@ void __catalyst__qis__State(MemRefT_CplxT_double_1d *result, int64_t numQubits, va_start(args, numQubits); std::vector wires(numQubits); for (int64_t i = 0; i < numQubits; i++) { - QubitIdType original_wire = va_arg(args, QubitIdType); - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - wires[i] = RTD_PTR->getRuntimeRouter()->getMappedWire(original_wire); - else - wires[i] = original_wire; + wires[i] = va_arg(args, QubitIdType); } va_end(args); @@ -1310,6 +1303,20 @@ void __catalyst__qis__State(MemRefT_CplxT_double_1d *result, int64_t numQubits, if (wires.empty()) { getQuantumDevicePtr()->State(view); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + // copy the result_p data + std::vector> tempState; + for(int i = 0; i < result_p->sizes[0]; i++) + tempState.push_back(result_p->data_aligned[i]); + + // permute indices + for(int i=0; isizes[0]; i++) + { + QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(i,result_p->sizes[0]); + result_p->data_aligned[i] = tempState[mapped_wire]; + } + } } else { RT_FAIL("Partial State-Vector not supported."); @@ -1330,11 +1337,7 @@ void __catalyst__qis__Probs(MemRefT_double_1d *result, int64_t numQubits, ...) va_start(args, numQubits); std::vector wires(numQubits); for (int64_t i = 0; i < numQubits; i++) { - QubitIdType original_wire = va_arg(args, QubitIdType); - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - wires[i] = RTD_PTR->getRuntimeRouter()->getMappedWire(original_wire); - else - wires[i] = original_wire; + wires[i] = va_arg(args, QubitIdType); } va_end(args); @@ -1365,11 +1368,7 @@ void __catalyst__qis__Sample(MemRefT_double_2d *result, int64_t numQubits, ...) va_start(args, numQubits); std::vector wires(numQubits); for (int64_t i = 0; i < numQubits; i++) { - QubitIdType original_wire = va_arg(args, QubitIdType); - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - wires[i] = RTD_PTR->getRuntimeRouter()->getMappedWire(original_wire); - else - wires[i] = original_wire; + wires[i] = va_arg(args, QubitIdType); } va_end(args); @@ -1400,11 +1399,7 @@ void __catalyst__qis__Counts(PairT_MemRefT_double_int64_1d *result, int64_t numQ va_start(args, numQubits); std::vector wires(numQubits); for (int64_t i = 0; i < numQubits; i++) { - QubitIdType original_wire = va_arg(args, QubitIdType); - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - wires[i] = RTD_PTR->getRuntimeRouter()->getMappedWire(original_wire); - else - wires[i] = original_wire; + wires[i] = va_arg(args, QubitIdType); } va_end(args); From 28016b30e5e40de43e654e7db4998dc84ec4e318 Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Tue, 26 Aug 2025 16:24:36 -0400 Subject: [PATCH 16/29] remove prints --- runtime/lib/capi/Routing.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/runtime/lib/capi/Routing.hpp b/runtime/lib/capi/Routing.hpp index e21833fc98..54142b245b 100644 --- a/runtime/lib/capi/Routing.hpp +++ b/runtime/lib/capi/Routing.hpp @@ -127,10 +127,6 @@ class RoutingPass final { QubitIdType getMappedWire(QubitIdType wire, int64_t num_elements) { - for (auto& pair : this->wireMap) { - std::cout << "Log: " << pair.first << "\n"; - std::cout << "Mapp: " << pair.second << "\n"; - } QubitIdType numQubits = std::log2(num_elements); std::vector binaryVector; if (wire == 0) From fa429f2b41dd42b977851088914e81e46daac1ac Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Wed, 27 Aug 2025 20:32:31 -0400 Subject: [PATCH 17/29] add checks for multiqubit gates in runtime --- runtime/lib/capi/RuntimeCAPI.cpp | 81 ++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index ec517bc693..42e2384d68 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -519,6 +519,24 @@ void __catalyst__qis__SetState(MemRefT_CplxT_double_1d *data, uint64_t numQubits getQuantumDevicePtr()->SetState(data_view, wires); } +void __catalyst__qis__PCPhase(double theta, double dim, const Modifiers *modifiers, + int64_t numQubits, ...) +{ + RT_ASSERT(numQubits >= 0); + RT_ASSERT(dim >= 0 && dim == static_cast(dim)); + + va_list args; + va_start(args, numQubits); + std::vector wires(numQubits); + for (int64_t i = 0; i < numQubits; i++) { + wires[i] = va_arg(args, QubitIdType); + } + va_end(args); + + getQuantumDevicePtr()->NamedOperation("PCPhase", {theta, dim}, wires, + /* modifiers */ MODIFIERS_ARGS(modifiers)); +} + void __catalyst__qis__SetBasisState(MemRefT_int8_1d *data, uint64_t numQubits, ...) { RT_ASSERT(numQubits > 0); @@ -658,6 +676,8 @@ void __catalyst__qis__CNOT(QUBIT *control, QUBIT *target, const Modifiers *modif void __catalyst__qis__CY(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF(control == target, + "Invalid input for CY gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -688,6 +708,8 @@ void __catalyst__qis__CY(QUBIT *control, QUBIT *target, const Modifiers *modifie void __catalyst__qis__CZ(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF(control == target, + "Invalid input for CZ gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -717,6 +739,8 @@ void __catalyst__qis__CZ(QUBIT *control, QUBIT *target, const Modifiers *modifie void __catalyst__qis__SWAP(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF(control == target, + "Invalid input for SWAP gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -747,6 +771,9 @@ void __catalyst__qis__IsingXX(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF( + control == target, + "Invalid input for IsingXX gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -777,6 +804,9 @@ void __catalyst__qis__IsingYY(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF( + control == target, + "Invalid input for IsingYY gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -807,6 +837,9 @@ void __catalyst__qis__IsingXY(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF( + control == target, + "Invalid input for IsingXY gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -837,6 +870,9 @@ void __catalyst__qis__IsingZZ(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF( + control == target, + "Invalid input for IsingZZ gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -863,10 +899,37 @@ void __catalyst__qis__IsingZZ(double theta, QUBIT *control, QUBIT *target, } } +void __catalyst__qis__SingleExcitation(double phi, QUBIT *wire0, QUBIT *wire1, + const Modifiers *modifiers) +{ + RT_FAIL_IF(wire0 == wire1, + "Invalid input for SingleExcitation gate. All two qubit operands must be distinct."); + getQuantumDevicePtr()->NamedOperation( + "SingleExcitation", {phi}, + {reinterpret_cast(wire0), reinterpret_cast(wire1)}, + MODIFIERS_ARGS(modifiers)); +} + +void __catalyst__qis__DoubleExcitation(double phi, QUBIT *wire0, QUBIT *wire1, QUBIT *wire2, + QUBIT *wire3, const Modifiers *modifiers) +{ + RT_FAIL_IF( + (wire0 == wire1 || wire0 == wire2 || wire0 == wire3 || wire1 == wire2 || wire1 == wire3 || + wire2 == wire3), + "Invalid input for DoubleExcitation gate. All four qubit operands must be distinct."); + getQuantumDevicePtr()->NamedOperation( + "DoubleExcitation", {phi}, + {reinterpret_cast(wire0), reinterpret_cast(wire1), + reinterpret_cast(wire2), reinterpret_cast(wire3)}, + MODIFIERS_ARGS(modifiers)); +} + void __catalyst__qis__ControlledPhaseShift(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF(control == target, "Invalid input for ControlledPhaseShift gate. Control and target " + "qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -896,6 +959,8 @@ void __catalyst__qis__ControlledPhaseShift(double theta, QUBIT *control, QUBIT * void __catalyst__qis__CRX(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF(control == target, + "Invalid input for CRX gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -925,6 +990,8 @@ void __catalyst__qis__CRX(double theta, QUBIT *control, QUBIT *target, const Mod void __catalyst__qis__CRY(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF(control == target, + "Invalid input for CRY gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -954,6 +1021,8 @@ void __catalyst__qis__CRY(double theta, QUBIT *control, QUBIT *target, const Mod void __catalyst__qis__CRZ(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF(control == target, + "Invalid input for CRZ gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -983,6 +1052,8 @@ void __catalyst__qis__CRZ(double theta, QUBIT *control, QUBIT *target, const Mod void __catalyst__qis__MS(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF(control == target, + "Invalid input for MS gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -1013,6 +1084,8 @@ void __catalyst__qis__CRot(double phi, double theta, double omega, QUBIT *contro const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF(control == target, + "Invalid input for CRot gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -1041,6 +1114,8 @@ void __catalyst__qis__CRot(double phi, double theta, double omega, QUBIT *contro void __catalyst__qis__CSWAP(QUBIT *control, QUBIT *aswap, QUBIT *bswap, const Modifiers *modifiers) { + RT_FAIL_IF((control == aswap || aswap == bswap || control == bswap), + "Invalid input for CSWAP gate. Control and target qubit operands must be distinct."); getQuantumDevicePtr()->NamedOperation("CSWAP", {}, {reinterpret_cast(control), reinterpret_cast(aswap), @@ -1050,6 +1125,8 @@ void __catalyst__qis__CSWAP(QUBIT *control, QUBIT *aswap, QUBIT *bswap, const Mo void __catalyst__qis__Toffoli(QUBIT *wire0, QUBIT *wire1, QUBIT *wire2, const Modifiers *modifiers) { + RT_FAIL_IF((wire0 == wire1 || wire1 == wire2 || wire0 == wire2), + "Invalid input for Toffoli gate. All three qubit operands must be distinct."); getQuantumDevicePtr()->NamedOperation("Toffoli", {}, {reinterpret_cast(wire0), reinterpret_cast(wire1), @@ -1076,6 +1153,8 @@ void __catalyst__qis__MultiRZ(double theta, const Modifiers *modifiers, int64_t void __catalyst__qis__ISWAP(QUBIT *wire0, QUBIT *wire1, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF(wire0 == wire1, + "Invalid input for ISWAP gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(wire0, wire1); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); @@ -1104,6 +1183,8 @@ void __catalyst__qis__ISWAP(QUBIT *wire0, QUBIT *wire1, const Modifiers *modifie void __catalyst__qis__PSWAP(double phi, QUBIT *wire0, QUBIT *wire1, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + RT_FAIL_IF(wire0 == wire1, + "Invalid input for PSWAP gate. Control and target qubit operands must be distinct."); std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(wire0, wire1); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); From 17d42c84de495f7c8cd2aa10da30f16b8ffa9230 Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Wed, 27 Aug 2025 20:48:41 -0400 Subject: [PATCH 18/29] clang formatting --- runtime/lib/capi/RuntimeCAPI.cpp | 228 +++++++++++++++++-------------- 1 file changed, 128 insertions(+), 100 deletions(-) diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index ffe02d3fbd..263f2e8f90 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -79,7 +79,8 @@ std::vector getModifiersControlledValues(const Modifiers *modifiers) std::string_view rtd_kwargs, bool auto_qubit_management, std::string_view coupling_map_str = {}) { - auto &&device = CTX->getOrCreateDevice(rtd_lib, rtd_name, rtd_kwargs, auto_qubit_management, coupling_map_str); + auto &&device = CTX->getOrCreateDevice(rtd_lib, rtd_name, rtd_kwargs, auto_qubit_management, + coupling_map_str); if (device) { RTD_PTR = device.get(); return RTD_PTR ? true : false; @@ -267,21 +268,22 @@ static int __catalyst__rt__device_init__impl(int8_t *rtd_lib, int8_t *rtd_name, const std::vector args{ reinterpret_cast(rtd_lib), (rtd_name ? reinterpret_cast(rtd_name) : ""), (rtd_kwargs ? reinterpret_cast(rtd_kwargs) : "")}; - + // Extract coupling map from the kwargs passed // If coupling map is provided then it takes in the form {...,'couplingMap' ((a,b),(b,c))} // else {...,'couplingMap' (a,b,c)} size_t start = args[2].find("coupling_map': ") + 15; // Find key and opening parenthesis size_t end = args[2].find("}", start); // Find closing parenthesis std::string coupling_map_str = std::string(args[2].substr(start, end - start)); - + if (coupling_map_str.find("((") != std::string::npos) { - RT_FAIL_IF(!initRTDevicePtr(args[0], args[1], args[2], auto_qubit_management, coupling_map_str), - "Failed initialization of the backend device"); + RT_FAIL_IF( + !initRTDevicePtr(args[0], args[1], args[2], auto_qubit_management, coupling_map_str), + "Failed initialization of the backend device"); } else { RT_FAIL_IF(!initRTDevicePtr(args[0], args[1], args[2], auto_qubit_management), - "Failed initialization of the backend device"); + "Failed initialization of the backend device"); } getQuantumDevicePtr()->SetDeviceShots(shots); if (CTX->getDeviceRecorderStatus()) { @@ -664,17 +666,18 @@ void __catalyst__qis__CNOT(QUBIT *control, QUBIT *target, const Modifiers *modif RT_FAIL_IF(control == target, "Invalid input for CNOT gate. Control and target qubit operands must be distinct."); if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - - if (swapPath.size() > 0) - { + + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("CNOT", {}, @@ -694,19 +697,21 @@ void __catalyst__qis__CNOT(QUBIT *control, QUBIT *target, const Modifiers *modif void __catalyst__qis__CY(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - RT_FAIL_IF(control == target, - "Invalid input for CY gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + RT_FAIL_IF( + control == target, + "Invalid input for CY gate. Control and target qubit operands must be distinct."); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - - if (swapPath.size() > 0) - { + + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("CY", {}, @@ -726,18 +731,20 @@ void __catalyst__qis__CY(QUBIT *control, QUBIT *target, const Modifiers *modifie void __catalyst__qis__CZ(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - RT_FAIL_IF(control == target, - "Invalid input for CZ gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + RT_FAIL_IF( + control == target, + "Invalid input for CZ gate. Control and target qubit operands must be distinct."); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("CZ", {}, @@ -757,18 +764,20 @@ void __catalyst__qis__CZ(QUBIT *control, QUBIT *target, const Modifiers *modifie void __catalyst__qis__SWAP(QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - RT_FAIL_IF(control == target, - "Invalid input for SWAP gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + RT_FAIL_IF( + control == target, + "Invalid input for SWAP gate. Control and target qubit operands must be distinct."); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("SWAP", {}, @@ -792,16 +801,17 @@ void __catalyst__qis__IsingXX(double theta, QUBIT *control, QUBIT *target, RT_FAIL_IF( control == target, "Invalid input for IsingXX gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("IsingXX", {theta}, @@ -825,16 +835,17 @@ void __catalyst__qis__IsingYY(double theta, QUBIT *control, QUBIT *target, RT_FAIL_IF( control == target, "Invalid input for IsingYY gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("IsingYY", {theta}, @@ -858,16 +869,17 @@ void __catalyst__qis__IsingXY(double theta, QUBIT *control, QUBIT *target, RT_FAIL_IF( control == target, "Invalid input for IsingXY gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("IsingXY", {theta}, @@ -891,16 +903,17 @@ void __catalyst__qis__IsingZZ(double theta, QUBIT *control, QUBIT *target, RT_FAIL_IF( control == target, "Invalid input for IsingZZ gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("IsingZZ", {theta}, @@ -971,18 +984,20 @@ void __catalyst__qis__ControlledPhaseShift(double theta, QUBIT *control, QUBIT * const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - RT_FAIL_IF(control == target, "Invalid input for ControlledPhaseShift gate. Control and target " - "qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + RT_FAIL_IF(control == target, + "Invalid input for ControlledPhaseShift gate. Control and target " + "qubit operands must be distinct."); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("ControlledPhaseShift", {theta}, @@ -1002,18 +1017,20 @@ void __catalyst__qis__ControlledPhaseShift(double theta, QUBIT *control, QUBIT * void __catalyst__qis__CRX(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - RT_FAIL_IF(control == target, - "Invalid input for CRX gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + RT_FAIL_IF( + control == target, + "Invalid input for CRX gate. Control and target qubit operands must be distinct."); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("CRX", {theta}, @@ -1033,18 +1050,20 @@ void __catalyst__qis__CRX(double theta, QUBIT *control, QUBIT *target, const Mod void __catalyst__qis__CRY(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - RT_FAIL_IF(control == target, - "Invalid input for CRY gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + RT_FAIL_IF( + control == target, + "Invalid input for CRY gate. Control and target qubit operands must be distinct."); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("CRY", {theta}, @@ -1064,18 +1083,20 @@ void __catalyst__qis__CRY(double theta, QUBIT *control, QUBIT *target, const Mod void __catalyst__qis__CRZ(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - RT_FAIL_IF(control == target, - "Invalid input for CRZ gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + RT_FAIL_IF( + control == target, + "Invalid input for CRZ gate. Control and target qubit operands must be distinct."); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("CRZ", {theta}, @@ -1095,18 +1116,20 @@ void __catalyst__qis__CRZ(double theta, QUBIT *control, QUBIT *target, const Mod void __catalyst__qis__MS(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - RT_FAIL_IF(control == target, - "Invalid input for MS gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + RT_FAIL_IF( + control == target, + "Invalid input for MS gate. Control and target qubit operands must be distinct."); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("MS", {theta}, @@ -1127,18 +1150,20 @@ void __catalyst__qis__CRot(double phi, double theta, double omega, QUBIT *contro const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - RT_FAIL_IF(control == target, - "Invalid input for CRot gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); + RT_FAIL_IF( + control == target, + "Invalid input for CRot gate. Control and target qubit operands must be distinct."); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(control, target); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("CRot", {phi, theta, omega}, @@ -1200,18 +1225,20 @@ void __catalyst__qis__MultiRZ(double theta, const Modifiers *modifiers, int64_t void __catalyst__qis__ISWAP(QUBIT *wire0, QUBIT *wire1, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - RT_FAIL_IF(wire0 == wire1, - "Invalid input for ISWAP gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(wire0, wire1); + RT_FAIL_IF( + wire0 == wire1, + "Invalid input for ISWAP gate. Control and target qubit operands must be distinct."); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(wire0, wire1); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("ISWAP", {}, @@ -1230,18 +1257,20 @@ void __catalyst__qis__ISWAP(QUBIT *wire0, QUBIT *wire1, const Modifiers *modifie void __catalyst__qis__PSWAP(double phi, QUBIT *wire0, QUBIT *wire1, const Modifiers *modifiers) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - RT_FAIL_IF(wire0 == wire1, - "Invalid input for PSWAP gate. Control and target qubit operands must be distinct."); - std::tuple> resultTuple = RTD_PTR->getRuntimeRouter()->getRoutedQubits(wire0, wire1); + RT_FAIL_IF( + wire0 == wire1, + "Invalid input for PSWAP gate. Control and target qubit operands must be distinct."); + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(wire0, wire1); QubitIdType routedQubitFirst = std::get<0>(resultTuple); QubitIdType routedQubitSecond = std::get<1>(resultTuple); std::vector swapPath = std::get<2>(resultTuple); - if (swapPath.size() > 0) - { + if (swapPath.size() > 0) { for (auto i = 1; i < swapPath.size() - 1; i++) { QubitIdType u = swapPath[i - 1]; QubitIdType v = swapPath[i]; - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, MODIFIERS_ARGS(modifiers)); + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); } } getQuantumDevicePtr()->NamedOperation("PSWAP", {phi}, @@ -1431,17 +1460,16 @@ void __catalyst__qis__State(MemRefT_CplxT_double_1d *result, int64_t numQubits, if (wires.empty()) { getQuantumDevicePtr()->State(view); - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { // copy the result_p data std::vector> tempState; - for(int i = 0; i < result_p->sizes[0]; i++) + for (int i = 0; i < result_p->sizes[0]; i++) tempState.push_back(result_p->data_aligned[i]); // permute indices - for(int i=0; isizes[0]; i++) - { - QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(i,result_p->sizes[0]); + for (int i = 0; i < result_p->sizes[0]; i++) { + QubitIdType mapped_wire = + RTD_PTR->getRuntimeRouter()->getMappedWire(i, result_p->sizes[0]); result_p->data_aligned[i] = tempState[mapped_wire]; } } From a5ac8642a86862e93b67f9200cea7352425cdf0f Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Wed, 27 Aug 2025 20:50:20 -0400 Subject: [PATCH 19/29] clang format --- runtime/lib/capi/ExecutionContext.hpp | 18 ++++++++++-------- runtime/lib/capi/Routing.hpp | 25 ++++++++++++------------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/runtime/lib/capi/ExecutionContext.hpp b/runtime/lib/capi/ExecutionContext.hpp index a4a4fc2aad..1a4ad060f6 100644 --- a/runtime/lib/capi/ExecutionContext.hpp +++ b/runtime/lib/capi/ExecutionContext.hpp @@ -29,8 +29,8 @@ #include "Exception.hpp" #include "QuantumDevice.hpp" -#include "Types.h" #include "Routing.hpp" +#include "Types.h" namespace Catalyst::Runtime { @@ -171,7 +171,7 @@ class RTDevice { std::unique_ptr rtd_dylib{nullptr}; std::unique_ptr rtd_qdevice{nullptr}; - //device specific routing pass pointer. + // device specific routing pass pointer. std::unique_ptr RUNTIME_ROUTER{nullptr}; RTDeviceStatus status{RTDeviceStatus::Inactive}; @@ -228,14 +228,15 @@ class RTDevice { } explicit RTDevice(std::string_view _rtd_lib, std::string_view _rtd_name, - std::string_view _rtd_kwargs, bool _auto_qubit_management, std::string_view coupling_map_str) + std::string_view _rtd_kwargs, bool _auto_qubit_management, + std::string_view coupling_map_str) : rtd_lib(_rtd_lib), rtd_name(_rtd_name), rtd_kwargs(_rtd_kwargs), auto_qubit_management(_auto_qubit_management) { - // Extract coupling map from the kwargs passed + // Extract coupling map from the kwargs passed // If coupling map is provided then it takes in the form {...,'couplingMap' ((a,b),(b,c))} // else {...,'couplingMap' (a,b,c)} - if (coupling_map_str.find("((") != std::string::npos) + if (coupling_map_str.find("((") != std::string::npos) RUNTIME_ROUTER = std::make_unique(coupling_map_str); _pl2runtime_device_info(rtd_lib, rtd_name); } @@ -280,7 +281,8 @@ class RTDevice { void setDeviceStatus(RTDeviceStatus new_status) noexcept { status = new_status; } bool getQubitManagementMode() { return auto_qubit_management; } - [[nodiscard]] auto getRuntimeRouter() -> std::unique_ptr& { + [[nodiscard]] auto getRuntimeRouter() -> std::unique_ptr & + { return RUNTIME_ROUTER; } @@ -346,8 +348,8 @@ class ExecutionContext final { { std::lock_guard lock(pool_mu); - auto device = - std::make_shared(rtd_lib, rtd_name, rtd_kwargs, auto_qubit_management, coupling_map_str); + auto device = std::make_shared(rtd_lib, rtd_name, rtd_kwargs, + auto_qubit_management, coupling_map_str); const size_t key = device_pool.size(); for (size_t i = 0; i < key; i++) { diff --git a/runtime/lib/capi/Routing.hpp b/runtime/lib/capi/Routing.hpp index 54142b245b..3a567e3640 100644 --- a/runtime/lib/capi/Routing.hpp +++ b/runtime/lib/capi/Routing.hpp @@ -125,25 +125,24 @@ class RoutingPass final { return path; } - QubitIdType getMappedWire(QubitIdType wire, int64_t num_elements) - { + QubitIdType getMappedWire(QubitIdType wire, int64_t num_elements) + { QubitIdType numQubits = std::log2(num_elements); std::vector binaryVector; - if (wire == 0) - binaryVector.push_back(0); + if (wire == 0) + binaryVector.push_back(0); while (wire > 0) { - binaryVector.push_back(wire % 2); - wire /= 2; + binaryVector.push_back(wire % 2); + wire /= 2; } while (binaryVector.size() < numQubits) binaryVector.push_back(0); std::reverse(binaryVector.begin(), binaryVector.end()); std::vector binaryVectorCopy; - for(auto i = 0; i < binaryVector.size(); i++) + for (auto i = 0; i < binaryVector.size(); i++) binaryVectorCopy.push_back(binaryVector[i]); - for(auto i=0; iwireMap) { // if (pair.second == i) // { @@ -153,7 +152,7 @@ class RoutingPass final { // } binaryVector[i] = binaryVectorCopy[this->wireMap[i]]; } - + QubitIdType mapped_wire = 0; int power = 0; for (int i = binaryVector.size() - 1; i >= 0; --i) { @@ -162,11 +161,11 @@ class RoutingPass final { } power++; } - return mapped_wire; + return mapped_wire; } - std::tuple> - getRoutedQubits(QUBIT *control, QUBIT *target) + std::tuple> getRoutedQubits(QUBIT *control, + QUBIT *target) { // Similar to qml.transpile implementation // https://docs.pennylane.ai/en/stable/_modules/pennylane/transforms/transpile.html From 4c4dc80f90ef51a989fbfcde936d6dcc253d0df5 Mon Sep 17 00:00:00 2001 From: ritu-thombre99 Date: Wed, 27 Aug 2025 20:59:34 -0400 Subject: [PATCH 20/29] remove redefinitions --- runtime/lib/capi/RuntimeCAPI.cpp | 43 -------------------------------- 1 file changed, 43 deletions(-) diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index 263f2e8f90..4829d98beb 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -539,24 +539,6 @@ void __catalyst__qis__PCPhase(double theta, double dim, const Modifiers *modifie /* modifiers */ MODIFIERS_ARGS(modifiers)); } -void __catalyst__qis__PCPhase(double theta, double dim, const Modifiers *modifiers, - int64_t numQubits, ...) -{ - RT_ASSERT(numQubits >= 0); - RT_ASSERT(dim >= 0 && dim == static_cast(dim)); - - va_list args; - va_start(args, numQubits); - std::vector wires(numQubits); - for (int64_t i = 0; i < numQubits; i++) { - wires[i] = va_arg(args, QubitIdType); - } - va_end(args); - - getQuantumDevicePtr()->NamedOperation("PCPhase", {theta, dim}, wires, - /* modifiers */ MODIFIERS_ARGS(modifiers)); -} - void __catalyst__qis__SetBasisState(MemRefT_int8_1d *data, uint64_t numQubits, ...) { RT_ASSERT(numQubits > 0); @@ -955,31 +937,6 @@ void __catalyst__qis__DoubleExcitation(double phi, QUBIT *wire0, QUBIT *wire1, Q MODIFIERS_ARGS(modifiers)); } -void __catalyst__qis__SingleExcitation(double phi, QUBIT *wire0, QUBIT *wire1, - const Modifiers *modifiers) -{ - RT_FAIL_IF(wire0 == wire1, - "Invalid input for SingleExcitation gate. All two qubit operands must be distinct."); - getQuantumDevicePtr()->NamedOperation( - "SingleExcitation", {phi}, - {reinterpret_cast(wire0), reinterpret_cast(wire1)}, - MODIFIERS_ARGS(modifiers)); -} - -void __catalyst__qis__DoubleExcitation(double phi, QUBIT *wire0, QUBIT *wire1, QUBIT *wire2, - QUBIT *wire3, const Modifiers *modifiers) -{ - RT_FAIL_IF( - (wire0 == wire1 || wire0 == wire2 || wire0 == wire3 || wire1 == wire2 || wire1 == wire3 || - wire2 == wire3), - "Invalid input for DoubleExcitation gate. All four qubit operands must be distinct."); - getQuantumDevicePtr()->NamedOperation( - "DoubleExcitation", {phi}, - {reinterpret_cast(wire0), reinterpret_cast(wire1), - reinterpret_cast(wire2), reinterpret_cast(wire3)}, - MODIFIERS_ARGS(modifiers)); -} - void __catalyst__qis__ControlledPhaseShift(double theta, QUBIT *control, QUBIT *target, const Modifiers *modifiers) { From f55c8c54df439d7a0d00e11ddb064ec05698d896 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum <> Date: Sat, 11 Oct 2025 03:48:35 +0000 Subject: [PATCH 21/29] [no ci] bump nightly version --- frontend/catalyst/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/catalyst/_version.py b/frontend/catalyst/_version.py index 2f04e5df30..852b022237 100644 --- a/frontend/catalyst/_version.py +++ b/frontend/catalyst/_version.py @@ -16,4 +16,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "0.14.0-dev4" +__version__ = "0.14.0-dev5" From 31b014ab0c296b077566c0561991a03028990d9f Mon Sep 17 00:00:00 2001 From: Ritu Thombre Date: Sat, 11 Oct 2025 22:28:03 -0700 Subject: [PATCH 22/29] return to trivial mapping before getting state --- runtime/lib/capi/ExecutionContext.hpp | 1 - runtime/lib/capi/Routing.hpp | 92 +++++++++++---------------- 2 files changed, 36 insertions(+), 57 deletions(-) diff --git a/runtime/lib/capi/ExecutionContext.hpp b/runtime/lib/capi/ExecutionContext.hpp index 1a4ad060f6..7bc1a10c83 100644 --- a/runtime/lib/capi/ExecutionContext.hpp +++ b/runtime/lib/capi/ExecutionContext.hpp @@ -310,7 +310,6 @@ class ExecutionContext final { // PRNG uint32_t *seed; - bool enable_routing{false}; std::mt19937 gen; public: diff --git a/runtime/lib/capi/Routing.hpp b/runtime/lib/capi/Routing.hpp index 3a567e3640..205c90d4d5 100644 --- a/runtime/lib/capi/Routing.hpp +++ b/runtime/lib/capi/Routing.hpp @@ -104,6 +104,8 @@ class RoutingPass final { } } + QubitIdType getMappedWire(QubitIdType wire) { return this->wireMap[wire]; } + std::vector getShortestPath(QubitIdType source, QubitIdType target) { std::vector path; @@ -125,64 +127,15 @@ class RoutingPass final { return path; } - QubitIdType getMappedWire(QubitIdType wire, int64_t num_elements) - { - QubitIdType numQubits = std::log2(num_elements); - std::vector binaryVector; - if (wire == 0) - binaryVector.push_back(0); - while (wire > 0) { - binaryVector.push_back(wire % 2); - wire /= 2; - } - while (binaryVector.size() < numQubits) - binaryVector.push_back(0); - std::reverse(binaryVector.begin(), binaryVector.end()); - std::vector binaryVectorCopy; - for (auto i = 0; i < binaryVector.size(); i++) - binaryVectorCopy.push_back(binaryVector[i]); - - for (auto i = 0; i < binaryVector.size(); i++) { - // for (auto& pair : this->wireMap) { - // if (pair.second == i) - // { - // binaryVector[i] = binaryVectorCopy[pair.first]; - // break; - // } - // } - binaryVector[i] = binaryVectorCopy[this->wireMap[i]]; - } - - QubitIdType mapped_wire = 0; - int power = 0; - for (int i = binaryVector.size() - 1; i >= 0; --i) { - if (binaryVector[i] == 1) { - mapped_wire += std::pow(2, power); - } - power++; - } - return mapped_wire; - } - std::tuple> getRoutedQubits(QUBIT *control, QUBIT *target) { - // Similar to qml.transpile implementation - // https://docs.pennylane.ai/en/stable/_modules/pennylane/transforms/transpile.html - - QubitIdType firstQubit = reinterpret_cast(control); - QubitIdType secondQubit = reinterpret_cast(target); + QubitIdType firstQubitMapping = this->wireMap[reinterpret_cast(control)]; + QubitIdType secondQubitMapping = this->wireMap[reinterpret_cast(target)]; std::vector swapPath = {}; - if (this->couplingMap[std::make_pair(firstQubit, secondQubit)]) { - // since in each iteration, we adjust indices of each op, - // we reset logical -> phyiscal mapping - for (auto it = this->wireMap.begin(); it != this->wireMap.end(); ++it) { - this->wireMap[it->second] = it->second; - } - } - else { - swapPath = this->getShortestPath(firstQubit, secondQubit); + if (!this->couplingMap[std::make_pair(firstQubitMapping, secondQubitMapping)]) { + swapPath = this->getShortestPath(firstQubitMapping, secondQubitMapping); // iwireMap[it->first] = u; } } - firstQubit = this->wireMap[firstQubit]; - secondQubit = this->wireMap[secondQubit]; + firstQubitMapping = this->wireMap[reinterpret_cast(control)]; + secondQubitMapping = this->wireMap[reinterpret_cast(target)]; + } + return std::make_tuple(firstQubitMapping, secondQubitMapping, swapPath); + } + + void findFinalSwaps(QubitIdType currWireIndex, std::vector> *finalSwaps) + { + if(currWireIndex == this->wireMap[currWireIndex]) + return; + QubitIdType nextWireIndex = this->wireMap[currWireIndex]; + QubitIdType temp = this->wireMap[currWireIndex]; + this->wireMap[currWireIndex] = this->wireMap[nextWireIndex]; + this->wireMap[nextWireIndex] = temp; + (*finalSwaps).push_back({this->wireMap[currWireIndex], this->wireMap[nextWireIndex] }); + findFinalSwaps(nextWireIndex,finalSwaps); + return; + } + std::vector> getFinalPermuteSwaps() + { + std::vector> finalSwaps; + for (auto it = this->wireMap.begin(); it != this->wireMap.end(); ++it) + { + while(true) + { + findFinalSwaps(this->wireMap[it->first], &finalSwaps); + if (this->wireMap[it->first] == this->wireMap[it->second] ) + break; + } } - return std::make_tuple(firstQubit, secondQubit, swapPath); + return finalSwaps; } ~RoutingPass() = default; From f078e39e5d3e03f6e4d153631503e5b4f1b759ec Mon Sep 17 00:00:00 2001 From: Ritu Thombre Date: Sat, 11 Oct 2025 22:30:47 -0700 Subject: [PATCH 23/29] return to trivial mapping before getting state --- runtime/lib/capi/RuntimeCAPI.cpp | 141 +++++++++++++++++++++++++------ 1 file changed, 115 insertions(+), 26 deletions(-) diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index 580bec8ee1..664db7b8c4 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -506,6 +506,7 @@ void __catalyst__qis__GlobalPhase(double phi, const Modifiers *modifiers) void __catalyst__qis__SetState(MemRefT_CplxT_double_1d *data, uint64_t numQubits, ...) { + // set_state is at the beginning of the circuit starting with 1->1 mapping RT_ASSERT(numQubits > 0); va_list args; @@ -535,7 +536,11 @@ void __catalyst__qis__PCPhase(double theta, double dim, const Modifiers *modifie wires[i] = va_arg(args, QubitIdType); } va_end(args); - + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + for (int64_t i = 0; i < numQubits; i++) + wires[i] = RTD_PTR->getRuntimeRouter()->getMappedWire(wires[i]); + } getQuantumDevicePtr()->NamedOperation("PCPhase", {theta, dim}, wires, /* modifiers */ MODIFIERS_ARGS(modifiers)); } @@ -571,77 +576,168 @@ void __catalyst__qis__Identity(const Modifiers *modifiers, int64_t numQubits, .. wires[i] = va_arg(args, QubitIdType); } va_end(args); - + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + for (int64_t i = 0; i < numQubits; i++) + wires[i] = RTD_PTR->getRuntimeRouter()->getMappedWire(wires[i]); + } getQuantumDevicePtr()->NamedOperation("Identity", {}, wires, /* modifiers */ MODIFIERS_ARGS(modifiers)); } void __catalyst__qis__PauliX(QUBIT *qubit, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("PauliX", {}, {reinterpret_cast(qubit)}, + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + getQuantumDevicePtr()->NamedOperation("PauliX", {}, {mapped_wire}, MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation("PauliX", {}, {reinterpret_cast(qubit)}, + MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__PauliY(QUBIT *qubit, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("PauliY", {}, {reinterpret_cast(qubit)}, + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + getQuantumDevicePtr()->NamedOperation("PauliY", {}, {mapped_wire}, MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation("PauliY", {}, {reinterpret_cast(qubit)}, + MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__PauliZ(QUBIT *qubit, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("PauliZ", {}, {reinterpret_cast(qubit)}, + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + getQuantumDevicePtr()->NamedOperation("PauliZ", {}, {mapped_wire}, MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation("PauliZ", {}, {reinterpret_cast(qubit)}, + MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__Hadamard(QUBIT *qubit, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("Hadamard", {}, {reinterpret_cast(qubit)}, + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + getQuantumDevicePtr()->NamedOperation("Hadamard", {}, {mapped_wire}, MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation("Hadamard", {}, {reinterpret_cast(qubit)}, + MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__S(QUBIT *qubit, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("S", {}, {reinterpret_cast(qubit)}, + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + getQuantumDevicePtr()->NamedOperation("S", {}, {mapped_wire}, MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation("S", {}, {reinterpret_cast(qubit)}, + MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__T(QUBIT *qubit, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("T", {}, {reinterpret_cast(qubit)}, + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + getQuantumDevicePtr()->NamedOperation("T", {}, {mapped_wire}, MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation("T", {}, {reinterpret_cast(qubit)}, + MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__PhaseShift(double theta, QUBIT *qubit, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation( - "PhaseShift", {theta}, {reinterpret_cast(qubit)}, MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + getQuantumDevicePtr()->NamedOperation("PhaseShift", {theta}, {mapped_wire}, + MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation("PhaseShift", {theta}, {reinterpret_cast(qubit)}, + MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__RX(double theta, QUBIT *qubit, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("RX", {theta}, {reinterpret_cast(qubit)}, + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + getQuantumDevicePtr()->NamedOperation("RX", {theta}, {mapped_wire}, MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation("RX", {theta}, {reinterpret_cast(qubit)}, + MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__RY(double theta, QUBIT *qubit, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("RY", {theta}, {reinterpret_cast(qubit)}, + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + getQuantumDevicePtr()->NamedOperation("RY", {theta}, {mapped_wire}, MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation("RY", {theta}, {reinterpret_cast(qubit)}, + MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__RZ(double theta, QUBIT *qubit, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("RZ", {theta}, {reinterpret_cast(qubit)}, + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + getQuantumDevicePtr()->NamedOperation("RZ", {theta}, {mapped_wire}, MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation("RZ", {theta}, {reinterpret_cast(qubit)}, + MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__Rot(double phi, double theta, double omega, QUBIT *qubit, const Modifiers *modifiers) { - getQuantumDevicePtr()->NamedOperation("Rot", {phi, theta, omega}, - {reinterpret_cast(qubit)}, + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + { + QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + getQuantumDevicePtr()->NamedOperation("Rot", {phi, theta, omega}, {mapped_wire}, MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation("Rot", {phi, theta, omega}, {reinterpret_cast(qubit)}, + MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__CNOT(QUBIT *control, QUBIT *target, const Modifiers *modifiers) @@ -1417,20 +1513,13 @@ void __catalyst__qis__State(MemRefT_CplxT_double_1d *result, int64_t numQubits, result_p->sizes, result_p->strides); if (wires.empty()) { - getQuantumDevicePtr()->State(view); if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - // copy the result_p data - std::vector> tempState; - for (int i = 0; i < result_p->sizes[0]; i++) - tempState.push_back(result_p->data_aligned[i]); - - // permute indices - for (int i = 0; i < result_p->sizes[0]; i++) { - QubitIdType mapped_wire = - RTD_PTR->getRuntimeRouter()->getMappedWire(i, result_p->sizes[0]); - result_p->data_aligned[i] = tempState[mapped_wire]; + std::vector> finalSwaps = RTD_PTR->getRuntimeRouter()->getFinalPermuteSwaps(); + for (auto i = 0; i < finalSwaps.size(); i++) { + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {std::get<0>(finalSwaps[i]), std::get<1>(finalSwaps[i])}); } } + getQuantumDevicePtr()->State(view); } else { RT_FAIL("Partial State-Vector not supported."); From 428779c95faca1cb2014ee8c9ad7db56a267e668 Mon Sep 17 00:00:00 2001 From: Ritu Thombre Date: Sun, 12 Oct 2025 17:30:08 -0700 Subject: [PATCH 24/29] remove NullQubit print operations --- runtime/lib/backend/null_qubit/NullQubit.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/runtime/lib/backend/null_qubit/NullQubit.hpp b/runtime/lib/backend/null_qubit/NullQubit.hpp index 00b5d9d5d2..5cc40d26f8 100644 --- a/runtime/lib/backend/null_qubit/NullQubit.hpp +++ b/runtime/lib/backend/null_qubit/NullQubit.hpp @@ -243,12 +243,6 @@ struct NullQubit final : public Catalyst::Runtime::QuantumDevice { const std::vector &controlled_wires = {}, const std::vector &controlled_values = {}) { - // Print to see what naive router does on Null qubits - std::cout << "Name: " << name << "\n"; - std::cout << "Wires : "; - for (auto i : wires) - std::cout << i << ","; - std::cout << "\n"; if (this->track_resources_) { this->resource_tracker_.NamedOperation(name, inverse, wires, controlled_wires); } From 10d263c8d9e06acff7ceadf1034e61e1fe15fe41 Mon Sep 17 00:00:00 2001 From: Ritu Thombre Date: Sun, 12 Oct 2025 18:04:07 -0700 Subject: [PATCH 25/29] check if only 1 and 2 qubit gates are present when performing qubit routing to a coupling_map --- runtime/lib/capi/Routing.hpp | 21 ++-- runtime/lib/capi/RuntimeCAPI.cpp | 194 +++++++++++++++++++------------ 2 files changed, 127 insertions(+), 88 deletions(-) diff --git a/runtime/lib/capi/Routing.hpp b/runtime/lib/capi/Routing.hpp index 205c90d4d5..3abc0710d4 100644 --- a/runtime/lib/capi/Routing.hpp +++ b/runtime/lib/capi/Routing.hpp @@ -154,31 +154,30 @@ class RoutingPass final { return std::make_tuple(firstQubitMapping, secondQubitMapping, swapPath); } - void findFinalSwaps(QubitIdType currWireIndex, std::vector> *finalSwaps) + void findFinalSwaps(QubitIdType currWireIndex, + std::vector> *finalSwaps) { - if(currWireIndex == this->wireMap[currWireIndex]) + if (currWireIndex == this->wireMap[currWireIndex]) return; QubitIdType nextWireIndex = this->wireMap[currWireIndex]; - QubitIdType temp = this->wireMap[currWireIndex]; + QubitIdType temp = this->wireMap[currWireIndex]; this->wireMap[currWireIndex] = this->wireMap[nextWireIndex]; this->wireMap[nextWireIndex] = temp; - (*finalSwaps).push_back({this->wireMap[currWireIndex], this->wireMap[nextWireIndex] }); - findFinalSwaps(nextWireIndex,finalSwaps); + (*finalSwaps).push_back({this->wireMap[currWireIndex], this->wireMap[nextWireIndex]}); + findFinalSwaps(nextWireIndex, finalSwaps); return; } std::vector> getFinalPermuteSwaps() { std::vector> finalSwaps; - for (auto it = this->wireMap.begin(); it != this->wireMap.end(); ++it) - { - while(true) - { + for (auto it = this->wireMap.begin(); it != this->wireMap.end(); ++it) { + while (true) { findFinalSwaps(this->wireMap[it->first], &finalSwaps); - if (this->wireMap[it->first] == this->wireMap[it->second] ) + if (this->wireMap[it->first] == this->wireMap[it->second]) break; } } - return finalSwaps; + return finalSwaps; } ~RoutingPass() = default; diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index 664db7b8c4..28c24e4430 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -536,11 +536,9 @@ void __catalyst__qis__PCPhase(double theta, double dim, const Modifiers *modifie wires[i] = va_arg(args, QubitIdType); } va_end(args); - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { - for (int64_t i = 0; i < numQubits; i++) - wires[i] = RTD_PTR->getRuntimeRouter()->getMappedWire(wires[i]); - } + RT_FAIL_IF(RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr, + "Only single and two-qubit gates are supported when compiling to a given hardware " + "coupling map."); getQuantumDevicePtr()->NamedOperation("PCPhase", {theta, dim}, wires, /* modifiers */ MODIFIERS_ARGS(modifiers)); } @@ -576,8 +574,7 @@ void __catalyst__qis__Identity(const Modifiers *modifiers, int64_t numQubits, .. wires[i] = va_arg(args, QubitIdType); } va_end(args); - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { for (int64_t i = 0; i < numQubits; i++) wires[i] = RTD_PTR->getRuntimeRouter()->getMappedWire(wires[i]); } @@ -587,156 +584,156 @@ void __catalyst__qis__Identity(const Modifiers *modifiers, int64_t numQubits, .. void __catalyst__qis__PauliX(QUBIT *qubit, const Modifiers *modifiers) { - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { - QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + QubitIdType mapped_wire = + RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); getQuantumDevicePtr()->NamedOperation("PauliX", {}, {mapped_wire}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } else { getQuantumDevicePtr()->NamedOperation("PauliX", {}, {reinterpret_cast(qubit)}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } } void __catalyst__qis__PauliY(QUBIT *qubit, const Modifiers *modifiers) { - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { - QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + QubitIdType mapped_wire = + RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); getQuantumDevicePtr()->NamedOperation("PauliY", {}, {mapped_wire}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } else { getQuantumDevicePtr()->NamedOperation("PauliY", {}, {reinterpret_cast(qubit)}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } } void __catalyst__qis__PauliZ(QUBIT *qubit, const Modifiers *modifiers) { - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { - QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + QubitIdType mapped_wire = + RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); getQuantumDevicePtr()->NamedOperation("PauliZ", {}, {mapped_wire}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } else { getQuantumDevicePtr()->NamedOperation("PauliZ", {}, {reinterpret_cast(qubit)}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } } void __catalyst__qis__Hadamard(QUBIT *qubit, const Modifiers *modifiers) { - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { - QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + QubitIdType mapped_wire = + RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); getQuantumDevicePtr()->NamedOperation("Hadamard", {}, {mapped_wire}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } else { - getQuantumDevicePtr()->NamedOperation("Hadamard", {}, {reinterpret_cast(qubit)}, - MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation( + "Hadamard", {}, {reinterpret_cast(qubit)}, MODIFIERS_ARGS(modifiers)); } } void __catalyst__qis__S(QUBIT *qubit, const Modifiers *modifiers) { - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { - QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); - getQuantumDevicePtr()->NamedOperation("S", {}, {mapped_wire}, - MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + QubitIdType mapped_wire = + RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + getQuantumDevicePtr()->NamedOperation("S", {}, {mapped_wire}, MODIFIERS_ARGS(modifiers)); } else { getQuantumDevicePtr()->NamedOperation("S", {}, {reinterpret_cast(qubit)}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } } void __catalyst__qis__T(QUBIT *qubit, const Modifiers *modifiers) { - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { - QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); - getQuantumDevicePtr()->NamedOperation("T", {}, {mapped_wire}, - MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + QubitIdType mapped_wire = + RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + getQuantumDevicePtr()->NamedOperation("T", {}, {mapped_wire}, MODIFIERS_ARGS(modifiers)); } else { getQuantumDevicePtr()->NamedOperation("T", {}, {reinterpret_cast(qubit)}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } } void __catalyst__qis__PhaseShift(double theta, QUBIT *qubit, const Modifiers *modifiers) { - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { - QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + QubitIdType mapped_wire = + RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); getQuantumDevicePtr()->NamedOperation("PhaseShift", {theta}, {mapped_wire}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } else { - getQuantumDevicePtr()->NamedOperation("PhaseShift", {theta}, {reinterpret_cast(qubit)}, - MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("PhaseShift", {theta}, + {reinterpret_cast(qubit)}, + MODIFIERS_ARGS(modifiers)); } } void __catalyst__qis__RX(double theta, QUBIT *qubit, const Modifiers *modifiers) { - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { - QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + QubitIdType mapped_wire = + RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); getQuantumDevicePtr()->NamedOperation("RX", {theta}, {mapped_wire}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } else { getQuantumDevicePtr()->NamedOperation("RX", {theta}, {reinterpret_cast(qubit)}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } } void __catalyst__qis__RY(double theta, QUBIT *qubit, const Modifiers *modifiers) { - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { - QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + QubitIdType mapped_wire = + RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); getQuantumDevicePtr()->NamedOperation("RY", {theta}, {mapped_wire}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } else { getQuantumDevicePtr()->NamedOperation("RY", {theta}, {reinterpret_cast(qubit)}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } } void __catalyst__qis__RZ(double theta, QUBIT *qubit, const Modifiers *modifiers) { - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { - QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + QubitIdType mapped_wire = + RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); getQuantumDevicePtr()->NamedOperation("RZ", {theta}, {mapped_wire}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } else { getQuantumDevicePtr()->NamedOperation("RZ", {theta}, {reinterpret_cast(qubit)}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } } void __catalyst__qis__Rot(double phi, double theta, double omega, QUBIT *qubit, const Modifiers *modifiers) { - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) - { - QubitIdType mapped_wire = RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + QubitIdType mapped_wire = + RTD_PTR->getRuntimeRouter()->getMappedWire(reinterpret_cast(qubit)); getQuantumDevicePtr()->NamedOperation("Rot", {phi, theta, omega}, {mapped_wire}, - MODIFIERS_ARGS(modifiers)); + MODIFIERS_ARGS(modifiers)); } else { - getQuantumDevicePtr()->NamedOperation("Rot", {phi, theta, omega}, {reinterpret_cast(qubit)}, - MODIFIERS_ARGS(modifiers)); + getQuantumDevicePtr()->NamedOperation("Rot", {phi, theta, omega}, + {reinterpret_cast(qubit)}, + MODIFIERS_ARGS(modifiers)); } } @@ -1014,10 +1011,31 @@ void __catalyst__qis__SingleExcitation(double phi, QUBIT *wire0, QUBIT *wire1, { RT_FAIL_IF(wire0 == wire1, "Invalid input for SingleExcitation gate. All two qubit operands must be distinct."); - getQuantumDevicePtr()->NamedOperation( - "SingleExcitation", {phi}, - {reinterpret_cast(wire0), reinterpret_cast(wire1)}, - MODIFIERS_ARGS(modifiers)); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::tuple> resultTuple = + RTD_PTR->getRuntimeRouter()->getRoutedQubits(wire0, wire1); + QubitIdType routedQubitFirst = std::get<0>(resultTuple); + QubitIdType routedQubitSecond = std::get<1>(resultTuple); + std::vector swapPath = std::get<2>(resultTuple); + + if (swapPath.size() > 0) { + for (auto i = 1; i < swapPath.size() - 1; i++) { + QubitIdType u = swapPath[i - 1]; + QubitIdType v = swapPath[i]; + RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {u, v}, + MODIFIERS_ARGS(modifiers)); + } + } + getQuantumDevicePtr()->NamedOperation("SingleExcitation", {phi}, + {routedQubitFirst, routedQubitSecond}, + MODIFIERS_ARGS(modifiers)); + } + else { + getQuantumDevicePtr()->NamedOperation( + "SingleExcitation", {phi}, + {reinterpret_cast(wire0), reinterpret_cast(wire1)}, + MODIFIERS_ARGS(modifiers)); + } } void __catalyst__qis__DoubleExcitation(double phi, QUBIT *wire0, QUBIT *wire1, QUBIT *wire2, @@ -1027,6 +1045,9 @@ void __catalyst__qis__DoubleExcitation(double phi, QUBIT *wire0, QUBIT *wire1, Q (wire0 == wire1 || wire0 == wire2 || wire0 == wire3 || wire1 == wire2 || wire1 == wire3 || wire2 == wire3), "Invalid input for DoubleExcitation gate. All four qubit operands must be distinct."); + RT_FAIL_IF(RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr, + "Only single and two-qubit gates are supported when compiling to a given hardware " + "coupling map."); getQuantumDevicePtr()->NamedOperation( "DoubleExcitation", {phi}, {reinterpret_cast(wire0), reinterpret_cast(wire1), @@ -1238,8 +1259,9 @@ void __catalyst__qis__CSWAP(QUBIT *control, QUBIT *aswap, QUBIT *bswap, const Mo { RT_FAIL_IF((control == aswap || aswap == bswap || control == bswap), "Invalid input for CSWAP gate. Control and target qubit operands must be distinct."); - RT_FAIL_IF((control == aswap || aswap == bswap || control == bswap), - "Invalid input for CSWAP gate. Control and target qubit operands must be distinct."); + RT_FAIL_IF(RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr, + "Only single and two-qubit gates are supported when compiling to a given hardware " + "coupling map."); getQuantumDevicePtr()->NamedOperation("CSWAP", {}, {reinterpret_cast(control), reinterpret_cast(aswap), @@ -1251,8 +1273,9 @@ void __catalyst__qis__Toffoli(QUBIT *wire0, QUBIT *wire1, QUBIT *wire2, const Mo { RT_FAIL_IF((wire0 == wire1 || wire1 == wire2 || wire0 == wire2), "Invalid input for Toffoli gate. All three qubit operands must be distinct."); - RT_FAIL_IF((wire0 == wire1 || wire1 == wire2 || wire0 == wire2), - "Invalid input for Toffoli gate. All three qubit operands must be distinct."); + RT_FAIL_IF(RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr, + "Only single and two-qubit gates are supported when compiling to a given hardware " + "coupling map."); getQuantumDevicePtr()->NamedOperation("Toffoli", {}, {reinterpret_cast(wire0), reinterpret_cast(wire1), @@ -1263,6 +1286,9 @@ void __catalyst__qis__Toffoli(QUBIT *wire0, QUBIT *wire1, QUBIT *wire2, const Mo void __catalyst__qis__MultiRZ(double theta, const Modifiers *modifiers, int64_t numQubits, ...) { RT_ASSERT(numQubits >= 0); + RT_FAIL_IF(RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr, + "Only single and two-qubit gates are supported when compiling to a given hardware " + "coupling map."); va_list args; va_start(args, numQubits); @@ -1378,6 +1404,10 @@ void __catalyst__qis__QubitUnitary(MemRefT_CplxT_double_2d *matrix, const Modifi RT_FAIL("Invalid number of wires"); } + RT_FAIL_IF(RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr, + "Only single and two-qubit gates are supported when compiling to a given hardware " + "coupling map."); + va_list args; std::vector> coeffs; std::vector wires; @@ -1401,6 +1431,10 @@ ObsIdType __catalyst__qis__HermitianObs(MemRefT_CplxT_double_2d *matrix, int64_t RT_FAIL("The Hermitian matrix must be initialized"); } + RT_FAIL_IF(RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr, + "Only single and two-qubit gates are supported when compiling to a given hardware " + "coupling map."); + const size_t num_rows = matrix->sizes[0]; const size_t num_col = matrix->sizes[1]; const size_t expected_size = std::pow(2, numQubits); @@ -1460,6 +1494,10 @@ ObsIdType __catalyst__qis__HamiltonianObs(MemRefT_double_1d *coeffs, int64_t num "The coefficients list must be initialized."); } + RT_FAIL_IF(RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr, + "Only single and two-qubit gates are supported when compiling to a given hardware " + "coupling map."); + const size_t coeffs_size = coeffs->sizes[0]; if (static_cast(numObs) != coeffs_size) { @@ -1514,9 +1552,11 @@ void __catalyst__qis__State(MemRefT_CplxT_double_1d *result, int64_t numQubits, if (wires.empty()) { if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { - std::vector> finalSwaps = RTD_PTR->getRuntimeRouter()->getFinalPermuteSwaps(); + std::vector> finalSwaps = + RTD_PTR->getRuntimeRouter()->getFinalPermuteSwaps(); for (auto i = 0; i < finalSwaps.size(); i++) { - RTD_PTR->getQuantumDevicePtr()->NamedOperation("SWAP", {}, {std::get<0>(finalSwaps[i]), std::get<1>(finalSwaps[i])}); + RTD_PTR->getQuantumDevicePtr()->NamedOperation( + "SWAP", {}, {std::get<0>(finalSwaps[i]), std::get<1>(finalSwaps[i])}); } } getQuantumDevicePtr()->State(view); From b52cfbbdce58c7fe354159196435dc231e19f6bd Mon Sep 17 00:00:00 2001 From: Ritu Thombre Date: Sun, 12 Oct 2025 23:57:27 -0700 Subject: [PATCH 26/29] integration tests --- frontend/test/pytest/test_routing.py | 113 +++++++++++++++++++++++++++ runtime/lib/capi/RuntimeCAPI.cpp | 55 ++++++++++++- 2 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 frontend/test/pytest/test_routing.py diff --git a/frontend/test/pytest/test_routing.py b/frontend/test/pytest/test_routing.py new file mode 100644 index 0000000000..8dee7fb954 --- /dev/null +++ b/frontend/test/pytest/test_routing.py @@ -0,0 +1,113 @@ +# Copyright 2025 Xanadu Quantum Technologies Inc. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Integration tests for routing at runtime""" + +from functools import partial + +import pytest + +import pennylane as qml +from pennylane import numpy as np +from pennylane.transforms.transpile import transpile + + +def qfunc_ops(wires, x, y, z): + qml.Hadamard(wires=wires[0]) + qml.RZ(z, wires=wires[2]) + qml.CNOT(wires=[wires[2], wires[0]]) + qml.CNOT(wires=[wires[1], wires[0]]) + qml.RX(x, wires=wires[0]) + qml.CNOT(wires=[wires[0], wires[2]]) + qml.RZ(-z, wires=wires[2]) + qml.RX(y, wires=wires[0]) + qml.PauliY(wires=wires[2]) + qml.CY(wires=[wires[1], wires[2]]) + + +# pylint: disable=too-many-public-methods +class TestRouting: + """Unit tests for testing routing function at runtime""" + + all_to__all_device = qml.device("lightning.qubit") + linear_device = qml.device("lightning.qubit", wires = [(0,1),(1,2)]) + + input_devices = ( + (all_to__all_device, linear_device), + ) + @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) + def test_state_invariance_under_routing(self,all_to__all_device, linear_device): + def circuit(wires, x, y, z): + qfunc_ops(wires, x, y, z) + return qml.state() + + all_to_all_qnode = qml.qjit(qml.QNode(circuit, all_to__all_device)) + linear_qnode = qml.qjit(qml.QNode(circuit, linear_device)) + + assert np.allclose(all_to_all_qnode([0,1,2], 0.1, 0.2, 0.3), linear_qnode([0,1,2], 0.1, 0.2, 0.3)) + + @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) + def test_probs_invariance_under_routing(self,all_to__all_device, linear_device): + def circuit(wires, x, y, z): + qfunc_ops(wires, x, y, z) + return qml.probs() + + all_to_all_qnode = qml.qjit(qml.QNode(circuit, all_to__all_device)) + linear_qnode = qml.qjit(qml.QNode(circuit, linear_device)) + + assert np.allclose(all_to_all_qnode([0,1,2], 0.1, 0.2, 0.3), linear_qnode([0,1,2], 0.1, 0.2, 0.3)) + + @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) + def test_sample_invariance_under_routing(self,all_to__all_device, linear_device): + def circuit(wires, x, y, z): + qfunc_ops(wires, x, y, z) + return qml.sample() + + all_to_all_qnode = qml.qjit( + partial(qml.set_shots, shots=10)(qml.QNode(circuit, all_to__all_device)), + seed=37 + ) + linear_qnode = qml.qjit( + partial(qml.set_shots, shots=10)(qml.QNode(circuit, linear_device)), + seed=37 + ) + assert np.allclose(all_to_all_qnode([0,1,2], 0.1, 0.2, 0.3), linear_qnode([0,1,2], 0.1, 0.2, 0.3)) + + @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) + def test_counts_invariance_under_routing(self,all_to__all_device, linear_device): + def circuit(wires, x, y, z): + qfunc_ops(wires, x, y, z) + return qml.counts() + + all_to_all_qnode = qml.qjit( + partial(qml.set_shots, shots=10)(qml.QNode(circuit, all_to__all_device)), + seed=37 + ) + linear_qnode = qml.qjit( + partial(qml.set_shots, shots=10)(qml.QNode(circuit, linear_device)), + seed=37 + ) + assert np.allclose(all_to_all_qnode([0,1,2], 0.1, 0.2, 0.3), linear_qnode([0,1,2], 0.1, 0.2, 0.3)) + + @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) + def test_expvals_invariance_under_routing(self,all_to__all_device, linear_device): + def circuit(wires, x, y, z): + qfunc_ops(wires, x, y, z) + return qml.expval(qml.X(0) @ qml.Y(1)), qml.var(qml.Z(2)) + + all_to_all_qnode = qml.qjit(qml.QNode(circuit, all_to__all_device)) + linear_qnode = qml.qjit(qml.QNode(circuit, linear_device)) + assert np.allclose(all_to_all_qnode([0,1,2], 0.1, 0.2, 0.3), linear_qnode([0,1,2], 0.1, 0.2, 0.3)) + + \ No newline at end of file diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index 28c24e4430..0d408cfbbc 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -1527,12 +1527,37 @@ RESULT *__catalyst__qis__Measure(QUBIT *wire, int32_t postselect) if (postselect != 0 && postselect != 1) { postselectOpt = std::nullopt; } - return getQuantumDevicePtr()->Measure(reinterpret_cast(wire), postselectOpt); + QubitIdType mappedWire = reinterpret_cast(wire); + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + mappedWire = RTD_PTR->getRuntimeRouter()->getMappedWire(mappedWire); + return getQuantumDevicePtr()->Measure(mappedWire, postselectOpt); } -double __catalyst__qis__Expval(ObsIdType obsKey) { return getQuantumDevicePtr()->Expval(obsKey); } +double __catalyst__qis__Expval(ObsIdType obsKey) +{ + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::vector> finalSwaps = + RTD_PTR->getRuntimeRouter()->getFinalPermuteSwaps(); + for (auto i = 0; i < finalSwaps.size(); i++) { + RTD_PTR->getQuantumDevicePtr()->NamedOperation( + "SWAP", {}, {std::get<0>(finalSwaps[i]), std::get<1>(finalSwaps[i])}); + } + } + return getQuantumDevicePtr()->Expval(obsKey); +} -double __catalyst__qis__Variance(ObsIdType obsKey) { return getQuantumDevicePtr()->Var(obsKey); } +double __catalyst__qis__Variance(ObsIdType obsKey) +{ + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::vector> finalSwaps = + RTD_PTR->getRuntimeRouter()->getFinalPermuteSwaps(); + for (auto i = 0; i < finalSwaps.size(); i++) { + RTD_PTR->getQuantumDevicePtr()->NamedOperation( + "SWAP", {}, {std::get<0>(finalSwaps[i]), std::get<1>(finalSwaps[i])}); + } + } + return getQuantumDevicePtr()->Var(obsKey); +} void __catalyst__qis__State(MemRefT_CplxT_double_1d *result, int64_t numQubits, ...) { @@ -1588,6 +1613,14 @@ void __catalyst__qis__Probs(MemRefT_double_1d *result, int64_t numQubits, ...) result_p->strides); if (wires.empty()) { + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::vector> finalSwaps = + RTD_PTR->getRuntimeRouter()->getFinalPermuteSwaps(); + for (auto i = 0; i < finalSwaps.size(); i++) { + RTD_PTR->getQuantumDevicePtr()->NamedOperation( + "SWAP", {}, {std::get<0>(finalSwaps[i]), std::get<1>(finalSwaps[i])}); + } + } getQuantumDevicePtr()->Probs(view); } else { @@ -1619,6 +1652,14 @@ void __catalyst__qis__Sample(MemRefT_double_2d *result, int64_t numQubits, ...) result_p->strides); if (wires.empty()) { + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::vector> finalSwaps = + RTD_PTR->getRuntimeRouter()->getFinalPermuteSwaps(); + for (auto i = 0; i < finalSwaps.size(); i++) { + RTD_PTR->getQuantumDevicePtr()->NamedOperation( + "SWAP", {}, {std::get<0>(finalSwaps[i]), std::get<1>(finalSwaps[i])}); + } + } getQuantumDevicePtr()->Sample(view); } else { @@ -1652,6 +1693,14 @@ void __catalyst__qis__Counts(PairT_MemRefT_double_int64_1d *result, int64_t numQ result_counts_p->sizes, result_counts_p->strides); if (wires.empty()) { + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { + std::vector> finalSwaps = + RTD_PTR->getRuntimeRouter()->getFinalPermuteSwaps(); + for (auto i = 0; i < finalSwaps.size(); i++) { + RTD_PTR->getQuantumDevicePtr()->NamedOperation( + "SWAP", {}, {std::get<0>(finalSwaps[i]), std::get<1>(finalSwaps[i])}); + } + } getQuantumDevicePtr()->Counts(eigvals_view, counts_view); } else { From d40f0de257d12f07eafa60c320267b0b7bfda8aa Mon Sep 17 00:00:00 2001 From: Ritu Thombre Date: Mon, 13 Oct 2025 00:14:37 -0700 Subject: [PATCH 27/29] fix format --- frontend/test/pytest/test_routing.py | 76 ++++++++++++++-------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/frontend/test/pytest/test_routing.py b/frontend/test/pytest/test_routing.py index 8dee7fb954..a7eb9615b3 100644 --- a/frontend/test/pytest/test_routing.py +++ b/frontend/test/pytest/test_routing.py @@ -16,9 +16,8 @@ from functools import partial -import pytest - import pennylane as qml +import pytest from pennylane import numpy as np from pennylane.transforms.transpile import transpile @@ -39,75 +38,78 @@ def qfunc_ops(wires, x, y, z): # pylint: disable=too-many-public-methods class TestRouting: """Unit tests for testing routing function at runtime""" - + all_to__all_device = qml.device("lightning.qubit") - linear_device = qml.device("lightning.qubit", wires = [(0,1),(1,2)]) + linear_device = qml.device("lightning.qubit", wires=[(0, 1), (1, 2)]) + + input_devices = ((all_to__all_device, linear_device),) - input_devices = ( - (all_to__all_device, linear_device), - ) @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) - def test_state_invariance_under_routing(self,all_to__all_device, linear_device): + def test_state_invariance_under_routing(self, all_to__all_device, linear_device): def circuit(wires, x, y, z): qfunc_ops(wires, x, y, z) return qml.state() - + all_to_all_qnode = qml.qjit(qml.QNode(circuit, all_to__all_device)) linear_qnode = qml.qjit(qml.QNode(circuit, linear_device)) - assert np.allclose(all_to_all_qnode([0,1,2], 0.1, 0.2, 0.3), linear_qnode([0,1,2], 0.1, 0.2, 0.3)) + assert np.allclose( + all_to_all_qnode([0, 1, 2], 0.1, 0.2, 0.3), linear_qnode([0, 1, 2], 0.1, 0.2, 0.3) + ) @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) - def test_probs_invariance_under_routing(self,all_to__all_device, linear_device): + def test_probs_invariance_under_routing(self, all_to__all_device, linear_device): def circuit(wires, x, y, z): qfunc_ops(wires, x, y, z) return qml.probs() - + all_to_all_qnode = qml.qjit(qml.QNode(circuit, all_to__all_device)) linear_qnode = qml.qjit(qml.QNode(circuit, linear_device)) - assert np.allclose(all_to_all_qnode([0,1,2], 0.1, 0.2, 0.3), linear_qnode([0,1,2], 0.1, 0.2, 0.3)) + assert np.allclose( + all_to_all_qnode([0, 1, 2], 0.1, 0.2, 0.3), linear_qnode([0, 1, 2], 0.1, 0.2, 0.3) + ) @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) - def test_sample_invariance_under_routing(self,all_to__all_device, linear_device): + def test_sample_invariance_under_routing(self, all_to__all_device, linear_device): def circuit(wires, x, y, z): qfunc_ops(wires, x, y, z) return qml.sample() - + all_to_all_qnode = qml.qjit( - partial(qml.set_shots, shots=10)(qml.QNode(circuit, all_to__all_device)), - seed=37 - ) + partial(qml.set_shots, shots=10)(qml.QNode(circuit, all_to__all_device)), seed=37 + ) linear_qnode = qml.qjit( - partial(qml.set_shots, shots=10)(qml.QNode(circuit, linear_device)), - seed=37 - ) - assert np.allclose(all_to_all_qnode([0,1,2], 0.1, 0.2, 0.3), linear_qnode([0,1,2], 0.1, 0.2, 0.3)) + partial(qml.set_shots, shots=10)(qml.QNode(circuit, linear_device)), seed=37 + ) + assert np.allclose( + all_to_all_qnode([0, 1, 2], 0.1, 0.2, 0.3), linear_qnode([0, 1, 2], 0.1, 0.2, 0.3) + ) @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) - def test_counts_invariance_under_routing(self,all_to__all_device, linear_device): + def test_counts_invariance_under_routing(self, all_to__all_device, linear_device): def circuit(wires, x, y, z): qfunc_ops(wires, x, y, z) return qml.counts() - + all_to_all_qnode = qml.qjit( - partial(qml.set_shots, shots=10)(qml.QNode(circuit, all_to__all_device)), - seed=37 - ) + partial(qml.set_shots, shots=10)(qml.QNode(circuit, all_to__all_device)), seed=37 + ) linear_qnode = qml.qjit( - partial(qml.set_shots, shots=10)(qml.QNode(circuit, linear_device)), - seed=37 - ) - assert np.allclose(all_to_all_qnode([0,1,2], 0.1, 0.2, 0.3), linear_qnode([0,1,2], 0.1, 0.2, 0.3)) - + partial(qml.set_shots, shots=10)(qml.QNode(circuit, linear_device)), seed=37 + ) + assert np.allclose( + all_to_all_qnode([0, 1, 2], 0.1, 0.2, 0.3), linear_qnode([0, 1, 2], 0.1, 0.2, 0.3) + ) + @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) - def test_expvals_invariance_under_routing(self,all_to__all_device, linear_device): + def test_expvals_invariance_under_routing(self, all_to__all_device, linear_device): def circuit(wires, x, y, z): qfunc_ops(wires, x, y, z) return qml.expval(qml.X(0) @ qml.Y(1)), qml.var(qml.Z(2)) - + all_to_all_qnode = qml.qjit(qml.QNode(circuit, all_to__all_device)) linear_qnode = qml.qjit(qml.QNode(circuit, linear_device)) - assert np.allclose(all_to_all_qnode([0,1,2], 0.1, 0.2, 0.3), linear_qnode([0,1,2], 0.1, 0.2, 0.3)) - - \ No newline at end of file + assert np.allclose( + all_to_all_qnode([0, 1, 2], 0.1, 0.2, 0.3), linear_qnode([0, 1, 2], 0.1, 0.2, 0.3) + ) From cd9ca02fb259a8e08a3e3edc50738c0781d94a5f Mon Sep 17 00:00:00 2001 From: Ritu Thombre Date: Mon, 13 Oct 2025 00:18:58 -0700 Subject: [PATCH 28/29] fix format --- runtime/lib/capi/RuntimeCAPI.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/runtime/lib/capi/RuntimeCAPI.cpp b/runtime/lib/capi/RuntimeCAPI.cpp index 0d408cfbbc..d9ddecb4f1 100644 --- a/runtime/lib/capi/RuntimeCAPI.cpp +++ b/runtime/lib/capi/RuntimeCAPI.cpp @@ -1528,13 +1528,13 @@ RESULT *__catalyst__qis__Measure(QUBIT *wire, int32_t postselect) postselectOpt = std::nullopt; } QubitIdType mappedWire = reinterpret_cast(wire); - if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) + if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) mappedWire = RTD_PTR->getRuntimeRouter()->getMappedWire(mappedWire); return getQuantumDevicePtr()->Measure(mappedWire, postselectOpt); } -double __catalyst__qis__Expval(ObsIdType obsKey) -{ +double __catalyst__qis__Expval(ObsIdType obsKey) +{ if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { std::vector> finalSwaps = RTD_PTR->getRuntimeRouter()->getFinalPermuteSwaps(); @@ -1543,11 +1543,11 @@ double __catalyst__qis__Expval(ObsIdType obsKey) "SWAP", {}, {std::get<0>(finalSwaps[i]), std::get<1>(finalSwaps[i])}); } } - return getQuantumDevicePtr()->Expval(obsKey); + return getQuantumDevicePtr()->Expval(obsKey); } -double __catalyst__qis__Variance(ObsIdType obsKey) -{ +double __catalyst__qis__Variance(ObsIdType obsKey) +{ if (RTD_PTR != nullptr && RTD_PTR->getRuntimeRouter() != nullptr) { std::vector> finalSwaps = RTD_PTR->getRuntimeRouter()->getFinalPermuteSwaps(); @@ -1556,7 +1556,7 @@ double __catalyst__qis__Variance(ObsIdType obsKey) "SWAP", {}, {std::get<0>(finalSwaps[i]), std::get<1>(finalSwaps[i])}); } } - return getQuantumDevicePtr()->Var(obsKey); + return getQuantumDevicePtr()->Var(obsKey); } void __catalyst__qis__State(MemRefT_CplxT_double_1d *result, int64_t numQubits, ...) From dbc635a8f5422f00e7b04b7cbf659f0c45ba4314 Mon Sep 17 00:00:00 2001 From: Ritu Thombre Date: Mon, 13 Oct 2025 01:17:39 -0700 Subject: [PATCH 29/29] docstring in tests --- frontend/test/pytest/test_routing.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/test/pytest/test_routing.py b/frontend/test/pytest/test_routing.py index a7eb9615b3..82cc3165c1 100644 --- a/frontend/test/pytest/test_routing.py +++ b/frontend/test/pytest/test_routing.py @@ -46,6 +46,7 @@ class TestRouting: @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) def test_state_invariance_under_routing(self, all_to__all_device, linear_device): + """test that transpile does not alter output for state measurement""" def circuit(wires, x, y, z): qfunc_ops(wires, x, y, z) return qml.state() @@ -59,6 +60,7 @@ def circuit(wires, x, y, z): @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) def test_probs_invariance_under_routing(self, all_to__all_device, linear_device): + """test that transpile does not alter output for probs measurement""" def circuit(wires, x, y, z): qfunc_ops(wires, x, y, z) return qml.probs() @@ -72,6 +74,7 @@ def circuit(wires, x, y, z): @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) def test_sample_invariance_under_routing(self, all_to__all_device, linear_device): + """test that transpile does not alter output for sample measurement""" def circuit(wires, x, y, z): qfunc_ops(wires, x, y, z) return qml.sample() @@ -88,6 +91,7 @@ def circuit(wires, x, y, z): @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) def test_counts_invariance_under_routing(self, all_to__all_device, linear_device): + """test that transpile does not alter output for counts measurement""" def circuit(wires, x, y, z): qfunc_ops(wires, x, y, z) return qml.counts() @@ -104,6 +108,7 @@ def circuit(wires, x, y, z): @pytest.mark.parametrize("all_to__all_device, linear_device", input_devices) def test_expvals_invariance_under_routing(self, all_to__all_device, linear_device): + """test that transpile does not alter output for expectation value measurement""" def circuit(wires, x, y, z): qfunc_ops(wires, x, y, z) return qml.expval(qml.X(0) @ qml.Y(1)), qml.var(qml.Z(2))