3535
3636
3737def demonstrate_basic_noise_types ():
38- """Demonstrate basic types of quantum noise."""
38+ """
39+ Demonstrate basic types of quantum noise.
40+
41+ MATHEMATICAL BACKGROUND (For Beginners):
42+ ==========================================
43+ Quantum noise happens because quantum states are fragile. When a qubit
44+ interacts with its environment, it loses information. There are three main types:
45+
46+ 1. DEPOLARIZING NOISE - "Random Direction Errors"
47+ Mathematical Formula: ρ_noisy = (1-p)ρ + p·(I/2)
48+ Physical Meaning: With probability p, the qubit state gets replaced by
49+ completely random noise (total chaos!)
50+ Example: Like randomly flipping a coin - you lose all information
51+
52+ 2. AMPLITUDE DAMPING - "Energy Loss" (T1 decay)
53+ Mathematical Formula: ρ_noisy = E₀·ρ·E₀† + E₁·ρ·E₁†
54+ where E₀ = [[1, 0], [0, √(1-γ)]], E₁ = [[0, √γ], [0, 0]]
55+ Physical Meaning: The excited state |1⟩ decays to ground state |0⟩
56+ Example: Like a battery slowly losing charge
57+
58+ 3. PHASE DAMPING - "Phase Information Loss" (T2 dephasing)
59+ Mathematical Formula: ρ_noisy = (1-γ/2)ρ + (γ/2)Z·ρ·Z
60+ Physical Meaning: The relative phase between |0⟩ and |1⟩ gets randomized
61+ Example: Like two synchronized clocks slowly going out of sync
62+
63+ KEY INSIGHT: All three noise types affect superposition states differently!
64+ """
3965 print ("=== BASIC QUANTUM NOISE TYPES ===" )
4066 print ()
4167
42- # Create a simple test circuit
68+ # ==================================================================
69+ # STEP 1: Create a simple test circuit
70+ # ==================================================================
71+ # We'll create a superposition state |+⟩ = (|0⟩ + |1⟩)/√2
72+ # This is the MOST SENSITIVE state to noise (it has both amplitudes and phase)
4373 qc = QuantumCircuit (1 )
44- qc .h (0 ) # Create superposition state
74+ qc .h (0 ) # Hadamard gate creates superposition: |0⟩ → (|0⟩ + |1⟩)/√2
4575
4676 initial_state = Statevector .from_instruction (qc )
4777 print (f"Initial state: { initial_state } " )
@@ -50,29 +80,56 @@ def demonstrate_basic_noise_types():
5080 )
5181 print ()
5282
53- # Define different noise models
83+ # ==================================================================
84+ # STEP 2: Define different noise models
85+ # ==================================================================
5486 noise_models = {}
5587
56- # 1. Depolarizing noise
57- error_rate = 0.1
58- depol_error = depolarizing_error (error_rate , 1 )
88+ # -------------------------------------------------------------------
89+ # 1. DEPOLARIZING NOISE - "Complete Randomization"
90+ # -------------------------------------------------------------------
91+ # MATH: With probability p, replace state with I/2 (maximally mixed state)
92+ # ρ_out = (1-p)ρ + p·(I/2)
93+ # INTUITION: Imagine shaking a box with a coin - it becomes random!
94+ error_rate = 0.1 # 10% chance of noise per gate
95+ depol_error = depolarizing_error (error_rate , 1 ) # 1 = single-qubit error
5996 noise_model_depol = NoiseModel ()
6097 noise_model_depol .add_all_qubit_quantum_error (depol_error , ["h" ])
6198 noise_models ["Depolarizing" ] = noise_model_depol
6299
63- # 2. Amplitude damping (T1 decay)
100+ # -------------------------------------------------------------------
101+ # 2. AMPLITUDE DAMPING - "Energy Decay" (Like a battery draining)
102+ # -------------------------------------------------------------------
103+ # MATH: Kraus operators E₀, E₁ describe energy loss
104+ # E₀ preserves |0⟩, partially preserves |1⟩
105+ # E₁ takes |1⟩ → |0⟩ (the decay process)
106+ # PHYSICAL MEANING: T1 = relaxation time (how long |1⟩ stays excited)
107+ # INTUITION: An atom in excited state falls back to ground state
64108 amp_damp_error = amplitude_damping_error (error_rate )
65109 noise_model_amp = NoiseModel ()
66110 noise_model_amp .add_all_qubit_quantum_error (amp_damp_error , ["h" ])
67111 noise_models ["Amplitude Damping" ] = noise_model_amp
68112
69- # 3. Phase damping (T2 dephasing)
113+ # -------------------------------------------------------------------
114+ # 3. PHASE DAMPING - "Clock Desynchronization"
115+ # -------------------------------------------------------------------
116+ # MATH: Randomly applies Z gate (phase flip): |0⟩ stays, |1⟩ → -|1⟩
117+ # Superposition (|0⟩ + |1⟩) gradually loses phase coherence
118+ # PHYSICAL MEANING: T2 = dephasing time (how long phase info survives)
119+ # INTUITION: Two clocks ticking at slightly different rates
120+ # KEY: T2 ≤ 2T1 always (phase info more fragile than population)
70121 phase_damp_error = phase_damping_error (error_rate )
71122 noise_model_phase = NoiseModel ()
72123 noise_model_phase .add_all_qubit_quantum_error (phase_damp_error , ["h" ])
73124 noise_models ["Phase Damping" ] = noise_model_phase
74125
75- # Test each noise model
126+ # ==================================================================
127+ # STEP 3: Test each noise model and measure the effects
128+ # ==================================================================
129+ # WHY MEASURE? To see how each noise type changes our superposition state
130+ # IDEAL RESULT: |+⟩ should give 50% |0⟩ and 50% |1⟩ when measured
131+ # NOISY RESULT: Different noise types will deviate differently!
132+
76133 simulator = AerSimulator ()
77134 results = {}
78135
@@ -81,21 +138,26 @@ def demonstrate_basic_noise_types():
81138 test_circuit = qc .copy ()
82139 test_circuit .measure_all ()
83140
84- # Run with noise
141+ # Run with noise (1000 shots = 1000 repetitions)
142+ # STATISTICS: More shots = more accurate probability estimates
143+ # Formula: Standard error ∝ 1/√(shots)
85144 job = simulator .run (
86145 transpile (test_circuit , simulator ), shots = 1000 , noise_model = noise_model
87146 )
88147 result = job .result ()
89148 counts = result .get_counts ()
90149 results [noise_name ] = counts
91150
92- # Calculate probabilities
151+ # Calculate probabilities from measurement counts
152+ # MATH: Probability = (# of outcomes) / (total shots)
153+ # This is Born's rule: P(i) = |⟨i|ψ⟩|²
93154 prob_0 = counts .get ("0" , 0 ) / 1000
94155 prob_1 = counts .get ("1" , 0 ) / 1000
95156
96157 print (f"{ noise_name } noise (error rate: { error_rate } ):" )
97158 print (f" Measured probabilities: |0⟩: { prob_0 :.3f} , |1⟩: { prob_1 :.3f} " )
98159 print (f" Deviation from ideal: { abs (prob_0 - 0.5 ):.3f} " )
160+ print (f" INTERPRETATION: Larger deviation = more noise damage!" )
99161 print ()
100162
101163 # Visualize results
@@ -124,54 +186,118 @@ def demonstrate_basic_noise_types():
124186
125187
126188def analyze_error_rates ():
127- """Analyze how different error rates affect quantum states."""
189+ """
190+ Analyze how different error rates affect quantum states.
191+
192+ MATHEMATICAL CONCEPT (For Beginners):
193+ ======================================
194+ FIDELITY = How similar two quantum states are
195+
196+ Mathematical Formula: F(ρ, σ) = Tr(√(√ρ σ √ρ))²
197+ For pure states: F = |⟨ψ|φ⟩|²
198+
199+ Range: 0 ≤ F ≤ 1
200+ - F = 1.0 means states are identical (perfect!)
201+ - F = 0.5 means states are somewhat similar
202+ - F = 0.0 means states are completely different
203+
204+ WHY IT MATTERS: Fidelity tells us how much damage noise has done.
205+ In quantum computing, we want F > 0.99 for useful computations!
206+
207+ EXPERIMENT GOAL: See how fidelity degrades as error rate increases
208+ """
128209 print ("=== ERROR RATE ANALYSIS ===" )
129210 print ()
130211
131- # Create test circuit
212+ # ==================================================================
213+ # STEP 1: Create a test circuit - Bell state
214+ # ==================================================================
215+ # Bell state: |Φ+⟩ = (|00⟩ + |11⟩)/√2
216+ # This is a MAXIMALLY ENTANGLED state - very sensitive to noise!
217+ # MATH: Starting from |00⟩, apply H to first qubit, then CNOT
218+ # H|0⟩|0⟩ = (|0⟩+|1⟩)|0⟩/√2
219+ # CNOT gives (|00⟩+|11⟩)/√2 ← Bell state!
132220 qc = QuantumCircuit (2 )
133- qc .h (0 )
134- qc .cx (0 , 1 ) # Create Bell state
221+ qc .h (0 ) # Create superposition on first qubit
222+ qc .cx (0 , 1 ) # Entangle: if qubit 0 is |1⟩, flip qubit 1
135223
136224 ideal_state = Statevector .from_instruction (qc )
137225
138- # Test different error rates
139- error_rates = np .logspace (- 3 , - 1 , 10 ) # 0.001 to 0.1
226+ # ==================================================================
227+ # STEP 2: Test a range of error rates (from very small to large)
228+ # ==================================================================
229+ # We use logarithmic spacing: 0.1%, 0.2%, 0.5%, 1%, 2%, 5%, 10%
230+ # WHY LOGARITHMIC? Error rates span multiple orders of magnitude!
231+ error_rates = np .logspace (- 3 , - 1 , 10 ) # 10 points from 0.001 to 0.1
140232
233+ # Store fidelity results for each noise type
141234 fidelities = {"Depolarizing" : [], "Amplitude Damping" : [], "Phase Damping" : []}
142235
236+ # Use density matrix method (needed for mixed states from noise)
237+ # MATH: Pure states → vectors |ψ⟩
238+ # Mixed states → density matrices ρ = Σᵢ pᵢ|ψᵢ⟩⟨ψᵢ|
143239 simulator = AerSimulator (method = "density_matrix" )
144240
241+ # ==================================================================
242+ # STEP 3: Loop through error rates and measure fidelity
243+ # ==================================================================
145244 for error_rate in error_rates :
146245 print (f"Testing error rate: { error_rate :.4f} " )
147246
148247 for noise_type in fidelities .keys ():
149- # Create noise model
248+ # =============================================================
249+ # Create noise model for this error rate
250+ # =============================================================
251+ # IMPORTANT: We need separate noise models for 1-qubit and 2-qubit gates
252+ # WHY? Gates have different durations and complexities
253+ # TYPICAL: 2-qubit gates have ~10× higher error rates than 1-qubit gates
254+
150255 if noise_type == "Depolarizing" :
151- error_1q = depolarizing_error (error_rate , 1 )
152- error_2q = depolarizing_error (error_rate , 2 )
256+ # DEPOLARIZING: Affects both single and two-qubit gates
257+ # MATH: ρ → (1-p)ρ + p·(I/d) where d = dimension (2 for qubits)
258+ error_1q = depolarizing_error (error_rate , 1 ) # Single-qubit H gate
259+ error_2q = depolarizing_error (error_rate , 2 ) # Two-qubit CNOT gate
153260 elif noise_type == "Amplitude Damping" :
261+ # AMPLITUDE DAMPING: |1⟩ → |0⟩ energy decay
262+ # NOTE: Only defined for single qubits (it's a physical process)
154263 error_1q = amplitude_damping_error (error_rate )
155- # For 2-qubit gates, use depolarizing as amplitude damping is 1-qubit only
264+ # For 2-qubit gates, approximate with depolarizing
156265 error_2q = depolarizing_error (error_rate , 2 )
157266 else : # Phase Damping
267+ # PHASE DAMPING: Phase coherence loss
268+ # MATH: Random Z rotations destroy phase relationships
269+ # NOTE: Also only for single qubits
158270 error_1q = phase_damping_error (error_rate )
159- # For 2-qubit gates, use depolarizing as phase damping is 1-qubit only
271+ # For 2-qubit gates, approximate with depolarizing
160272 error_2q = depolarizing_error (error_rate , 2 )
161273
274+ # Build the complete noise model
162275 noise_model = NoiseModel ()
163- noise_model .add_all_qubit_quantum_error (error_1q , ["h" ])
164- noise_model .add_all_qubit_quantum_error (error_2q , ["cx" ])
165-
166- # Run simulation with noise - need to save and retrieve density matrix
276+ noise_model .add_all_qubit_quantum_error (error_1q , ["h" ]) # H gate gets error_1q
277+ noise_model .add_all_qubit_quantum_error (error_2q , ["cx" ]) # CNOT gets error_2q
278+
279+ # =============================================================
280+ # Run noisy simulation
281+ # =============================================================
282+ # TECHNICAL: We save the density matrix (not just measurements)
283+ # WHY? Density matrix ρ contains full info about mixed states
284+ # PURE STATE: ρ = |ψ⟩⟨ψ| (rank-1 matrix)
285+ # NOISY STATE: ρ = Σᵢ pᵢ|ψᵢ⟩⟨ψᵢ| (rank > 1, mixed state)
167286 qc_copy = qc .copy ()
168- qc_copy .save_density_matrix ()
287+ qc_copy .save_density_matrix () # Tell simulator to save ρ
169288
170289 job = simulator .run (transpile (qc_copy , simulator ), noise_model = noise_model )
171290 result = job .result ()
172291 noisy_state = result .data ()['density_matrix' ]
173292
174- # Calculate fidelity
293+ # =============================================================
294+ # Calculate fidelity (how similar ideal vs noisy states are)
295+ # =============================================================
296+ # FORMULA: F = Tr(√(√ρ₁ ρ₂ √ρ₁))²
297+ # INTERPRETATION:
298+ # - F ≈ 1.0: Very little noise damage (excellent!)
299+ # - F ≈ 0.8-0.9: Moderate noise (usable)
300+ # - F < 0.7: High noise (problematic)
175301 fidelity = state_fidelity (ideal_state , noisy_state )
176302 fidelities [noise_type ].append (fidelity )
177303
0 commit comments