Skip to content

Commit

Permalink
feat: support ternary logic instructions (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
nilslice committed Mar 15, 2022
1 parent 1ced6e6 commit 85185fd
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 25 deletions.
53 changes: 53 additions & 0 deletions src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,44 @@ impl fmt::Display for UnaryOperator {
}
}

#[derive(Clone, Debug, PartialEq)]
pub enum TernaryOperand {
LiteralInteger(i64),
LiteralReal(f64),
MemoryReference(MemoryReference),
}

impl fmt::Display for TernaryOperand {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
TernaryOperand::LiteralInteger(value) => write!(f, "{}", value),
TernaryOperand::LiteralReal(value) => write!(f, "{}", value),
TernaryOperand::MemoryReference(value) => write!(f, "{}", value),
}
}
}

#[derive(Clone, Debug, PartialEq)]
pub enum TernaryOperator {
Equal,
GreaterThanOrEqual,
GreaterThan,
LessThanOrEqual,
LessThan,
}

impl fmt::Display for TernaryOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
TernaryOperator::Equal => write!(f, "EQ"),
TernaryOperator::GreaterThanOrEqual => write!(f, "GE"),
TernaryOperator::GreaterThan => write!(f, "GT"),
TernaryOperator::LessThanOrEqual => write!(f, "LE"),
TernaryOperator::LessThan => write!(f, "LT"),
}
}
}

#[derive(Clone, Debug, PartialEq)]
pub enum AttributeValue {
String(String),
Expand Down Expand Up @@ -410,6 +448,12 @@ pub struct Arithmetic {
pub source: ArithmeticOperand,
}

#[derive(Clone, Debug, PartialEq)]
pub struct TernaryLogic {
pub operator: TernaryOperator,
pub operands: (MemoryReference, MemoryReference, TernaryOperand),
}

#[derive(Clone, Debug, PartialEq)]
pub struct BinaryLogic {
pub operator: BinaryOperator,
Expand Down Expand Up @@ -493,6 +537,7 @@ pub enum Instruction {
SwapPhases(SwapPhases),
WaveformDefinition(WaveformDefinition),
Arithmetic(Arithmetic),
TernaryLogic(TernaryLogic),
BinaryLogic(BinaryLogic),
UnaryLogic(UnaryLogic),
Halt,
Expand Down Expand Up @@ -541,6 +586,7 @@ impl From<&Instruction> for InstructionRole {
| Instruction::ShiftPhase(_)
| Instruction::SwapPhases(_) => InstructionRole::RFControl,
Instruction::Arithmetic(_)
| Instruction::TernaryLogic(_)
| Instruction::BinaryLogic(_)
| Instruction::UnaryLogic(_)
| Instruction::Move(_)
Expand Down Expand Up @@ -863,6 +909,13 @@ impl fmt::Display for Instruction {
write!(f, "JUMP-WHEN @{} {}", target, condition)
}
Instruction::Label(Label(label)) => write!(f, "LABEL @{}", label),
Instruction::TernaryLogic(TernaryLogic { operator, operands }) => {
write!(
f,
"{} {} {} {}",
operator, operands.0, operands.1, operands.2
)
}
Instruction::BinaryLogic(BinaryLogic { operator, operands }) => {
write!(f, "{} {} {}", operator, operands.0, operands.1)
}
Expand Down
23 changes: 21 additions & 2 deletions src/parser/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use crate::instruction::{
Arithmetic, ArithmeticOperand, ArithmeticOperator, BinaryLogic, BinaryOperator, Calibration,
Capture, CircuitDefinition, Declaration, Delay, Exchange, Fence, FrameDefinition, Instruction,
Jump, JumpUnless, JumpWhen, Label, Load, Measurement, Move, Pragma, Pulse, RawCapture, Reset,
SetFrequency, SetPhase, SetScale, ShiftFrequency, ShiftPhase, Store, UnaryLogic, UnaryOperator,
Waveform, WaveformDefinition,
SetFrequency, SetPhase, SetScale, ShiftFrequency, ShiftPhase, Store, TernaryLogic,
TernaryOperator, UnaryLogic, UnaryOperator, Waveform, WaveformDefinition,
};
use crate::parser::common::parse_variable_qubit;
use crate::parser::instruction::parse_block;
Expand Down Expand Up @@ -58,6 +58,25 @@ pub fn parse_arithmetic(
))
}

/// Parse a logical ternary instruction of the form `addr addr ( addr | number )`.
/// Called using the logical operator itself (such as `EQ`) which should be previously parsed.
pub fn parse_logical_ternary(
operator: TernaryOperator,
input: ParserInput,
) -> ParserResult<Instruction> {
let (input, destination) = common::parse_memory_reference(input)?;
let (input, left) = common::parse_memory_reference(input)?;
let (input, right) = common::parse_ternary_logic_operand(input)?;

Ok((
input,
Instruction::TernaryLogic(TernaryLogic {
operator,
operands: (destination, left, right),
}),
))
}

/// Parse a logical binary instruction of the form `addr ( addr | INT )`.
/// Called using the logical operator itself (such as `AND`) which should be previously parsed.
pub fn parse_logical_binary(
Expand Down
39 changes: 32 additions & 7 deletions src/parser/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::{
expression::Expression,
instruction::{
ArithmeticOperand, AttributeValue, BinaryOperand, FrameIdentifier, GateModifier,
MemoryReference, Qubit, ScalarType, Vector, WaveformInvocation,
MemoryReference, Qubit, ScalarType, TernaryOperand, Vector, WaveformInvocation,
},
parser::lexer::Operator,
token,
Expand Down Expand Up @@ -65,9 +65,36 @@ pub fn parse_arithmetic_operand<'a>(input: ParserInput<'a>) -> ParserResult<'a,
ArithmeticOperand::LiteralInteger(sign * (v as i64))
},
),
map(parse_memory_reference, |f| {
ArithmeticOperand::MemoryReference(f)
}),
map(parse_memory_reference, ArithmeticOperand::MemoryReference),
))(input)
}

