1use crate::{
25 error::{QuantRS2Error, QuantRS2Result},
26 gate::GateOp,
27 qubit::QubitId,
28};
29use std::collections::HashMap;
30use std::fmt::Write as FmtWrite;
31
32#[inline]
34fn fmt_err(e: std::fmt::Error) -> QuantRS2Error {
35 QuantRS2Error::ComputationError(format!("String formatting error: {e}"))
36}
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
39pub enum QuantumLanguage {
40 OpenQASM2,
42 OpenQASM3,
44 Quil,
46 QSharp,
48 Cirq,
50 Qiskit,
52 PyQuil,
54 ProjectQ,
56 BraketIR,
58 Silq,
60 Pennylane,
62}
63impl QuantumLanguage {
64 pub const fn name(&self) -> &'static str {
66 match self {
67 Self::OpenQASM2 => "OpenQASM 2.0",
68 Self::OpenQASM3 => "OpenQASM 3.0",
69 Self::Quil => "Quil",
70 Self::QSharp => "Q#",
71 Self::Cirq => "Cirq",
72 Self::Qiskit => "Qiskit",
73 Self::PyQuil => "PyQuil",
74 Self::ProjectQ => "ProjectQ",
75 Self::BraketIR => "Braket IR",
76 Self::Silq => "Silq",
77 Self::Pennylane => "Pennylane",
78 }
79 }
80 pub const fn extension(&self) -> &'static str {
82 match self {
83 Self::OpenQASM2 | Self::OpenQASM3 => "qasm",
84 Self::Quil => "quil",
85 Self::QSharp => "qs",
86 Self::Cirq | Self::Qiskit | Self::PyQuil | Self::ProjectQ | Self::Pennylane => "py",
87 Self::BraketIR => "json",
88 Self::Silq => "slq",
89 }
90 }
91 pub fn supported_gates(&self) -> Vec<&'static str> {
93 match self {
94 Self::OpenQASM2 | Self::OpenQASM3 => {
95 vec![
96 "x", "y", "z", "h", "s", "sdg", "t", "tdg", "rx", "ry", "rz", "cx", "cy", "cz",
97 "ch", "swap", "ccx", "cswap",
98 ]
99 }
100 Self::Quil => {
101 vec![
102 "X", "Y", "Z", "H", "S", "T", "RX", "RY", "RZ", "CNOT", "CZ", "SWAP", "CCNOT",
103 "CSWAP", "PHASE",
104 ]
105 }
106 Self::QSharp => {
107 vec![
108 "X", "Y", "Z", "H", "S", "T", "CNOT", "CCNOT", "SWAP", "Rx", "Ry", "Rz", "R1",
109 ]
110 }
111 Self::Cirq => {
112 vec![
113 "X",
114 "Y",
115 "Z",
116 "H",
117 "S",
118 "T",
119 "CNOT",
120 "CZ",
121 "SWAP",
122 "Rx",
123 "Ry",
124 "Rz",
125 "ISWAP",
126 "SQRT_ISWAP",
127 ]
128 }
129 Self::Qiskit => {
130 vec![
131 "x", "y", "z", "h", "s", "sdg", "t", "tdg", "rx", "ry", "rz", "cx", "cy", "cz",
132 "ch", "swap", "ccx",
133 ]
134 }
135 Self::PyQuil => {
136 vec![
137 "X", "Y", "Z", "H", "S", "T", "RX", "RY", "RZ", "CNOT", "CZ", "SWAP", "PHASE",
138 ]
139 }
140 Self::ProjectQ => {
141 vec![
142 "X", "Y", "Z", "H", "S", "T", "Rx", "Ry", "Rz", "CNOT", "Swap",
143 ]
144 }
145 Self::BraketIR => {
146 vec![
147 "x", "y", "z", "h", "s", "si", "t", "ti", "rx", "ry", "rz", "cnot", "cy", "cz",
148 "swap", "iswap",
149 ]
150 }
151 Self::Silq => vec!["X", "Y", "Z", "H", "S", "T", "CNOT", "phase"],
152 Self::Pennylane => {
153 vec![
154 "PauliX", "PauliY", "PauliZ", "Hadamard", "S", "T", "RX", "RY", "RZ", "CNOT",
155 "CZ", "SWAP",
156 ]
157 }
158 }
159 }
160}
161#[derive(Debug, Clone)]
163pub struct CompilableCircuit {
164 pub num_qubits: usize,
166 pub num_cbits: usize,
168 pub gates: Vec<GateInstruction>,
170 pub measurements: Vec<(usize, usize)>,
172}
173#[derive(Debug, Clone)]
175pub struct GateInstruction {
176 pub name: String,
178 pub params: Vec<f64>,
180 pub qubits: Vec<usize>,
182 pub controls: Vec<usize>,
184}
185impl CompilableCircuit {
186 pub const fn new(num_qubits: usize, num_cbits: usize) -> Self {
188 Self {
189 num_qubits,
190 num_cbits,
191 gates: Vec::new(),
192 measurements: Vec::new(),
193 }
194 }
195 pub fn add_gate(&mut self, instruction: GateInstruction) {
197 self.gates.push(instruction);
198 }
199 pub fn add_measurement(&mut self, qubit: usize, cbit: usize) {
201 self.measurements.push((qubit, cbit));
202 }
203 #[must_use]
205 pub fn measure_all(&mut self) {
206 for i in 0..self.num_qubits.min(self.num_cbits) {
207 self.measurements.push((i, i));
208 }
209 }
210}
211pub struct QuantumLanguageCompiler {
213 target_language: QuantumLanguage,
214 optimize: bool,
215 include_comments: bool,
216}
217impl QuantumLanguageCompiler {
218 pub const fn new(target_language: QuantumLanguage) -> Self {
220 Self {
221 target_language,
222 optimize: true,
223 include_comments: true,
224 }
225 }
226 #[must_use]
228 pub const fn with_optimization(mut self, optimize: bool) -> Self {
229 self.optimize = optimize;
230 self
231 }
232 #[must_use]
234 pub const fn with_comments(mut self, include_comments: bool) -> Self {
235 self.include_comments = include_comments;
236 self
237 }
238 pub fn compile(&self, circuit: &CompilableCircuit) -> QuantRS2Result<String> {
240 match self.target_language {
241 QuantumLanguage::OpenQASM2 => Self::compile_to_openqasm2(circuit),
242 QuantumLanguage::OpenQASM3 => Self::compile_to_openqasm3(circuit),
243 QuantumLanguage::Quil => Self::compile_to_quil(circuit),
244 QuantumLanguage::QSharp => Self::compile_to_qsharp(circuit),
245 QuantumLanguage::Cirq => Self::compile_to_cirq(circuit),
246 QuantumLanguage::Qiskit => Self::compile_to_qiskit(circuit),
247 QuantumLanguage::PyQuil => Self::compile_to_pyquil(circuit),
248 QuantumLanguage::ProjectQ => Self::compile_to_projectq(circuit),
249 QuantumLanguage::BraketIR => Self::compile_to_braket_ir(circuit),
250 QuantumLanguage::Silq => Self::compile_to_silq(circuit),
251 QuantumLanguage::Pennylane => Self::compile_to_pennylane(circuit),
252 }
253 }
254 fn compile_to_openqasm2(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
256 let mut output = String::new();
257 writeln!(output, "OPENQASM 2.0;").map_err(fmt_err)?;
258 writeln!(output, "include \"qelib1.inc\";").map_err(fmt_err)?;
259 writeln!(output).map_err(fmt_err)?;
260 writeln!(output, "qreg q[{}];", circuit.num_qubits).map_err(fmt_err)?;
261 if circuit.num_cbits > 0 {
262 writeln!(output, "creg c[{}];", circuit.num_cbits).map_err(fmt_err)?;
263 }
264 writeln!(output).map_err(fmt_err)?;
265 for gate in &circuit.gates {
266 let qubit0 = gate.qubits.first().ok_or_else(|| {
267 QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
268 })?;
269 match gate.name.as_str() {
270 "H" | "h" => {
271 writeln!(output, "h q[{qubit0}];").map_err(fmt_err)?;
272 }
273 "X" | "x" => {
274 writeln!(output, "x q[{qubit0}];").map_err(fmt_err)?;
275 }
276 "Y" | "y" => {
277 writeln!(output, "y q[{qubit0}];").map_err(fmt_err)?;
278 }
279 "Z" | "z" => {
280 writeln!(output, "z q[{qubit0}];").map_err(fmt_err)?;
281 }
282 "S" | "s" => {
283 writeln!(output, "s q[{qubit0}];").map_err(fmt_err)?;
284 }
285 "T" | "t" => {
286 writeln!(output, "t q[{qubit0}];").map_err(fmt_err)?;
287 }
288 "RX" | "rx" => {
289 let param = gate.params.first().ok_or_else(|| {
290 QuantRS2Error::InvalidInput("RX gate missing angle parameter".to_string())
291 })?;
292 writeln!(output, "rx({param}) q[{qubit0}];").map_err(fmt_err)?;
293 }
294 "RY" | "ry" => {
295 let param = gate.params.first().ok_or_else(|| {
296 QuantRS2Error::InvalidInput("RY gate missing angle parameter".to_string())
297 })?;
298 writeln!(output, "ry({param}) q[{qubit0}];").map_err(fmt_err)?;
299 }
300 "RZ" | "rz" => {
301 let param = gate.params.first().ok_or_else(|| {
302 QuantRS2Error::InvalidInput("RZ gate missing angle parameter".to_string())
303 })?;
304 writeln!(output, "rz({param}) q[{qubit0}];").map_err(fmt_err)?;
305 }
306 "CNOT" | "cx" => {
307 let qubit1 = gate.qubits.get(1).ok_or_else(|| {
308 QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
309 })?;
310 writeln!(output, "cx q[{qubit0}], q[{qubit1}];").map_err(fmt_err)?;
311 }
312 "CZ" | "cz" => {
313 let qubit1 = gate.qubits.get(1).ok_or_else(|| {
314 QuantRS2Error::InvalidInput("CZ gate missing second qubit".to_string())
315 })?;
316 writeln!(output, "cz q[{qubit0}], q[{qubit1}];").map_err(fmt_err)?;
317 }
318 "SWAP" | "swap" => {
319 let qubit1 = gate.qubits.get(1).ok_or_else(|| {
320 QuantRS2Error::InvalidInput("SWAP gate missing second qubit".to_string())
321 })?;
322 writeln!(output, "swap q[{qubit0}], q[{qubit1}];").map_err(fmt_err)?;
323 }
324 _ => {
325 return Err(QuantRS2Error::UnsupportedOperation(format!(
326 "Gate {} not supported in OpenQASM 2.0",
327 gate.name
328 )));
329 }
330 }
331 }
332 if !circuit.measurements.is_empty() {
333 writeln!(output).map_err(fmt_err)?;
334 for (qubit, cbit) in &circuit.measurements {
335 writeln!(output, "measure q[{qubit}] -> c[{cbit}];").map_err(fmt_err)?;
336 }
337 }
338 Ok(output)
339 }
340 fn compile_to_openqasm3(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
342 let mut output = String::new();
343 writeln!(output, "OPENQASM 3.0;").map_err(fmt_err)?;
344 writeln!(output, "include \"stdgates.inc\";").map_err(fmt_err)?;
345 writeln!(output).map_err(fmt_err)?;
346 writeln!(output, "qubit[{}] q;", circuit.num_qubits).map_err(fmt_err)?;
347 if circuit.num_cbits > 0 {
348 writeln!(output, "bit[{}] c;", circuit.num_cbits).map_err(fmt_err)?;
349 }
350 writeln!(output).map_err(fmt_err)?;
351 for gate in &circuit.gates {
352 let qubit0 = gate.qubits.first().ok_or_else(|| {
353 QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
354 })?;
355 match gate.name.as_str() {
356 "H" | "h" => writeln!(output, "h q[{qubit0}];").map_err(fmt_err)?,
357 "X" | "x" => writeln!(output, "x q[{qubit0}];").map_err(fmt_err)?,
358 "CNOT" | "cx" => {
359 let qubit1 = gate.qubits.get(1).ok_or_else(|| {
360 QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
361 })?;
362 writeln!(output, "cx q[{qubit0}], q[{qubit1}];").map_err(fmt_err)?;
363 }
364 _ => {}
365 }
366 }
367 for (qubit, cbit) in &circuit.measurements {
368 writeln!(output, "c[{cbit}] = measure q[{qubit}];").map_err(fmt_err)?;
369 }
370 Ok(output)
371 }
372 fn compile_to_quil(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
374 let mut output = String::new();
375 if circuit.num_cbits > 0 {
376 writeln!(output, "DECLARE ro BIT[{}]", circuit.num_cbits).map_err(fmt_err)?;
377 writeln!(output).map_err(fmt_err)?;
378 }
379 for gate in &circuit.gates {
380 let qubit0 = gate.qubits.first().ok_or_else(|| {
381 QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
382 })?;
383 match gate.name.as_str() {
384 "H" | "h" => writeln!(output, "H {qubit0}").map_err(fmt_err)?,
385 "X" | "x" => writeln!(output, "X {qubit0}").map_err(fmt_err)?,
386 "Y" | "y" => writeln!(output, "Y {qubit0}").map_err(fmt_err)?,
387 "Z" | "z" => writeln!(output, "Z {qubit0}").map_err(fmt_err)?,
388 "RX" | "rx" => {
389 let param = gate.params.first().ok_or_else(|| {
390 QuantRS2Error::InvalidInput("RX gate missing angle parameter".to_string())
391 })?;
392 writeln!(output, "RX({param}) {qubit0}").map_err(fmt_err)?;
393 }
394 "RY" | "ry" => {
395 let param = gate.params.first().ok_or_else(|| {
396 QuantRS2Error::InvalidInput("RY gate missing angle parameter".to_string())
397 })?;
398 writeln!(output, "RY({param}) {qubit0}").map_err(fmt_err)?;
399 }
400 "RZ" | "rz" => {
401 let param = gate.params.first().ok_or_else(|| {
402 QuantRS2Error::InvalidInput("RZ gate missing angle parameter".to_string())
403 })?;
404 writeln!(output, "RZ({param}) {qubit0}").map_err(fmt_err)?;
405 }
406 "CNOT" | "cx" => {
407 let qubit1 = gate.qubits.get(1).ok_or_else(|| {
408 QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
409 })?;
410 writeln!(output, "CNOT {qubit0} {qubit1}").map_err(fmt_err)?;
411 }
412 "CZ" | "cz" => {
413 let qubit1 = gate.qubits.get(1).ok_or_else(|| {
414 QuantRS2Error::InvalidInput("CZ gate missing second qubit".to_string())
415 })?;
416 writeln!(output, "CZ {qubit0} {qubit1}").map_err(fmt_err)?;
417 }
418 _ => {}
419 }
420 }
421 for (qubit, cbit) in &circuit.measurements {
422 writeln!(output, "MEASURE {qubit} ro[{cbit}]").map_err(fmt_err)?;
423 }
424 Ok(output)
425 }
426 fn compile_to_qsharp(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
428 let mut output = String::new();
429 writeln!(output, "namespace QuantumCircuit {{").map_err(fmt_err)?;
430 writeln!(output, " open Microsoft.Quantum.Canon;").map_err(fmt_err)?;
431 writeln!(output, " open Microsoft.Quantum.Intrinsic;").map_err(fmt_err)?;
432 writeln!(output).map_err(fmt_err)?;
433 writeln!(output, " operation RunCircuit() : Result[] {{").map_err(fmt_err)?;
434 writeln!(
435 output,
436 " use qubits = Qubit[{}];",
437 circuit.num_qubits
438 )
439 .map_err(fmt_err)?;
440 writeln!(output).map_err(fmt_err)?;
441 for gate in &circuit.gates {
442 let qubit0 = gate.qubits.first().ok_or_else(|| {
443 QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
444 })?;
445 match gate.name.as_str() {
446 "H" | "h" => {
447 writeln!(output, " H(qubits[{qubit0}]);").map_err(fmt_err)?;
448 }
449 "X" | "x" => {
450 writeln!(output, " X(qubits[{qubit0}]);").map_err(fmt_err)?;
451 }
452 "Y" | "y" => {
453 writeln!(output, " Y(qubits[{qubit0}]);").map_err(fmt_err)?;
454 }
455 "Z" | "z" => {
456 writeln!(output, " Z(qubits[{qubit0}]);").map_err(fmt_err)?;
457 }
458 "CNOT" | "cx" => {
459 let qubit1 = gate.qubits.get(1).ok_or_else(|| {
460 QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
461 })?;
462 writeln!(output, " CNOT(qubits[{qubit0}], qubits[{qubit1}]);")
463 .map_err(fmt_err)?;
464 }
465 _ => {}
466 }
467 }
468 writeln!(output).map_err(fmt_err)?;
469 writeln!(output, " let results = ForEach(M, qubits);").map_err(fmt_err)?;
470 writeln!(output, " ResetAll(qubits);").map_err(fmt_err)?;
471 writeln!(output, " return results;").map_err(fmt_err)?;
472 writeln!(output, " }}").map_err(fmt_err)?;
473 writeln!(output, "}}").map_err(fmt_err)?;
474 Ok(output)
475 }
476 fn compile_to_cirq(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
478 let mut output = String::new();
479 writeln!(output, "import cirq").map_err(fmt_err)?;
480 writeln!(output).map_err(fmt_err)?;
481 writeln!(output, "# Create qubits").map_err(fmt_err)?;
482 writeln!(
483 output,
484 "qubits = [cirq.LineQubit(i) for i in range({})]",
485 circuit.num_qubits
486 )
487 .map_err(fmt_err)?;
488 writeln!(output).map_err(fmt_err)?;
489 writeln!(output, "# Create circuit").map_err(fmt_err)?;
490 writeln!(output, "circuit = cirq.Circuit()").map_err(fmt_err)?;
491 writeln!(output).map_err(fmt_err)?;
492 for gate in &circuit.gates {
493 let qubit0 = gate.qubits.first().ok_or_else(|| {
494 QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
495 })?;
496 match gate.name.as_str() {
497 "H" | "h" => {
498 writeln!(output, "circuit.append(cirq.H(qubits[{qubit0}]))")
499 .map_err(fmt_err)?;
500 }
501 "X" | "x" => {
502 writeln!(output, "circuit.append(cirq.X(qubits[{qubit0}]))")
503 .map_err(fmt_err)?;
504 }
505 "Y" | "y" => {
506 writeln!(output, "circuit.append(cirq.Y(qubits[{qubit0}]))")
507 .map_err(fmt_err)?;
508 }
509 "Z" | "z" => {
510 writeln!(output, "circuit.append(cirq.Z(qubits[{qubit0}]))")
511 .map_err(fmt_err)?;
512 }
513 "CNOT" | "cx" => {
514 let qubit1 = gate.qubits.get(1).ok_or_else(|| {
515 QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
516 })?;
517 writeln!(
518 output,
519 "circuit.append(cirq.CNOT(qubits[{qubit0}], qubits[{qubit1}]))"
520 )
521 .map_err(fmt_err)?;
522 }
523 "RX" | "rx" => {
524 let param = gate.params.first().ok_or_else(|| {
525 QuantRS2Error::InvalidInput("RX gate missing angle parameter".to_string())
526 })?;
527 writeln!(
528 output,
529 "circuit.append(cirq.rx({param}).on(qubits[{qubit0}]))"
530 )
531 .map_err(fmt_err)?;
532 }
533 "RY" | "ry" => {
534 let param = gate.params.first().ok_or_else(|| {
535 QuantRS2Error::InvalidInput("RY gate missing angle parameter".to_string())
536 })?;
537 writeln!(
538 output,
539 "circuit.append(cirq.ry({param}).on(qubits[{qubit0}]))"
540 )
541 .map_err(fmt_err)?;
542 }
543 "RZ" | "rz" => {
544 let param = gate.params.first().ok_or_else(|| {
545 QuantRS2Error::InvalidInput("RZ gate missing angle parameter".to_string())
546 })?;
547 writeln!(
548 output,
549 "circuit.append(cirq.rz({param}).on(qubits[{qubit0}]))"
550 )
551 .map_err(fmt_err)?;
552 }
553 _ => {}
554 }
555 }
556 if !circuit.measurements.is_empty() {
557 writeln!(output).map_err(fmt_err)?;
558 write!(output, "circuit.append(cirq.measure(").map_err(fmt_err)?;
559 for (i, (qubit, _)) in circuit.measurements.iter().enumerate() {
560 if i > 0 {
561 write!(output, ", ").map_err(fmt_err)?;
562 }
563 write!(output, "qubits[{qubit}]").map_err(fmt_err)?;
564 }
565 writeln!(output, ", key='result'))").map_err(fmt_err)?;
566 }
567 writeln!(output).map_err(fmt_err)?;
568 writeln!(output, "print(circuit)").map_err(fmt_err)?;
569 Ok(output)
570 }
571 fn compile_to_qiskit(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
573 let mut output = String::new();
574 writeln!(
575 output,
576 "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister"
577 )
578 .map_err(fmt_err)?;
579 writeln!(output).map_err(fmt_err)?;
580 writeln!(output, "# Create registers").map_err(fmt_err)?;
581 writeln!(
582 output,
583 "qreg = QuantumRegister({}, 'q'))",
584 circuit.num_qubits
585 )
586 .map_err(fmt_err)?;
587 if circuit.num_cbits > 0 {
588 writeln!(
589 output,
590 "creg = ClassicalRegister({}, 'c')",
591 circuit.num_cbits
592 )
593 .map_err(fmt_err)?;
594 writeln!(output, "circuit = QuantumCircuit(qreg, creg)").map_err(fmt_err)?;
595 } else {
596 writeln!(output, "circuit = QuantumCircuit(qreg)").map_err(fmt_err)?;
597 }
598 writeln!(output).map_err(fmt_err)?;
599 for gate in &circuit.gates {
600 let qubit0 = gate.qubits.first().ok_or_else(|| {
601 QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
602 })?;
603 match gate.name.as_str() {
604 "H" | "h" => writeln!(output, "circuit.h({qubit0})").map_err(fmt_err)?,
605 "X" | "x" => writeln!(output, "circuit.x({qubit0})").map_err(fmt_err)?,
606 "CNOT" | "cx" => {
607 let qubit1 = gate.qubits.get(1).ok_or_else(|| {
608 QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
609 })?;
610 writeln!(output, "circuit.cx({qubit0}, {qubit1})").map_err(fmt_err)?;
611 }
612 _ => {}
613 }
614 }
615 for (qubit, cbit) in &circuit.measurements {
616 writeln!(output, "circuit.measure({qubit}, {cbit})").map_err(fmt_err)?;
617 }
618 writeln!(output).map_err(fmt_err)?;
619 writeln!(output, "print(circuit)").map_err(fmt_err)?;
620 Ok(output)
621 }
622 fn compile_to_pyquil(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
624 let mut output = String::new();
625 writeln!(output, "from pyquil import Program").map_err(fmt_err)?;
626 writeln!(output, "from pyquil.gates import *").map_err(fmt_err)?;
627 writeln!(output).map_err(fmt_err)?;
628 writeln!(output, "program = Program()").map_err(fmt_err)?;
629 writeln!(output).map_err(fmt_err)?;
630 for gate in &circuit.gates {
631 let qubit0 = gate.qubits.first().ok_or_else(|| {
632 QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
633 })?;
634 match gate.name.as_str() {
635 "H" | "h" => writeln!(output, "program += H({qubit0})").map_err(fmt_err)?,
636 "X" | "x" => writeln!(output, "program += X({qubit0})").map_err(fmt_err)?,
637 "CNOT" | "cx" => {
638 let qubit1 = gate.qubits.get(1).ok_or_else(|| {
639 QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
640 })?;
641 writeln!(output, "program += CNOT({qubit0}, {qubit1})").map_err(fmt_err)?;
642 }
643 _ => {}
644 }
645 }
646 Ok(output)
647 }
648 fn compile_to_projectq(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
650 let mut output = String::new();
651 writeln!(output, "from projectq import MainEngine").map_err(fmt_err)?;
652 writeln!(output, "from projectq.ops import *").map_err(fmt_err)?;
653 writeln!(output).map_err(fmt_err)?;
654 writeln!(output, "eng = MainEngine()").map_err(fmt_err)?;
655 writeln!(
656 output,
657 "qubits = eng.allocate_qureg({}))",
658 circuit.num_qubits
659 )
660 .map_err(fmt_err)?;
661 writeln!(output).map_err(fmt_err)?;
662 for gate in &circuit.gates {
663 let qubit0 = gate.qubits.first().ok_or_else(|| {
664 QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
665 })?;
666 match gate.name.as_str() {
667 "H" | "h" => writeln!(output, "H | qubits[{qubit0}]").map_err(fmt_err)?,
668 "X" | "x" => writeln!(output, "X | qubits[{qubit0}]").map_err(fmt_err)?,
669 "CNOT" | "cx" => {
670 let qubit1 = gate.qubits.get(1).ok_or_else(|| {
671 QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
672 })?;
673 writeln!(output, "CNOT | (qubits[{qubit0}], qubits[{qubit1}])")
674 .map_err(fmt_err)?;
675 }
676 _ => {}
677 }
678 }
679 Ok(output)
680 }
681 fn compile_to_braket_ir(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
683 let mut output = String::new();
684 writeln!(output, "{{").map_err(fmt_err)?;
685 writeln!(output, " \"braketSchemaHeader\": {{").map_err(fmt_err)?;
686 writeln!(output, " \"name\": \"braket.ir.jaqcd.program\",").map_err(fmt_err)?;
687 writeln!(output, " \"version\": \"1\"").map_err(fmt_err)?;
688 writeln!(output, " }},").map_err(fmt_err)?;
689 writeln!(output, " \"instructions\": [").map_err(fmt_err)?;
690 for (i, gate) in circuit.gates.iter().enumerate() {
691 if i > 0 {
692 writeln!(output, ",").map_err(fmt_err)?;
693 }
694 let qubit0 = gate.qubits.first().ok_or_else(|| {
695 QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
696 })?;
697 write!(output, " {{").map_err(fmt_err)?;
698 match gate.name.as_str() {
699 "H" | "h" => {
700 write!(output, "\"type\": \"h\", \"target\": {qubit0}").map_err(fmt_err)?;
701 }
702 "X" | "x" => {
703 write!(output, "\"type\": \"x\", \"target\": {qubit0}").map_err(fmt_err)?;
704 }
705 "CNOT" | "cx" => {
706 let qubit1 = gate.qubits.get(1).ok_or_else(|| {
707 QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
708 })?;
709 write!(
710 output,
711 "\"type\": \"cnot\", \"control\": {qubit0}, \"target\": {qubit1}"
712 )
713 .map_err(fmt_err)?;
714 }
715 _ => {}
716 }
717 write!(output, "}}").map_err(fmt_err)?;
718 }
719 writeln!(output).map_err(fmt_err)?;
720 writeln!(output, " ]").map_err(fmt_err)?;
721 writeln!(output, "}}").map_err(fmt_err)?;
722 Ok(output)
723 }
724 fn compile_to_silq(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
726 let mut output = String::new();
727 writeln!(output, "def circuit() {{").map_err(fmt_err)?;
728 writeln!(output, " // Allocate qubits").map_err(fmt_err)?;
729 writeln!(output, " q := 0:^{};", circuit.num_qubits).map_err(fmt_err)?;
730 writeln!(output).map_err(fmt_err)?;
731 for gate in &circuit.gates {
732 let qubit0 = gate.qubits.first().ok_or_else(|| {
733 QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
734 })?;
735 match gate.name.as_str() {
736 "H" | "h" => {
737 writeln!(output, " q[{qubit0}] := H(q[{qubit0}]);").map_err(fmt_err)?;
738 }
739 "X" | "x" => {
740 writeln!(output, " q[{qubit0}] := X(q[{qubit0}]);").map_err(fmt_err)?;
741 }
742 _ => {}
743 }
744 }
745 writeln!(output, " return q;").map_err(fmt_err)?;
746 writeln!(output, "}}").map_err(fmt_err)?;
747 Ok(output)
748 }
749 fn compile_to_pennylane(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
751 let mut output = String::new();
752 writeln!(output, "import pennylane as qml").map_err(fmt_err)?;
753 writeln!(output).map_err(fmt_err)?;
754 writeln!(
755 output,
756 "dev = qml.device('default.qubit', wires={})",
757 circuit.num_qubits
758 )
759 .map_err(fmt_err)?;
760 writeln!(output).map_err(fmt_err)?;
761 writeln!(output, "@qml.qnode(dev)").map_err(fmt_err)?;
762 writeln!(output, "def circuit():").map_err(fmt_err)?;
763 for gate in &circuit.gates {
764 let qubit0 = gate.qubits.first().ok_or_else(|| {
765 QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
766 })?;
767 match gate.name.as_str() {
768 "H" | "h" => {
769 writeln!(output, " qml.Hadamard(wires={qubit0})").map_err(fmt_err)?;
770 }
771 "X" | "x" => {
772 writeln!(output, " qml.PauliX(wires={qubit0})").map_err(fmt_err)?;
773 }
774 "CNOT" | "cx" => {
775 let qubit1 = gate.qubits.get(1).ok_or_else(|| {
776 QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
777 })?;
778 writeln!(output, " qml.CNOT(wires=[{qubit0}, {qubit1}])")
779 .map_err(fmt_err)?;
780 }
781 _ => {}
782 }
783 }
784 writeln!(
785 output,
786 " return qml.probs(wires=range({}))",
787 circuit.num_qubits
788 )
789 .map_err(fmt_err)?;
790 Ok(output)
791 }
792}
793#[cfg(test)]
794mod tests {
795 use super::*;
796 #[test]
797 fn test_openqasm2_compilation() {
798 let mut circuit = CompilableCircuit::new(2, 2);
799 circuit.add_gate(GateInstruction {
800 name: "H".to_string(),
801 params: vec![],
802 qubits: vec![0],
803 controls: vec![],
804 });
805 circuit.add_gate(GateInstruction {
806 name: "CNOT".to_string(),
807 params: vec![],
808 qubits: vec![0, 1],
809 controls: vec![],
810 });
811 circuit.add_measurement(0, 0);
812 circuit.add_measurement(1, 1);
813 let compiler = QuantumLanguageCompiler::new(QuantumLanguage::OpenQASM2);
814 let result = compiler
815 .compile(&circuit)
816 .expect("OpenQASM 2.0 compilation should succeed");
817 assert!(result.contains("OPENQASM 2.0"));
818 assert!(result.contains("h q[0]"));
819 assert!(result.contains("cx q[0], q[1]"));
820 assert!(result.contains("measure q[0] -> c[0]"));
821 }
822 #[test]
823 fn test_quil_compilation() {
824 let mut circuit = CompilableCircuit::new(1, 1);
825 circuit.add_gate(GateInstruction {
826 name: "H".to_string(),
827 params: vec![],
828 qubits: vec![0],
829 controls: vec![],
830 });
831 let compiler = QuantumLanguageCompiler::new(QuantumLanguage::Quil);
832 let result = compiler
833 .compile(&circuit)
834 .expect("Quil compilation should succeed");
835 assert!(result.contains("H 0"));
836 }
837}