Skip to content

Commit

Permalink
Merge pull request #113 from chensgit169/master
Browse files Browse the repository at this point in the history
Pick ahead features of ``elements`` from stable/0.3 branch
  • Loading branch information
Zhaoyilunnn authored Nov 20, 2023
2 parents fb2d5d1 + 182782c commit 3c4ba6b
Show file tree
Hide file tree
Showing 34 changed files with 1,110 additions and 756 deletions.
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

0 comments on commit 3c4ba6b

Please sign in to comment.