-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Support classical expressions (#86)
Closes #83 ~~The json schema has not been updated yet (see CQCL/tket#1654), so the format may not be completely correct.~~ Edit: json schema is now merged CQCL/tket#1660 --------- Co-authored-by: Alec Edgington <[email protected]>
- Loading branch information
Showing
12 changed files
with
735 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
//! Classical expressions | ||
pub mod op; | ||
pub mod operator; | ||
|
||
use operator::ClOperator; | ||
use serde::de::SeqAccess; | ||
use serde::ser::SerializeSeq; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
/// Data encoding a classical expression. | ||
/// | ||
/// A classical expression operates over multi-bit registers and/or individual bits, | ||
/// which are identified here by their individual bit positions. | ||
/// | ||
/// This is included in a [`Operation`] when the operation is a [`OpType::ClExpr`]. | ||
/// | ||
/// [`Operation`]: crate::circuit_json::Operation | ||
/// [`OpType::ClExpr`]: crate::optype::OpType::ClExpr | ||
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)] | ||
#[non_exhaustive] | ||
pub struct ClExpr { | ||
/// Mapping between bit variables in the expression and the position of the | ||
/// corresponding bit in the `args` list. | ||
pub bit_posn: Vec<(u32, u32)>, | ||
/// The encoded expression. | ||
pub expr: ClOperator, | ||
/// The input bits of the expression. | ||
pub reg_posn: Vec<InputClRegister>, | ||
/// The output bits of the expression. | ||
pub output_posn: ClRegisterBits, | ||
} | ||
|
||
/// An input register for a classical expression. | ||
/// | ||
/// Contains the input index as well as the bits that are part of the register. | ||
/// | ||
/// Serialized as a list with two elements: the index and the bits. | ||
#[derive(Debug, Default, PartialEq, Clone)] | ||
pub struct InputClRegister { | ||
/// The index of the register variable in the expression. | ||
pub index: u32, | ||
/// The sequence of positions of bits comprising the register variable. | ||
pub bits: ClRegisterBits, | ||
} | ||
|
||
/// The sequence of positions of bits in the output. | ||
/// | ||
/// Registers are little-endian, so the first bit is the least significant. | ||
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)] | ||
#[serde(transparent)] | ||
pub struct ClRegisterBits(pub Vec<u32>); | ||
|
||
impl Serialize for InputClRegister { | ||
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { | ||
let mut seq = serializer.serialize_seq(Some(2))?; | ||
seq.serialize_element(&self.index)?; | ||
seq.serialize_element(&self.bits)?; | ||
seq.end() | ||
} | ||
} | ||
|
||
impl<'de> Deserialize<'de> for InputClRegister { | ||
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { | ||
struct Visitor; | ||
|
||
impl<'de_vis> serde::de::Visitor<'de_vis> for Visitor { | ||
type Value = InputClRegister; | ||
|
||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
formatter.write_str("a list of two elements: the index and the bits") | ||
} | ||
|
||
fn visit_seq<A: SeqAccess<'de_vis>>(self, mut seq: A) -> Result<Self::Value, A::Error> { | ||
let index = seq | ||
.next_element::<u32>()? | ||
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; | ||
let bits = seq | ||
.next_element::<ClRegisterBits>()? | ||
.ok_or_else(|| serde::de::Error::invalid_length(1, &self))?; | ||
Ok(InputClRegister { index, bits }) | ||
} | ||
} | ||
|
||
deserializer.deserialize_seq(Visitor) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
//! Classical expression operations. | ||
use serde::{Deserialize, Serialize}; | ||
use strum::EnumString; | ||
|
||
/// List of supported classical expressions. | ||
/// | ||
/// Corresponds to `pytket.circuit.ClOp`. | ||
#[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq, Eq, Hash, EnumString)] | ||
#[non_exhaustive] | ||
pub enum ClOp { | ||
/// Invalid operation | ||
#[default] | ||
INVALID, | ||
|
||
/// Bitwise AND | ||
BitAnd, | ||
/// Bitwise OR | ||
BitOr, | ||
/// Bitwise XOR | ||
BitXor, | ||
/// Bitwise equality | ||
BitEq, | ||
/// Bitwise inequality | ||
BitNeq, | ||
/// Bitwise NOT | ||
BitNot, | ||
/// Constant zero bit | ||
BitZero, | ||
/// Constant one bit | ||
BitOne, | ||
|
||
/// Registerwise AND | ||
RegAnd, | ||
/// Registerwise OR | ||
RegOr, | ||
/// Registerwise XOR | ||
RegXor, | ||
/// Registerwise equality | ||
RegEq, | ||
/// Registerwise inequality | ||
RegNeq, | ||
/// Registerwise NOT | ||
RegNot, | ||
/// Constant all-zeros register | ||
RegZero, | ||
/// Constant all-ones register | ||
RegOne, | ||
/// Integer less-than comparison | ||
RegLt, | ||
/// Integer greater-than comparison | ||
RegGt, | ||
/// Integer less-than-or-equal comparison | ||
RegLeq, | ||
/// Integer greater-than-or-equal comparison | ||
RegGeq, | ||
/// Integer addition | ||
RegAdd, | ||
/// Integer subtraction | ||
RegSub, | ||
/// Integer multiplication | ||
RegMul, | ||
/// Integer division | ||
RegDiv, | ||
/// Integer exponentiation | ||
RegPow, | ||
/// Left shift | ||
RegLsh, | ||
/// Right shift | ||
RegRsh, | ||
/// Integer negation | ||
RegNeg, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
//! A tree of operators forming a classical expression. | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use super::op::ClOp; | ||
|
||
/// A node in a classical expression tree. | ||
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)] | ||
#[non_exhaustive] | ||
pub struct ClOperator { | ||
/// The operation to be performed. | ||
pub op: ClOp, | ||
/// The arguments to the operation. | ||
pub args: Vec<ClArgument>, | ||
} | ||
|
||
/// An argument to a classical expression operation. | ||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] | ||
#[non_exhaustive] | ||
#[serde(tag = "type", content = "input")] | ||
pub enum ClArgument { | ||
/// A terminal argument. | ||
#[serde(rename = "term")] | ||
Terminal(ClTerminal), | ||
/// A sub-expression. | ||
#[serde(rename = "expr")] | ||
Expression(Box<ClOperator>), | ||
} | ||
|
||
/// A terminal argument in a classical expression operation. | ||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] | ||
#[non_exhaustive] | ||
#[serde(tag = "type", content = "term")] | ||
pub enum ClTerminal { | ||
/// A terminal argument. | ||
#[serde(rename = "var")] | ||
Variable(ClVariable), | ||
/// A constant integer. | ||
#[serde(rename = "int")] | ||
Int(u64), | ||
} | ||
|
||
/// A variable terminal argument in a classical expression operation. | ||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Hash)] | ||
#[non_exhaustive] | ||
#[serde(tag = "type", content = "var")] | ||
pub enum ClVariable { | ||
/// A register variable. | ||
#[serde(rename = "reg")] | ||
Register { | ||
/// The register index. | ||
index: u32, | ||
}, | ||
/// A constant bit. | ||
#[serde(rename = "bit")] | ||
Bit { | ||
/// The bit index. | ||
index: u32, | ||
}, | ||
} | ||
|
||
impl Default for ClArgument { | ||
fn default() -> Self { | ||
ClArgument::Terminal(ClTerminal::default()) | ||
} | ||
} | ||
|
||
impl Default for ClTerminal { | ||
fn default() -> Self { | ||
ClTerminal::Int(0) | ||
} | ||
} | ||
|
||
impl Default for ClVariable { | ||
fn default() -> Self { | ||
ClVariable::Register { index: 0 } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.