Circuit

This module provides a representation of quantum circuits and operations for quantum computing simulations. It implements the fundamental building blocks for creating, manipulating, and measuring quantum circuits.

Circuit Module Documentation

Overview

The Circuit module provides the core functionality for building and executing quantum circuits in LogosQ. It allows you to construct quantum circuits by adding gates sequentially, execute them on quantum states, and perform various circuit manipulations.

Core Components

Circuit Structure

pub struct Circuit {
    // Fields are private - use getter methods to access
}

Access Methods:

  • num_qubits(): Returns the number of qubits in the circuit
  • operations(): Returns a reference to the operations vector
  • num_operations(): Returns the number of operations
  • name(): Returns an optional reference to the circuit name

Operation Structure

pub struct Operation {
    // Fields are private - use getter methods to access
}

Access Methods:

  • gate(): Returns a reference to the gate (wrapped in Arc for thread safety)
  • qubits(): Returns a slice of qubit indices
  • name(): Returns the operation name

Note: Internal fields are encapsulated. The gate field uses Arc instead of Rc for thread-safe shared ownership.

Basic Usage

Creating a Circuit

use logosq::circuits::Circuit;
use logosq::states::State;

// Create a 3-qubit circuit
let mut circuit = Circuit::new(3);

// Create a named circuit
let mut named_circuit = Circuit::new(2).with_name("Bell State Circuit");

Adding Gates

Single-Qubit Gates

// Add Pauli gates
circuit.x(0);  // Pauli-X on qubit 0
circuit.y(1);  // Pauli-Y on qubit 1
circuit.z(2);  // Pauli-Z on qubit 2

// Add Hadamard gate
circuit.h(0);  // Hadamard on qubit 0

// Add phase gates
circuit.s(1);  // S gate on qubit 1
circuit.t(2);  // T gate on qubit 2

// Add rotation gates
circuit.rx(0, std::f64::consts::PI / 4.0);  // RX rotation
circuit.ry(1, std::f64::consts::PI / 2.0);  // RY rotation
circuit.rz(2, std::f64::consts::PI / 3.0);  // RZ rotation

Two-Qubit Gates

// CNOT gate
circuit.cnot(0, 1);  // Control: qubit 0, Target: qubit 1

// Controlled-Z gate
circuit.cz(0, 2);    // Control: qubit 0, Target: qubit 2

// SWAP gate
circuit.swap(1, 2);  // Swap qubits 1 and 2

Three-Qubit Gates

// Toffoli (CCX) gate
circuit.toffoli(0, 1, 2);  // Controls: qubits 0,1, Target: qubit 2

Method Chaining

The circuit methods support method chaining for convenient circuit construction:

let mut circuit = Circuit::new(3)
    .with_name("Example Circuit");

circuit.h(0)
       .cnot(0, 1)
       .x(2)
       .cz(1, 2)
       .ry(0, std::f64::consts::PI / 4.0);

Circuit Execution

Execute on a State

use logosq::prelude::*;

// Create initial state
let mut state = State::zero_state(3);

// Execute circuit (returns Result)
circuit.execute(&mut state)?;

// The state is now modified according to the circuit operations

Execute and Measure

use logosq::prelude::*;

// Execute circuit and measure all qubits (returns Result)
let measurement_results = circuit.execute_and_measure()?;
println!("Measurement results: {:?}", measurement_results);

Execute with Noise

// Add noise model to circuit
circuit.add_noise(some_noise_model);

// Execute with noise applied
let noisy_results = circuit.execute_and_measure_with_noise();

Advanced Operations

Circuit Composition

Combine multiple circuits together:

use logosq::prelude::*;

let mut circuit1 = Circuit::new(2);
circuit1.h(0).cnot(0, 1);

let mut circuit2 = Circuit::new(2);
circuit2.x(0).z(1);

// Compose circuits (returns Result)
circuit1.compose(&circuit2)?;
// circuit1 now contains operations from both circuits

Circuit Reversal

Create a reversed version of a circuit:

let original = Circuit::new(2);
original.h(0).cnot(0, 1).x(1);

let reversed = original.reversed();
// Operations are applied in reverse order

Expectation Values

Calculate expectation values of observables:

use logosq::prelude::*;

let observable = z_gate();
let expectation = circuit.expectation(&observable)?;
println!("Expectation value: {}", expectation);

Custom Gates

Adding Matrix Gates

You can add custom gates by providing their matrix representation:

use ndarray::Array2;
use num_complex::Complex64;

// Define a custom 2x2 matrix
let custom_matrix = Array2::from_shape_vec(
    (2, 2),
    vec![
        Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0),
        Complex64::new(0.0, 0.0), Complex64::new(-1.0, 0.0),
    ],
).unwrap();

