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

Pick ahead features of elements from stable/0.3 branch #113

Merged
merged 13 commits into from
Nov 20, 2023
Merged
34 changes: 34 additions & 0 deletions doc/source/apiref/apiref_0.3.5.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
API Reference
=============

.. note::

This page is still under refinement, the contents you see may be incomplete at present.

Quantum Circuit
------------------

.. autoclass:: quafu.QuantumCircuit
:members: cnot, add_gate, barrier
:undoc-members: add_pulse

Quantum Elements
------------------
.. hint::
hello

.. autoclass:: quafu.elements.quantum_element.Instruction
:members:


Task and User
------------------

.. autoclass:: quafu.Task
:members: config, send, retrieve

.. autoclass:: quafu.User
:members:

.. autoclass:: quafu.results.results.Result
:members:
2 changes: 1 addition & 1 deletion quafu/algorithms/hamiltonian.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from collections.abc import Iterable
import numpy as np
from quafu.exceptions import QuafuError
from quafu.elements.element_gates.matrices import XMatrix, YMatrix, ZMatrix, IdMatrix
from quafu.elements.matrices import XMatrix, YMatrix, ZMatrix, IdMatrix


PAULI_MAT = {"I": IdMatrix, "X": XMatrix, "Y": YMatrix, "Z": ZMatrix}
Expand Down
100 changes: 57 additions & 43 deletions quafu/circuits/quantum_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,15 @@

from contextlib import contextmanager
from typing import Any, List
import warnings

import numpy as np

