use crate::error::{QuantumError, Result};
use moonlab_sys::{
moonlab_z2_lgt_1d_build, moonlab_z2_lgt_1d_gauss_law,
};
use std::slice;
pub struct Z2LgtHamiltonian {
pub paulis: Vec<u8>,
pub coeffs: Vec<f64>,
pub num_terms: u32,
pub num_qubits: u32,
}
pub fn build(
num_matter_sites: u32,
t_hop: f64,
h_link: f64,
mass: f64,
gauss_penalty: f64,
) -> Result<Z2LgtHamiltonian> {
if num_matter_sites < 2 {
return Err(QuantumError::InvalidQubit {
index: num_matter_sites as usize,
max: 2,
});
}
let mut paulis_ptr: *mut u8 = std::ptr::null_mut();
let mut coeffs_ptr: *mut f64 = std::ptr::null_mut();
let mut num_terms: u32 = 0;
let mut num_qubits: u32 = 0;
let rc = unsafe {
moonlab_z2_lgt_1d_build(
num_matter_sites,
t_hop,
h_link,
mass,
gauss_penalty,
&mut paulis_ptr,
&mut coeffs_ptr,
&mut num_terms,
&mut num_qubits,
)
};
if rc != 0 {
return Err(QuantumError::Ffi(format!(
"moonlab_z2_lgt_1d_build rc={rc}"
)));
}
if paulis_ptr.is_null() || coeffs_ptr.is_null() {
return Err(QuantumError::Ffi(
"moonlab_z2_lgt_1d_build returned null buffers".to_string(),
));
}
let paulis_len = num_terms as usize * num_qubits as usize;
let paulis = unsafe { slice::from_raw_parts(paulis_ptr, paulis_len) }
.to_vec();
let coeffs = unsafe { slice::from_raw_parts(coeffs_ptr, num_terms as usize) }
.to_vec();
unsafe {
libc::free(paulis_ptr as *mut libc::c_void);
libc::free(coeffs_ptr as *mut libc::c_void);
}
Ok(Z2LgtHamiltonian {
paulis,
coeffs,
num_terms,
num_qubits,
})
}
pub fn gauss_law(num_matter_sites: u32, site_x: u32) -> Result<Vec<u8>> {
if num_matter_sites < 2 {
return Err(QuantumError::InvalidQubit {
index: num_matter_sites as usize,
max: 2,
});
}
let n_qubits = (2 * num_matter_sites - 1) as usize;
let mut out = vec![0u8; n_qubits];
let rc = unsafe {
moonlab_z2_lgt_1d_gauss_law(num_matter_sites, site_x, out.as_mut_ptr())
};
if rc != 0 {
return Err(QuantumError::Ffi(format!(
"moonlab_z2_lgt_1d_gauss_law rc={rc}"
)));
}
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn build_n4_returns_nonempty_hamiltonian() {
let h = build(4, 1.0, 1.0, 0.5, 10.0).unwrap();
assert_eq!(h.num_qubits, 2 * 4 - 1);
assert!(h.num_terms > 0);
assert_eq!(
h.paulis.len(),
h.num_terms as usize * h.num_qubits as usize
);
assert_eq!(h.coeffs.len(), h.num_terms as usize);
}
#[test]
fn gauss_law_n4_site1_layout() {
let g = gauss_law(4, 1).unwrap();
assert_eq!(g.len(), 7);
assert_eq!(g[0], 0); assert_eq!(g[1], 1); assert_eq!(g[2], 3); assert_eq!(g[3], 1); assert_eq!(g[4], 0); assert_eq!(g[5], 0); assert_eq!(g[6], 0); }
#[test]
fn reject_too_few_sites() {
assert!(build(1, 1.0, 1.0, 0.5, 10.0).is_err());
assert!(gauss_law(1, 0).is_err());
}
}