Skip to main content
โšก Calmops

Quantum Computing: Quantum Algorithms and Quantum Simulators

Introduction

Quantum computing leverages quantum mechanical phenomena to process information in fundamentally different ways than classical computers. This article covers quantum computing fundamentals, algorithms, and practical implementation with modern quantum frameworks.

Key Statistics:

  • Quantum computers: 1000+ qubits (IBM, Google)
  • Quantum advantage: certain problems exponentially faster
  • Market size: $1.2B (2025), projected $8B by 2030
  • Error rates: 0.1-1% (improving rapidly)

Quantum Computing Fundamentals

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚              Classical vs Quantum Computing                              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                  โ”‚
โ”‚  Classical Bit                                                    โ”‚
โ”‚  โ”œโ”€โ”€ States: 0 or 1                                              โ”‚
โ”‚  โ”œโ”€โ”€ N bits: 2^N possible states                                โ”‚
โ”‚  โ””โ”€โ”€ Operations: Boolean logic                                   โ”‚
โ”‚                                                                  โ”‚
โ”‚  Quantum Bit (Qubit)                                             โ”‚
โ”‚  โ”œโ”€โ”€ States: |0โŸฉ or |1โŸฉ (superposition)                         โ”‚
โ”‚  โ”œโ”€โ”€ N qubits: 2^N possible states (entangled)                  โ”‚
โ”‚  โ””โ”€โ”€ Operations: Quantum gates                                   โ”‚
โ”‚                                                                  โ”‚
โ”‚  Key Phenomena                                                   โ”‚
โ”‚  โ”œโ”€โ”€ Superposition: Multiple states simultaneously              โ”‚
โ”‚  โ”œโ”€โ”€ Entanglement: Correlated qubit states                      โ”‚
โ”‚  โ””โ”€โ”€ Interference: Amplify correct answers                      โ”‚
โ”‚                                                                  โ”‚
โ”‚  Limitations                                                     โ”‚
โ”‚  โ”œโ”€โ”€ Decoherence: Quantum states degrade                        โ”‚
โ”‚  โ”œโ”€โ”€ Error rates: 0.1-1% gate errors                            โ”‚
โ”‚  โ””โ”€โ”€ No-cloning: Cannot copy quantum states                     โ”‚
โ”‚                                                                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Quantum Gates and Circuits

#!/usr/bin/env python3
"""Quantum circuit construction with Qiskit."""

from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
from qiskit.quantum_info import Statevector
import numpy as np

# Single Qubit Gates
qc = QuantumCircuit(1)

# Pauli gates
qc.x(0)  # NOT gate (Pauli-X)
qc.y(0)  # Pauli-Y
qc.z(0)  # Pauli-Z

# Hadamard gate (creates superposition)
qc.h(0)

# Phase gates
qc.s(0)   # S gate (phase shift by ฯ€/2)
qc.t(0)   # T gate (phase shift by ฯ€/4)

# Rotation gates
qc.rx(np.pi/4, 0)  # Rotation around X axis
qc.ry(np.pi/4, 0)  # Rotation around Y axis
qc.rz(np.pi/4, 0)  # Rotation around Z axis

# Two-Qubit Gates
qc2 = QuantumCircuit(2)

# CNOT (Controlled-NOT)
qc2.cx(0, 1)  # If qubit 0 is |1โŸฉ, apply X to qubit 1

# Controlled-Z
qc2.cz(0, 1)

# SWAP
qc2.swap(0, 1)

# Toffoli (CCNOT) - universal classical gate
qc2.ccx(0, 1, 2)

# Bell State (Entangled pair)
def create_bell_state(qc: QuantumCircuit, q0: int, q1: int):
    """Create Bell state |ฮฆ+โŸฉ = (|00โŸฉ + |11โŸฉ)/โˆš2."""
    qc.h(q0)      # Hadamard on first qubit
    qc.cx(q0, q1)  # CNOT entangles them

# GHZ State (Greenberger-Horne-Zeilinger)
def create_ghz_state(qc: QuantumCircuit, num_qubits: int):
    """Create GHZ state: (|0...0โŸฉ + |1...1โŸฉ)/โˆš2."""
    qc.h(0)
    for i in range(num_qubits - 1):
        qc.cx(i, i + 1)