/// Parse the operand of a ternary instruction, which may be a literal integer, literal real number, or memory reference.
pub fn parse_ternary_logic_operand<'a>(input: ParserInput<'a>) -> ParserResult<'a, TernaryOperand> {
alt((
map(
tuple((opt(token!(Operator(o))), token!(Float(v)))),
|(op, v)| {
let sign = match op {
None => 1f64,
Some(Operator::Minus) => -1f64,
_ => panic!("Implement this error"), // TODO
};
TernaryOperand::LiteralReal(sign * v)
},
),
map(
tuple((opt(token!(Operator(o))), token!(Integer(v)))),
|(op, v)| {
let sign = match op {
None => 1,
Some(Operator::Minus) => -1,
_ => panic!("Implement this error"), // TODO
};
TernaryOperand::LiteralInteger(sign * (v as i64))
},
),
map(parse_memory_reference, TernaryOperand::MemoryReference),
))(input)
}

Expand All @@ -85,9 +112,7 @@ pub fn parse_binary_logic_operand<'a>(input: ParserInput<'a>) -> ParserResult<'a
BinaryOperand::LiteralInteger(sign * (v as i64))
},
),
map(parse_memory_reference, |f| {
BinaryOperand::MemoryReference(f)
}),
map(parse_memory_reference, BinaryOperand::MemoryReference),
))(input)
}

Expand Down
122 changes: 114 additions & 8 deletions src/parser/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ use nom::{
};

use crate::{
instruction::{ArithmeticOperator, BinaryOperator, Instruction, UnaryOperator},
instruction::{
ArithmeticOperator, BinaryOperator, Instruction, TernaryOperator, UnaryOperator,
},
token,
};

