use crate::backend::backend::{Gate1, Gate2, QuantumBackend};
use crate::error::{QnectError, Result};
use async_trait::async_trait;
use log::info;
use serde_json::json;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::Mutex;
pub struct MockQnpuBackend {
_endpoint: String,
node_id: String,
n_qubits: usize,
link_success_rate: f64,
pending_eprs: Arc<Mutex<HashMap<u64, (usize, usize)>>>,
internal_state: Arc<Mutex<Vec<u8>>>, api_calls: Arc<Mutex<u64>>,
}
impl MockQnpuBackend {
pub fn new(endpoint: String, node_id: String, n_qubits: usize) -> Self {
MockQnpuBackend {
_endpoint: endpoint,
node_id,
n_qubits,
link_success_rate: 0.85, pending_eprs: Arc::new(Mutex::new(HashMap::new())),
internal_state: Arc::new(Mutex::new(vec![0; n_qubits])),
api_calls: Arc::new(Mutex::new(0)),
}
}
async fn api_call(&self, method: &str, params: serde_json::Value) -> Result<serde_json::Value> {
{
let mut calls = self.api_calls.lock().await;
*calls += 1;
}
tokio::time::sleep(tokio::time::Duration::from_millis(5)).await;
info!(
"[QNPU API #{:04}] {} -> {}: {}",
self.api_calls.lock().await,
self.node_id,
method,
params
);
match method {
"gate/apply" => Ok(json!({ "success": true, "gate_id": rand::random::<u64>() })),
"measure" => {
let qubit = params["qubit"].as_u64().unwrap() as usize;
let result = if rand::random::<f64>() < 0.5 { 0 } else { 1 };
let mut state = self.internal_state.lock().await;
state[qubit] = result;
Ok(json!({ "success": true, "result": result }))
}
"epr/create" => {
let success = rand::random::<f64>() < self.link_success_rate;
if success {
let epr_id = rand::random::<u64>();
Ok(json!({
"success": true,
"epr_id": epr_id,
"fidelity": 0.92 + rand::random::<f64>() * 0.06 }))
} else {
Ok(json!({ "success": false, "reason": "EPR generation failed" }))
}
}
_ => Ok(json!({ "success": true })),
}
}
}
#[async_trait]
impl QuantumBackend for MockQnpuBackend {
async fn apply_single_gate(&mut self, qubit: usize, gate: Gate1) -> Result<()> {
if qubit >= self.n_qubits {
return Err(QnectError::qubit_out_of_range(qubit, self.n_qubits));
}
let gate_name = match gate {
Gate1::H => "H",
Gate1::X => "X",
Gate1::Y => "Y",
Gate1::Z => "Z",
Gate1::S => "S",
Gate1::SDag => "Sdag",
Gate1::T => "T",
Gate1::TDag => "Tdag",
Gate1::Rx(_) => "Rx",
Gate1::Ry(_) => "Ry",
Gate1::Rz(_) => "Rz",
};
let params = match gate {
Gate1::Rx(theta) | Gate1::Ry(theta) | Gate1::Rz(theta) => {
json!({
"gate": gate_name,
"qubit": qubit,
"params": { "theta": theta }
})
}
_ => {
json!({
"gate": gate_name,
"qubit": qubit
})
}
};
self.api_call("gate/apply", params).await?;
Ok(())
}
async fn apply_two_gate(&mut self, q1: usize, q2: usize, gate: Gate2) -> Result<()> {
if q1 >= self.n_qubits || q2 >= self.n_qubits {
return Err(QnectError::qubit_out_of_range(q1.max(q2), self.n_qubits));
}
if q1 == q2 {
return Err(QnectError::invalid_gate(
"Cannot apply two-qubit gate to same qubit",
));
}
let gate_name = match gate {
Gate2::CNOT => "CNOT",
Gate2::CZ => "CZ",
Gate2::SWAP => "SWAP",
Gate2::CY => "CY",
};
let params = json!({
"gate": gate_name,
"control": q1,
"target": q2
});
self.api_call("gate/apply", params).await?;
Ok(())
}
async fn measure(&mut self, qubit: usize) -> Result<u8> {
if qubit >= self.n_qubits {
return Err(QnectError::qubit_out_of_range(qubit, self.n_qubits));
}
let params = json!({ "qubit": qubit });
let response = self.api_call("measure", params).await?;
let result = response["result"].as_u64().unwrap() as u8;
Ok(result)
}
async fn create_entanglement(&mut self, q1: usize, q2: usize) -> Result<()> {
if q1 >= self.n_qubits || q2 >= self.n_qubits {
return Err(QnectError::qubit_out_of_range(q1.max(q2), self.n_qubits));
}
let params = json!({
"method": "heralded_epr",
"qubits": [q1, q2],
"target_fidelity": 0.95
});
let response = self.api_call("epr/create", params).await?;
if !response["success"].as_bool().unwrap() {
return Err(QnectError::invalid_operation(
"create_entanglement".to_string(),
"EPR generation failed".to_string(),
));
}
let epr_id = response["epr_id"].as_u64().unwrap();
let mut eprs = self.pending_eprs.lock().await;
eprs.insert(epr_id, (q1, q2));
Ok(())
}
fn qubit_count(&self) -> usize {
self.n_qubits
}
}
impl MockQnpuBackend {
pub async fn request_epr_with_heralding(
&mut self,
peer: &str,
local_qubit: usize,
remote_qubit: usize,
) -> Result<(u64, f64)> {
let params = json!({
"peer": peer,
"local_qubit": local_qubit,
"remote_qubit": remote_qubit,
"heralded": true
});
let response = self.api_call("epr/create", params).await?;
if response["success"].as_bool().unwrap() {
let epr_id = response["epr_id"].as_u64().unwrap();
let fidelity = response["fidelity"].as_f64().unwrap();
Ok((epr_id, fidelity))
} else {
Err(QnectError::invalid_operation(
"request_epr_with_heralding".to_string(),
"EPR generation failed".to_string(),
))
}
}
pub async fn check_epr_heralding(&self, epr_id: u64) -> Result<bool> {
tokio::time::sleep(tokio::time::Duration::from_micros(50)).await;
let eprs = self.pending_eprs.lock().await;
Ok(eprs.contains_key(&epr_id))
}
pub async fn get_hardware_time_ns(&self) -> Result<u64> {
let response = self.api_call("system/time", json!({})).await?;
Ok(response["time_ns"].as_u64().unwrap_or(0))
}
}