# Example: Create Bell state and simulate
def run_bell_state_simulation():
    """Run Bell state simulation."""
    
    qc = QuantumCircuit(2, 2)
    create_bell_state(qc, 0, 1)
    qc.measure([0, 1], [0, 1])
    
    # Use Aer simulator
    simulator = AerSimulator()
    job = simulator.run(qc, shots=1000)
    result = job.result()
    counts = result.get_counts()
    
    print(f"Bell state measurement: {counts}")
    # Expected: {'00': ~500, '11': ~500}

run_bell_state_simulation()

Quantum Algorithms

Grover’s Search Algorithm

#!/usr/bin/env python3
"""Grover's algorithm implementation with Qiskit."""

from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
import numpy as np

def grover_oracle(qc: QuantumCircuit, target_state: int, 
                  num_qubits: int):
    """
    Oracle for Grover's search.
    Marks the target state with a phase flip.
    """
    
    # Convert target to binary and apply X gates for |1โŸฉ bits
    for i in range(num_qubits):
        if not (target_state >> i) & 1:
            qc.x(i)
    
    # Multi-controlled Z gate (using CZ from last to first)
    qc.h(num_qubits - 1)
    qc.mcx(list(range(num_qubits - 1)), num_qubits - 1)
    qc.h(num_qubits - 1)
    
    # Undo X gates
    for i in range(num_qubits):
        if not (target_state >> i) & 1:
            qc.x(i)

def grover_diffuser(qc: QuantumCircuit, num_qubits: int):
    """
    Grover diffuser (inversion about the mean).
    Amplifies the probability of marked states.
    """
    
    # Apply Hadamard to all qubits
    for i in range(num_qubits):
        qc.h(i)
    
    # Apply multi-controlled Z
    qc.h(num_qubits - 1)
    qc.mcx(list(range(num_qubits - 1)), num_qubits - 1)
    qc.h(num_qubits - 1)
    
    # Apply Hadamard to all qubits
    for i in range(num_qubits):
        qc.h(i)

def grover_algorithm(num_qubits: int, target_state: int, 
                     iterations: int = None):
    """
    Grover's search algorithm.
    
    Optimal iterations: round(ฯ€/4 * sqrt(N))
    where N = 2^n (number of qubits)
    """
    
    if iterations is None:
        iterations = int(np.round(np.pi / 4 * np.sqrt(2 ** num_qubits)))
    
    qc = QuantumCircuit(num_qubits, num_qubits)
    
    # Initialize superposition
    for i in range(num_qubits):
        qc.h(i)
    
    # Apply Grover iterations
    for _ in range(iterations):
        grover_oracle(qc, target_state, num_qubits)
        grover_diffuser(qc, num_qubits)
    
    # Measure
    qc.measure(range(num_qubits), range(num_qubits))
    
    return qc

# Example: Search in 4-qubit space (16 elements)
def run_grover_example():
    """Run Grover's algorithm example."""
    
    num_qubits = 4
    target = 5  # Searching for state |0101โŸฉ
    
    qc = grover_algorithm(num_qubits, target)
    
    simulator = AerSimulator()
    job = simulator.run(qc, shots=1000)
    result = job.result()
    counts = result.get_counts()
    
    print(f"Grover's search for state {target}:")
    for state, count in sorted(counts.items(), 
                               key=lambda x: -x[1]):
        print(f"  |{state}โŸฉ: {count} shots")
    
    # Target should have highest probability

run_grover_example()

Quantum Phase Estimation

#!/usr/bin/env python3
"""Quantum Phase Estimation algorithm."""

from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit_aer import AerSimulator
import numpy as np

