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 circuitoperations(): Returns a reference to the operations vectornum_operations(): Returns the number of operationsname(): 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 indicesname(): 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 rangeControlTargetSameQubit: Control and target qubits are the sameCircuitQubitMismatch: 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
- Gate Order: The order of operations matters for quantum circuits
- Memory Usage: Large circuits with many qubits consume exponential memory
- Noise Models: Adding noise models increases execution time
- 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.