@@ -49,6 +49,53 @@ void identityPlacement(Placement &placement) {
4949 placement.map (Placement::VirtualQ (i), Placement::DeviceQ (i));
5050}
5151
52+ // / Place circuit qubits on the most centrally-connected device positions using
53+ // / BFS from the highest-degree node. Remaining device qubits receive auxiliary
54+ // / virtual qubits in BFS order.
55+ void bfsPlacement (Placement &placement, const Device &device) {
56+ unsigned numDeviceQubits = device.getNumQubits ();
57+ if (numDeviceQubits == 0 )
58+ return ;
59+
60+ // Find the highest-degree node (tie-break: lowest index).
61+ unsigned bestNode = 0 ;
62+ unsigned bestDegree = 0 ;
63+ for (unsigned i = 0 ; i < numDeviceQubits; ++i) {
64+ unsigned degree = device.getNeighbours (Device::Qubit (i)).size ();
65+ if (degree > bestDegree) {
66+ bestDegree = degree;
67+ bestNode = i;
68+ }
69+ }
70+
71+ // BFS from bestNode to produce a device-qubit ordering.
72+ SmallVector<unsigned > bfsOrder;
73+ bfsOrder.reserve (numDeviceQubits);
74+ SmallVector<bool > visited (numDeviceQubits, false );
75+ SmallVector<unsigned > queue;
76+ queue.push_back (bestNode);
77+ visited[bestNode] = true ;
78+ while (!queue.empty ()) {
79+ SmallVector<unsigned > nextQueue;
80+ for (unsigned node : queue) {
81+ bfsOrder.push_back (node);
82+ for (auto neighbor : device.getNeighbours (Device::Qubit (node))) {
83+ if (!visited[neighbor.index ]) {
84+ visited[neighbor.index ] = true ;
85+ nextQueue.push_back (neighbor.index );
86+ }
87+ }
88+ }
89+ queue = std::move (nextQueue);
90+ }
91+
92+ // Assign virtual qubits to physical qubits in BFS order.
93+ for (unsigned v = 0 , end = placement.getNumVirtualQubits (); v < end; ++v) {
94+ unsigned p = (v < bfsOrder.size ()) ? bfsOrder[v] : v;
95+ placement.map (Placement::VirtualQ (v), Placement::DeviceQ (p));
96+ }
97+ }
98+
5299// ===----------------------------------------------------------------------===//
53100// Routing
54101// ===----------------------------------------------------------------------===//
@@ -843,6 +890,13 @@ struct MappingFunc : public cudaq::opt::impl::MappingFuncBase<MappingFunc> {
843890 return WalkResult::advance ();
844891 });
845892
893+ // Count circuit qubits (user-provided, not auxiliary) before creating
894+ // auxiliary wires.
895+ unsigned numCircuitQubits = 0 ;
896+ for (auto &s : sources)
897+ if (s)
898+ ++numCircuitQubits;
899+
846900 // Create or borrow auxillary qubits if needed. Place them after the last
847901 // allocated qubit.
848902 builder.setInsertionPointAfter (lastSource);
@@ -856,11 +910,19 @@ struct MappingFunc : public cudaq::opt::impl::MappingFuncBase<MappingFunc> {
856910 }
857911
858912 // Place
859- Placement placement (sources.size (), deviceInstance->getNumQubits ());
860- identityPlacement (placement);
913+ Placement qPlacement (sources.size (), deviceInstance->getNumQubits ());
914+ if (placement == " identity" ) {
915+ identityPlacement (qPlacement);
916+ } else if (placement == " bfs" ) {
917+ bfsPlacement (qPlacement, *deviceInstance);
918+ } else {
919+ func.emitWarning (" Unknown placement strategy '" + placement +
920+ " ', defaulting to bfs" );
921+ bfsPlacement (qPlacement, *deviceInstance);
922+ }
861923
862924 // Route
863- SabreRouter router (*deviceInstance, wireToVirtualQ, placement ,
925+ SabreRouter router (*deviceInstance, wireToVirtualQ, qPlacement ,
864926 extendedLayerSize, extendedLayerWeight, decayDelta,
865927 roundsDecayReset);
866928 router.route (*blocks.begin (), sources);
@@ -902,7 +964,7 @@ struct MappingFunc : public cudaq::opt::impl::MappingFuncBase<MappingFunc> {
902964 for (unsigned int v = 0 ; v < *highestIdentity + 1 ; v++)
903965 attrs[v] =
904966 IntegerAttr::get (builder.getIntegerType (64 ),
905- placement .getPhy (Placement::VirtualQ (v)).index );
967+ qPlacement .getPhy (Placement::VirtualQ (v)).index );
906968
907969 func->setAttr (" mapping_v2p" , builder.getArrayAttr (attrs));
908970
@@ -919,7 +981,7 @@ struct MappingFunc : public cudaq::opt::impl::MappingFuncBase<MappingFunc> {
919981 measuredQubits.reserve (userQubitsMeasured.size ());
920982 for (auto mq : userQubitsMeasured) {
921983 measuredQubits.emplace_back (
922- mq, placement .getPhy (Placement::VirtualQ (mq)).index );
984+ mq, qPlacement .getPhy (Placement::VirtualQ (mq)).index );
923985 }
924986 // First sort the pairs according to the physical qubits.
925987 llvm::sort (measuredQubits,
@@ -961,6 +1023,7 @@ struct MappingPipelineOptions
9611023 DECLARE_SUB_OPTION (MappingFuncOptions, extendedLayerWeight);
9621024 DECLARE_SUB_OPTION (MappingFuncOptions, decayDelta);
9631025 DECLARE_SUB_OPTION (MappingFuncOptions, roundsDecayReset);
1026+ DECLARE_SUB_OPTION (MappingFuncOptions, placement);
9641027 PassOptions::Option<bool > nonComposable{*this , " raise-fatal-errors" };
9651028};
9661029
@@ -989,6 +1052,7 @@ void registerMappingPipeline() {
9891052 setIt (funcOpts.decayDelta , opt.decayDelta );
9901053 setIt (funcOpts.roundsDecayReset , opt.roundsDecayReset );
9911054 setIt (funcOpts.nonComposable , opt.nonComposable );
1055+ setIt (funcOpts.placement , opt.placement );
9921056 pm.addNestedPass <func::FuncOp>(cudaq::opt::createMappingFunc (funcOpts));
9931057 });
9941058}
0 commit comments