Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delay instruction #233

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions pyqir/pyqir/_basicqis.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ def reset(self, qubit: Value) -> None:
"""
qis.reset(self._builder, qubit)

def delay(self, duration: Union[Value, float], qubit: Value) -> None:
"""
Inserts a delay operation.

:param duration: The duration the qubit needs to wait for.
:param qubit: The qubit to make wait.
"""
qis.delay(self._builder, duration, qubit)

def rx(self, theta: Union[Value, float], qubit: Value) -> None:
"""
Inserts a rotation gate about the :math:`x` axis.
Expand Down
9 changes: 9 additions & 0 deletions pyqir/pyqir/_native.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,15 @@ def reset(builder: Builder, qubit: Value) -> None:
"""
...

def delay(builder: Builder, duration: Union[Value, float], qubit: Value) -> None:
"""
Inserts a delay operation.

:param builder: The underlying builder used to build QIS instructions.
:param duration: The duration the qubit needs to wait for.
:param qubit: The qubit to make wait.
"""

def rx(builder: Builder, theta: Union[Value, float], qubit: Value) -> None:
"""
Inserts a rotation gate about the :math:`x` axis.
Expand Down
2 changes: 2 additions & 0 deletions pyqir/pyqir/qis.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
h,
mz,
reset,
delay,
rx,
ry,
rz,
Expand All @@ -31,6 +32,7 @@
"h",
"mz",
"reset",
"delay",
"rx",
"ry",
"rz",
Expand Down
5 changes: 3 additions & 2 deletions pyqir/src/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use crate::{
metadata::{ConstantAsMetadata, Metadata, MetadataString},
module::{Linkage, Module, ModuleFlagBehavior},
qis::{
barrier, ccx, cx, cz, h, if_result, mz, reset, rx, ry, rz, s, s_adj, swap, t, t_adj, x, y,
z,
barrier, ccx, cx, cz, delay, h, if_result, mz, reset, rx, ry, rz, s, s_adj, swap, t, t_adj,
x, y, z,
},
rt::{array_record_output, initialize, result_record_output, tuple_record_output},
types::{
Expand Down Expand Up @@ -93,6 +93,7 @@ fn _native(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(h, m)?)?;
m.add_function(wrap_pyfunction!(mz, m)?)?;
m.add_function(wrap_pyfunction!(reset, m)?)?;
m.add_function(wrap_pyfunction!(delay, m)?)?;
m.add_function(wrap_pyfunction!(rx, m)?)?;
m.add_function(wrap_pyfunction!(ry, m)?)?;
m.add_function(wrap_pyfunction!(rz, m)?)?;
Expand Down
51 changes: 42 additions & 9 deletions pyqir/src/qis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,39 @@ pub(crate) fn reset(py: Python, builder: &Builder, qubit: &Value) -> PyResult<()
Ok(())
}

/// Inserts a delay operation.
///
/// :param Builder builder: The IR Builder used to create the instructions
/// :param typing.Union[Value, float] duration: The duration the qubit needs to wait for.
/// :param Value qubit: The qubit to make wait.
/// :rtype: None
#[pyfunction]
#[pyo3(text_signature = "(builder, duration, qubit)")]
pub(crate) fn delay(
py: Python,
builder: &Builder,
duration: Double,
qubit: &Value,
) -> PyResult<()> {
Owner::merge(
py,
[Some(builder.owner()), duration.owner(), Some(qubit.owner())]
.into_iter()
.flatten(),
)?;

let context = builder.owner().context(py);
let context = context.borrow(py);
unsafe {
qis::build_delay(
builder.as_ptr(),
duration.to_value(context.as_ptr()),
qubit.as_ptr(),
);
}
Ok(())
}

/// Inserts a rotation gate about the :math:`x` axis.
///
/// :param Builder builder: The IR Builder used to create the instructions
Expand All @@ -164,7 +197,7 @@ pub(crate) fn reset(py: Python, builder: &Builder, qubit: &Value) -> PyResult<()
/// :rtype: None
#[pyfunction]
#[pyo3(text_signature = "(builder, theta, qubit)")]
pub(crate) fn rx(py: Python, builder: &Builder, theta: Angle, qubit: &Value) -> PyResult<()> {
pub(crate) fn rx(py: Python, builder: &Builder, theta: Double, qubit: &Value) -> PyResult<()> {
Owner::merge(
py,
[Some(builder.owner()), theta.owner(), Some(qubit.owner())]
Expand Down Expand Up @@ -192,7 +225,7 @@ pub(crate) fn rx(py: Python, builder: &Builder, theta: Angle, qubit: &Value) ->
/// :rtype: None
#[pyfunction]
#[pyo3(text_signature = "(builder, theta, qubit)")]
pub(crate) fn ry(py: Python, builder: &Builder, theta: Angle, qubit: &Value) -> PyResult<()> {
pub(crate) fn ry(py: Python, builder: &Builder, theta: Double, qubit: &Value) -> PyResult<()> {
Owner::merge(
py,
[Some(builder.owner()), theta.owner(), Some(qubit.owner())]
Expand Down Expand Up @@ -220,7 +253,7 @@ pub(crate) fn ry(py: Python, builder: &Builder, theta: Angle, qubit: &Value) ->
/// :rtype: None
#[pyfunction]
#[pyo3(text_signature = "(builder, theta, qubit)")]
pub(crate) fn rz(py: Python, builder: &Builder, theta: Angle, qubit: &Value) -> PyResult<()> {
pub(crate) fn rz(py: Python, builder: &Builder, theta: Double, qubit: &Value) -> PyResult<()> {
Owner::merge(
py,
[Some(builder.owner()), theta.owner(), Some(qubit.owner())]
Expand Down Expand Up @@ -379,23 +412,23 @@ pub(crate) fn if_result(
}

#[derive(FromPyObject)]
pub(crate) enum Angle<'py> {
pub(crate) enum Double<'py> {
Value(PyRef<'py, Value>),
Constant(f64),
}

impl Angle<'_> {
impl Double<'_> {
fn owner(&self) -> Option<&Owner> {
match self {
Angle::Value(v) => Some(v.owner()),
Angle::Constant(_) => None,
Double::Value(v) => Some(v.owner()),
Double::Constant(_) => None,
}
}

unsafe fn to_value(&self, context: LLVMContextRef) -> LLVMValueRef {
match self {
Angle::Value(v) => v.as_ptr(),
&Angle::Constant(c) => LLVMConstReal(LLVMDoubleTypeInContext(context), c),
Double::Value(v) => v.as_ptr(),
&Double::Constant(c) => LLVMConstReal(LLVMDoubleTypeInContext(context), c),
}
}
}
1 change: 1 addition & 0 deletions pyqir/tests/test_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def test_all_gates() -> None:
qis.cz(q[1], control)
qis.h(q[0])
qis.reset(q[0])
qis.delay(14.0, q[0])
qis.rx(15.0, q[1])
qis.ry(16.0, q[2])
qis.rz(17.0, q[3])
Expand Down
3 changes: 2 additions & 1 deletion pyqir/tests/test_qis.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def test_adjoint(
@pytest.mark.parametrize(
"name, get_gate",
[
("delay", lambda qis: qis.delay),
("rx", lambda qis: qis.rx),
("ry", lambda qis: qis.ry),
("rz", lambda qis: qis.rz),
Expand All @@ -130,7 +131,7 @@ def test_adjoint(
lambda _: 1.0,
],
)
def test_rotated(
def test_double_param_gates(
name: str,
get_gate: Callable[[BasicQisBuilder], Callable[[Union[Value, float], Value], None]],
get_value: Callable[[Context], Union[Value, float]],
Expand Down
13 changes: 13 additions & 0 deletions qirlib/resources/tests/qis/delay.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
; ModuleID = 'delay'
source_filename = "delay"

%Qubit = type opaque

define void @main() #0 {
call void @__quantum__qis__delay__body(double 0.000000e+00, %Qubit* null)
ret void
}

declare void @__quantum__qis__delay__body(double, %Qubit*)

attributes #0 = { "entry_point" "num_required_qubits"="1" "num_required_results"="0" "output_labeling_schema" "qir_profiles"="custom" }
27 changes: 22 additions & 5 deletions qirlib/src/qis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::{
builder::{build_if, try_build_if},
types,
utils::{
build_call, builder_module, controlled_gate, declare_qis, doubly_controlled_gate,
function_type, no_param, rotation_gate, simple_gate, two_qubit_gate, Functor,
build_call, builder_module, controlled_gate, declare_qis, double_param_gate,
doubly_controlled_gate, function_type, no_param, simple_gate, two_qubit_gate, Functor,
},
};

Expand Down Expand Up @@ -127,23 +127,23 @@ pub unsafe fn build_z(builder: LLVMBuilderRef, qubit: LLVMValueRef) {
pub unsafe fn build_rx(builder: LLVMBuilderRef, theta: LLVMValueRef, qubit: LLVMValueRef) {
build_call(
builder,
rotation_gate(builder_module(builder), "rx"),
double_param_gate(builder_module(builder), "rx"),
&mut [theta, qubit],
);
}

pub unsafe fn build_ry(builder: LLVMBuilderRef, theta: LLVMValueRef, qubit: LLVMValueRef) {
build_call(
builder,
rotation_gate(builder_module(builder), "ry"),
double_param_gate(builder_module(builder), "ry"),
&mut [theta, qubit],
);
}

pub unsafe fn build_rz(builder: LLVMBuilderRef, theta: LLVMValueRef, qubit: LLVMValueRef) {
build_call(
builder,
rotation_gate(builder_module(builder), "rz"),
double_param_gate(builder_module(builder), "rz"),
&mut [theta, qubit],
);
}
Expand All @@ -156,6 +156,14 @@ pub unsafe fn build_reset(builder: LLVMBuilderRef, qubit: LLVMValueRef) {
);
}

pub unsafe fn build_delay(builder: LLVMBuilderRef, theta: LLVMValueRef, qubit: LLVMValueRef) {
build_call(
builder,
double_param_gate(builder_module(builder), "delay"),
&mut [theta, qubit],
);
}

pub unsafe fn build_mz(builder: LLVMBuilderRef, qubit: LLVMValueRef, result: LLVMValueRef) {
build_call(builder, mz(builder_module(builder)), &mut [qubit, result]);
}
Expand Down Expand Up @@ -391,6 +399,15 @@ mod tests {
});
}

#[test]
fn delay() {
assert_reference_ir("qis/delay", 1, 0, |builder| unsafe {
let context = builder_context(builder).unwrap().as_ptr();
let double = LLVMDoubleTypeInContext(context);
build_delay(builder, LLVMConstReal(double, 0.0), qubit(context, 0));
});
}

#[test]
fn mz() {
assert_reference_ir("qis/mz", 1, 1, |builder| unsafe {
Expand Down
2 changes: 1 addition & 1 deletion qirlib/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pub(crate) unsafe fn doubly_controlled_gate(module: LLVMModuleRef, name: &str) -
declare_qis(module, name, Functor::Body, ty)
}

pub(crate) unsafe fn rotation_gate(module: LLVMModuleRef, name: &str) -> LLVMValueRef {
pub(crate) unsafe fn double_param_gate(module: LLVMModuleRef, name: &str) -> LLVMValueRef {
let context = LLVMGetModuleContext(module);
let ty = function_type(
LLVMVoidTypeInContext(context),
Expand Down