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

Add support for to_openqasm with param and create prerelease draft for all whl #149

Merged
merged 5 commits into from
Mar 28, 2024
Merged
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
10 changes: 10 additions & 0 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,13 @@ jobs:
env:
TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}

# Used to update whl in latest draft
- uses: ncipollo/release-action@v1
with:
artifacts: dist/*.whl
allowUpdates: true
tag: pre-release
draft: true
prerelease: true
token: ${{ secrets.GITHUB_TOKEN }}
15 changes: 9 additions & 6 deletions quafu/circuits/quantum_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
from .classical_register import ClassicalRegister
from .quantum_register import QuantumRegister


class QuantumCircuit:
"""
Representation of quantum circuit.
Expand Down Expand Up @@ -482,23 +481,27 @@ def from_openqasm(self, openqasm: str):

return qasm2_to_quafu_qc(self, openqasm)

def to_openqasm(self) -> str:
def to_openqasm(self, with_para=False) -> str:
"""
Convert the circuit to openqasm text.

Returns:
openqasm text.
"""
valid_gates = QuantumGate.gate_classes #TODO:include instruction futher
valid_gates = QuantumGate.gate_classes # TODO:include instruction futher
qasm = 'OPENQASM 2.0;\ninclude "qelib1.inc";\n'
qasm += "qreg q[%d];\n" % self.num
qasm += "creg meas[%d];\n" % self.cbits_num
if with_para:
for variable in self.variables:
qasm += f"{variable.latex} = {variable.value};\n"
for gate in self.gates:
if gate.name.lower() in valid_gates:
qasm += gate.to_qasm() + ";\n"
qasm += gate.to_qasm(with_para) + ";\n"
else:
#TODO: add decompose subroutine
raise NotImplementedError(f"gate {gate.name} can not convert to qasm2 directly, you may decompose it manuallly")
# TODO: add decompose subroutine
raise NotImplementedError(
f"gate {gate.name} can not convert to qasm2 directly, you may decompose it manuallly")
for key in self.measures:
qasm += "measure q[%d] -> meas[%d];\n" % (key, self.measures[key])

Expand Down
2 changes: 1 addition & 1 deletion quafu/elements/classical_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def __init__(self, cbits: List[int], condition: int, instructions=None):
def named_pos(self) -> Dict:
return {"cbits": self.cbits}

def to_qasm(self):
def to_qasm(self, with_para):
raise NotImplementedError

def set_ins(self, instructions: List[Instruction]):
Expand Down
12 changes: 6 additions & 6 deletions quafu/elements/element_gates/element_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class SYGate(QuantumGate):
def __init__(self, pos: int):
self.pos = [pos]

def to_qasm(self):
def to_qasm(self, with_para):
return "ry(pi/2) q[%d]" %(self.pos[0])

@QuantumGate.register()
Expand Down Expand Up @@ -161,7 +161,7 @@ class WGate(QuantumGate):
def __init__(self, pos: int):
self.pos = [pos]

def to_qasm(self):
def to_qasm(self, with_para):
q = self.pos[0]
return "rz(-pi/4) q[%d];\nrx(pi) q[%d];\nrz(pi/4) q[%d]" %(q, q, q)

Expand All @@ -173,7 +173,7 @@ class SWGate(QuantumGate):
def __init__(self, pos: int):
self.pos = [pos]

def to_qasm(self):
def to_qasm(self, with_para):
q = self.pos[0]
return "rz(-pi/4) q[%d];\nrx(pi/2) q[%d];\nrz(pi/4) q[%d]" %(q, q, q)

Expand All @@ -185,7 +185,7 @@ class SWdgGate(QuantumGate):
def __init__(self, pos: int):
self.pos = [pos]

def to_qasm(self):
def to_qasm(self, with_para):
q = self.pos[0]
return "rz(-pi/4) q[%d];\nrx(-pi/2) q[%d];\nrz(pi/4) q[%d]" %(q, q, q)

Expand Down Expand Up @@ -300,7 +300,7 @@ def __init__(self, ctrl:int, targ:int):
self.targs = [targ]
self.pos = self.ctrls + self.targs

def to_qasm(self):
def to_qasm(self, with_para):
return "cp(pi/2) " + "q[%d],q[%d]" % (self.pos[0], self.pos[1])

@QuantumGate.register()
Expand All @@ -316,7 +316,7 @@ def __init__(self, ctrl:int, targ:int):
self.targs = [targ]
self.pos = self.ctrls + self.targs

def to_qasm(self):
def to_qasm(self, with_para):
return "cp(pi/4) " + "q[%d],q[%d]" % (self.pos[0], self.pos[1])


Expand Down
8 changes: 4 additions & 4 deletions quafu/elements/instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def wrapper(subclass):
return wrapper

@abstractmethod
def to_qasm(self):
def to_qasm(self, with_para):
pass


Expand Down Expand Up @@ -130,7 +130,7 @@ def named_paras(self):
def __repr__(self):
return f"{self.__class__.__name__}"

def to_qasm(self):
def to_qasm(self, with_para):
return "barrier " + ",".join(
["q[%d]" % p for p in range(min(self.pos), max(self.pos) + 1)]
)
Expand Down Expand Up @@ -161,7 +161,7 @@ def named_paras(self):
def __repr__(self):
return f"{self.__class__.__name__}"

def to_qasm(self):
def to_qasm(self, with_para):
return "reset " + ",".join(
["q[%d]" % p for p in range(min(self.pos), max(self.pos) + 1)]
)
Expand All @@ -187,7 +187,7 @@ def named_pos(self):
def named_paras(self):
return self.named_paras

def to_qasm(self):
def to_qasm(self, with_para):
lines = [
"measure q[%d] -> meas[%d];\n" % (q, c)
for q, c in zip(self.qbits, self.cbits)
Expand Down
2 changes: 1 addition & 1 deletion quafu/elements/noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def named_pos(self):
def named_paras(self):
return {"paras": self.paras}

def to_qasm(self):
def to_qasm(self, with_para):
raise ValueError("Can not convert noise channel to qasm")

@property
Expand Down
2 changes: 1 addition & 1 deletion quafu/elements/oracle.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def named_paras(self) -> Dict:
# TODO: how to manage paras and the names?
return self._named_pos

def to_qasm(self):
def to_qasm(self, with_para):
# TODO: this is similar to QuantumCircuit.to_qasm
raise NotImplemented

Expand Down
4 changes: 2 additions & 2 deletions quafu/elements/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,10 @@ def __pow__(self, n):
operands = [opr for opr in self.operands]
funcs = copy.deepcopy(self.funcs)
operands.append(n)
funcs.append(_operator.truediv)
funcs.append(_operator.pow)
v = 0.0
if isinstance(n, float) or isinstance(n, int):
v = self**n
v = self.value**n
else:
raise NotImplementedError
return ParameterExpression(self.pivot, v, operands, funcs)
Expand Down
6 changes: 3 additions & 3 deletions quafu/elements/pulses.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def __copy__(self):
"""Return a deepcopy of the pulse"""
return deepcopy(self)

def to_qasm(self):
def to_qasm(self, with_para):
return self.__str__() + " q[%d]" % self.pos

def plot(
Expand Down Expand Up @@ -256,7 +256,7 @@ def __init__(self, pos: int, duration: int, unit="ns"):
def __repr__(self):
return f"{self.__class__.__name__}"

def to_qasm(self):
def to_qasm(self, with_para):
return "delay(%d%s) q[%d]" % (self.duration, self.unit, self.pos)


Expand All @@ -272,7 +272,7 @@ def __init__(self, qs: int, qe: int, duration: int, unit="ns"):
self.unit = unit
self.symbol = "XY(%d%s)" % (duration, unit)

def to_qasm(self):
def to_qasm(self, with_para):
return "xy(%d%s) " % (self.duration, self.unit) + ",".join(
["q[%d]" % p for p in range(min(self.pos), max(self.pos) + 1)]
)
Expand Down
13 changes: 8 additions & 5 deletions quafu/elements/quantum_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

from .instruction import Instruction
from .parameters import ParameterType
from .utils import extract_float
from .utils import extract_float, handle_expression

__all__ = [
"QuantumGate",
Expand Down Expand Up @@ -197,12 +197,15 @@ def _get_raw_matrix(self, reverse_order=False):
return raw_mat


def to_qasm(self) -> str:
def to_qasm(self, with_para=False) -> str:
"""OPENQASM 2.0"""
# TODO: support register naming
qstr = "%s" %self.name.lower()
if self.paras:
qstr += "(" + ",".join(["%s" %para for para in self._paras]) + ")"
if with_para:
qstr += "(" + ",".join(["%s" % handle_expression(para) for para in self.paras]) + ")"
else:
qstr += "(" + ",".join(["%s" % para for para in self._paras]) + ")"
qstr += " "
qstr += ",".join(["q[%d]" % p for p in self.pos])
return qstr
Expand Down Expand Up @@ -480,10 +483,10 @@ def dagger(self):
self.circuit = self.circuit.dagger()
return self

def to_qasm(self):
def to_qasm(self, with_para=False):
qasm = ''
for operation in self.circuit.operations:
qasm += operation.to_qasm() + ";\n"
qasm += operation.to_qasm(with_para) + ";\n"
return qasm

class ControlledCircuitWrapper(CircuitWrapper):
Expand Down
42 changes: 38 additions & 4 deletions quafu/elements/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@


from typing import Iterable, List, Union

import numpy as np

from .parameters import Parameter, ParameterExpression

from quafu.elements.parameters import ParameterType, Parameter, ParameterExpression
import _operator
import autograd.numpy as anp

def reorder_matrix(matrix: np.ndarray, pos: List):
"""Reorder the input sorted matrix to the pos order"""
Expand All @@ -40,3 +39,38 @@ def extract_float(paras):
elif isinstance(para, Parameter) or isinstance(para, ParameterExpression):
paras_f.append(para.get_value())
return paras_f

def handle_expression(param: ParameterType):
if isinstance(param, float) or isinstance(param, int):
return param
if param.latex:
return param.latex
retstr = handle_expression(param.pivot)
for i in range(len(param.funcs)):
if param.funcs[i] == _operator.add:
retstr = f"({retstr} + {handle_expression(param.operands[i])})"
elif param.funcs[i] == _operator.mul:
retstr = f"{retstr} * {handle_expression(param.operands[i])}"
elif param.funcs[i] == _operator.sub:
retstr = f"({retstr} - {handle_expression(param.operands[i])})"
elif param.funcs[i] == _operator.truediv:
retstr = f"{retstr} / {handle_expression(param.operands[i])}"
elif param.funcs[i] == anp.sin:
retstr = f"sin({retstr})"
elif param.funcs[i] == anp.cos:
retstr = f"cos({retstr})"
elif param.funcs[i] == anp.tan:
retstr = f"tan({retstr})"
elif param.funcs[i] == _operator.pow:
retstr = f"pow({retstr}, {handle_expression(param.operands[i])})"
elif param.funcs[i] == anp.arcsin:
retstr = f"asin({retstr})"
elif param.funcs[i] == anp.arccos:
retstr = f"acos({retstr})"
elif param.funcs[i] == anp.arctan:
retstr = f"atan({retstr})"
elif param.funcs[i] == anp.exp:
retstr = f"exp({retstr})"
elif param.funcs[i] == anp.log:
retstr = f"ln({retstr})"
return retstr
Loading