import quafu.elements.element_gates as qeg
from quafu.elements.quantum_element.classical_element import Cif
from quafu.elements.quantum_element.instruction import Instruction
from quafu.elements.quantum_element.pulses.quantum_pulse import QuantumPulse
from quafu.elements.quantum_element.quantum_element import Measure, Reset
from ..elements.quantum_element import (
from quafu.elements.classical_element import Cif
from quafu.elements.instruction import Instruction
from quafu.elements import Measure, Reset
from quafu.elements.pulses import QuantumPulse
from ..elements import (
Barrier,
Delay,
MultiQubitGate,
Expand All @@ -43,8 +42,8 @@ class QuantumCircuit(object):
"""
Representation of quantum circuit.
"""
def __init__(self, qnum: int, cnum: int=None, *args, **kwargs):

def __init__(self, qnum: int, cnum: int = None, *args, **kwargs):
"""
Initialize a QuantumCircuit object

Expand Down Expand Up @@ -87,37 +86,40 @@ def used_qubits(self) -> List:
@property
def measures(self):
measures = {}
for meas in self._measures:
for meas in self._measures:
measures.update(dict(zip(meas.qbits, meas.cbits)))
return measures

@measures.setter
def measures(self, measures:dict):
def measures(self, measures: dict):
self._measures = [Measure(measures)]

@property
def gates(self):
"""Deprecated warning: due to historical reason, ``gates`` contains not only instances of
QuantumGate, meanwhile not contains measurements. This attributes might be deprecated in
the future. Better to use ``instructions`` which contains all the instructions."""
return self._gates

@gates.setter
def gates(self, gates:list):
def gates(self, gates: list):
self._gates = gates

#TODO(qtzhuang): add_gates is just a temporary call function to add gate from gate_list
# TODO(qtzhuang): add_gates is just a temporary call function to add gate from gate_list
def add_gates(self, gates: list):
for gate in gates:
self.add_gate(gate)

def add_gate(self, gate: QuantumGate):
"""
Add quantum gate to circuit, with some checking.
"""
pos = np.array(gate.pos)
if np.any(pos >= self.num):
raise CircuitError(f"Gate position out of range: {gate.pos}")
self.gates.append(gate)

def add_ins(self, ins:Instruction):
def add_ins(self, ins: Instruction):
"""
Add instruction to circuit, with NO checking yet.
"""
Expand All @@ -126,7 +128,7 @@ def add_ins(self, ins:Instruction):
# Figure out better handling in the future.
self.add_gate(ins)
self.instructions.append(ins)

def update_params(self, paras_list: List[Any]):
"""Update parameters of parameterized gates
Args:
Expand Down Expand Up @@ -157,18 +159,18 @@ def layered_circuit(self) -> np.ndarray:
used_qubits = []
for gate in gatelist:
if (
isinstance(gate, SingleQubitGate)
or isinstance(gate, Delay)
or isinstance(gate, QuantumPulse)
isinstance(gate, SingleQubitGate)
or isinstance(gate, Delay)
or isinstance(gate, QuantumPulse)
):
gateQlist[gate.pos].append(gate)
if gate.pos not in used_qubits:
used_qubits.append(gate.pos)

elif (
isinstance(gate, Barrier)
or isinstance(gate, MultiQubitGate)
or isinstance(gate, XYResonance)
isinstance(gate, Barrier)
or isinstance(gate, MultiQubitGate)
or isinstance(gate, XYResonance)
):
pos1 = min(gate.pos)
pos2 = max(gate.pos)
Expand All @@ -188,34 +190,35 @@ def layered_circuit(self) -> np.ndarray:
if not layerj == maxlayer:
for i in range(abs(layerj - maxlayer)):
gateQlist[j].insert(pos, None)

# Add support of used_qubits for Reset and Cif
def get_used_qubits(instructions):
used_q = []
for ins in instructions:
if(isinstance(ins, Cif)):
if (isinstance(ins, Cif)):
used_q_h = get_used_qubits(ins.instructions)
for pos in used_q_h:
if pos not in used_q:
used_q.append(pos)
elif(isinstance(ins, Barrier)):
elif (isinstance(ins, Barrier)):
continue
elif(isinstance(ins.pos, int)):
elif (isinstance(ins.pos, int)):
if ins.pos not in used_q:
used_q.append(ins.pos)
elif(isinstance(ins.pos, list)):
elif (isinstance(ins.pos, list)):
for pos in ins.pos:
if pos not in used_q:
used_q.append(pos)
return used_q

# Only consider of reset and cif
for ins in self.instructions:
if isinstance(ins, (Reset, Cif)):
used_q = get_used_qubits([ins])
for pos in used_q:
if pos not in used_qubits:
used_qubits.append(pos)



maxdepth = max([len(gateQlist[i]) for i in range(num)])

for gates in gateQlist:
Expand Down Expand Up @@ -260,17 +263,17 @@ def draw_circuit(self, width: int = 4, return_str: bool = False):
for i in range(num):
gate = layergates[i]
if (
isinstance(gate, SingleQubitGate)
or isinstance(gate, Delay)
or (isinstance(gate, QuantumPulse))
isinstance(gate, SingleQubitGate)
or isinstance(gate, Delay)
or (isinstance(gate, QuantumPulse))
):
printlist[i * 2, l] = gate.symbol
maxlen = max(maxlen, len(gate.symbol) + width)

elif isinstance(gate, MultiQubitGate) or isinstance(gate, XYResonance):
q1 = reduce_map[min(gate.pos)]
q2 = reduce_map[max(gate.pos)]
printlist[2 * q1 + 1 : 2 * q2, l] = "|"
printlist[2 * q1 + 1: 2 * q2, l] = "|"
printlist[q1 * 2, l] = "#"
printlist[q2 * 2, l] = "#"
if isinstance(gate, ControlledGate): # Controlled-Multiqubit gate
Expand Down Expand Up @@ -306,7 +309,7 @@ def draw_circuit(self, width: int = 4, return_str: bool = False):
pos = [i for i in gate.pos if i in reduce_map.keys()]
q1 = reduce_map[min(pos)]
q2 = reduce_map[max(pos)]
printlist[2 * q1 : 2 * q2 + 1, l] = "||"
printlist[2 * q1: 2 * q2 + 1, l] = "||"
maxlen = max(maxlen, len("||"))

printlist[-1, l] = maxlen
Expand Down Expand Up @@ -378,7 +381,7 @@ def wrap_to_gate(self, name: str):
"""
Wrap the circuit to a subclass of QuantumGate, create by metaclass.
"""
from quafu.elements.quantum_element.quantum_gate import customize_gate
from quafu.elements.quantum_gate import customize_gate

gate_structure = []
qubit_mapping = {q: i for i, q in enumerate(self.used_qubits)}
Expand Down Expand Up @@ -613,6 +616,9 @@ def cnot(self, ctrl: int, tar: int) -> "QuantumCircuit":
return self

def cx(self, ctrl: int, tar: int) -> "QuantumCircuit":
"""
Ally of cnot.
"""
return self.cnot(ctrl=ctrl, tar=tar)

def cy(self, ctrl: int, tar: int) -> "QuantumCircuit":
Expand Down Expand Up @@ -640,6 +646,7 @@ def cz(self, ctrl: int, tar: int) -> "QuantumCircuit":
def cs(self, ctrl: int, tar: int) -> "QuantumCircuit":
"""
Control-S gate.

Args:
ctrl (int): control qubit.
tar (int): target qubit.
Expand All @@ -650,6 +657,7 @@ def cs(self, ctrl: int, tar: int) -> "QuantumCircuit":
def ct(self, ctrl: int, tar: int) -> "QuantumCircuit":
"""
Control-T gate.

Args:
ctrl (int): control qubit.
tar (int): target qubit.
Expand Down Expand Up @@ -731,6 +739,7 @@ def barrier(self, qlist: List[int] = None) -> "QuantumCircuit":
def xy(self, qs: int, qe: int, duration: int, unit: str = "ns") -> "QuantumCircuit":
"""
XY resonance time evolution for quantum simulator

Args:
qs: start position of resonant qubits.
qe: end position of resonant qubits.
Expand All @@ -744,6 +753,7 @@ def xy(self, qs: int, qe: int, duration: int, unit: str = "ns") -> "QuantumCircu
def rxx(self, q1: int, q2: int, theta):
"""
Rotation about 2-qubit XX axis.

Args:
q1 (int): qubit the gate act.
q2 (int): qubit the gate act.
Expand All @@ -755,6 +765,7 @@ def rxx(self, q1: int, q2: int, theta):
def ryy(self, q1: int, q2: int, theta):
"""
Rotation about 2-qubit YY axis.

Args:
q1 (int): qubit the gate act.
q2 (int): qubit the gate act.
Expand All @@ -766,6 +777,7 @@ def ryy(self, q1: int, q2: int, theta):
def rzz(self, q1: int, q2: int, theta):
"""
Rotation about 2-qubit ZZ axis.

Args:
q1 (int): qubit the gate act.
q2 (int): qubit the gate act.
Expand All @@ -777,6 +789,7 @@ def rzz(self, q1: int, q2: int, theta):
def mcx(self, ctrls: List[int], targ: int):
"""
Multi-controlled X gate.

Args:
ctrls: A list of control qubits.
targ: Target qubits.
Expand All @@ -786,6 +799,7 @@ def mcx(self, ctrls: List[int], targ: int):
def mcy(self, ctrls: List[int], targ: int):
"""
Multi-controlled Y gate.

Args:
ctrls: A list of control qubits.
targ: Target qubits.
Expand All @@ -795,6 +809,7 @@ def mcy(self, ctrls: List[int], targ: int):
def mcz(self, ctrls: List[int], targ: int):
"""
Multi-controlled Z gate.

Args:
ctrls: A list of control qubits.
targ: Target qubits.
Expand All @@ -811,7 +826,7 @@ def unitary(self, matrix: np.ndarray, pos: List[int]):
"""
compiler = qeg.UnitaryDecomposer(array=matrix, qubits=pos)
compiler.apply_to_qc(self)

def delay(self, pos, duration, unit="ns") -> "QuantumCircuit":
"""
Let the qubit idle for a certain duration.
Expand All @@ -824,7 +839,7 @@ def delay(self, pos, duration, unit="ns") -> "QuantumCircuit":
self.add_ins(Delay(pos, duration, unit=unit))
return self

def reset(self, qlist:List[int]= None) -> "QuantumCircuit":
def reset(self, qlist: List[int] = None) -> "QuantumCircuit":
"""
Add reset for qubits in qlist.

Expand All @@ -838,7 +853,7 @@ def reset(self, qlist:List[int]= None) -> "QuantumCircuit":
self.add_ins(Reset(qlist))
self.executable_on_backend = False
return self

def measure(self, pos: List[int] = None, cbits: List[int] = None) -> None:
"""
Measurement setting for experiment device.
Expand Down Expand Up @@ -877,7 +892,7 @@ def measure(self, pos: List[int] = None, cbits: List[int] = None) -> None:
self.add_ins(measure)

@contextmanager
def cif(self, cbits:List[int], condition:int):
def cif(self, cbits: List[int], condition: int):
"""
Create an `if` statement on this circuit.
If cbits equals to condition, the subsequent operaterations will be performed.
Expand All @@ -904,14 +919,14 @@ def cif(self, cbits:List[int], condition:int):
# check cbits
if not len(set(cbits)) == len(cbits):
raise ValueError("Classical bits not uniquely assigned.")
if max(cbits) > self.cbits_num -1 or min(cbits) < 0:
if max(cbits) > self.cbits_num - 1 or min(cbits) < 0:
raise ValueError("Classical bits index out of range.")
# check condition
if condition < 0:
raise ValueError("Classical should be a positive integer.")
self.executable_on_backend = False
cif_ins = Cif(cbits=cbits, condition=condition)
self.add_ins(cif_ins)
self.add_ins(cif_ins)

yield

Expand All @@ -920,7 +935,7 @@ def cif(self, cbits:List[int], condition:int):
if isinstance(self.instructions[i], Cif) and self.instructions[i].instructions is None:
instructions.reverse()
self.instructions[i].set_ins(instructions)
self.instructions = self.instructions[0:i+1]
self.instructions = self.instructions[0:i + 1]
return
else:
instructions.append(self.instructions[i])
Expand All @@ -933,4 +948,3 @@ def add_pulse(self, pulse: QuantumPulse, pos: int = None) -> "QuantumCircuit":
pulse.set_pos(pos)
self.add_ins(pulse)
return self

Loading
Loading