Expand Down Expand Up @@ -54,20 +56,26 @@ pub fn parse_instruction(input: ParserInput) -> ParserResult<Instruction> {
Command::DefWaveform => command::parse_defwaveform(remainder),
Command::Delay => command::parse_delay(remainder),
Command::Div => command::parse_arithmetic(ArithmeticOperator::Divide, remainder),
// Command::Eq => {}
Command::Eq => command::parse_logical_ternary(TernaryOperator::Equal, remainder),
Command::GE => {
command::parse_logical_ternary(TernaryOperator::GreaterThanOrEqual, remainder)
}
Command::GT => {
command::parse_logical_ternary(TernaryOperator::GreaterThan, remainder)
}
Command::LE => {
command::parse_logical_ternary(TernaryOperator::LessThanOrEqual, remainder)
}
Command::LT => command::parse_logical_ternary(TernaryOperator::LessThan, remainder),
Command::Fence => command::parse_fence(remainder),
// Command::GE => {}
// Command::GT => {}
Command::Halt => Ok((remainder, Instruction::Halt)),
// Command::Include => {}
Command::Ior => command::parse_logical_binary(BinaryOperator::Ior, remainder),
Command::Jump => command::parse_jump(remainder),
Command::JumpUnless => command::parse_jump_unless(remainder),
Command::JumpWhen => command::parse_jump_when(remainder),
Command::Label => command::parse_label(remainder),
// Command::LE => {}
Command::Load => command::parse_load(remainder),
// Command::LT => {}
Command::Measure => command::parse_measurement(remainder),
Command::Move => command::parse_move(remainder),
Command::Exchange => command::parse_exchange(remainder),
Expand Down Expand Up @@ -152,8 +160,9 @@ mod tests {
Arithmetic, ArithmeticOperand, ArithmeticOperator, AttributeValue, BinaryLogic,
BinaryOperand, BinaryOperator, Calibration, Capture, FrameDefinition, FrameIdentifier,
Gate, Instruction, Jump, JumpWhen, Label, MemoryReference, Move, Pulse, Qubit, RawCapture,
Reset, SetFrequency, SetPhase, SetScale, ShiftFrequency, ShiftPhase, UnaryLogic,
UnaryOperator, Waveform, WaveformDefinition, WaveformInvocation,
Reset, SetFrequency, SetPhase, SetScale, ShiftFrequency, ShiftPhase, TernaryLogic,
TernaryOperand, TernaryOperator, UnaryLogic, UnaryOperator, Waveform, WaveformDefinition,
WaveformInvocation,
};
use crate::parser::lexer::lex;
use crate::{make_test, real};
Expand Down Expand Up @@ -237,6 +246,103 @@ mod tests {
]
);

make_test!(
ternary_logic,
parse_instructions,
"EQ dest ro 0\nLT dest ro[1] -1\nLE dest ro 1.2\nGT dest ro[2] 1e-6\nGE dest ro x",
vec![
Instruction::TernaryLogic(TernaryLogic {
operator: TernaryOperator::Equal,
operands: (
MemoryReference {
name: "dest".to_owned(),
index: 0
},
MemoryReference {
name: "ro".to_owned(),
index: 0
},
TernaryOperand::LiteralInteger(0)
)
}),
Instruction::TernaryLogic(TernaryLogic {
operator: TernaryOperator::LessThan,
operands: (
MemoryReference {
name: "dest".to_owned(),
index: 0
},
MemoryReference {
name: "ro".to_owned(),
index: 1
},
TernaryOperand::LiteralInteger(-1)
)
}),
Instruction::TernaryLogic(TernaryLogic {
operator: TernaryOperator::LessThanOrEqual,
operands: (
MemoryReference {
name: "dest".to_owned(),
index: 0
},
MemoryReference {
name: "ro".to_owned(),
index: 0
},
TernaryOperand::LiteralReal(1.2)
)
}),
Instruction::TernaryLogic(TernaryLogic {
operator: TernaryOperator::GreaterThan,
operands: (
MemoryReference {
name: "dest".to_owned(),
index: 0
},
MemoryReference {
name: "ro".to_owned(),
index: 2
},
TernaryOperand::LiteralReal(0.000001)
)
}),
Instruction::TernaryLogic(TernaryLogic {
operator: TernaryOperator::GreaterThanOrEqual,
operands: (
MemoryReference {
name: "dest".to_owned(),
index: 0
},
MemoryReference {
name: "ro".to_owned(),
index: 0
},
TernaryOperand::MemoryReference(MemoryReference {
name: "x".to_owned(),
index: 0
}),
)
})
]
);

#[test]
fn test_ternary_logic_error() {
[
"EQ ro 1 1",
"LT 1 1 1",
"LE 1 x ro",
"GT 1 ro x",
"GE dest 0.3 4",
]
.iter()
.for_each(|input| {
let tokens = lex(input).unwrap();
assert!(parse_instructions(&tokens).is_err())
})
}

make_test!(
binary_logic,
parse_instructions,
Expand Down
1 change: 1 addition & 0 deletions src/program/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ impl ScheduledProgram {
let instruction_index = Some(index);
match instruction {
Instruction::Arithmetic(_)
| Instruction::TernaryLogic(_)
| Instruction::BinaryLogic(_)
| Instruction::UnaryLogic(_)
| Instruction::Capture(_)
Expand Down
Loading

0 comments on commit 85185fd

Please sign in to comment.