diff options
| author | hachem <im@hachem.wtf> | 2025-12-06 22:33:56 +0100 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2025-12-06 22:33:56 +0100 |
| commit | 1fb7989e9405f9795a1d5b3953881b9bb8a137b4 (patch) | |
| tree | c680f041fe41e5ccd1e311ec7b1502abb96237af /libpsi-core/src/core/custom_gate.rs | |
| parent | edc6bae7bf5039c8cef2f2c9c164187478b1c7eb (diff) | |
[add]: custom gates + rework vertical renderer
Diffstat (limited to 'libpsi-core/src/core/custom_gate.rs')
| -rw-r--r-- | libpsi-core/src/core/custom_gate.rs | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/libpsi-core/src/core/custom_gate.rs b/libpsi-core/src/core/custom_gate.rs new file mode 100644 index 0000000..9e49ac9 --- /dev/null +++ b/libpsi-core/src/core/custom_gate.rs @@ -0,0 +1,245 @@ +use crate::{Complex, Matrix, QuantumGate}; + +#[derive(Clone)] +pub enum CustomGateDefinition { + Matrix(Matrix<Complex<f64>>), + Composite(Vec<(CompositeOp, Vec<usize>)>), +} + +#[derive(Clone, Copy)] +pub enum CompositeOp { + H, + X, + Y, + Z, + S, + T, + CNOT, + CZ, + SWAP, + CCNOT, + CSWAP, +} + +#[derive(Clone)] +pub struct CustomGate { + pub name: String, + pub num_qubits: usize, + pub definition: CustomGateDefinition, +} + +impl CustomGate { + pub fn from_matrix(name: &str, matrix: Matrix<Complex<f64>>) -> Self { + let dim = matrix.rows; + let num_qubits = (dim as f64).log2() as usize; + assert_eq!( + 1 << num_qubits, + dim, + "Matrix dimension must be a power of 2" + ); + assert_eq!(matrix.rows, matrix.cols, "Matrix must be square"); + + CustomGate { + name: String::from(name), + num_qubits, + definition: CustomGateDefinition::Matrix(matrix), + } + } + + pub fn from_composite( + name: &str, + num_qubits: usize, + ops: Vec<(CompositeOp, Vec<usize>)>, + ) -> Self { + CustomGate { + name: String::from(name), + num_qubits, + definition: CustomGateDefinition::Composite(ops), + } + } + + pub fn to_quantum_gate(&self) -> QuantumGate<'static> { + match &self.definition { + CustomGateDefinition::Matrix(matrix) => { + let name: &'static str = Box::leak(self.name.clone().into_boxed_str()); + QuantumGate { + name, + matrix: matrix.clone(), + num_qubits: self.num_qubits, + } + } + CustomGateDefinition::Composite(ops) => { + let matrix = self.compute_composite_matrix(ops); + let name: &'static str = Box::leak(self.name.clone().into_boxed_str()); + QuantumGate { + name, + matrix, + num_qubits: self.num_qubits, + } + } + } + } + + fn compute_composite_matrix(&self, ops: &[(CompositeOp, Vec<usize>)]) -> Matrix<Complex<f64>> { + use crate::gates::*; + use crate::Complex; + + let dim = 1 << self.num_qubits; + let mut result = Matrix::new(dim, dim, vec![Complex::new(0.0, 0.0); dim * dim]); + for i in 0..dim { + result.data[i * dim + i] = Complex::new(1.0, 0.0); + } + + for (op, targets) in ops { + let gate: &QuantumGate = match op { + CompositeOp::H => &HADAMARD, + CompositeOp::X => &PAULI_X, + CompositeOp::Y => &PAULI_Y, + CompositeOp::Z => &PAULI_Z, + CompositeOp::S => &S_GATE, + CompositeOp::T => &T_GATE, + CompositeOp::CNOT => &CNOT, + CompositeOp::CZ => &CZ, + CompositeOp::SWAP => &SWAP, + CompositeOp::CCNOT => &TOFFOLI, + CompositeOp::CSWAP => &FREDKIN, + }; + + let full_gate = build_full_operator(&gate.matrix, targets, self.num_qubits); + result = matrix_multiply(&full_gate, &result); + } + + result + } +} + +fn build_full_operator( + gate_matrix: &Matrix<Complex<f64>>, + targets: &[usize], + total_qubits: usize, +) -> Matrix<Complex<f64>> { + let dim = 1 << total_qubits; + let gate_dim = gate_matrix.rows; + let num_gate_qubits = targets.len(); + + let mut result = Matrix::new(dim, dim, vec![Complex::new(0.0, 0.0); dim * dim]); + + for i in 0..dim { + for j in 0..dim { + let mut gate_i = 0usize; + let mut gate_j = 0usize; + let mut match_non_targets = true; + + for q in 0..total_qubits { + let bit_i = (i >> (total_qubits - 1 - q)) & 1; + let bit_j = (j >> (total_qubits - 1 - q)) & 1; + + if let Some(pos) = targets.iter().position(|&t| t == q) { + gate_i |= bit_i << (num_gate_qubits - 1 - pos); + gate_j |= bit_j << (num_gate_qubits - 1 - pos); + } else if bit_i != bit_j { + match_non_targets = false; + break; + } + } + + if match_non_targets { + result.data[i * dim + j] = gate_matrix.data[gate_i * gate_dim + gate_j]; + } + } + } + + result +} + +fn matrix_multiply(a: &Matrix<Complex<f64>>, b: &Matrix<Complex<f64>>) -> Matrix<Complex<f64>> { + let n = a.rows; + let mut result = Matrix::new(n, n, vec![Complex::new(0.0, 0.0); n * n]); + + for i in 0..n { + for j in 0..n { + let mut sum = Complex::new(0.0, 0.0); + for k in 0..n { + sum = sum + a.data[i * n + k] * b.data[k * n + j]; + } + result.data[i * n + j] = sum; + } + } + + result +} + +pub struct CustomGateBuilder { + name: String, + num_qubits: usize, + ops: Vec<(CompositeOp, Vec<usize>)>, +} + +impl CustomGateBuilder { + pub fn new(name: &str, num_qubits: usize) -> Self { + CustomGateBuilder { + name: String::from(name), + num_qubits, + ops: Vec::new(), + } + } + + pub fn h(mut self, target: usize) -> Self { + self.ops.push((CompositeOp::H, vec![target])); + self + } + + pub fn x(mut self, target: usize) -> Self { + self.ops.push((CompositeOp::X, vec![target])); + self + } + + pub fn y(mut self, target: usize) -> Self { + self.ops.push((CompositeOp::Y, vec![target])); + self + } + + pub fn z(mut self, target: usize) -> Self { + self.ops.push((CompositeOp::Z, vec![target])); + self + } + + pub fn s(mut self, target: usize) -> Self { + self.ops.push((CompositeOp::S, vec![target])); + self + } + + pub fn t(mut self, target: usize) -> Self { + self.ops.push((CompositeOp::T, vec![target])); + self + } + + pub fn cnot(mut self, control: usize, target: usize) -> Self { + self.ops.push((CompositeOp::CNOT, vec![control, target])); + self + } + + pub fn cz(mut self, control: usize, target: usize) -> Self { + self.ops.push((CompositeOp::CZ, vec![control, target])); + self + } + + pub fn swap(mut self, a: usize, b: usize) -> Self { + self.ops.push((CompositeOp::SWAP, vec![a, b])); + self + } + + pub fn ccnot(mut self, c1: usize, c2: usize, target: usize) -> Self { + self.ops.push((CompositeOp::CCNOT, vec![c1, c2, target])); + self + } + + pub fn cswap(mut self, control: usize, t1: usize, t2: usize) -> Self { + self.ops.push((CompositeOp::CSWAP, vec![control, t1, t2])); + self + } + + pub fn build(self) -> CustomGate { + CustomGate::from_composite(&self.name, self.num_qubits, self.ops) + } +} |
