2 Shared Test Circuits: SQUANDER vs Qiskit 4 Contains DualBuilder class and circuit factory functions for use in both 5 validation and benchmarking scripts. 8 - 1 qubit: 5 mixed ops, 5 gates (no noise) 9 - 2 qubits: 5/7/10 mixed ops, 5/7/10 gates (no noise) 10 - 3 qubits: 5/10/15/20/25 mixed ops 11 - 4 qubits: 15/20/25 mixed ops 12 - 5 qubits: 30 mixed ops (commented out - slow with Qiskit) 16 from qiskit
import QuantumCircuit
17 from qiskit_aer
import AerSimulator
18 from qiskit_aer.noise
import (
19 amplitude_damping_error,
28 """Build identical circuits in both SQUANDER and Qiskit frameworks.""" 32 self.
sq = NoisyCircuit(n_qubits)
33 self.
qk = QuantumCircuit(n_qubits)
41 self.
ops.append(f
"H({t})")
46 self.
ops.append(f
"X({t})")
51 self.
ops.append(f
"Y({t})")
56 self.
ops.append(f
"Z({t})")
61 self.
ops.append(f
"S({t})")
66 self.
ops.append(f
"T({t})")
71 self.
ops.append(f
"Sdg({t})")
76 self.
ops.append(f
"Tdg({t})")
81 self.
ops.append(f
"SX({t})")
83 def U3(self, t, theta, phi, lam):
85 qiskit_theta = np.fmod(2.0 * theta, 4.0 * np.pi)
86 qiskit_phi = np.fmod(phi, 2.0 * np.pi)
87 qiskit_lambda = np.fmod(lam, 2.0 * np.pi)
88 self.
qk.u(qiskit_theta, qiskit_phi, qiskit_lambda, t)
89 self.
params.extend([theta, phi, lam])
90 self.
ops.append(f
"U3({t},{theta},{phi},{lam})")
94 self.
sq.add_CNOT(tgt, ctrl)
96 self.
ops.append(f
"CNOT({ctrl}->{tgt})")
98 def CZ(self, tgt, ctrl):
99 self.
sq.add_CZ(tgt, ctrl)
100 self.
qk.cz(ctrl, tgt)
101 self.
ops.append(f
"CZ({ctrl},{tgt})")
105 self.
sq.add_depolarizing(self.
n, error_rate=p)
106 self.
qk.append(depolarizing_error(p, self.
n), list(range(self.
n)))
107 self.
ops.append(f
"Depol({p})")
110 self.
sq.add_local_depolarizing(t, error_rate=p)
111 self.
qk.append(depolarizing_error(p, 1), [t])
112 self.
ops.append(f
"LocalDepol({t},{p})")
115 self.
sq.add_amplitude_damping(t, gamma=gamma)
116 self.
qk.append(amplitude_damping_error(gamma), [t])
117 self.
ops.append(f
"AD({t},{gamma})")
120 self.
sq.add_phase_damping(t, lambda_param=lam)
121 self.
qk.append(phase_damping_error(lam), [t])
122 self.
ops.append(f
"PD({t},{lam})")
126 """Execute both and return density matrices as numpy arrays.""" 134 return sq_rho.to_numpy(), qk_rho
137 """Execute SQUANDER only.""" 138 sq_rho = DensityMatrix(self.
n)
143 """Execute Qiskit only using optimal Aer density matrix simulation. 145 Uses AerSimulator with method='density_matrix' which: 146 - Directly simulates the density matrix evolution 147 - Natively handles QuantumError noise channels (depolarizing, amplitude/phase damping) 148 - Is more efficient than qiskit.quantum_info.DensityMatrix.evolve() for noisy circuits 152 qc.save_density_matrix()
157 simulator = AerSimulator(method=
"density_matrix")
160 result = simulator.run(qc, shots=1).
result()
162 return result.data()[
"density_matrix"]
165 """Return the numeric parameter vector used for parametric operations.""" 166 return np.asarray(self.
params, dtype=np.float64)
175 """1 qubit, 5 mixed operations.""" 186 """1 qubit, 5 gate operations (no noise).""" 202 """2 qubits, 5 mixed operations.""" 213 """2 qubits, 7 mixed operations.""" 220 b.phase_damp(1, 0.03)
226 """2 qubits, 10 mixed operations.""" 236 b.phase_damp(1, 0.025)
247 """2 qubits, 5 gate operations (no noise).""" 258 """2 qubits, 7 gate operations (no noise).""" 271 """2 qubits, 10 gate operations (no noise).""" 292 """3 qubits, 5 mixed operations.""" 303 """3 qubits, 10 mixed operations.""" 313 b.phase_damp(2, 0.02)
319 """3 qubits, 15 mixed operations.""" 330 b.phase_damp(2, 0.02)
340 """3 qubits, 20 mixed operations.""" 353 b.phase_damp(1, 0.025)
361 b.phase_damp(0, 0.02)
366 """3 qubits, 25 mixed operations.""" 373 b.depolarizing(0.035)
379 b.phase_damp(1, 0.02)
383 b.depolarizing(0.025)
388 b.phase_damp(2, 0.018)
402 """4 qubits, 15 mixed operations.""" 415 b.phase_damp(3, 0.025)
423 """4 qubits, 20 mixed operations.""" 438 b.phase_damp(1, 0.02)
441 b.depolarizing(0.025)
444 b.phase_damp(2, 0.018)
449 """4 qubits, 25 mixed operations.""" 457 b.depolarizing(0.025)
465 b.phase_damp(1, 0.018)
472 b.phase_damp(3, 0.015)
485 """5 qubits, 30 mixed operations.""" 508 b.phase_damp(4, 0.02)
510 b.depolarizing(0.015)
520 b.phase_damp(2, 0.015)
532 (
"1q/5ops mixed", build_1q_5ops_mixed),
533 (
"1q/5ops gates", build_1q_5ops_gates),
534 (
"2q/5ops mixed", build_2q_5ops_mixed),
535 (
"2q/7ops mixed", build_2q_7ops_mixed),
536 (
"2q/10ops mixed", build_2q_10ops_mixed),
537 (
"2q/5ops gates", build_2q_5ops_gates),
538 (
"2q/7ops gates", build_2q_7ops_gates),
539 (
"2q/10ops gates", build_2q_10ops_gates),
540 (
"3q/5ops mixed", build_3q_5ops_mixed),
541 (
"3q/10ops mixed", build_3q_10ops_mixed),
542 (
"3q/15ops mixed", build_3q_15ops_mixed),
543 (
"3q/20ops mixed", build_3q_20ops_mixed),
544 (
"3q/25ops mixed", build_3q_25ops_mixed),
545 (
"4q/15ops mixed", build_4q_15ops_mixed),
546 (
"4q/20ops mixed", build_4q_20ops_mixed),
547 (
"4q/25ops mixed", build_4q_25ops_mixed),
550 build_5q_30ops_mixed,
555 BENCHMARK_CIRCUITS = [
556 (
"1q/5ops mixed", build_1q_5ops_mixed),
557 (
"1q/5ops gates", build_1q_5ops_gates),
558 (
"2q/5ops mixed", build_2q_5ops_mixed),
559 (
"2q/10ops mixed", build_2q_10ops_mixed),
560 (
"3q/10ops mixed", build_3q_10ops_mixed),
561 (
"3q/25ops mixed", build_3q_25ops_mixed),
562 (
"4q/15ops mixed", build_4q_15ops_mixed),
563 (
"4q/25ops mixed", build_4q_25ops_mixed),
566 build_5q_30ops_mixed,
571 CIRCUITS_BY_QUBITS = {
573 (
"1q/5ops mixed", build_1q_5ops_mixed),
574 (
"1q/5ops gates", build_1q_5ops_gates),
577 (
"2q/5ops mixed", build_2q_5ops_mixed),
578 (
"2q/7ops mixed", build_2q_7ops_mixed),
579 (
"2q/10ops mixed", build_2q_10ops_mixed),
580 (
"2q/5ops gates", build_2q_5ops_gates),
581 (
"2q/7ops gates", build_2q_7ops_gates),
582 (
"2q/10ops gates", build_2q_10ops_gates),
585 (
"3q/5ops mixed", build_3q_5ops_mixed),
586 (
"3q/10ops mixed", build_3q_10ops_mixed),
587 (
"3q/15ops mixed", build_3q_15ops_mixed),
588 (
"3q/20ops mixed", build_3q_20ops_mixed),
589 (
"3q/25ops mixed", build_3q_25ops_mixed),
592 (
"4q/15ops mixed", build_4q_15ops_mixed),
593 (
"4q/20ops mixed", build_4q_20ops_mixed),
594 (
"4q/25ops mixed", build_4q_25ops_mixed),
597 (
"5q/30ops mixed", build_5q_30ops_mixed),
603 "I": np.eye(2, dtype=complex),
604 "X": np.array([[0, 1], [1, 0]], dtype=complex),
605 "Y": np.array([[0, -1j], [1j, 0]], dtype=complex),
606 "Z": np.array([[1, 0], [0, -1]], dtype=complex),
611 matrix = np.array([[1.0 + 0.0j]])
612 for symbol
in pauli_string:
613 matrix = np.kron(matrix, PAULI_MATRICES[symbol])
618 qbit_num = len(term_specs[0][1])
619 matrix = np.zeros((2**qbit_num, 2**qbit_num), dtype=complex)
620 for coeff, pauli_string
in term_specs:
628 {
"coeff": float(coeff),
"pauli_string": pauli_string}
629 for coeff, pauli_string
in term_specs
639 required_gate_family,
640 required_noise_models,
646 "case_name": case_name,
647 "qbit_num": qbit_num,
648 "builder_fn": builder_fn,
649 "required_gate_family": list(required_gate_family),
650 "required_noise_models": list(required_noise_models),
651 "case_kind": case_kind,
660 b.U3(0, 0.73, -0.41, 0.19)
661 b.local_depolarizing(0, 0.08)
667 b.U3(0, 1.11, 0.37, -0.52)
674 b.U3(0, 0.92, -0.63, 0.28)
675 b.phase_damp(0, 0.12)
681 b.U3(0, 0.61, -0.22, 0.47)
682 b.U3(1, 0.35, 0.18, -0.41)
684 b.local_depolarizing(0, 0.07)
690 b.U3(0, 0.84, 0.12, -0.33)
691 b.U3(1, 0.56, -0.48, 0.25)
699 b.U3(0, 0.49, -0.31, 0.67)
700 b.U3(1, 0.71, 0.42, -0.28)
702 b.phase_damp(0, 0.09)
708 b.U3(0, 0.58, -0.27, 0.44)
709 b.U3(1, 0.93, 0.21, -0.36)
711 b.local_depolarizing(0, 0.05)
712 b.U3(2, 0.67, -0.39, 0.16)
715 b.phase_damp(2, 0.06)
719 MANDATORY_MICROCASES = [
721 case_name=
"micro_validation_1q_u3_local_depolarizing",
723 builder_fn=build_1q_u3_local_depolarizing_microcase,
724 required_gate_family=[
"U3"],
725 required_noise_models=[
"local_depolarizing"],
726 case_kind=
"individual_noise",
727 purpose=
"Validate U3 plus local single-qubit depolarizing on the 1-qubit microcase floor.",
728 term_specs=[(0.60,
"Z"), (-0.35,
"X")],
731 case_name=
"micro_validation_1q_u3_amplitude_damping",
733 builder_fn=build_1q_u3_amplitude_damping_microcase,
734 required_gate_family=[
"U3"],
735 required_noise_models=[
"amplitude_damping"],
736 case_kind=
"individual_noise",
737 purpose=
"Validate U3 plus local amplitude damping on the 1-qubit microcase floor.",
738 term_specs=[(0.45,
"Z"), (0.30,
"X")],
741 case_name=
"micro_validation_1q_u3_phase_damping",
743 builder_fn=build_1q_u3_phase_damping_microcase,
744 required_gate_family=[
"U3"],
745 required_noise_models=[
"phase_damping"],
746 case_kind=
"individual_noise",
747 purpose=
"Validate U3 plus local phase damping on the 1-qubit microcase floor.",
748 term_specs=[(-0.40,
"Z"), (0.25,
"Y")],
751 case_name=
"micro_validation_2q_u3_cnot_local_depolarizing",
753 builder_fn=build_2q_u3_cnot_local_depolarizing_microcase,
754 required_gate_family=[
"U3",
"CNOT"],
755 required_noise_models=[
"local_depolarizing"],
756 case_kind=
"individual_noise",
757 purpose=
"Validate the required U3/CNOT bridge with local single-qubit depolarizing.",
758 term_specs=[(0.55,
"ZI"), (-0.20,
"IZ"), (0.18,
"XX")],
761 case_name=
"micro_validation_2q_u3_cnot_amplitude_damping",
763 builder_fn=build_2q_u3_cnot_amplitude_damping_microcase,
764 required_gate_family=[
"U3",
"CNOT"],
765 required_noise_models=[
"amplitude_damping"],
766 case_kind=
"individual_noise",
767 purpose=
"Validate the required U3/CNOT bridge with local amplitude damping.",
768 term_specs=[(0.35,
"ZI"), (0.22,
"IX"), (-0.16,
"YY")],
771 case_name=
"micro_validation_2q_u3_cnot_phase_damping",
773 builder_fn=build_2q_u3_cnot_phase_damping_microcase,
774 required_gate_family=[
"U3",
"CNOT"],
775 required_noise_models=[
"phase_damping"],
776 case_kind=
"individual_noise",
777 purpose=
"Validate the required U3/CNOT bridge with local phase damping.",
778 term_specs=[(-0.48,
"ZZ"), (0.17,
"XI"), (0.14,
"IY")],
781 case_name=
"micro_validation_3q_u3_cnot_mixed_local_noise",
783 builder_fn=build_3q_u3_cnot_mixed_local_noise_microcase,
784 required_gate_family=[
"U3",
"CNOT"],
785 required_noise_models=[
786 "local_depolarizing",
790 case_kind=
"mixed_sequence",
791 purpose=
"Validate the mixed-sequence micro-validation path with all required local noise models in one 3-qubit case.",
803 MANDATORY_MICROCASES_BY_QUBITS = {
805 case
for case
in MANDATORY_MICROCASES
if case[
"qbit_num"] == qbit_num
807 for qbit_num
in sorted({case[
"qbit_num"]
for case
in MANDATORY_MICROCASES})
def build_2q_7ops_gates()
def build_1q_u3_amplitude_damping_microcase()
def build_2q_10ops_mixed()
def build_2q_5ops_mixed()
def get_parameter_vector(self)
def build_1q_5ops_gates()
def apply_to(self, parameters_mtx, state_to_be_transformed)
def build_2q_10ops_gates()
def build_4q_15ops_mixed()
def build_3q_15ops_mixed()
def build_2q_u3_cnot_amplitude_damping_microcase()
def amp_damp(self, t, gamma)
def build_3q_10ops_mixed()
def _pauli_string_matrix(pauli_string)
def __init__(self, n_qubits)
def _make_microcase(case_name, qbit_num, builder_fn, required_gate_family, required_noise_models, case_kind, purpose, term_specs)
def build_4q_20ops_mixed()
def local_depolarizing(self, t, p)
def _build_microcase_hamiltonian_metadata(term_specs)
def build_1q_5ops_mixed()
def depolarizing(self, p)
def build_5q_30ops_mixed()
def U3(self, t, theta, phi, lam)
def build_2q_u3_cnot_phase_damping_microcase()
def build_2q_5ops_gates()
def phase_damp(self, t, lam)
def CNOT(self, tgt, ctrl)
def build_2q_7ops_mixed()
def build_3q_u3_cnot_mixed_local_noise_microcase()
def build_1q_u3_phase_damping_microcase()
def build_4q_25ops_mixed()
def build_2q_u3_cnot_local_depolarizing_microcase()
def _build_microcase_hamiltonian(term_specs)
def build_3q_5ops_mixed()
def build_3q_20ops_mixed()
def build_3q_25ops_mixed()
def build_1q_u3_local_depolarizing_microcase()