1use crate::{QvmError, Result, Qubit, ClassicalBit, Topology};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct ResourceMapping {
10 pub qubit_mapping: Vec<usize>,
12 pub classical_mapping: Vec<usize>,
14 pub metadata: MappingMetadata,
16}
17
18#[derive(Debug, Clone, Default, Serialize, Deserialize)]
20pub struct MappingMetadata {
21 pub quality_score: f64,
23 pub swap_count: usize,
25 pub routing_overhead: f64,
27 pub properties: HashMap<String, String>,
29}
30
31#[derive(Debug, Clone)]
33pub struct QubitMapper {
34 topology: Topology,
35 config: MapperConfig,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct MapperConfig {
41 pub strategy: MappingStrategy,
43 pub enable_swaps: bool,
45 pub max_swap_overhead: f64,
47 pub prioritize_connectivity: bool,
49}
50
51impl Default for MapperConfig {
52 fn default() -> Self {
53 Self {
54 strategy: MappingStrategy::ConnectivityAware,
55 enable_swaps: true,
56 max_swap_overhead: 0.5,
57 prioritize_connectivity: true,
58 }
59 }
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
64pub enum MappingStrategy {
65 Linear,
67 Random,
69 ConnectivityAware,
71 DistanceMinimizing,
73 Adaptive,
75}
76
77impl QubitMapper {
78 pub fn new(topology: &Topology) -> Self {
80 Self {
81 topology: topology.clone(),
82 config: MapperConfig::default(),
83 }
84 }
85
86 pub fn create_classical_allocator(&self) -> ClassicalAllocator {
88 ClassicalAllocator::new(self.topology.qubit_count()) }
90
91 pub fn with_config(topology: &Topology, config: MapperConfig) -> Self {
93 Self {
94 topology: topology.clone(),
95 config,
96 }
97 }
98
99 pub fn create_mapping(
101 &self,
102 qubit_assignments: &[usize],
103 classical_assignments: &[usize],
104 ) -> Result<ResourceMapping> {
105 let quality_score = self.calculate_mapping_quality(qubit_assignments);
106
107 let metadata = MappingMetadata {
108 quality_score,
109 swap_count: 0, routing_overhead: 0.0,
111 properties: HashMap::new(),
112 };
113
114 Ok(ResourceMapping {
115 qubit_mapping: qubit_assignments.to_vec(),
116 classical_mapping: classical_assignments.to_vec(),
117 metadata,
118 })
119 }
120
121 pub fn find_optimal_mapping(
123 &self,
124 logical_qubits: usize,
125 connectivity_requirements: &[(usize, usize)],
126 ) -> Result<Vec<usize>> {
127 match self.config.strategy {
128 MappingStrategy::Linear => self.linear_mapping(logical_qubits),
129 MappingStrategy::Random => self.random_mapping(logical_qubits),
130 MappingStrategy::ConnectivityAware => {
131 self.connectivity_aware_mapping(logical_qubits, connectivity_requirements)
132 }
133 MappingStrategy::DistanceMinimizing => {
134 self.distance_minimizing_mapping(logical_qubits, connectivity_requirements)
135 }
136 MappingStrategy::Adaptive => {
137 self.adaptive_mapping(logical_qubits, connectivity_requirements)
138 }
139 }
140 }
141
142 fn linear_mapping(&self, logical_qubits: usize) -> Result<Vec<usize>> {
144 if logical_qubits > self.topology.qubit_count() {
145 return Err(QvmError::allocation_error(
146 "Not enough physical qubits available".to_string()
147 ));
148 }
149
150 Ok((0..logical_qubits).collect())
151 }
152
153 fn random_mapping(&self, logical_qubits: usize) -> Result<Vec<usize>> {
155 use std::collections::HashSet;
156
157 if logical_qubits > self.topology.qubit_count() {
158 return Err(QvmError::allocation_error(
159 "Not enough physical qubits available".to_string()
160 ));
161 }
162
163 let mut mapping = Vec::new();
164 let mut used_qubits = HashSet::new();
165
166 let mut seed = 12345u64;
168 for _ in 0..logical_qubits {
169 loop {
170 seed = (seed.wrapping_mul(1103515245).wrapping_add(12345)) & 0x7fffffff;
171 let physical_qubit = (seed as usize) % self.topology.qubit_count();
172
173 if !used_qubits.contains(&physical_qubit) {
174 mapping.push(physical_qubit);
175 used_qubits.insert(physical_qubit);
176 break;
177 }
178 }
179 }
180
181 Ok(mapping)
182 }
183
184 fn connectivity_aware_mapping(
186 &self,
187 logical_qubits: usize,
188 connectivity_requirements: &[(usize, usize)],
189 ) -> Result<Vec<usize>> {
190 if logical_qubits > self.topology.qubit_count() {
191 return Err(QvmError::allocation_error(
192 "Not enough physical qubits available".to_string()
193 ));
194 }
195
196 let mut mapping = (0..logical_qubits).collect::<Vec<_>>();
198
199 for &(logical1, logical2) in connectivity_requirements {
201 if logical1 >= logical_qubits || logical2 >= logical_qubits {
202 continue;
203 }
204
205 let physical1 = mapping[logical1];
206 let physical2 = mapping[logical2];
207
208 if !self.topology.are_connected(Qubit(physical1), Qubit(physical2)) {
210 if let Some(better_mapping) = self.find_connected_pair(logical1, logical2, &mapping) {
212 mapping = better_mapping;
213 }
214 }
215 }
216
217 Ok(mapping)
218 }
219
220 fn distance_minimizing_mapping(
222 &self,
223 logical_qubits: usize,
224 connectivity_requirements: &[(usize, usize)],
225 ) -> Result<Vec<usize>> {
226 if logical_qubits > self.topology.qubit_count() {
227 return Err(QvmError::allocation_error(
228 "Not enough physical qubits available".to_string()
229 ));
230 }
231
232 let mut mapping = vec![0; logical_qubits];
234 let mut used_physical = std::collections::HashSet::new();
235
236 let mut connectivity_count = vec![0; logical_qubits];
238 for &(q1, q2) in connectivity_requirements {
239 if q1 < logical_qubits { connectivity_count[q1] += 1; }
240 if q2 < logical_qubits { connectivity_count[q2] += 1; }
241 }
242
243 let mut qubit_order: Vec<_> = (0..logical_qubits).collect();
245 qubit_order.sort_by_key(|&q| std::cmp::Reverse(connectivity_count[q]));
246
247 let physical_centrality = self.calculate_centrality();
249 let mut physical_order: Vec<_> = (0..self.topology.qubit_count()).collect();
250 physical_order.sort_by(|&a, &b| {
251 physical_centrality[b].partial_cmp(&physical_centrality[a]).unwrap_or(std::cmp::Ordering::Equal)
252 });
253
254 for (i, &logical_qubit) in qubit_order.iter().enumerate() {
255 if i < physical_order.len() {
256 mapping[logical_qubit] = physical_order[i];
257 used_physical.insert(physical_order[i]);
258 }
259 }
260
261 Ok(mapping)
262 }
263
264 fn adaptive_mapping(
266 &self,
267 logical_qubits: usize,
268 connectivity_requirements: &[(usize, usize)],
269 ) -> Result<Vec<usize>> {
270 let connectivity_density = connectivity_requirements.len() as f64 / (logical_qubits * logical_qubits) as f64;
272
273 if connectivity_density > 0.5 {
274 self.distance_minimizing_mapping(logical_qubits, connectivity_requirements)
275 } else if connectivity_density > 0.1 {
276 self.connectivity_aware_mapping(logical_qubits, connectivity_requirements)
277 } else {
278 self.linear_mapping(logical_qubits)
279 }
280 }
281
282 fn calculate_centrality(&self) -> Vec<f64> {
284 let qubit_count = self.topology.qubit_count();
285 let mut centrality = vec![0.0; qubit_count];
286
287 for i in 0..qubit_count {
288 centrality[i] = self.topology.neighbors(Qubit(i)).len() as f64;
290 }
291
292 centrality
293 }
294
295 fn find_connected_pair(
297 &self,
298 logical1: usize,
299 logical2: usize,
300 current_mapping: &[usize],
301 ) -> Option<Vec<usize>> {
302 let mut used_physical: std::collections::HashSet<_> = current_mapping.iter().collect();
303
304 for physical1 in 0..self.topology.qubit_count() {
306 if used_physical.contains(&physical1) && current_mapping[logical1] != physical1 {
307 continue;
308 }
309
310 for neighbor in self.topology.neighbors(Qubit(physical1)) {
311 let physical2 = neighbor.index();
312
313 if used_physical.contains(&physical2) && current_mapping[logical2] != physical2 {
314 continue;
315 }
316
317 let mut new_mapping = current_mapping.to_vec();
319 new_mapping[logical1] = physical1;
320 new_mapping[logical2] = physical2;
321
322 return Some(new_mapping);
323 }
324 }
325
326 None
327 }
328
329 fn calculate_mapping_quality(&self, mapping: &[usize]) -> f64 {
331 if mapping.is_empty() {
332 return 1.0;
333 }
334
335 let mut total_distance = 0.0;
336 let mut pair_count = 0;
337
338 for i in 0..(mapping.len() - 1) {
340 if let Some(path) = self.topology.shortest_path(Qubit(mapping[i]), Qubit(mapping[i + 1])) {
341 total_distance += (path.len() - 1) as f64;
342 pair_count += 1;
343 }
344 }
345
346 if pair_count == 0 {
347 return 1.0;
348 }
349
350 let avg_distance = total_distance / pair_count as f64;
351
352 1.0 / (1.0 + avg_distance - 1.0)
354 }
355
356 pub fn route_two_qubit_gate(
358 &self,
359 control: usize,
360 target: usize,
361 mapping: &mut [usize],
362 ) -> Result<Vec<SwapOperation>> {
363 let physical_control = mapping[control];
364 let physical_target = mapping[target];
365
366 if self.topology.are_connected(Qubit(physical_control), Qubit(physical_target)) {
367 return Ok(vec![]);
369 }
370
371 if !self.config.enable_swaps {
372 return Err(QvmError::allocation_error(
373 "Qubits not connected and SWAP insertion disabled".to_string()
374 ));
375 }
376
377 if let Some(path) = self.topology.shortest_path(Qubit(physical_control), Qubit(physical_target)) {
379 let mut swaps = Vec::new();
380
381 for i in 0..(path.len() - 2) {
383 let swap_op = SwapOperation {
384 qubit1: path[i].index(),
385 qubit2: path[i + 1].index(),
386 };
387 swaps.push(swap_op);
388
389 }
392
393 let overhead = swaps.len() as f64 / mapping.len() as f64;
395 if overhead > self.config.max_swap_overhead {
396 return Err(QvmError::allocation_error(
397 "SWAP overhead too high".to_string()
398 ));
399 }
400
401 Ok(swaps)
402 } else {
403 Err(QvmError::allocation_error(
404 "No path found between qubits".to_string()
405 ))
406 }
407 }
408}
409
410#[derive(Debug, Clone, Serialize, Deserialize)]
412pub struct SwapOperation {
413 pub qubit1: usize,
414 pub qubit2: usize,
415}
416
417#[derive(Debug, Clone)]
419pub struct ClassicalAllocator {
420 total_bits: usize,
422 allocated_bits: std::collections::HashSet<usize>,
424 strategy: ClassicalAllocationStrategy,
426}
427
428#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
430pub enum ClassicalAllocationStrategy {
431 Sequential,
433 Random,
435 ConflictMinimizing,
437}
438
439impl ClassicalAllocator {
440 pub fn new(total_bits: usize) -> Self {
442 Self {
443 total_bits,
444 allocated_bits: std::collections::HashSet::new(),
445 strategy: ClassicalAllocationStrategy::Sequential,
446 }
447 }
448
449 pub fn allocate_bits(&mut self, required_bits: usize) -> Result<Vec<usize>> {
451 if required_bits > self.available_bits() {
452 return Err(QvmError::allocation_error(
453 format!("Not enough classical bits: need {}, have {}",
454 required_bits, self.available_bits())
455 ));
456 }
457
458 match self.strategy {
459 ClassicalAllocationStrategy::Sequential => self.allocate_sequential(required_bits),
460 ClassicalAllocationStrategy::Random => self.allocate_random(required_bits),
461 ClassicalAllocationStrategy::ConflictMinimizing => self.allocate_conflict_minimizing(required_bits),
462 }
463 }
464
465 fn allocate_sequential(&mut self, required_bits: usize) -> Result<Vec<usize>> {
467 let mut allocation = Vec::new();
468
469 for bit in 0..self.total_bits {
470 if !self.allocated_bits.contains(&bit) {
471 allocation.push(bit);
472 self.allocated_bits.insert(bit);
473
474 if allocation.len() >= required_bits {
475 break;
476 }
477 }
478 }
479
480 Ok(allocation)
481 }
482
483 fn allocate_random(&mut self, required_bits: usize) -> Result<Vec<usize>> {
485 let mut allocation = Vec::new();
486 let available: Vec<_> = (0..self.total_bits)
487 .filter(|bit| !self.allocated_bits.contains(bit))
488 .collect();
489
490 let mut seed = 54321u64;
492 for _ in 0..required_bits {
493 if available.is_empty() {
494 break;
495 }
496
497 seed = (seed.wrapping_mul(1103515245).wrapping_add(12345)) & 0x7fffffff;
498 let idx = (seed as usize) % available.len();
499 let bit = available[idx];
500
501 allocation.push(bit);
502 self.allocated_bits.insert(bit);
503 }
504
505 Ok(allocation)
506 }
507
508 fn allocate_conflict_minimizing(&mut self, required_bits: usize) -> Result<Vec<usize>> {
510 self.allocate_sequential(required_bits)
513 }
514
515 pub fn release_bits(&mut self, bits: &[usize]) {
517 for &bit in bits {
518 self.allocated_bits.remove(&bit);
519 }
520 }
521
522 pub fn available_bits(&self) -> usize {
524 self.total_bits - self.allocated_bits.len()
525 }
526
527 pub fn reset(&mut self) {
529 self.allocated_bits.clear();
530 }
531
532 pub fn is_allocated(&self, bit: usize) -> bool {
534 self.allocated_bits.contains(&bit)
535 }
536}
537
538#[cfg(test)]
539mod tests {
540 use super::*;
541 use crate::topology::TopologyBuilder;
542
543 #[test]
544 fn test_qubit_mapper_creation() {
545 let topology = TopologyBuilder::grid(3, 3);
546 let mapper = QubitMapper::new(&topology);
547 assert_eq!(mapper.config.strategy, MappingStrategy::ConnectivityAware);
548 }
549
550 #[test]
551 fn test_linear_mapping() {
552 let topology = TopologyBuilder::grid(3, 3);
553 let mapper = QubitMapper::new(&topology);
554
555 let mapping = mapper.linear_mapping(4).unwrap();
556 assert_eq!(mapping, vec![0, 1, 2, 3]);
557 }
558
559 #[test]
560 fn test_mapping_quality() {
561 let topology = TopologyBuilder::linear(5);
562 let mapper = QubitMapper::new(&topology);
563
564 let good_mapping = vec![0, 1, 2]; let bad_mapping = vec![0, 2, 4]; let quality_good = mapper.calculate_mapping_quality(&good_mapping);
568 let quality_bad = mapper.calculate_mapping_quality(&bad_mapping);
569
570 assert!(quality_good > quality_bad);
571 }
572
573 #[test]
574 fn test_resource_mapping_creation() {
575 let topology = TopologyBuilder::grid(2, 2);
576 let mapper = QubitMapper::new(&topology);
577
578 let qubit_assignments = vec![0, 1];
579 let classical_assignments = vec![0, 1];
580
581 let mapping = mapper.create_mapping(&qubit_assignments, &classical_assignments).unwrap();
582 assert_eq!(mapping.qubit_mapping, vec![0, 1]);
583 assert_eq!(mapping.classical_mapping, vec![0, 1]);
584 assert!(mapping.metadata.quality_score > 0.0);
585 }
586
587 #[test]
588 fn test_connectivity_aware_mapping() {
589 let topology = TopologyBuilder::grid(3, 3);
590 let mapper = QubitMapper::new(&topology);
591
592 let connectivity_requirements = vec![(0, 1), (1, 2)];
593 let mapping = mapper.connectivity_aware_mapping(3, &connectivity_requirements).unwrap();
594
595 assert_eq!(mapping.len(), 3);
596 }
598}