def quantum_phase_estimation(unitary, num_qubits=5, num_iterations=1):
    """
    Quantum Phase Estimation (QPE).
    
    Estimates the phase (eigenvalue) of a unitary operator.
    Used in Shor's algorithm and many quantum algorithms.
    """
    
    # Number of precision qubits
    precision_qubits = num_qubits
    
    # Create circuit
    qc = QuantumCircuit(
        QuantumRegister(precision_qubits, 'precision'),
        QuantumRegister(num_qubits, 'eigenstate'),
        ClassicalRegister(precision_qubits, 'result')
    )
    
    # Initialize eigenstate to |1โŸฉ
    for i in range(num_qubits):
        qc.x(precision_qubits + i)
    
    # Apply Hadamard to precision qubits
    for i in range(precision_qubits):
        qc.h(i)
    
    # Apply controlled unitary operations
    for i in range(precision_qubits):
        power = 2 ** i
        for _ in range(power):
            # Controlled-U^(2^i)
            # In practice, use qiskit.circuit.libraryControlledU1
            qc.cp(np.pi / (2 ** (i + 1)), 
                  precision_qubits + num_qubits - 1, 
                  i)
    
    # Inverse QFT (simplified for demonstration)
    for i in range(precision_qubits // 2):
        qc.swap(i, precision_qubits - 1 - i)
    
    for i in range(precision_qubits):
        for j in range(i + 1, precision_qubits):
            qc.cp(-np.pi / (2 ** (j - i)), i, j)
    
    for i in range(precision_qubits):
        qc.h(i)
    
    # Measure precision qubits
    qc.measure(range(precision_qubits), 
               range(precision_qubits))
    
    return qc

Quantum Simulators

Running on Simulators vs Real Hardware

#!/usr/bin/env python3
"""Quantum simulator comparison and usage."""

from qiskit_aer import AerSimulator, QasmSimulator
from qiskit_aer.noise import NoiseModel, QuantumError, ReadoutError
from qiskit import transpile
import numpy as np

class QuantumSimulatorManager:
    """Manage different quantum simulators."""
    
    def __init__(self):
        self.simulators = {}
        self._setup_simulators()
    
    def _setup_simulators(self):
        """Initialize various simulators."""
        
        # State vector simulator (exact, no noise)
        self.simulators['statevector'] = AerSimulator(
            method='statevector'
        )
        
        # QASM simulator (like real hardware)
        self.simulators['qasm'] = QasmSimulator(
            method='automatic'
        )
        
        # Matrix product state (efficient for certain circuits)
        self.simulators['mps'] = AerSimulator(
            method='matrix_product_state'
        )
        
        # Stabilizer simulator (for Clifford circuits)
        self.simulators['stabilizer'] = AerSimulator(
            method='stabilizer'
        )
    
    def simulate_statevector(self, circuit, 
                            return_statevector: bool = True):
        """Simulate and return statevector."""
        
        result = self.simulators['statevector'].run(
            circuit, 
            return_statevector=return_statevector
        ).result()
        
        return result
    
    def simulate_with_noise(self, circuit, noise_model: NoiseModel):
        """Simulate with realistic noise model."""
        
        # Create noisy simulator
        noisy_simulator = QasmSimulator()
        
        result = noisy_simulator.run(
            circuit,
            noise_model=noise_model,
            shots=1000
        ).result()
        
        return result
    
    def benchmark_circuit(self, circuit, 
                         num_qubits_range: list):
        """Benchmark circuit across different simulators."""
        
        results = {}
        
        for name, sim in self.simulators.items():
            try:
                import time
                start = time.time()
                
                job = sim.run(circuit, shots=100)
                result = job.result()
                
                results[name] = {
                    'success': True,
                    'time': time.time() - start,
                    'counts': result.get_counts()
                }
            except Exception as e:
                results[name] = {
                    'success': False,
                    'error': str(e)
                }
        
        return results

def create_noise_model():
    """Create realistic noise model based on IBM hardware."""
    
    noise_model = NoiseModel()
    
    # Single-qubit gate errors (typical for 127-qubit systems)
    error_1q = 0.001  # 0.1% error rate
    
    # Two-qubit gate errors
    error_2q = 0.01  # 1% error rate
    
    # Measurement errors
    meas_error = 0.02  # 2% error rate
    
    # Add depolarizing errors
    from qiskit_aer.noise import depolarizing_error
    
    # 1-qubit depolarizing error
    error_gate1 = depolarizing_error(error_1q, 1)
    
    # 2-qubit depolarizing error
    error_gate2 = depolarizing_error(error_2q, 2)
    
    # Add errors to noise model
    noise_model.add_all_qubit_quantum_error(error_gate1, ['h', 'x', 'y', 'z', 's', 't'])
    noise_model.add_all_qubit_quantum_error(error_gate2, ['cx', 'cz', 'swap'])
    
    return noise_model

Qiskit Implementation

#!/usr/bin/env python3
"""Complete Qiskit implementation example."""

from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
from qiskit.quantum_info import Statevector, Operator
from qiskit.circuit import Parameter
from qiskit.visualization import plot_histogram, plot_state_city
import numpy as np

class QuantumApplication:
    """Example quantum application."""
    
    def __init__(self, backend=None):
        self.backend = backend or AerSimulator()
    
    def variational_circuit(self, params):
        """
        Variational quantum circuit (like VQE).
        Parameters are optimized classically.
        """
        
        num_qubits = 4
        qc = QuantumCircuit(num_qubits)
        
        # Initial superposition
        for i in range(num_qubits):
            qc.h(i)
        
        # Parameterized rotations
        param_idx = 0
        for layer in range(3):  # 3 layers
            # Rotation layer
            for i in range(num_qubits):
                qc.ry(params[param_idx], i)
                param_idx += 1
            
            # Entanglement layer
            for i in range(num_qubits - 1):
                qc.cx(i, i + 1)
            qc.cx(num_qubits - 1, 0)
        
        return qc
    
    def run_vqe_step(self, params):
        """Run one VQE optimization step."""
        
        qc = self.variational_circuit(params)
        
        # Transpile for backend
        qc_transpiled = transpile(qc, self.backend)
        
        # Run
        result = self.backend.run(qc_transpiled, shots=1000).result()
        
        # Calculate expectation value (simplified)
        counts = result.get_counts()
        
        # Example: maximize |0000โŸฉ probability
        probability_0000 = counts.get('0000', 0) / 1000
        
        return probability_0000
    
    def quantum_approximate_optimization(self, num_qubits=4, 
                                         iterations=5):
        """
        QAOA (Quantum Approximate Optimization Algorithm).
        For solving combinatorial optimization problems.
        """
        
        # Problem Hamiltonian (simplified: maximize ones)
        gamma = Parameter('gamma')
        beta = Parameter('beta')
        
        qc = QuantumCircuit(num_qubits)
        
        # Initial superposition
        for i in range(num_qubits):
            qc.h(i)
        
        # QAOA layers
        for _ in range(iterations):
            # Problem unitary (cost function)
            for i in range(num_qubits):
                qc.rz(2 * gamma, i)
            
            # Mixer unitary (driver)
            for i in range(num_qubits):
                qc.rx(2 * beta, i)
        
        return qc
    
    def quantum_machine_learning(self):
        """
        Quantum machine learning circuits.
        Data encoding and parameterized circuits.
        """
        
        # Amplitude encoding (2^n dimensions with n qubits)
        data = [0.1, 0.2, 0.3, 0.4]  # 4-dimensional
        norm = np.linalg.norm(data)
        
        qc = QuantumCircuit(2)
        
        # Encode as amplitudes (normalized)
        qc.initialize([d/norm for d in data], [0, 1])
        
        # Feature map (like kernel trick)
        # For classification: qkernel = FeatureMap(...)
        
        return qc

def quantum_fourier_transform(n_qubits):
    """
    Quantum Fourier Transform (QFT).
    Exponential speedup over classical FFT.
    """
    
    qc = QuantumCircuit(n_qubits)
    
    # Apply QFT
    for j in range(n_qubits):
        for k in range(j + 1):
            qc.h(j)
            qc.cp(np.pi / (2 ** (j - k)), k, j)
    
    # Swap qubits (reverse order)
    for i in range(n_qubits // 2):
        qc.swap(i, n_qubits - 1 - i)
    
    return qc

Cirq Implementation

#!/usr/bin/env python3
"""Google Cirq quantum computing framework."""

import cirq
import numpy as np

class CirqQuantumCircuit:
    """Cirq implementation examples."""
    
    def __init__(self):
        self.simulator = cirq.Simulator()
    
    def create_ghz_circuit(self, num_qubits):
        """Create GHZ state circuit."""
        
        # Create qubits
        qubits = [cirq.LineQubit(i) for i in range(num_qubits)]
        
        # Create circuit
        circuit = cirq.Circuit()
        
        # Apply gates
        circuit.append(cirq.H(qubits[0]))
        
        for i in range(num_qubits - 1):
            circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
        
        # Measure
        circuit.append(cirq.measure(*qubits, key='result'))
        
        return circuit
    
    def run_simulation(self, circuit, shots=1000):
        """Run circuit simulation."""
        
        result = self.simulator.run(circuit, repetitions=shots)
        
        return result
    
    def create_parametrized_circuit(self):
        """Create parametrized circuit for optimization."""
        
        qubits = cirq.LineQubit.range(2)
        
        # Parametrized gates
        circuit = cirq.Circuit(
            cirq.rx(cirq.Symbol('theta'))(qubits[0]),
            cirq.ry(cirq.Symbol('phi'))(qubits[1]),
            cirq.CNOT(qubits[0], qubits[1]),
        )
        
        return circuit
    
    def optimize_parameters(self):
        """Optimize circuit parameters (similar to VQE)."""
        
        # Create circuit with parameters
        circuit = self.create_parametrized_circuit()
        
        # Sample different parameter values
        theta_values = np.linspace(0, 2 * np.pi, 10)
        phi_values = np.linspace(0, 2 * np.pi, 10)
        
        best_energy = float('inf')
        best_params = None
        
        for theta in theta_values:
            for phi in phi_values:
                # Resolve parameters
                resolved = circuit.with_parameters(
                    {'theta': theta, 'phi': phi}
                )
                
                # Simulate
                result = self.simulator.simulate(resolved)
                
                # Calculate expectation value
                # (simplified example)
                energy = np.abs(result.final_state_vector[0])
                
                if energy < best_energy:
                    best_energy = energy
                    best_params = (theta, phi)
        
        return best_params, best_energy

def cirq_quantum_walk(num_steps=10):
    """Quantum walk algorithm implementation."""
    
    # Position and coin qubits
    num_position = 4  # 2^4 = 16 positions
    num_coin = 2  # 2 coin states
    
    qubits = cirq.LineQubit.range(num_position + num_coin)
    position_qubits = qubits[:num_position]
    coin_qubits = qubits[num_position:]
    
    circuit = cirq.Circuit()
    
    # Initial state
    circuit.append(cirq.H.on_each(*coin_qubits))
    
    # Quantum walk steps
    for _ in range(num_steps):
        # Coin operator (Hadamard)
        circuit.append(cirq.H.on_each(*coin_qubits))
        
        # Shift operator (simplified)
        # In practice: conditional shifts based on coin state
        
        # Position mixing
        for i in range(num_position - 1):
            circuit.append(cirq.CNOT(position_qubits[i], 
                                     position_qubits[i + 1]))
    
    return circuit

Quantum Computing as a Service

# AWS Braket quantum computing configuration
quantum_computing:
  providers:
    - name: "IBM Quantum"
      endpoint: "https://quantum-computing.ibm.com/api"
      backends:
        - "ibm_brisbane"    # 127 qubits
        - "ibm_oslo"        # 127 qubits
        - "ibm_perth"       # 127 qubits
        
    - name: "AWS Braket"
      backends:
        - "Aspen-M-3"       # 80 qubits
        - "ionq_device"     # 11 qubits (ion trap)
        - "rigetti_aspen"   # 80 qubits
        
    - name: "Google Quantum AI"
      backends:
        - "sycamore"        # 53 qubits
        - "quantum_eagle"   # 127 qubits
        
    - name: "Microsoft Azure Quantum"
      backends:
        - "quantinuum_h2"   # 12 qubits
        - "ionq"            # 11 qubits

  job_configuration:
    max_shots: 10000
    priority: "normal"  # or "high" for faster execution
    job_tags:
      - "research"
      - "optimization"
#!/usr/bin/env python3
"""Submit quantum job to cloud provider."""

from qiskit import QuantumCircuit
from qiskit_ibm_provider import IBMProvider

class QuantumJobSubmitter:
    """Submit quantum jobs to cloud providers."""
    
    def __init__(self, provider_name='ibm'):
        self.provider_name = provider_name
        self.provider = None
        
        if provider_name == 'ibm':
            self.provider = IBMProvider()
    
    def list_backends(self):
        """List available backends."""
        
        if self.provider_name == 'ibm':
            backends = self.provider.backends()
            
            for backend in backends:
                print(f"{backend.name()}: "
                      f"{backend.num_qubits()} qubits, "
                      f"status: {backend.status().status_msg}")
    
    def submit_job(self, circuit: QuantumCircuit, 
                   backend_name: str = None, 
                   shots: int = 1000):
        """Submit job to quantum backend."""
        
        if not backend_name:
            # Get least busy backend
            backend = self.provider.get_backend(
                least_busy=True, 
                operational=True
            )
        else:
            backend = self.provider.get_backend(backend_name)
        
        # Transpile for backend
        transpiled = transpile(circuit, backend)
        
        # Submit job
        job = backend.run(transpiled, shots=shots)
        
        print(f"Job submitted: {job.job_id()}")
        
        return job
    
    def get_job_status(self, job_id: str):
        """Get job status."""
        
        job = self.provider.retrieve_job(job_id)
        
        return {
            'status': job.status(),
            'creation_date': job.creation_date(),
            'result': job.result() if job.done() else None
        }

Best Practices

Aspect Recommendation
Qubit selection Choose qubits with lowest error rates
Circuit depth Minimize gates; transpile optimally
Noise mitigation Use error suppression techniques
Shot count Balance accuracy vs. runtime cost
Hybrid quantum Use classical optimization with quantum
Job queuing Submit during off-peak hours

External Resources


Comments