Skip to content

Commit

Permalink
Merge pull request #149 from beizhansl/master
Browse files Browse the repository at this point in the history
Add support for to_openqasm with param and create prerelease draft for all whl
  • Loading branch information
ScQ-Cloud authored Mar 28, 2024
2 parents 983fa51 + 220a470 commit 2c114ba
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 33 deletions.
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

0 comments on commit 2c114ba

Please sign in to comment.