From 6995d1dfc36983bc11f3c33e1041396a64385d46 Mon Sep 17 00:00:00 2001 From: beizha Date: Tue, 26 Mar 2024 14:28:31 +0800 Subject: [PATCH 1/4] feat: put whl in release draft --- .github/workflows/wheels.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 032a0a9..f368b5c 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -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 }} \ No newline at end of file From 98790f8b94b469e6a04f0bfe5dfba8b08c99be8d Mon Sep 17 00:00:00 2001 From: beizha Date: Thu, 28 Mar 2024 09:31:41 +0800 Subject: [PATCH 2/4] fix: fix func pow of parameter --- quafu/elements/parameters.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quafu/elements/parameters.py b/quafu/elements/parameters.py index 103952d..31feaac 100644 --- a/quafu/elements/parameters.py +++ b/quafu/elements/parameters.py @@ -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) From b8a77cff82e413c21001d45f72ee70095268322b Mon Sep 17 00:00:00 2001 From: beizha Date: Thu, 28 Mar 2024 09:39:10 +0800 Subject: [PATCH 3/4] feat: add support for to_openqasm with parameter --- quafu/circuits/quantum_circuit.py | 15 ++++--- quafu/elements/classical_element.py | 2 +- quafu/elements/element_gates/element_gates.py | 12 +++--- quafu/elements/instruction.py | 8 ++-- quafu/elements/noise.py | 2 +- quafu/elements/oracle.py | 2 +- quafu/elements/pulses.py | 6 +-- quafu/elements/quantum_gate.py | 13 +++--- quafu/elements/utils.py | 42 +++++++++++++++++-- 9 files changed, 71 insertions(+), 31 deletions(-) diff --git a/quafu/circuits/quantum_circuit.py b/quafu/circuits/quantum_circuit.py index 18aed16..bd63260 100644 --- a/quafu/circuits/quantum_circuit.py +++ b/quafu/circuits/quantum_circuit.py @@ -36,7 +36,6 @@ from .classical_register import ClassicalRegister from .quantum_register import QuantumRegister - class QuantumCircuit: """ Representation of quantum circuit. @@ -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]) diff --git a/quafu/elements/classical_element.py b/quafu/elements/classical_element.py index 3e1172e..d7680c7 100644 --- a/quafu/elements/classical_element.py +++ b/quafu/elements/classical_element.py @@ -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]): diff --git a/quafu/elements/element_gates/element_gates.py b/quafu/elements/element_gates/element_gates.py index 201b23b..8526374 100644 --- a/quafu/elements/element_gates/element_gates.py +++ b/quafu/elements/element_gates/element_gates.py @@ -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() @@ -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) @@ -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) @@ -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) @@ -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() @@ -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]) diff --git a/quafu/elements/instruction.py b/quafu/elements/instruction.py index af0cdb3..de795ca 100644 --- a/quafu/elements/instruction.py +++ b/quafu/elements/instruction.py @@ -90,7 +90,7 @@ def wrapper(subclass): return wrapper @abstractmethod - def to_qasm(self): + def to_qasm(self, with_para): pass @@ -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)] ) @@ -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)] ) @@ -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) diff --git a/quafu/elements/noise.py b/quafu/elements/noise.py index 7871477..cb83c78 100644 --- a/quafu/elements/noise.py +++ b/quafu/elements/noise.py @@ -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 diff --git a/quafu/elements/oracle.py b/quafu/elements/oracle.py index 070bf0e..1075f01 100644 --- a/quafu/elements/oracle.py +++ b/quafu/elements/oracle.py @@ -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 diff --git a/quafu/elements/pulses.py b/quafu/elements/pulses.py index 346b39f..adfaaac 100644 --- a/quafu/elements/pulses.py +++ b/quafu/elements/pulses.py @@ -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( @@ -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) @@ -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)] ) diff --git a/quafu/elements/quantum_gate.py b/quafu/elements/quantum_gate.py index a124b47..e9f5262 100644 --- a/quafu/elements/quantum_gate.py +++ b/quafu/elements/quantum_gate.py @@ -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", @@ -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 @@ -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): diff --git a/quafu/elements/utils.py b/quafu/elements/utils.py index 528b26d..48149d8 100644 --- a/quafu/elements/utils.py +++ b/quafu/elements/utils.py @@ -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""" @@ -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"arcsin({retstr})" + elif param.funcs[i] == anp.arccos: + retstr = f"arccos({retstr})" + elif param.funcs[i] == anp.arctan: + retstr = f"arctan({retstr})" + elif param.funcs[i] == anp.exp: + retstr = f"exp({retstr})" + elif param.funcs[i] == anp.log: + retstr = f"log({retstr})" + return retstr From 220a470e83409d3f0336c730c615290899352fad Mon Sep 17 00:00:00 2001 From: beizha Date: Thu, 28 Mar 2024 09:45:19 +0800 Subject: [PATCH 4/4] fix: use the same func name of qfasm --- quafu/elements/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/quafu/elements/utils.py b/quafu/elements/utils.py index 48149d8..be0954f 100644 --- a/quafu/elements/utils.py +++ b/quafu/elements/utils.py @@ -64,13 +64,13 @@ def handle_expression(param: ParameterType): elif param.funcs[i] == _operator.pow: retstr = f"pow({retstr}, {handle_expression(param.operands[i])})" elif param.funcs[i] == anp.arcsin: - retstr = f"arcsin({retstr})" + retstr = f"asin({retstr})" elif param.funcs[i] == anp.arccos: - retstr = f"arccos({retstr})" + retstr = f"acos({retstr})" elif param.funcs[i] == anp.arctan: - retstr = f"arctan({retstr})" + retstr = f"atan({retstr})" elif param.funcs[i] == anp.exp: retstr = f"exp({retstr})" elif param.funcs[i] == anp.log: - retstr = f"log({retstr})" + retstr = f"ln({retstr})" return retstr