// Add to circuit (returns Result)
circuit.add_matrix_gate(custom_matrix, vec![0], "CustomGate")?;

Single-Qubit Custom Gates

use logosq::prelude::*;

circuit.add_single_qubit_gate(custom_matrix, 0, "MyGate")?;

Two-Qubit Custom Gates

use logosq::prelude::*;

// 4x4 matrix for two-qubit gate
let two_qubit_matrix = Array2::zeros((4, 4));
circuit.add_two_qubit_gate(two_qubit_matrix, 0, 1, "CustomTwoQubit")?;

Common Quantum Circuit Patterns

Bell State Preparation

let mut bell_circuit = Circuit::new(2).with_name("Bell State");
bell_circuit.h(0)
           .cnot(0, 1);

let mut state = State::zero_state(2);
bell_circuit.execute(&mut state)?;
// Now |state⟩ = (|00⟩ + |11⟩)/√2

GHZ State Preparation

let mut ghz_circuit = Circuit::new(3).with_name("GHZ State");
ghz_circuit.h(0)
          .cnot(0, 1)
          .cnot(0, 2);

let mut state = State::zero_state(3);
ghz_circuit.execute(&mut state)?;
// Now |state⟩ = (|000⟩ + |111⟩)/√2

Quantum Fourier Transform

use logosq::algorithms::qft;

let qft_circuit = qft::create_circuit(4);  // 4-qubit QFT
let mut state = State::plus_state(4);
qft_circuit.execute(&mut state)?;

Error Handling

The circuit module uses comprehensive error handling with Result types:

use logosq::prelude::*;

// Methods return Result types - handle errors appropriately
match circuit.add_operation(gate, vec![5], "Gate") {
    Ok(_) => println!("Gate added successfully"),
    Err(LogosQError::InvalidQubitIndex { index, num_qubits }) => {
        println!("Qubit {} is out of range for {} qubit circuit", index, num_qubits);
    }
    Err(e) => println!("Error: {}", e),
}

// Or use the ? operator for error propagation
circuit.add_operation(gate, vec![0], "Gate")?;

Common Errors:

  • InvalidQubitIndex: Qubit index is out of range
  • ControlTargetSameQubit: Control and target qubits are the same
  • CircuitQubitMismatch: Circuit and state have different qubit counts

Debugging and Visualization

Debug Output

println!("{:?}", circuit);
// Output:
// Circuit: Bell State (2 qubits)
// 0: H(qubits: [0])
// 1: CNOT(qubits: [0, 1])

Circuit Information

use logosq::prelude::*;

println!("Circuit has {} qubits", circuit.num_qubits());
println!("Circuit has {} operations", circuit.num_operations());

if let Some(name) = circuit.name() {
    println!("Circuit name: {}", name);
}

Performance Considerations

  1. Gate Order: The order of operations matters for quantum circuits
  2. Memory Usage: Large circuits with many qubits consume exponential memory
  3. Noise Models: Adding noise models increases execution time
  4. Matrix Operations: Custom matrix gates may be slower than built-in gates

Integration with Other Modules

States Module

use logosq::prelude::*;
let mut state = State::zero_state(circuit.num_qubits());
circuit.execute(&mut state)?;

Gates Module

use logosq::gates::{x_gate, h_gate};
// Built-in gates are automatically available through circuit methods

Algorithms Module

use logosq::algorithms::qft;
let algorithm_circuit = qft::create_circuit(4);
circuit.compose(&algorithm_circuit);

Example: Complete Quantum Algorithm

use logosq::prelude::*;

fn quantum_teleportation_circuit() -> Circuit {
    let mut circuit = Circuit::new(3).with_name("Quantum Teleportation");
    
    // Prepare Bell pair between qubits 1 and 2
    circuit.h(1)
           .cnot(1, 2);
    
    // Alice's operations (teleporting qubit 0)
    circuit.cnot(0, 1)
           .h(0);
    
    // Measurements would go here (not shown in circuit)
    
    // Bob's corrections (conditional on measurements)
    // circuit.cnot(1, 2);  // If Alice measured 1 on qubit 1
    // circuit.z(2);        // If Alice measured 1 on qubit 0
    
    circuit
}

fn main() -> Result<(), LogosQError> {
    let circuit = quantum_teleportation_circuit();
    let results = circuit.execute_and_measure()?;
    println!("Teleportation results: {:?}", results);
    Ok(())
}

This documentation provides comprehensive coverage of the Circuit module's functionality, from basic usage to advanced features, with practical examples throughout.