1use serde::{Deserialize, Serialize};
6use std::collections::{HashMap, HashSet};
7
8use crate::{
9 circuit::Circuit,
10 decompose::{AuxMode, Registry, Schema, State},
11 error::{KetError, Result},
12 execution::{Configuration, FeatureStatus, QuantumExecution, Qubit},
13 ir::{
14 gate::QuantumGate,
15 hamiltonian::Hamiltonian,
16 instructions::Instruction,
17 qubit::{LogicalQubit, PhysicalQubit},
18 },
19 mapping,
20 prelude::QPU,
21};
22
23type QubitList = Vec<LogicalQubit>;
24type CtrlStack = Vec<QubitList>;
25
26#[derive(Debug)]
27enum GateInstruction {
28 Gate {
29 gate: QuantumGate,
30 target: LogicalQubit,
31 control: Vec<LogicalQubit>,
32 },
33 AuxRegistry(std::rc::Rc<std::cell::RefCell<Registry>>),
34}
35
36impl GateInstruction {
37 fn inverse(self) -> Self {
38 match self {
39 Self::Gate {
40 gate,
41 target,
42 control,
43 } => Self::Gate {
44 gate: gate.inverse(),
45 target,
46 control,
47 },
48 Self::AuxRegistry(registry) => Self::AuxRegistry(registry),
49 }
50 }
51}
52
53type GateList = Vec<GateInstruction>;
54pub type Sample = (Vec<u64>, Vec<u64>);
55
56#[derive(Debug, Clone, Default, Deserialize, Serialize)]
57pub struct DumpData {
58 pub basis_states: Vec<Vec<u64>>,
59 pub amplitudes_real: Vec<f64>,
60 pub amplitudes_imag: Vec<f64>,
61}
62
63#[derive(Debug, Serialize)]
64pub struct Metadata {
65 pub logical_gate_count: HashMap<usize, usize>,
66 pub logical_circuit_depth: usize,
67 pub physical_gate_count: Option<HashMap<usize, usize>>,
68 pub physical_circuit_depth: Option<usize>,
69 pub allocated_qubits: usize,
70 pub terminated: bool,
71 pub decomposition: HashMap<String, usize>,
72}
73
74#[derive(Debug, Default)]
75pub struct Process {
76 ctrl_stack: Vec<CtrlStack>,
77 ctrl_list: QubitList,
78 ctrl_list_is_valid: bool,
79
80 logical_circuit: Circuit<LogicalQubit>,
81
82 physical_circuit: Option<Circuit<PhysicalQubit>>,
83
84 adj_stack: Vec<GateList>,
85
86 measurements: Vec<Option<u64>>,
87
88 samples: Vec<Option<Sample>>,
89
90 exp_values: Vec<Option<f64>>,
91
92 dumps: Vec<Option<DumpData>>,
93
94 configuration: Configuration,
95
96 allocated_qubits: usize,
97 qubit_count: usize,
98
99 aux_count: usize,
100
101 pub(crate) qubit_valid: HashMap<LogicalQubit, bool>,
102 pub(crate) qubit_measured: HashMap<LogicalQubit, bool>,
103
104 alloc_stack: Vec<LogicalQubit>,
105 clean_qubits: HashSet<LogicalQubit>,
106
107 terminated: bool,
108
109 decomposition_stats: HashMap<String, usize>,
110}
111
112impl Process {
113 pub fn new(configuration: Configuration) -> Self {
114 Self {
115 ctrl_stack: vec![Vec::new()],
116 configuration,
117 ..Default::default()
118 }
119 }
120
121 fn flatten_control_qubits(&mut self) {
122 if !self.ctrl_list_is_valid {
123 self.ctrl_list = self
124 .ctrl_stack
125 .last()
126 .unwrap()
127 .clone()
128 .into_iter()
129 .flatten()
130 .collect();
131 self.ctrl_list_is_valid = true;
132 }
133 }
134
135 fn non_gate_checks(
136 &mut self,
137 qubits: Option<&[LogicalQubit]>,
138 feature: Option<FeatureStatus>,
139 ) -> Result<()> {
140 if self.terminated {
141 Err(KetError::TerminatedProcess)
142 } else if matches!(feature, Some(FeatureStatus::Disable)) {
143 Err(KetError::MeasurementDisabled)
144 } else if !(self.ctrl_stack.len() == 1 && self.ctrl_stack[0].is_empty()) {
145 Err(KetError::ControlledScope)
146 } else if !self.adj_stack.is_empty() {
147 Err(KetError::InverseScope)
148 } else if qubits.map_or(false, |qubits| {
149 qubits
150 .iter()
151 .any(|qubit| !*self.qubit_valid.entry(*qubit).or_insert(true))
152 }) {
153 Err(KetError::QubitUnavailable)
154 } else {
155 Ok(())
156 }
157 }
158
159 fn gate_checks(&mut self, target: LogicalQubit) -> Result<()> {
160 if !*self.qubit_valid.entry(target).or_insert(true) {
161 Err(KetError::QubitUnavailable)
162 } else if self.ctrl_list.contains(&target) {
163 Err(KetError::ControlTargetOverlap)
164 } else if self.terminated {
165 Err(KetError::TerminatedProcess)
166 } else {
167 Ok(())
168 }
169 }
170
171 fn adj_ctrl_checks(&mut self, qubits: Option<&[LogicalQubit]>) -> Result<()> {
172 if qubits.map_or(false, |qubits| {
173 qubits
174 .iter()
175 .any(|qubit| !*self.qubit_valid.entry(*qubit).or_insert(true))
176 }) {
177 Err(KetError::QubitUnavailable)
178 } else if qubits.map_or(false, |qubits| {
179 qubits.iter().any(|qubit| self.ctrl_list.contains(qubit))
180 }) {
181 Err(KetError::ControlTwice)
182 } else if self.terminated {
183 Err(KetError::TerminatedProcess)
184 } else {
185 Ok(())
186 }
187 }
188
189 pub fn alloc(&mut self) -> Result<LogicalQubit> {
190 self.non_gate_checks(None, None)?;
191
192 self.reserve_qubits(1)?;
193 self.allocated_qubits += 1;
194
195 Ok(self.alloc_stack.pop().unwrap())
196 }
197
198 fn reserve_qubits(&mut self, num_qubits: usize) -> Result<()> {
199 while self.alloc_stack.len() < num_qubits {
200 if self.allocated_qubits > self.configuration.num_qubits {
201 return Err(KetError::MaxQubitsReached);
202 }
203
204 let qubit = LogicalQubit::main(self.qubit_count);
205
206 self.qubit_count += 1;
207
208 self.alloc_stack.push(qubit);
209 assert!(self.clean_qubits.insert(qubit));
210 }
211
212 Ok(())
213 }
214
215 fn try_alloc_aux(
216 &mut self,
217 num_qubits: usize,
218 interacting_qubits: Option<&[LogicalQubit]>,
219 ) -> Option<Vec<LogicalQubit>> {
220 if (interacting_qubits.is_none()
221 && (num_qubits + self.allocated_qubits) > self.configuration.num_qubits)
222 || (interacting_qubits.is_some()
223 && (num_qubits + interacting_qubits.unwrap().len()) > self.configuration.num_qubits)
224 {
225 return None;
226 }
227
228 let result: Vec<_> = (0..num_qubits)
229 .map(|index| LogicalQubit::aux(index + self.aux_count))
230 .collect();
231
232 self.aux_count += num_qubits;
233
234 let reserver_qubits = if let Some(interacting_qubits) = interacting_qubits {
235 let dirty_available = self.allocated_qubits - interacting_qubits.len();
236 if dirty_available >= num_qubits {
237 0
238 } else {
239 num_qubits - dirty_available
240 }
241 } else {
242 num_qubits
243 };
244
245 self.reserve_qubits(reserver_qubits).unwrap(); Some(result)
248 }
249
250 fn free_aux(&mut self, registry: &Registry) {
251 if let Some(aux_qubits) = ®istry.aux_qubits {
252 let mut allocated = HashSet::new();
253 for aux_qubit in aux_qubits {
254 let mut main_qubit = None;
255 for interacting_qubit in self.logical_circuit.interacting_qubits(*aux_qubit) {
256 for candidate_qubit in self
257 .logical_circuit
258 .interacting_qubits_rev(*interacting_qubit)
259 {
260 if candidate_qubit.is_aux() {
261 continue;
262 }
263 let use_this = match ®istry.interacting_qubits {
264 Some(interacting_qubits) => {
265 !interacting_qubits.contains(candidate_qubit)
266 && !allocated.contains(candidate_qubit)
267 }
268 None => {
269 self.clean_qubits.contains(candidate_qubit)
270 && !allocated.contains(candidate_qubit)
271 }
272 };
273
274 if use_this {
275 main_qubit = Some(*candidate_qubit);
276 break;
277 }
278 }
279 }
280 let main_qubit = if let Some(main_qubit) = main_qubit {
281 main_qubit
282 } else {
283 let mut main_qubit = None;
284 for candidate_qubit in &self.clean_qubits {
285 if !allocated.contains(candidate_qubit) {
286 main_qubit = Some(*candidate_qubit);
287 break;
288 }
289 }
290
291 if main_qubit.is_none() {
292 for candidate_qubit in 0..self.allocated_qubits {
293 let candidate_qubit = LogicalQubit::main(candidate_qubit);
294 if !allocated.contains(&candidate_qubit)
295 && !registry
296 .interacting_qubits
297 .as_ref()
298 .unwrap()
299 .contains(&candidate_qubit)
300 {
301 main_qubit = Some(candidate_qubit);
302 break;
303 }
304 }
305 }
306
307 main_qubit.unwrap()
308 };
309 allocated.insert(main_qubit);
310 self.logical_circuit.alloc_aux_qubit(*aux_qubit, main_qubit);
311 }
312 }
313 }
314
315 pub fn gate(&mut self, gate: QuantumGate, target: LogicalQubit) -> Result<()> {
316 if gate.is_identity() {
317 return Ok(());
318 }
319
320 self.flatten_control_qubits();
321 self.gate_checks(target)?;
322
323 for qubit in self.ctrl_list.iter().chain([&target]) {
324 self.clean_qubits.remove(qubit);
325 }
326
327 if !self.ctrl_list.is_empty() && self.configuration.qpu.is_some() {
328 let mut schema = Schema::default();
329 let interacting_qubits: Vec<_> =
330 self.ctrl_list.iter().cloned().chain([target]).collect();
331
332 for algorithm in gate.decomposition_list(self.ctrl_list.len()) {
333 if !algorithm.need_aux() {
334 schema = Schema {
335 algorithm,
336 aux_qubits: None,
337 };
338 break;
339 }
340
341 if let Some(qubits) = self.try_alloc_aux(
342 algorithm.aux_needed(self.ctrl_list.len()),
343 if matches!(algorithm.aux_mode(), AuxMode::Dirty) {
344 Some(&interacting_qubits)
345 } else {
346 None
347 },
348 ) {
349 schema = Schema {
350 algorithm,
351 aux_qubits: Some(qubits),
352 };
353 break;
354 }
355 }
356
357 let registry: std::rc::Rc<std::cell::RefCell<Registry>> =
358 std::rc::Rc::new(std::cell::RefCell::new(Registry {
359 algorithm: schema.algorithm,
360 aux_qubits: schema.aux_qubits.clone(),
361 interacting_qubits: if schema.algorithm.aux_mode() == AuxMode::Dirty {
362 Some(interacting_qubits)
363 } else {
364 None
365 },
366 ..Default::default()
367 }));
368
369 self.push_gate(GateInstruction::AuxRegistry(registry.clone()));
370
371 for (gate, target, control) in gate.decompose(
372 target,
373 &self.ctrl_list,
374 schema,
375 self.configuration.qpu.as_ref().unwrap().u4_gate,
376 ) {
377 let control = control.map_or(vec![], |control| vec![control]);
378 self.push_gate(GateInstruction::Gate {
379 gate,
380 target,
381 control,
382 });
383 }
384
385 self.push_gate(GateInstruction::AuxRegistry(registry));
386 } else {
387 self.push_gate(GateInstruction::Gate {
388 gate,
389 target,
390 control: self.ctrl_list.to_owned(),
391 });
392 }
393
394 Ok(())
395 }
396
397 fn push_gate(&mut self, gate: GateInstruction) {
398 if let Some(ajd_stack) = self.adj_stack.last_mut() {
399 ajd_stack.push(gate);
400 } else {
401 match gate {
402 GateInstruction::Gate {
403 gate,
404 target,
405 control,
406 } => {
407 self.logical_circuit.gate(gate, target, &control);
408 if let Some(QuantumExecution::Live(execution)) =
409 self.configuration.execution.as_mut()
410 {
411 execution.gate(gate, target, &control);
412 }
413 }
414 GateInstruction::AuxRegistry(registry) => {
415 let mut registry = registry.borrow_mut();
416 match registry.state {
417 State::Begin => {
418 registry.num_u4 =
419 *self.logical_circuit.gate_count.entry(2).or_default();
420 registry.state = State::End;
421 }
422 State::End => {
423 *self
424 .decomposition_stats
425 .entry(registry.algorithm.to_string())
426 .or_default() +=
427 *self.logical_circuit.gate_count.entry(2).or_default()
428 - registry.num_u4;
429 self.free_aux(®istry);
430 }
431 }
432 }
433 }
434 }
435 }
436
437 pub fn global_phase(&mut self, angle: f64) -> Result<()> {
438 self.adj_ctrl_checks(None)?;
439 self.flatten_control_qubits();
440
441 if self.ctrl_list.is_empty() {
442 return Ok(());
443 }
444
445 let qubits = self.ctrl_list.clone();
446
447 self.ctrl_begin()?;
448 self.ctrl_push(&qubits[1..])?;
449 self.gate(QuantumGate::Phase(angle), qubits[0])?;
450 self.ctrl_pop()?;
451 self.ctrl_end()?;
452 Ok(())
453 }
454
455 pub fn measure(&mut self, qubits: &[LogicalQubit]) -> Result<usize> {
456 self.non_gate_checks(Some(qubits), Some(self.configuration.measure))?;
457
458 let index = self.measurements.len();
459
460 self.logical_circuit.measure(qubits, index);
461
462 self.measurements.push(
463 if let Some(QuantumExecution::Live(execution)) = self.configuration.execution.as_mut() {
464 Some(execution.measure(qubits))
465 } else {
466 None
467 },
468 );
469
470 for qubit in qubits {
471 self.qubit_measured.insert(*qubit, true);
472 }
473
474 if !matches!(self.configuration.measure, FeatureStatus::ValidAfter) {
475 for qubit in qubits {
476 self.qubit_valid.insert(*qubit, false);
477 }
478 }
479 Ok(index)
480 }
481
482 pub fn sample(&mut self, qubits: &[LogicalQubit], shots: usize) -> Result<usize> {
483 self.non_gate_checks(Some(qubits), Some(self.configuration.sample))?;
484
485 let index = self.samples.len();
486
487 self.logical_circuit.sample(qubits, shots, index);
488
489 self.samples.push(
490 if let Some(QuantumExecution::Live(execution)) = self.configuration.execution.as_mut() {
491 Some(execution.sample(qubits, shots))
492 } else {
493 None
494 },
495 );
496
497 if !matches!(self.configuration.sample, FeatureStatus::ValidAfter) {
498 self.terminated = true;
499 self.transpile();
500 }
501
502 Ok(index)
503 }
504
505 pub fn exp_value(&mut self, hamiltonian: Hamiltonian<LogicalQubit>) -> Result<usize> {
506 let qubits = hamiltonian.qubits().cloned().collect::<Vec<_>>();
507 self.non_gate_checks(Some(&qubits), Some(self.configuration.exp_value))?;
508
509 let index = self.exp_values.len();
510
511 self.exp_values.push(
512 if let Some(QuantumExecution::Live(execution)) = self.configuration.execution.as_mut() {
513 Some(execution.exp_value(&hamiltonian))
514 } else {
515 None
516 },
517 );
518
519 self.logical_circuit.exp_value(hamiltonian, index);
520
521 if !matches!(self.configuration.exp_value, FeatureStatus::ValidAfter) {
522 self.terminated = true;
523 self.transpile();
524 }
525
526 Ok(index)
527 }
528
529 pub fn dump(&mut self, qubits: &[LogicalQubit]) -> Result<usize> {
530 self.non_gate_checks(Some(qubits), Some(self.configuration.dump))?;
531
532 let index = self.dumps.len();
533
534 self.logical_circuit.dump(qubits, index);
535
536 self.dumps.push(
537 if let Some(QuantumExecution::Live(execution)) = self.configuration.execution.as_mut() {
538 Some(execution.dump(qubits))
539 } else {
540 None
541 },
542 );
543
544 if !matches!(self.configuration.dump, FeatureStatus::ValidAfter) {
545 self.terminated = true;
546 self.transpile();
547 }
548
549 Ok(index)
550 }
551
552 pub fn transpile(&mut self) {
553 self.terminated = true;
554
555 if let (
556 Some(QPU {
557 coupling_graph: Some(coupling_graph),
558 ..
559 }),
560 None,
561 ) = (
562 self.configuration.qpu.as_mut(),
563 self.physical_circuit.as_ref(),
564 ) {
565 coupling_graph.calculate_distance();
566 }
567
568 if let (
569 Some(QPU {
570 coupling_graph: Some(coupling_graph),
571 u4_gate,
572 u2_gates,
573 }),
574 None,
575 ) = (
576 self.configuration.qpu.as_ref(),
577 self.physical_circuit.as_ref(),
578 ) {
579 let mapping = mapping::allocation::initial(
580 &self.logical_circuit.interaction_graph(),
581 coupling_graph,
582 );
583 let mut physical_circuit =
584 mapping::map_circuit(mapping, coupling_graph, &self.logical_circuit, *u4_gate, 4);
585 physical_circuit.gate_map(*u2_gates);
586 self.physical_circuit = Some(physical_circuit);
587 }
588 }
589
590 pub fn execute(&mut self) -> Result<()> {
591 self.transpile();
592
593 let mut results = None;
594
595 if let Some(QuantumExecution::Batch(execution)) = self.configuration.execution.as_mut() {
596 execution.submit_execution(
597 &self.logical_circuit.instructions,
598 self.physical_circuit
599 .as_ref()
600 .map(|circuit| circuit.instructions.as_ref()),
601 );
602 results = Some(execution.get_results());
603 }
604
605 if let Some(mut results) = results {
606 if self.measurements.len() != results.measurements.len()
607 || self.exp_values.len() != results.exp_values.len()
608 || self.samples.len() != results.samples.len()
609 || self.dumps.len() != results.dumps.len()
610 {
611 return Err(KetError::ResultDataMismatch);
612 }
613
614 results
615 .measurements
616 .drain(..)
617 .zip(self.measurements.iter_mut())
618 .for_each(|(result, measurement)| {
619 *measurement = Some(result);
620 });
621
622 results
623 .exp_values
624 .drain(..)
625 .zip(self.exp_values.iter_mut())
626 .for_each(|(result, exp_value)| {
627 *exp_value = Some(result);
628 });
629
630 results
631 .samples
632 .drain(..)
633 .zip(self.samples.iter_mut())
634 .for_each(|(result, sample)| {
635 assert_eq!(result.0.len(), result.1.len());
636 *sample = Some(result);
637 });
638
639 results
640 .dumps
641 .drain(..)
642 .zip(self.dumps.iter_mut())
643 .for_each(|(result, dump)| {
644 *dump = Some(result);
645 });
646 }
647 Ok(())
648 }
649
650 pub fn get_measure(&self, index: usize) -> Option<u64> {
651 self.measurements.get(index).copied().flatten()
652 }
653
654 pub fn get_sample(&self, index: usize) -> Option<&Sample> {
655 self.samples.get(index).and_then(|s| s.as_ref())
656 }
657
658 pub fn get_exp_value(&self, index: usize) -> Option<f64> {
659 self.exp_values.get(index).copied().flatten()
660 }
661
662 pub fn get_dump(&self, index: usize) -> Option<&DumpData> {
663 self.dumps.get(index).and_then(|d| d.as_ref())
664 }
665
666 pub fn ctrl_push(&mut self, qubits: &[LogicalQubit]) -> Result<()> {
667 self.flatten_control_qubits();
668 self.adj_ctrl_checks(Some(qubits))?;
669 self.ctrl_stack.last_mut().unwrap().push(qubits.to_owned());
670 self.ctrl_list_is_valid = false;
671 Ok(())
672 }
673
674 pub fn ctrl_pop(&mut self) -> Result<()> {
675 self.ctrl_list_is_valid = false;
676
677 if self.ctrl_stack.last_mut().unwrap().pop().is_none() {
678 Err(KetError::ControlStackEmpty)
679 } else {
680 Ok(())
681 }
682 }
683
684 pub fn adj_begin(&mut self) -> Result<()> {
685 self.adj_ctrl_checks(None)?;
686 self.adj_stack.push(vec![]);
687 Ok(())
688 }
689
690 pub fn adj_end(&mut self) -> Result<()> {
691 if let Some(mut gates) = self.adj_stack.pop() {
692 while let Some(gate) = gates.pop() {
693 self.push_gate(gate.inverse());
694 }
695 Ok(())
696 } else {
697 Err(KetError::InverseScopeEmpty)
698 }
699 }
700
701 pub fn ctrl_begin(&mut self) -> Result<()> {
702 self.adj_ctrl_checks(None)?;
703 self.ctrl_stack.push(vec![]);
704 self.ctrl_list_is_valid = false;
705 Ok(())
706 }
707
708 pub fn ctrl_end(&mut self) -> Result<()> {
709 self.adj_ctrl_checks(None)?;
710 match self.ctrl_stack.pop() {
711 Some(stack) => {
712 if !stack.is_empty() {
713 Err(KetError::ControlStackNotEmpty)
714 } else {
715 self.ctrl_list_is_valid = false;
716 if self.ctrl_stack.is_empty() {
717 Err(KetError::ControlStackRemovePrimary)
718 } else {
719 Ok(())
720 }
721 }
722 }
723 None => Err(KetError::ControlStackRemovePrimary),
724 }
725 }
726
727 pub fn instructions(&self) -> &[Instruction<LogicalQubit>] {
728 &self.logical_circuit.instructions
729 }
730
731 pub fn instructions_json(&self) -> String {
732 serde_json::to_string(&self.instructions()).unwrap()
733 }
734
735 pub fn isa_instructions(&self) -> Option<&[Instruction<PhysicalQubit>]> {
736 self.physical_circuit
737 .as_ref()
738 .map(|c| c.instructions.as_ref())
739 }
740
741 pub fn isa_instructions_json(&self) -> String {
742 serde_json::to_string(&self.isa_instructions()).unwrap()
743 }
744
745 pub fn metadata(&self) -> Metadata {
746 Metadata {
747 logical_gate_count: self.logical_circuit.gate_count.clone(),
748 logical_circuit_depth: self.logical_circuit.depth(),
749 physical_gate_count: self
750 .physical_circuit
751 .as_ref()
752 .map(|circuit| circuit.gate_count.clone()),
753 physical_circuit_depth: self
754 .physical_circuit
755 .as_ref()
756 .map(|circuit| circuit.depth()),
757 allocated_qubits: self.allocated_qubits,
758 terminated: self.terminated,
759 decomposition: self.decomposition_stats.clone(),
760 }
761 }
762}