use qudit_core::{ClassicalSystem, HybridSystem, ParamIndices, QuditSystem};
use qudit_core::{HasParams, Radices};
use serde::{Deserialize, Serialize};
use slotmap::Key;
use slotmap::SlotMap;
use slotmap::new_key_type;
new_key_type! { pub struct CircuitId; }
use crate::OpCode;
use crate::Result;
use crate::circuit::InternableOperation;
use crate::instruction::Instruction;
use crate::operation::OperationSet;
use crate::param::{IntoArgumentList, ParameterVector};
#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct CircuitOperation {
qudit_radices: Radices,
dit_radices: Radices,
instructions: Vec<Instruction>,
num_params: usize,
}
impl CircuitOperation {
pub fn new(
qudit_radices: Radices,
dit_radices: Radices,
instructions: Vec<Instruction>,
num_params: usize,
) -> Self {
CircuitOperation {
qudit_radices,
dit_radices,
instructions,
num_params,
}
}
pub fn specialize(
self,
args: crate::param::ArgumentList,
source_ops: &OperationSet,
target_ops: &mut OperationSet,
) -> Result<Self> {
if args.len() != self.num_params {
return Err(crate::Error::IncorrectNumberOfArguments(
args.len(),
self.num_params,
));
}
let mut specialized_instructions = Vec::with_capacity(self.instructions.len());
for inst in self.instructions {
let op = source_ops
.get(inst.op_code())
.ok_or(crate::Error::MissingOperation(inst.op_code()))?;
let sub_args = args.slice_by_indices(&inst.params());
let specialized_op = op.specialize(sub_args, source_ops, target_ops)?;
let new_op_code = target_ops.insert(specialized_op)?;
let new_params = args.map_indices_for_instruction(&inst.params());
let new_inst = Instruction::new(new_op_code, inst.wires(), new_params);
specialized_instructions.push(new_inst);
}
let new_num_params = args.parameters().len();
Ok(Self {
qudit_radices: self.qudit_radices,
dit_radices: self.dit_radices,
instructions: specialized_instructions,
num_params: new_num_params,
})
}
}
impl HasParams for CircuitOperation {
fn num_params(&self) -> usize {
self.num_params
}
}
impl QuditSystem for CircuitOperation {
fn radices(&self) -> Radices {
self.qudit_radices.clone()
}
}
impl ClassicalSystem for CircuitOperation {
fn radices(&self) -> Radices {
self.dit_radices.clone()
}
}
impl HybridSystem for CircuitOperation {}
impl InternableOperation for CircuitOperation {
fn intern_operation(
self,
_operation_set: &mut OperationSet,
_parameter_vector: &mut ParameterVector,
_args: impl IntoArgumentList,
_qudit_radices: Radices,
_dit_radices: Radices,
) -> Result<(OpCode, ParamIndices)> {
todo!();
}
}
impl std::ops::Deref for CircuitOperation {
type Target = [Instruction];
fn deref(&self) -> &Self::Target {
&self.instructions
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct CircuitCache {
circuits: SlotMap<CircuitId, CircuitOperation>,
}
impl CircuitCache {
pub fn new() -> Self {
CircuitCache {
circuits: SlotMap::with_key(),
}
}
pub fn insert(&mut self, circuit: CircuitOperation) -> CircuitId {
let id = self.circuits.insert(circuit);
if id.data().as_ffi() & (0b111 << 61) != 0 {
panic!("CircuitOperation cache overflow.");
}
id
}
pub fn remove(&mut self, circuit_id: CircuitId) -> Option<CircuitOperation> {
self.circuits.remove(circuit_id)
}
#[allow(dead_code)]
pub fn get(&self, circuit_id: CircuitId) -> Option<&CircuitOperation> {
self.circuits.get(circuit_id)
}
#[allow(dead_code)]
pub fn num_params(&self, circuit_id: CircuitId) -> Option<usize> {
self.get(circuit_id).map(|c| c.num_params())
}
}